on October 16, 2017. in Programming, Development. A 2 minute read.
I wouldn’t be writing this blog post, if I’d read all the “fineprints” in the PHP manual. Alas, here we are.
The DateTime
and DateTimeImmutable
classes have a createFromFormat
method. As you can probably guess from it’s name, it creates a datetime object from a datetime string formatted in the specified format. Something like this:
<?php
$dtString = '2017-10-16 07:50:00';
$format = 'Y-m-d H:i:s';
$dt = \DateTimeImmutable::createFromFormat($format, $dtString);
print_r($dt);
gives an immutable datetime object:
DateTimeImmutable Object (
[date] => 2017-10-16 07:50:00.000000
[timezone_type] => 3
[timezone] => Europe/Belgrade
)
Nothing wrong with that. The timezone is Europe/Belgrade
, as we didn’t provide the third parameter to the createFromFormat
method, which is the optional timezone, and in this case PHP
defaulted to the server’s timezone. Business as usual.
If we tell it to use a specific timezone, it’ll use that one instead of the server’s timezone:
<?php
$dtString = '2017-10-16 07:50:00';
$format = 'Y-m-d H:i:s';
$timezone = new \DateTimeZone('America/New_York');
$dt = \DateTimeImmutable::createFromFormat($format, $dtString, $timezone);
print_r($dt);
and an expected result of:
DateTimeImmutable Object (
[date] => 2017-10-16 07:50:00.000000
[timezone_type] => 3
[timezone] => America/New_York
)
Again, business as usual, because we told PHP in what timezone the datetime string is, America/New_York
.
When the format has a timezone offset though, that’s… the part I skipped in the manual:
<?php
$dtString = '2017-10-16T07:50:00+00:00';
$format = 'Y-m-d\TH:i:sP';
$timezone = new \DateTimeZone('America/New_York');
$dt = \DateTimeImmutable::createFromFormat($format, $dtString, $timezone);
print_r($dt);
and a result of:
DateTimeImmutable Object (
[date] => 2017-10-16 07:50:00.000000
[timezone_type] => 1
[timezone] => +00:00
)
Errr… Not really what I wanted, but okay. I guess.
The createFromFormat
method ignores the provided timezone (or the server’s timezone if there’s none provided), if the datetime string and it’s format have a timezone offset.
It’s noted in the manual, my bad for not reading carefully, but this still caught me by surprise.
Not being aware of this can cause some hard to track down bugs in applications. While the DateTime
objects are being created without an error, they are being created with a different timezone_type
from what I originally expected and can potentially lead to a loss of information as the timezone identifier can’t be retrieved from the timezone offset.
Happy hackin’!