WordPress.org

Make WordPress Core

Ticket #31809: date-converting-functions.patch

File date-converting-functions.patch, 9.8 KB (added by Rarst, 5 months ago)

Needs wp_timezone() merged.

  • src/wp-includes/formatting.php

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
     
    33793379/**
    33803380 * Returns a date in the GMT equivalent.
    33813381 *
    3382  * Requires and returns a date in the Y-m-d H:i:s format. If there is a
    3383  * timezone_string available, the date is assumed to be in that timezone,
    3384  * otherwise it simply subtracts the value of the 'gmt_offset' option. Return
    3385  * format can be overridden using the $format parameter.
    3386  *
    3387  * @since 1.2.0
     3382 * Requires and returns a date in the Y-m-d H:i:s format.
     3383 * Return format can be overridden using the $format parameter.
    33883384 *
    33893385 * @param string $string The date to be converted.
    33903386 * @param string $format The format string for the returned date (default is Y-m-d H:i:s)
     3387 *
    33913388 * @return string GMT version of the date provided.
     3389 *
     3390 * @since 1.2.0
    33923391 */
    33933392function get_gmt_from_date( $string, $format = 'Y-m-d H:i:s' ) {
    3394         $tz = get_option( 'timezone_string' );
    3395         if ( $tz ) {
    3396                 $datetime = date_create( $string, new DateTimeZone( $tz ) );
    3397                 if ( ! $datetime ) {
    3398                         return gmdate( $format, 0 );
    3399                 }
    3400                 $datetime->setTimezone( new DateTimeZone( 'UTC' ) );
    3401                 $string_gmt = $datetime->format( $format );
    3402         } else {
    3403                 if ( ! preg_match( '#([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2}) ([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})#', $string, $matches ) ) {
    3404                         $datetime = strtotime( $string );
    3405                         if ( false === $datetime ) {
    3406                                 return gmdate( $format, 0 );
    3407                         }
    3408                         return gmdate( $format, $datetime );
    3409                 }
    3410                 $string_time = gmmktime( $matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1] );
    3411                 $string_gmt  = gmdate( $format, $string_time - get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
     3393
     3394        $datetime = date_create( $string, wp_timezone() );
     3395
     3396        if ( false === $datetime ) {
     3397                return gmdate( $format, 0 );
    34123398        }
    3413         return $string_gmt;
     3399
     3400        return $datetime->setTimezone( new DateTimeZone( 'UTC' ) )->format( $format );
    34143401}
    34153402
    34163403/**
    34173404 * Converts a GMT date into the correct format for the blog.
    34183405 *
    3419  * Requires and returns a date in the Y-m-d H:i:s format. If there is a
    3420  * timezone_string available, the returned date is in that timezone, otherwise
    3421  * it simply adds the value of gmt_offset. Return format can be overridden
    3422  * using the $format parameter
    3423  *
    3424  * @since 1.2.0
     3406 * Requires and returns a date in the Y-m-d H:i:s format.
     3407 * Return format can be overridden using the $format parameter
    34253408 *
    34263409 * @param string $string The date to be converted.
    34273410 * @param string $format The format string for the returned date (default is Y-m-d H:i:s)
    3428  * @return string Formatted date relative to the timezone / GMT offset.
     3411 *
     3412 * @return string Formatted date relative to the timezone.
     3413 *
     3414 * @since 1.2.0
    34293415 */
    34303416function get_date_from_gmt( $string, $format = 'Y-m-d H:i:s' ) {
    3431         $tz = get_option( 'timezone_string' );
    3432         if ( $tz ) {
    3433                 $datetime = date_create( $string, new DateTimeZone( 'UTC' ) );
    3434                 if ( ! $datetime ) {
    3435                         return gmdate( $format, 0 );
    3436                 }
    3437                 $datetime->setTimezone( new DateTimeZone( $tz ) );
    3438                 $string_localtime = $datetime->format( $format );
    3439         } else {
    3440                 if ( ! preg_match( '#([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2}) ([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})#', $string, $matches ) ) {
    3441                         return gmdate( $format, 0 );
    3442                 }
    3443                 $string_time      = gmmktime( $matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1] );
    3444                 $string_localtime = gmdate( $format, $string_time + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
     3417
     3418        $datetime = date_create( $string, new DateTimeZone( 'UTC' ) );
     3419
     3420        if ( false === $datetime ) {
     3421                return gmdate( $format, 0 );
    34453422        }
    3446         return $string_localtime;
     3423
     3424        return $datetime->setTimezone( wp_timezone() )->format( $format );
    34473425}
    34483426
    34493427/**
     
    34683446}
    34693447
    34703448/**
    3471  * Converts an iso8601 date to MySQL DateTime format used by post_date[_gmt].
     3449 * Converts an iso8601 (Ymd\TH:i:sO) date to MySQL DateTime (Y-m-d H:i:s) format used by post_date[_gmt].
    34723450 *
    34733451 * @since 1.5.0
    34743452 *
    34753453 * @param string $date_string Date and time in ISO 8601 format {@link https://en.wikipedia.org/wiki/ISO_8601}.
    3476  * @param string $timezone    Optional. If set to GMT returns the time minus gmt_offset. Default is 'user'.
    3477  * @return string The date and time in MySQL DateTime format - Y-m-d H:i:s.
     3454 * @param string $timezone    Optional. If set to 'gmt' returns result in UTC. Default is 'user'.
     3455 *
     3456 * @return string|bool The date and time in MySQL DateTime format - Y-m-d H:i:s or false on failure.
    34783457 */
    34793458function iso8601_to_datetime( $date_string, $timezone = 'user' ) {
    3480         $timezone = strtolower( $timezone );
     3459
     3460        $timezone    = strtolower( $timezone );
     3461        $wp_timezone = wp_timezone();
     3462        $datetime    = date_create( $date_string, $wp_timezone ); // Time zone is ignored if input has one.
    34813463
    3482         if ( $timezone == 'gmt' ) {
     3464        if ( false === $datetime ) {
     3465                return false;
     3466        }
    34833467
    3484                 preg_match( '#([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(Z|[\+|\-][0-9]{2,4}){0,1}#', $date_string, $date_bits );
     3468        if ( 'gmt' === $timezone ) {
     3469                return $datetime->setTimezone( new DateTimeZone( 'UTC' ) )->format( 'Y-m-d H:i:s' );
     3470        }
    34853471
    3486                 if ( ! empty( $date_bits[7] ) ) { // we have a timezone, so let's compute an offset
    3487                         $offset = iso8601_timezone_to_offset( $date_bits[7] );
    3488                 } else { // we don't have a timezone, so we assume user local timezone (not server's!)
    3489                         $offset = HOUR_IN_SECONDS * get_option( 'gmt_offset' );
    3490                 }
     3472        if ( 'user' === $timezone ) {
     3473                return $datetime->setTimezone( $wp_timezone )->format( 'Y-m-d H:i:s' );
     3474        }
    34913475
    3492                 $timestamp  = gmmktime( $date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1] );
    3493                 $timestamp -= $offset;
    3494 
    3495                 return gmdate( 'Y-m-d H:i:s', $timestamp );
    3496 
    3497         } elseif ( $timezone == 'user' ) {
    3498                 return preg_replace( '#([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(Z|[\+|\-][0-9]{2,4}){0,1}#', '$1-$2-$3 $4:$5:$6', $date_string );
    3499         }
     3476        return false;
    35003477}
    35013478
    35023479/**
  • tests/phpunit/tests/formatting/date.php

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
     
    9393                $gmt   = gmdate( 'Y-m-d H:i:s' );
    9494                $this->assertEquals( strtotime( $gmt ), strtotime( get_gmt_from_date( $local ) ), 'The dates should be equal', 2 );
    9595        }
     96
     97        /**
     98         * @dataProvider timezone_provider
     99         */
     100        public function test_gmt_from_date_correct_time( $timezone_string, $gmt_offset ) {
     101
     102                update_option( 'timezone_string', $timezone_string );
     103                update_option( 'gmt_offset', $gmt_offset );
     104
     105                $local       = new DateTimeImmutable( 'now', wp_timezone() );
     106                $utc         = $local->setTimezone( new DateTimeZone( 'UTC' ) );
     107                $mysql_local = $local->format( 'Y-m-d H:i:s' );
     108
     109                $this->assertEquals( $utc->format( DATE_RFC3339 ), get_gmt_from_date( $mysql_local, DATE_RFC3339 ) );
     110        }
     111
     112        /**
     113         * @dataProvider timezone_provider
     114         */
     115        public function test_date_from_gmt_correct_time( $timezone_string, $gmt_offset ) {
     116
     117                update_option( 'timezone_string', $timezone_string );
     118                update_option( 'gmt_offset', $gmt_offset );
     119
     120                $local     = new DateTimeImmutable( 'now', wp_timezone() );
     121                $utc       = $local->setTimezone( new DateTimeZone( 'UTC' ) );
     122                $mysql_utc = $utc->format( 'Y-m-d H:i:s' );
     123
     124                $this->assertEquals( $local->format( DATE_RFC3339 ), get_date_from_gmt( $mysql_utc, DATE_RFC3339 ) );
     125        }
     126
     127        /**
     128         * @dataProvider timezone_provider
     129         */
     130        public function test_is8601_to_datetime_correct_time( $timezone_string, $gmt_offset ) {
     131
     132                update_option( 'timezone_string', $timezone_string );
     133                update_option( 'gmt_offset', $gmt_offset );
     134
     135                $format       = 'Ymd\TH:i:sO';
     136                $format_no_tz = 'Ymd\TH:i:s';
     137
     138                $local = new DateTimeImmutable( 'now', wp_timezone() );
     139                $utc   = $local->setTimezone( new DateTimeZone( 'UTC' ) );
     140
     141                $this->assertEquals(
     142                        $local->format( 'Y-m-d H:i:s' ),
     143                        iso8601_to_datetime( $local->format( $format ) ),
     144                        'Local time from local time.'
     145                );
     146                $this->assertEquals(
     147                        $utc->format( 'Y-m-d H:i:s' ),
     148                        iso8601_to_datetime( $local->format( $format ), 'gmt' ),
     149                        'UTC time from local time.'
     150                );
     151
     152                $this->assertEquals(
     153                        $local->format( 'Y-m-d H:i:s' ),
     154                        iso8601_to_datetime( $local->format( $format_no_tz ) ),
     155                        'Local time from local time w/o timezone.'
     156                );
     157                $this->assertEquals(
     158                        $utc->format( 'Y-m-d H:i:s' ),
     159                        iso8601_to_datetime( $local->format( $format_no_tz ), 'gmt' ),
     160                        'UTC time from local time w/o timezone.'
     161                );
     162
     163                $this->assertEquals(
     164                        $local->format( 'Y-m-d H:i:s' ),
     165                        iso8601_to_datetime( $utc->format( $format ) ),
     166                        'Local time from UTC time.'
     167                );
     168                $this->assertEquals(
     169                        $utc->format( 'Y-m-d H:i:s' ),
     170                        iso8601_to_datetime( $utc->format( $format ), 'gmt' ),
     171                        'UTC time from UTC time.'
     172                );
     173
     174                $this->assertEquals(
     175                        $local->format( 'Y-m-d H:i:s' ),
     176                        iso8601_to_datetime( $utc->format( $format_no_tz ) . 'Z' ),
     177                        'Local time from UTC w/ Z timezone.'
     178                );
     179                $this->assertEquals(
     180                        $utc->format( 'Y-m-d H:i:s' ),
     181                        iso8601_to_datetime( $utc->format( $format_no_tz ) . 'Z', 'gmt' ),
     182                        'UTC time from UTC w/ Z timezone.'
     183                );
     184        }
     185
     186        /**
     187         * Data provider to test different timezone modes..
     188         *
     189         * @return array
     190         */
     191        public function timezone_provider() {
     192                return [
     193                        [
     194                                'timezone_string' => 'Europe/Kiev',
     195                                'gmt_offset'      => 3,
     196                        ],
     197                        [
     198                                'timezone_string' => '',
     199                                'gmt_offset'      => 3,
     200                        ],
     201                ];
     202        }
    96203}