WordPress.org

Make WordPress Core

Changeset 46580


Ignore:
Timestamp:
10/25/2019 01:06:29 PM (2 years ago)
Author:
SergeyBiryukov
Message:

Date/Time: Make sure get_post_time() keeps UTC time on timezone change.

Add $source parameter to get_post_datetime() to instantiate from local or UTC time in database.

Props Rarst, david.binda.
Reviewed by azaozz, SergeyBiryukov.
Fixes #48384.

Location:
trunk
Files:
2 edited

Legend:

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

    r46290 r46580  
    25662566    }
    25672567
    2568     $datetime = get_post_datetime( $post );
     2568    $source   = ( $gmt ) ? 'gmt' : 'local';
     2569    $datetime = get_post_datetime( $post, 'date', $source );
    25692570
    25702571    if ( false === $datetime ) {
     
    26072608 * The object will be set to the timezone from WordPress settings.
    26082609 *
     2610 * For legacy reasons, this function allows to choose to instantiate from local or UTC time in database.
     2611 * Normally this should make no difference to the result. However, the values might get out of sync in database,
     2612 * typically because of timezone setting changes. The parameter ensures the ability to reproduce backwards
     2613 * compatible behaviors in such cases.
     2614 *
    26092615 * @since 5.3.0
    26102616 *
    2611  * @param int|WP_Post $post  Optional. WP_Post object or ID. Default is global `$post` object.
    2612  * @param string      $field Optional. Post field to use. Accepts 'date' or 'modified'.
     2617 * @param int|WP_Post $post   Optional. WP_Post object or ID. Default is global `$post` object.
     2618 * @param string      $field  Optional. Published or modified time to use from database. Accepts 'date' or 'modified'.
     2619 *                            Default 'date'.
     2620 * @param string      $source Optional. Local or UTC time to use from database. Accepts 'local' or 'gmt'.
     2621 *                            Default 'local'.
    26132622 * @return DateTimeImmutable|false Time object on success, false on failure.
    26142623 */
    2615 function get_post_datetime( $post = null, $field = 'date' ) {
     2624function get_post_datetime( $post = null, $field = 'date', $source = 'local' ) {
    26162625    $post = get_post( $post );
    26172626
     
    26202629    }
    26212630
    2622     $time = ( 'modified' === $field ) ? $post->post_modified : $post->post_date;
     2631    $wp_timezone = wp_timezone();
     2632
     2633    if ( 'gmt' === $source ) {
     2634        $time     = ( 'modified' === $field ) ? $post->post_modified_gmt : $post->post_date_gmt;
     2635        $timezone = new DateTimeZone( 'UTC' );
     2636    } else {
     2637        $time     = ( 'modified' === $field ) ? $post->post_modified : $post->post_date;
     2638        $timezone = $wp_timezone;
     2639    }
    26232640
    26242641    if ( empty( $time ) || '0000-00-00 00:00:00' === $time ) {
     
    26262643    }
    26272644
    2628     return date_create_immutable_from_format( 'Y-m-d H:i:s', $time, wp_timezone() );
     2645    $datetime = date_create_immutable_from_format( 'Y-m-d H:i:s', $time, $timezone );
     2646
     2647    if ( false === $datetime ) {
     2648        return false;
     2649    }
     2650
     2651    return $datetime->setTimezone( $wp_timezone );
    26292652}
    26302653
     
    26382661 *
    26392662 * @param int|WP_Post $post  Optional. WP_Post object or ID. Default is global `$post` object.
    2640  * @param string      $field Optional. Post field to use. Accepts 'date' or 'modified'.
     2663 * @param string      $field Optional. Published or modified time to use from database. Accepts 'date' or 'modified'.
     2664 *                           Default 'date'.
    26412665 * @return int|false Unix timestamp on success, false on failure.
    26422666 */
     
    27302754    }
    27312755
    2732     $datetime = get_post_datetime( $post, 'modified' );
     2756    $source   = ( $gmt ) ? 'gmt' : 'local';
     2757    $datetime = get_post_datetime( $post, 'modified', $source );
    27332758
    27342759    if ( false === $datetime ) {
  • trunk/tests/phpunit/tests/date/postTime.php

    r46154 r46580  
    6363        $this->assertEquals( $rfc3339_utc, get_post_modified_time( DATE_RFC3339, true, $post_id, true ) );
    6464    }
     65
     66    /**
     67     * @ticket 48384
     68     */
     69    public function test_should_keep_utc_time_on_timezone_change_with_gmt_offset() {
     70        // Set the timezone to UTC+0.
     71        update_option( 'gmt_offset', 0 );
     72
     73        $datetime = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );
     74        $mysql    = $datetime->format( 'Y-m-d H:i:s' );
     75        $rfc3339  = $datetime->format( DATE_RFC3339 );
     76        $post_id  = self::factory()->post->create(
     77            array(
     78                'post_date'     => $mysql,
     79                'post_modified' => $mysql,
     80            )
     81        );
     82
     83        // Change the timezone to UTC+2.
     84        update_option( 'gmt_offset', 2 );
     85
     86        $this->assertEquals( $rfc3339, get_post_time( DATE_RFC3339, true, $post_id ) );
     87        $this->assertEquals( $rfc3339, get_post_modified_time( DATE_RFC3339, true, $post_id ) );
     88    }
     89
     90    /**
     91     * @ticket 48384
     92     */
     93    public function test_should_keep_utc_time_on_timezone_change() {
     94        $timezone = 'UTC';
     95        update_option( 'timezone_string', $timezone );
     96
     97        $datetime = new DateTimeImmutable( 'now', new DateTimeZone( $timezone ) );
     98        $mysql    = $datetime->format( 'Y-m-d H:i:s' );
     99        $rfc3339  = $datetime->format( DATE_RFC3339 );
     100        $post_id  = self::factory()->post->create(
     101            array(
     102                'post_date'     => $mysql,
     103                'post_modified' => $mysql,
     104            )
     105        );
     106
     107        update_option( 'timezone_string', 'Europe/Kiev' );
     108
     109        $this->assertEquals( $rfc3339, get_post_time( DATE_RFC3339, true, $post_id ) );
     110        $this->assertEquals( $rfc3339, get_post_modified_time( DATE_RFC3339, true, $post_id ) );
     111    }
    65112}
Note: See TracChangeset for help on using the changeset viewer.