WordPress breaks time (and how to fix it)

Andrey “Rarst” Savchenko, WordCamp Retreat Soltau 2018

Old man watch

WP breaks time & how to fix it

Andrey “Rarst” Savchenko

Had you ever...

changed WP time zone?

Settings → General → Timezone

Had you ever...

output localized time?

date_i18n(), the_date(), etc.

A very brief history of time

  1. solar time
  2. city time
  3. rail time
  4. time zones
  5. Universal Coordinated Time

Unix time

1 525 435 200

seconds since 1970–01–01 00:00:00 UTC

Unix time

PHP DateTime

$dt = new DateTime();
echo $dt->getTimestamp();
1525435200
echo $dt->formatDATE_RFC3339 );
2018-05-04T14:00:00+02:00
echo $dt->getTimezone()->getName();
Europe/Berlin
php.net/datetime

PHP DateTime

php.net/datetime
PHP Date Book phpdatebook.com
Time on fire

WP time

WpDateTime

github.com/Rarst/wpdatetime

WP time zone options

settinggmt_offsettimezone_string
Berlin2'Europe/Berlin'
UTC+2'2'''

WP time zone in all cases

  1. get timezone_string
  2. if empty — get gmt_offset
  3. convert the offset number to ±00:00 (PHP 5.5+)

WpDateTimeZone to parse time zone

$timezone WpDateTimeZone::getWpTimezone();
setting$timezone->getName()
Berlin'Europe/Berlin'
UTC+2'+02:00'

date_i18n()

DateTime date() date_i18n()
language English English WP locale
time zone arbitrary current PHP timezone_string
input arbitrary timestamp “WP timestamp”
formats date() date() date(), incomplete
developer.wordpress.org/reference/functions/date_i18n

date_i18n() logic

echo date_i18n'j. F Y, G.i \U\h\r T' );
  1. j. F Y, G.i \U\h\r T
  2. j. \M\a\i Y, G.i \U\h\r T — locale
  3. j. \M\a\i Y, G.i \U\h\r \C\E\S\T — zone
  4. 4. Mai 2018, 14.00 Uhr CEST — date()

date_i18n() fails w/ gmt_offset

WP set to Berlin time zone:
echo date_i18nDATE_RFC3339 );
2018-05-04T14:00:00+02:00
WP set to UTC+2 time zone:
echo date_i18nDATE_RFC3339 );
2018-05-04T14:00:00+00:00
#34835

date_i18n() fails w/ Unix timestamp

echo dateDATE_RFC3339time() );
2018-05-04T12:00:00+00:00
echo date_i18nDATE_RFC3339time() ); 2018-05-04T12:00:00+02:00
#38771

date_i18n() fails w/ some formats

echo date_i18nDATE_RFC3339 ); // === 'Y-m-d\TH:i:sP'
2018-05-04T14:00:00+02:00
echo date_i18n'c' ); // === 'c'
2018-05-04T14:00:00+00:00
echo date_i18nDATE_RFC2822 ); // === 'D, d M Y H:i:s O'
Fr, 04 Mai 2018 14:00:00 +0200
echo date_i18n'r' ); // === 'r'
Fri, 04 May 2018 14:00:00 +0000
			
#20973

WpDateTime to wrap date_i18n()

WP set to UTC+2 time zone:
$time     = new WpDateTime'@' time() );
$timezone WpDateTimeZone::getWpTimezone();
$time     $time->setTimezone$timezone );
echo $time->formatI18n'c' );
2018-05-04T14:00:00+02:00
echo $time->formatI18n'r' );
Fr, 04 Mai 2018 14:00:00 +0200
			

post_date

post_datepost_date_gmtpost_title
2018-05-04 13:00:00 2018-05-04 12:00:00 A post made in London
WP set to London time zone:
the_dateDATE_RFC3339 );
2018-05-04T13:00:00+01:00

post_date fails w/ changed time zone

post_datepost_date_gmtpost_title
2018-05-04 13:00:00 2018-05-04 12:00:00 A post made in London
WP set to Berlin time zone:
the_dateDATE_RFC3339 );
2018-05-04T13:00:00+02:00
#38774

post_date in all cases

  1. get post_date_gmt
  2. if empty — get post_date
  3. get WP time zone
  4. adjust post_date[_gmt] with the time zone
  5. convert to desired format

WpDateTime to parse post date

post_datepost_date_gmtpost_title
2018-05-04 13:00:00 2018-05-04 12:00:00 A post made in London
WP set to Berlin time zone:
$time WpDateTime::createFromPostget_post() );
echo $time->formatI18nDATE_RFC3339 );
2018-05-04T14:00:00+02:00

Takeaways

Thank you for your time! Questions?

twitter.com/Rarst




Rarst.net/slides/time

Image credits