Last active
March 6, 2017 20:24
-
-
Save dfwood/6196705 to your computer and use it in GitHub Desktop.
Datetime conversion functions for WordPress using the ISO8601 standard.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Why does this exist? http://xkcd.com/1179/ also because it makes sense to have a standard way in WordPress to work with | |
* dates and times so that plugin developers can create plugins that will work in any timezone worldwide. | |
* | |
* WordPress sets the default timezone during execution to UTC, reguardless of what the server is set to. | |
* This means that date( 'FORMAT' ) will always give you the current time in UTC, not the timezone you have set | |
* in the WP admin settings. Use date( 'FORMAT', current_time( 'timestamp' ) ) instead to get WP local time. Likewise, | |
* use current_time( 'timestamp' ) instead of time() for the local time. | |
*/ | |
/** | |
* Changes the timezone on an ISO 8601 formatted datetime string to GMT | |
* | |
* @param string $date_string ISO 8601 formatted date string (e.g. 2012-12-21T13:52-05:00 would be Dec. 21, 2012, at 1:52PM EST) | |
* @return string Returns ISO 8601 formatted date string in GMT/UTC time (+00:00 timezone) | |
*/ | |
function iso8601_to_gmt( $date_string ) { | |
// Split the datetime into individual items | |
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}:?[0-9]{2}?){0,1}#', $date_string, $date_bits ); | |
if ( ! empty( $date_bits[7] ) ) { // we have a timezone, so let's compute an offset | |
$date_bits[7] = str_replace( ':', '', $date_bits[7] ); // Make sure this is in the right format for the iso8601_timezone_to_offset() function ( no colon ( : ) ) | |
$offset = iso8601_timezone_to_offset( $date_bits[7] ); | |
} else { // we don't have a timezone, so we assume user local timezone (not server's!) | |
$offset = HOUR_IN_SECONDS * get_option( 'gmt_offset' ); | |
} | |
$timestamp = gmmktime( $date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1] ); | |
$timestamp -= $offset; | |
return gmdate( 'c', $timestamp ); | |
} | |
/** | |
* Changes an ISO 8601 formatted date from GMT/UTC (+00:00) to WordPress' set time or the timezone supplied. | |
* | |
* @param string $date_string ISO 8601 formatted datetime in GMT/UTC | |
* @param string $format The format you want the date to be returned in, defaults to ISO 8601. See http://php.net/manual/en/function.date.php for formatting options | |
* @param string|null $tzID The timezone identifier of the timezone to convert to, see http://php.net/manual/en/timezones.php, defaults to what is set in the WP admin | |
* @return string Returns formatted date string in either WordPress' local time or the specified offset | |
*/ | |
function iso8601_gmt_to_local( $date_string, $format = 'c', $tzID = null ) { | |
if ( null === $tzID ) { | |
$tzID = get_option( 'timezone_string' ); | |
} | |
if ( null === $tzID ) { | |
$offset = ( get_option( 'gmt_offset' ) * -1 ); | |
$tzID = 'Etc/GMT' . ( ( 0 > $offset ) ? $offset : '+' . $offset ); // This line is here for compatibility reasons | |
} | |
$tz = new DateTimeZone( $tzID ); | |
$date = DateTime::createFromFormat( 'U', strtotime( $date_string ) ); | |
$date->setTimezone( $tz ); | |
return $date->format( $format ); | |
} | |
/** | |
* Changes an ISO 8601 formatted date to WordPress' set time or the timezone supplied. | |
* | |
* @param string $date_string ISO 8601 formatted datetime | |
* @param string $format The format you want the date to be returned in, defaults to ISO 8601. See http://php.net/manual/en/function.date.php for formatting options | |
* @param string|null $tzID The timezone identifier of the timezone to convert to, see http://php.net/manual/en/timezones.php, defaults to what is set in the WP admin | |
* @return string Returns formatted date string in either WordPress' local time or the specified offset | |
*/ | |
function iso8601_to_local( $date_string, $format = 'c', $tzID = null ) { | |
return iso8601_gmt_to_local( iso8601_to_gmt( $date_string ), $format, $tzID ); | |
} |
Lines 48 - 50 can be condensed to this:
$date = DateTime::createFromFormat( 'U', strtotime( $date_string ), new DateTimeZone( $tzID ) );
NOTE: In actual testing, this didn't seem to properly set the timezone.
So rewriting the iso8601_gmt_to_local() function would look like this:
function iso8601_gmt_to_local( $date_string, $format = 'c', $timezone = null ) {
$timezone = is_null( $timezone ) ? get_timezone() : $timezone;
$date = DateTime::createFromFormat( 'U', strtotime( $date_string ) );
$date->setTimezone( new DateTimeZone( $timezone ) );
return $date->format( $format );
}
https://gist.github.com/dfwood90/6196705#file-wp-iso8601-datetime-php-L46
I believe this should be 'Etc/GMT' . ( ( $offset < 0 ) ? $offset : '+' . $offset );
should it not?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I think we need a separate function that reliably gets the correct timezone string. This function should be called in the place of lines 41 - 47 in your code above if the user doesn't explicitly set the timezone.
This is what I have come up with: