diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index 019f8b6bf6..6a2fede355 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -74,7 +74,49 @@ function current_time( $type, $gmt = 0 ) { } /** - * Retrieve the date in localized format, based on a sum of Unix timestamp and + * Retrieves the timezone from current settings as a string. + * + * Uses the `timezone_string` option to get a proper timezone if available, + * otherwise falls back to an offset. + * + * @since 5.3.0 + * + * @return string PHP timezone string or a ±HH:MM offset. + */ +function wp_timezone_string() { + $timezone_string = get_option( 'timezone_string' ); + + if ( $timezone_string ) { + return $timezone_string; + } + + $offset = (float) get_option( 'gmt_offset' ); + $hours = (int) $offset; + $minutes = ( $offset - $hours ); + + $sign = ( $offset < 0 ) ? '-' : '+'; + $abs_hour = abs( $hours ); + $abs_mins = abs( $minutes * 60 ); + $tz_offset = sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins ); + + return $tz_offset; +} + +/** + * Retrieves the timezone from current settings as a `DateTimeZone` object. + * + * Timezone can be based on a PHP timezone string or a ±HH:MM offset. + * + * @since 5.3.0 + * + * @return DateTimeZone Timezone object. + */ +function wp_timezone() { + return new DateTimeZone( wp_timezone_string() ); +} + +/** + * Retrieves the date in localized format, based on a sum of Unix timestamp and * timezone offset in seconds. * * If the locale specifies the locale month and weekday, then the locale will diff --git a/tests/phpunit/tests/date/wpTimezone.php b/tests/phpunit/tests/date/wpTimezone.php new file mode 100644 index 0000000000..6df378ca7c --- /dev/null +++ b/tests/phpunit/tests/date/wpTimezone.php @@ -0,0 +1,111 @@ +assertEquals( $tz_name, wp_timezone_string() ); + + $timezone = wp_timezone(); + + $this->assertEquals( $tz_name, $timezone->getName() ); + } + + /** + * @ticket 24730 + */ + public function test_should_return_timezone_string() { + update_option( 'timezone_string', 'Europe/Kiev' ); + + $this->assertEquals( 'Europe/Kiev', wp_timezone_string() ); + + $timezone = wp_timezone(); + + $this->assertEquals( 'Europe/Kiev', $timezone->getName() ); + } + + /** + * Data provider to test numeric offset conversion. + * + * @return array + */ + public function timezone_offset_provider() { + + return [ + [ - 12, '-12:00' ], + [ - 11.5, '-11:30' ], + [ - 11, '-11:00' ], + [ - 10.5, '-10:30' ], + [ - 10, '-10:00' ], + [ - 9.5, '-09:30' ], + [ - 9, '-09:00' ], + [ - 8.5, '-08:30' ], + [ - 8, '-08:00' ], + [ - 7.5, '-07:30' ], + [ - 7, '-07:00' ], + [ - 6.5, '-06:30' ], + [ - 6, '-06:00' ], + [ - 5.5, '-05:30' ], + [ - 5, '-05:00' ], + [ - 4.5, '-04:30' ], + [ - 4, '-04:00' ], + [ - 3.5, '-03:30' ], + [ - 3, '-03:00' ], + [ - 2.5, '-02:30' ], + [ - 2, '-02:00' ], + [ '-1.5', '-01:30' ], + [ - 1.5, '-01:30' ], + [ - 1, '-01:00' ], + [ - 0.5, '-00:30' ], + [ 0, '+00:00' ], + [ '0', '+00:00' ], + [ 0.5, '+00:30' ], + [ 1, '+01:00' ], + [ 1.5, '+01:30' ], + [ '1.5', '+01:30' ], + [ 2, '+02:00' ], + [ 2.5, '+02:30' ], + [ 3, '+03:00' ], + [ 3.5, '+03:30' ], + [ 4, '+04:00' ], + [ 4.5, '+04:30' ], + [ 5, '+05:00' ], + [ 5.5, '+05:30' ], + [ 5.75, '+05:45' ], + [ 6, '+06:00' ], + [ 6.5, '+06:30' ], + [ 7, '+07:00' ], + [ 7.5, '+07:30' ], + [ 8, '+08:00' ], + [ 8.5, '+08:30' ], + [ 8.75, '+08:45' ], + [ 9, '+09:00' ], + [ 9.5, '+09:30' ], + [ 10, '+10:00' ], + [ 10.5, '+10:30' ], + [ 11, '+11:00' ], + [ 11.5, '+11:30' ], + [ 12, '+12:00' ], + [ 12.75, '+12:45' ], + [ 13, '+13:00' ], + [ 13.75, '+13:45' ], + [ 14, '+14:00' ], + ]; + } +} + +