Do not change the default timezone from UTC in WordPress

I discovered something a bit surprising about WordPress related to timezones: WordPress explicitly sets and expects the default timezone to be UTC (in settings.php) and the date/time functions sometimes rely on the fact that the default timezone is UTC. For instance if you do date_default_timezone_set(get_option('timezone_string')) and then later try to get a GMT timestamp from get_post_time() or get_post_modified_time(), it will fail to give you the right date.

So from calling $timestamp = get_post_time('U', true /*GMT*/), if we step up into core:

function get_post_time( $d = 'U', $gmt = false, $post = null, $translate = false ) { // returns timestamp
	$post = get_post($post);

	if ( $gmt )
		$time = $post->post_date_gmt;
	else
		$time = $post->post_date;

	$time = mysql2date($d, $time, $translate);
	return apply_filters('get_post_time', $time, $d, $gmt);
}

You can see that it is going to pass post_date_gmt into mysql2date() but that this date/time (e.g. 2013-02-19 18:22:42) does not include with it any timezone information (a sad fact about the WordPress posts schema). So then mysql2date() is passed this timezone-free date/time:

function mysql2date( $format, $date, $translate = true ) {
	if ( empty( $date ) )
		return false;

	if ( 'G' == $format )
		return strtotime( $date . ' +0000' );

	$i = strtotime( $date );

	if ( 'U' == $format )
		return $i;

	if ( $translate )
		return date_i18n( $format, $i );
	else
		return date( $format, $i );
}

And the strtotime() is going to interpret that timezone-agnostic date as the time in the current timezone! So even though the original date/time is coming from $post->post_date_gmt, it is getting passed into strtotime() with a default timezone not being UTC/GMT, and so the end resulting date/time returned is not GMT as originally requested.

If you find your code does this, the quick solution to the problem is to just reset the default timezone to UTC once you’ve finished working in the other timezone:

date_default_timezone_set(get_option('timezone_string'));
// do some stuff
date_default_timezone_set('UTC');

But a more elegant solution would be to move to using DateTime objects and specify the DateTimeZone for each.

Anyway, this is something to be aware of, as I had to pull out a few hairs (and I don’t intend to go bald).

See also: Default timezone hardcoded as UTC? (Stack Exchange)

3 thoughts on “Do not change the default timezone from UTC in WordPress

  1. So, if I have this right, if my view needs to do things like show a message only if a given post is less than a certain age, I can’t set the timezone in the wp-config.php or everything will get screwed up as far as post date stamps and such. Instead, if I need to date math in the view, I should set the default timezone there, do my math, and then set it back to UTC, just in case anything in the sidebar hasn’t been rendered yet?

    1. You could do that, but it is much better to not set the default timezone at all, but instead to create a new DateTime object and set the desired Timezone on it, and then do your operations on this DateTime object.

Leave a Reply