From 91f60afbe51feb939144aa06d37017a4b6e1a516 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Mon, 19 Aug 2019 21:05:42 +0000 Subject: [PATCH] Date/Time: Use PHP `DateTime` class API in `current_time()`. Only use the legacy WP timestamp approach (a sum of timestamp and timezone offset) for `timestamp` and `U` formats without the `$gmt` flag. Otherwise, make sure the function returns correct local time for any format. Props Rarst, jdgrimes. Fixes #40653. git-svn-id: https://develop.svn.wordpress.org/trunk@45856 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/functions.php | 24 ++++++++++------ tests/phpunit/tests/date/currentTime.php | 36 +++++++++++++++++++++++- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index 8e17499be0..857d16fd60 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -46,10 +46,11 @@ function mysql2date( $format, $date, $translate = true ) { } /** - * Retrieve the current time based on specified type. + * Retrieves the current time based on specified type. * * The 'mysql' type will return the time in the format for MySQL DATETIME field. - * The 'timestamp' type will return the current timestamp. + * The 'timestamp' type will return the current timestamp or a sum of timestamp + * and timezone offset, depending on `$gmt`. * Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d'). * * If $gmt is set to either '1' or 'true', then both types will use GMT time. @@ -63,14 +64,19 @@ function mysql2date( $format, $date, $translate = true ) { * @return int|string Integer if $type is 'timestamp', string otherwise. */ function current_time( $type, $gmt = 0 ) { - switch ( $type ) { - case 'mysql': - return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', ( time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ) ); - case 'timestamp': - return ( $gmt ) ? time() : time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ); - default: - return ( $gmt ) ? gmdate( $type ) : gmdate( $type, time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ); + // Don't use non-GMT timestamp, unless you know the difference and really need to. + if ( 'timestamp' === $type || 'U' === $type ) { + return $gmt ? time() : time() + (int) ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ); } + + if ( 'mysql' === $type ) { + $type = 'Y-m-d H:i:s'; + } + + $timezone = $gmt ? new DateTimeZone( 'UTC' ) : wp_timezone(); + $datetime = new DateTime( 'now', $timezone ); + + return $datetime->format( $type ); } /** diff --git a/tests/phpunit/tests/date/currentTime.php b/tests/phpunit/tests/date/currentTime.php index 209eb128c6..7cc88dbe3e 100644 --- a/tests/phpunit/tests/date/currentTime.php +++ b/tests/phpunit/tests/date/currentTime.php @@ -6,8 +6,10 @@ */ class Tests_Date_CurrentTime extends WP_UnitTestCase { + /** + * @ticket 37440 + */ public function test_should_work_with_changed_timezone() { - $format = 'Y-m-d H:i:s'; $timezone_string = 'America/Regina'; update_option( 'timezone_string', $timezone_string ); @@ -21,4 +23,36 @@ class Tests_Date_CurrentTime extends WP_UnitTestCase { $this->assertEquals( gmdate( $format ), current_time( $format, true ) ); $this->assertEquals( $datetime->format( $format ), current_time( $format ) ); } + + /** + * @ticket 40653 + */ + public function test_should_return_wp_timestamp() { + update_option( 'timezone_string', 'Europe/Kiev' ); + $timestamp = time(); + $datetime = new DateTime( '@' . $timestamp ); + $datetime->setTimezone( wp_timezone() ); + $wp_timestamp = $timestamp + $datetime->getOffset(); + + $this->assertEquals( $timestamp, current_time( 'timestamp', true ), '', 2 ); + $this->assertEquals( $timestamp, current_time( 'U', true ), '', 2 ); + $this->assertEquals( $wp_timestamp, current_time( 'timestamp' ), '', 2 ); + $this->assertEquals( $wp_timestamp, current_time( 'U' ), '', 2 ); + $this->assertInternalType( 'int', current_time( 'timestamp' ) ); + } + + /** + * @ticket 40653 + */ + public function test_should_return_correct_local_time() { + update_option( 'timezone_string', 'Europe/Kiev' ); + $timestamp = time(); + $datetime_local = new DateTime( '@' . $timestamp ); + $datetime_local->setTimezone( wp_timezone() ); + $datetime_utc = new DateTime( '@' . $timestamp ); + $datetime_utc->setTimezone( new DateTimeZone( 'UTC' ) ); + + $this->assertEquals( $datetime_local->format( DATE_W3C ), current_time( DATE_W3C ), '', 2 ); + $this->assertEquals( $datetime_utc->format( DATE_W3C ), current_time( DATE_W3C, true ), '', 2 ); + } }