diff options
author | Sergey Biryukov <sergeybiryukov@git.wordpress.org> | 2019-10-25 13:06:29 +0000 |
---|---|---|
committer | Sergey Biryukov <sergeybiryukov@git.wordpress.org> | 2019-10-25 13:06:29 +0000 |
commit | c67b47c66ed357287a44f07ae93f6c139c5cdd17 (patch) | |
tree | 36eb6e3e10d1f9eae3417a5f8f4ab40d8036bc43 | |
parent | db4e52b923322155521b054e8079fd1a270af8c7 (diff) | |
download | wordpress-c67b47c66ed357287a44f07ae93f6c139c5cdd17.tar.gz wordpress-c67b47c66ed357287a44f07ae93f6c139c5cdd17.zip |
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.
git-svn-id: https://develop.svn.wordpress.org/trunk@46580 602fd350-edb4-49c9-b593-d223f7449a82
-rw-r--r-- | src/wp-includes/general-template.php | 41 | ||||
-rw-r--r-- | tests/phpunit/tests/date/postTime.php | 47 |
2 files changed, 80 insertions, 8 deletions
diff --git a/src/wp-includes/general-template.php b/src/wp-includes/general-template.php index 32d5595bb1..f9b5661f09 100644 --- a/src/wp-includes/general-template.php +++ b/src/wp-includes/general-template.php @@ -2565,7 +2565,8 @@ function get_post_time( $d = 'U', $gmt = false, $post = null, $translate = false return false; } - $datetime = get_post_datetime( $post ); + $source = ( $gmt ) ? 'gmt' : 'local'; + $datetime = get_post_datetime( $post, 'date', $source ); if ( false === $datetime ) { return false; @@ -2606,26 +2607,48 @@ function get_post_time( $d = 'U', $gmt = false, $post = null, $translate = false * * The object will be set to the timezone from WordPress settings. * + * For legacy reasons, this function allows to choose to instantiate from local or UTC time in database. + * Normally this should make no difference to the result. However, the values might get out of sync in database, + * typically because of timezone setting changes. The parameter ensures the ability to reproduce backwards + * compatible behaviors in such cases. + * * @since 5.3.0 * - * @param int|WP_Post $post Optional. WP_Post object or ID. Default is global `$post` object. - * @param string $field Optional. Post field to use. Accepts 'date' or 'modified'. + * @param int|WP_Post $post Optional. WP_Post object or ID. Default is global `$post` object. + * @param string $field Optional. Published or modified time to use from database. Accepts 'date' or 'modified'. + * Default 'date'. + * @param string $source Optional. Local or UTC time to use from database. Accepts 'local' or 'gmt'. + * Default 'local'. * @return DateTimeImmutable|false Time object on success, false on failure. */ -function get_post_datetime( $post = null, $field = 'date' ) { +function get_post_datetime( $post = null, $field = 'date', $source = 'local' ) { $post = get_post( $post ); if ( ! $post ) { return false; } - $time = ( 'modified' === $field ) ? $post->post_modified : $post->post_date; + $wp_timezone = wp_timezone(); + + if ( 'gmt' === $source ) { + $time = ( 'modified' === $field ) ? $post->post_modified_gmt : $post->post_date_gmt; + $timezone = new DateTimeZone( 'UTC' ); + } else { + $time = ( 'modified' === $field ) ? $post->post_modified : $post->post_date; + $timezone = $wp_timezone; + } if ( empty( $time ) || '0000-00-00 00:00:00' === $time ) { return false; } - return date_create_immutable_from_format( 'Y-m-d H:i:s', $time, wp_timezone() ); + $datetime = date_create_immutable_from_format( 'Y-m-d H:i:s', $time, $timezone ); + + if ( false === $datetime ) { + return false; + } + + return $datetime->setTimezone( $wp_timezone ); } /** @@ -2637,7 +2660,8 @@ function get_post_datetime( $post = null, $field = 'date' ) { * @since 5.3.0 * * @param int|WP_Post $post Optional. WP_Post object or ID. Default is global `$post` object. - * @param string $field Optional. Post field to use. Accepts 'date' or 'modified'. + * @param string $field Optional. Published or modified time to use from database. Accepts 'date' or 'modified'. + * Default 'date'. * @return int|false Unix timestamp on success, false on failure. */ function get_post_timestamp( $post = null, $field = 'date' ) { @@ -2729,7 +2753,8 @@ function get_post_modified_time( $d = 'U', $gmt = false, $post = null, $translat return false; } - $datetime = get_post_datetime( $post, 'modified' ); + $source = ( $gmt ) ? 'gmt' : 'local'; + $datetime = get_post_datetime( $post, 'modified', $source ); if ( false === $datetime ) { return false; diff --git a/tests/phpunit/tests/date/postTime.php b/tests/phpunit/tests/date/postTime.php index 02da7b5487..14115704ae 100644 --- a/tests/phpunit/tests/date/postTime.php +++ b/tests/phpunit/tests/date/postTime.php @@ -62,4 +62,51 @@ class Tests_Date_Post_Time extends WP_UnitTestCase { $this->assertEquals( $rfc3339, get_post_modified_time( DATE_RFC3339, false, $post_id, true ) ); $this->assertEquals( $rfc3339_utc, get_post_modified_time( DATE_RFC3339, true, $post_id, true ) ); } + + /** + * @ticket 48384 + */ + public function test_should_keep_utc_time_on_timezone_change_with_gmt_offset() { + // Set the timezone to UTC+0. + update_option( 'gmt_offset', 0 ); + + $datetime = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) ); + $mysql = $datetime->format( 'Y-m-d H:i:s' ); + $rfc3339 = $datetime->format( DATE_RFC3339 ); + $post_id = self::factory()->post->create( + array( + 'post_date' => $mysql, + 'post_modified' => $mysql, + ) + ); + + // Change the timezone to UTC+2. + update_option( 'gmt_offset', 2 ); + + $this->assertEquals( $rfc3339, get_post_time( DATE_RFC3339, true, $post_id ) ); + $this->assertEquals( $rfc3339, get_post_modified_time( DATE_RFC3339, true, $post_id ) ); + } + + /** + * @ticket 48384 + */ + public function test_should_keep_utc_time_on_timezone_change() { + $timezone = 'UTC'; + update_option( 'timezone_string', $timezone ); + + $datetime = new DateTimeImmutable( 'now', new DateTimeZone( $timezone ) ); + $mysql = $datetime->format( 'Y-m-d H:i:s' ); + $rfc3339 = $datetime->format( DATE_RFC3339 ); + $post_id = self::factory()->post->create( + array( + 'post_date' => $mysql, + 'post_modified' => $mysql, + ) + ); + + update_option( 'timezone_string', 'Europe/Kiev' ); + + $this->assertEquals( $rfc3339, get_post_time( DATE_RFC3339, true, $post_id ) ); + $this->assertEquals( $rfc3339, get_post_modified_time( DATE_RFC3339, true, $post_id ) ); + } } |