WP breaks time & how to ﬁx it

2

Andrey “Rarst” Savchenko— Rarst.net— WP contractor— 1 Gs old— 310 Ms WP

3

Had you ever...

changed WP time zone?
Settings → General → Timezone

4

Had you ever...

output localized time?
date_i18n() , the_date() , etc.

5

A very brief history of time
1. solar time
2. city time
3. rail time
4. time zones
5. Universal Coordinated Time

6

Unix time

1 525 435 200
seconds since 1970–01–01 00:00:00 UTC

7

Unix time— consistent— storage–friendly— comparison–friendly— not human readable

8PHP DateTime$dt = new DateTime();echo $dt->getTimestamp();1525435200
echo $dt->format( DATE_RFC3339 );2018-05-04T14:00:00+02:00
echo $dt->getTimezone()->getName();Europe/Berlin

php.net/datetime

9

PHP DateTime— UTC–based— formatting— parsing— primarily English

php.net/datetime

10

phpdatebook.com

12

WP time— PHP 4 code
— partial PHP 5 retroﬁt— custom time zone logic— custom internationalization

13

WpDateTime— extends PHP DateTime classes— works around WP bugs
— parses WP datagithub.com/Rarst/wpdatetime

14

WP time zone options
setting

gmt_offset

timezone_string

Berlin2'Europe/Berlin'

UTC+2'2'''

15

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+)

16

WpDateTimeZone to parse time zone
$timezone = WpDateTimeZone::getWpTimezone();setting$timezone->getName()

Berlin'Europe/Berlin'

UTC+2'+02:00'

17

date_i18n()
DateTimedate()

date_i18n()language

EnglishEnglishWP localetime zone

arbitrarycurrent PHP

timezone_string

input

arbitrarytimestamp“WP timestamp”

formatsdate()date()date(), incomplete

developer.wordpress.org/reference/functions/date_i18n18date_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()

19

date_i18n() fails w/ gmt_offset
WP set to Berlin time zone:
echo date_i18n( DATE_RFC3339 );2018-05-04T14:00:00+02:00
WP set to UTC+2 time zone:
echo date_i18n( DATE_RFC3339 );2018-05-04T14:00:00+00:00#3483520

date_i18n() fails w/ Unix timestampecho date( DATE_RFC3339, time() );2018-05-04T12:00:00+00:00

echo date_i18n( DATE_RFC3339, time() );2018-05-04T12:00:00+02:00#38771

21

date_i18n() fails w/ some formats
echo date_i18n( DATE_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_i18n( DATE_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

22

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

23

post_date
post_date

post_date_gmt

post_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_date( DATE_RFC3339 );2018-05-04T13:00:00+01:00

24

post_date fails w/ changed time zone
post_date

post_date_gmt

post_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_date( DATE_RFC3339 );2018-05-04T13:00:00+02:00#38774

25

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

26

WpDateTime to parse post date
post_date

post_date_gmt

post_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::createFromPost( get_post() );echo $time->formatI18n( DATE_RFC3339 );2018-05-04T14:00:00+02:00

27

Takeaways— WP gets time storage and output wrong— read and use UTC time
— write timestamp, UTC, or RFC 3339
— use DateTime to operate time
— use WpDateTime to bridge WP and PHP

28

Thank you for your time! Questions?
twitter.com/Rarst

Rarst.net/slides/time29

Image credits— Photo by Adina Voicu CC0— Photo by Eugene Shelestov CC0