Make WordPress Core

Changeset 45887


Ignore:
Timestamp:
08/23/2019 11:02:51 AM (5 years ago)
Author:
SergeyBiryukov
Message:

Date/Time: Rewrite and simplify get_gmt_from_date(), get_date_from_gmt(), and iso8601_to_datetime() using wp_timezone().

Improve unit test coverage.

Props Rarst, goodevilgenius.
Fixes #31809.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/formatting.php

    r45796 r45887  
    33853385 * Returns a date in the GMT equivalent.
    33863386 *
    3387  * Requires and returns a date in the Y-m-d H:i:s format. If there is a
    3388  * timezone_string available, the date is assumed to be in that timezone,
    3389  * otherwise it simply subtracts the value of the 'gmt_offset' option. Return
    3390  * format can be overridden using the $format parameter.
     3387 * Requires and returns a date in the Y-m-d H:i:s format.
     3388 * Return format can be overridden using the $format parameter.
    33913389 *
    33923390 * @since 1.2.0
    33933391 *
    33943392 * @param string $string The date to be converted.
    3395  * @param string $format The format string for the returned date (default is Y-m-d H:i:s)
     3393 * @param string $format The format string for the returned date. Default 'Y-m-d H:i:s'.
    33963394 * @return string GMT version of the date provided.
    33973395 */
    33983396function get_gmt_from_date( $string, $format = 'Y-m-d H:i:s' ) {
    3399     $tz = get_option( 'timezone_string' );
    3400     if ( $tz ) {
    3401         $datetime = date_create( $string, new DateTimeZone( $tz ) );
    3402         if ( ! $datetime ) {
    3403             return gmdate( $format, 0 );
    3404         }
    3405         $datetime->setTimezone( new DateTimeZone( 'UTC' ) );
    3406         $string_gmt = $datetime->format( $format );
    3407     } else {
    3408         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 ) ) {
    3409             $datetime = strtotime( $string );
    3410             if ( false === $datetime ) {
    3411                 return gmdate( $format, 0 );
    3412             }
    3413             return gmdate( $format, $datetime );
    3414         }
    3415         $string_time = gmmktime( $matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1] );
    3416         $string_gmt  = gmdate( $format, $string_time - get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
    3417     }
    3418     return $string_gmt;
     3397    $datetime = date_create( $string, wp_timezone() );
     3398
     3399    if ( false === $datetime ) {
     3400        return gmdate( $format, 0 );
     3401    }
     3402
     3403    return $datetime->setTimezone( new DateTimeZone( 'UTC' ) )->format( $format );
    34193404}
    34203405
     
    34223407 * Converts a GMT date into the correct format for the blog.
    34233408 *
    3424  * Requires and returns a date in the Y-m-d H:i:s format. If there is a
    3425  * timezone_string available, the returned date is in that timezone, otherwise
    3426  * it simply adds the value of gmt_offset. Return format can be overridden
    3427  * using the $format parameter
     3409 * Requires and returns a date in the Y-m-d H:i:s format.
     3410 * Return format can be overridden using the $format parameter.
    34283411 *
    34293412 * @since 1.2.0
    34303413 *
    34313414 * @param string $string The date to be converted.
    3432  * @param string $format The format string for the returned date (default is Y-m-d H:i:s)
    3433  * @return string Formatted date relative to the timezone / GMT offset.
     3415 * @param string $format The format string for the returned date. Default 'Y-m-d H:i:s'.
     3416 * @return string Formatted date relative to the timezone.
    34343417 */
    34353418function get_date_from_gmt( $string, $format = 'Y-m-d H:i:s' ) {
    3436     $tz = get_option( 'timezone_string' );
    3437     if ( $tz ) {
    3438         $datetime = date_create( $string, new DateTimeZone( 'UTC' ) );
    3439         if ( ! $datetime ) {
    3440             return gmdate( $format, 0 );
    3441         }
    3442         $datetime->setTimezone( new DateTimeZone( $tz ) );
    3443         $string_localtime = $datetime->format( $format );
    3444     } else {
    3445         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 ) ) {
    3446             return gmdate( $format, 0 );
    3447         }
    3448         $string_time      = gmmktime( $matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1] );
    3449         $string_localtime = gmdate( $format, $string_time + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
    3450     }
    3451     return $string_localtime;
     3419    $datetime = date_create( $string, new DateTimeZone( 'UTC' ) );
     3420
     3421    if ( false === $datetime ) {
     3422        return gmdate( $format, 0 );
     3423    }
     3424
     3425    return $datetime->setTimezone( wp_timezone() )->format( $format );
    34523426}
    34533427
     
    34743448
    34753449/**
    3476  * Converts an iso8601 date to MySQL DateTime format used by post_date[_gmt].
     3450 * Converts an iso8601 (Ymd\TH:i:sO) date to MySQL DateTime (Y-m-d H:i:s) format used by post_date[_gmt].
    34773451 *
    34783452 * @since 1.5.0
    34793453 *
    34803454 * @param string $date_string Date and time in ISO 8601 format {@link https://en.wikipedia.org/wiki/ISO_8601}.
    3481  * @param string $timezone    Optional. If set to GMT returns the time minus gmt_offset. Default is 'user'.
    3482  * @return string The date and time in MySQL DateTime format - Y-m-d H:i:s.
     3455 * @param string $timezone    Optional. If set to 'gmt' returns the result in UTC. Default 'user'.
     3456 * @return string|bool The date and time in MySQL DateTime format - Y-m-d H:i:s, or false on failure.
    34833457 */
    34843458function iso8601_to_datetime( $date_string, $timezone = 'user' ) {
    3485     $timezone = strtolower( $timezone );
    3486 
    3487     if ( $timezone == 'gmt' ) {
    3488 
    3489         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 );
    3490 
    3491         if ( ! empty( $date_bits[7] ) ) { // we have a timezone, so let's compute an offset
    3492             $offset = iso8601_timezone_to_offset( $date_bits[7] );
    3493         } else { // we don't have a timezone, so we assume user local timezone (not server's!)
    3494             $offset = HOUR_IN_SECONDS * get_option( 'gmt_offset' );
    3495         }
    3496 
    3497         $timestamp  = gmmktime( $date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1] );
    3498         $timestamp -= $offset;
    3499 
    3500         return gmdate( 'Y-m-d H:i:s', $timestamp );
    3501 
    3502     } elseif ( $timezone == 'user' ) {
    3503         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 );
    3504     }
     3459    $timezone    = strtolower( $timezone );
     3460    $wp_timezone = wp_timezone();
     3461    $datetime    = date_create( $date_string, $wp_timezone ); // Timezone is ignored if input has one.
     3462
     3463    if ( false === $datetime ) {
     3464        return false;
     3465    }
     3466
     3467    if ( 'gmt' === $timezone ) {
     3468        return $datetime->setTimezone( new DateTimeZone( 'UTC' ) )->format( 'Y-m-d H:i:s' );
     3469    }
     3470
     3471    if ( 'user' === $timezone ) {
     3472        return $datetime->setTimezone( $wp_timezone )->format( 'Y-m-d H:i:s' );
     3473    }
     3474
     3475    return false;
    35053476}
    35063477
  • trunk/tests/phpunit/tests/formatting/date.php

    r45588 r45887  
    9797        $this->assertEquals( strtotime( $gmt ), strtotime( get_gmt_from_date( $local ) ), 'The dates should be equal', 2 );
    9898    }
     99
     100    /**
     101     * @ticket 31809
     102     *
     103     * @dataProvider timezone_provider
     104     */
     105    public function test_gmt_from_date_correct_time( $timezone_string, $gmt_offset ) {
     106        update_option( 'timezone_string', $timezone_string );
     107        update_option( 'gmt_offset', $gmt_offset );
     108
     109        $local       = new DateTimeImmutable( 'now', wp_timezone() );
     110        $utc         = $local->setTimezone( new DateTimeZone( 'UTC' ) );
     111        $mysql_local = $local->format( 'Y-m-d H:i:s' );
     112
     113        $this->assertEquals( $utc->format( DATE_RFC3339 ), get_gmt_from_date( $mysql_local, DATE_RFC3339 ) );
     114    }
     115
     116    /**
     117     * @ticket 31809
     118     *
     119     * @dataProvider timezone_provider
     120     */
     121    public function test_date_from_gmt_correct_time( $timezone_string, $gmt_offset ) {
     122        update_option( 'timezone_string', $timezone_string );
     123        update_option( 'gmt_offset', $gmt_offset );
     124
     125        $local     = new DateTimeImmutable( 'now', wp_timezone() );
     126        $utc       = $local->setTimezone( new DateTimeZone( 'UTC' ) );
     127        $mysql_utc = $utc->format( 'Y-m-d H:i:s' );
     128
     129        $this->assertEquals( $local->format( DATE_RFC3339 ), get_date_from_gmt( $mysql_utc, DATE_RFC3339 ) );
     130    }
     131
     132    /**
     133     * @ticket 31809
     134     *
     135     * @dataProvider timezone_provider
     136     */
     137    public function test_is8601_to_datetime_correct_time( $timezone_string, $gmt_offset ) {
     138        update_option( 'timezone_string', $timezone_string );
     139        update_option( 'gmt_offset', $gmt_offset );
     140
     141        $format       = 'Ymd\TH:i:sO';
     142        $format_no_tz = 'Ymd\TH:i:s';
     143
     144        $local = new DateTimeImmutable( 'now', wp_timezone() );
     145        $utc   = $local->setTimezone( new DateTimeZone( 'UTC' ) );
     146
     147        $this->assertEquals(
     148            $local->format( 'Y-m-d H:i:s' ),
     149            iso8601_to_datetime( $local->format( $format ) ),
     150            'Local time from local time.'
     151        );
     152        $this->assertEquals(
     153            $utc->format( 'Y-m-d H:i:s' ),
     154            iso8601_to_datetime( $local->format( $format ), 'gmt' ),
     155            'UTC time from local time.'
     156        );
     157
     158        $this->assertEquals(
     159            $local->format( 'Y-m-d H:i:s' ),
     160            iso8601_to_datetime( $local->format( $format_no_tz ) ),
     161            'Local time from local time w/o timezone.'
     162        );
     163        $this->assertEquals(
     164            $utc->format( 'Y-m-d H:i:s' ),
     165            iso8601_to_datetime( $local->format( $format_no_tz ), 'gmt' ),
     166            'UTC time from local time w/o timezone.'
     167        );
     168
     169        $this->assertEquals(
     170            $local->format( 'Y-m-d H:i:s' ),
     171            iso8601_to_datetime( $utc->format( $format ) ),
     172            'Local time from UTC time.'
     173        );
     174        $this->assertEquals(
     175            $utc->format( 'Y-m-d H:i:s' ),
     176            iso8601_to_datetime( $utc->format( $format ), 'gmt' ),
     177            'UTC time from UTC time.'
     178        );
     179
     180        $this->assertEquals(
     181            $local->format( 'Y-m-d H:i:s' ),
     182            iso8601_to_datetime( $utc->format( $format_no_tz ) . 'Z' ),
     183            'Local time from UTC w/ Z timezone.'
     184        );
     185        $this->assertEquals(
     186            $utc->format( 'Y-m-d H:i:s' ),
     187            iso8601_to_datetime( $utc->format( $format_no_tz ) . 'Z', 'gmt' ),
     188            'UTC time from UTC w/ Z timezone.'
     189        );
     190    }
     191
     192    /**
     193     * Data provider to test different timezone modes.
     194     *
     195     * @return array
     196     */
     197    public function timezone_provider() {
     198        return array(
     199            array(
     200                'timezone_string' => 'Europe/Kiev',
     201                'gmt_offset'      => 3,
     202            ),
     203            array(
     204                'timezone_string' => '',
     205                'gmt_offset'      => 3,
     206            ),
     207        );
     208    }
    99209}
Note: See TracChangeset for help on using the changeset viewer.