DateTimeZone and DST in PHP
2017-12-03I ran into something a little unexpected a few days ago at work and I thought I'd share (possibly in case I end up Googling this again myself later). I have a function like this:
function isDaylightSavingDifferent(DateTimeInterface $dt1, DateTimeInterface $dt2): bool
{
return $dt1->format('I') !== $dt2->format('I');
}
It mostly does its job just fine, but I ran into some puzzling behavior when attempting to feed some data into it. The
dates were in Atom (i.e. PHP's broken ISO-8601)
format, ex. 2017-11-01T15:00:00-0500
.
class DateTime#4319 (3) {
public $date =>
string(26) "2017-11-01 15:00:00.000000"
public $timezone_type =>
int(1)
public $timezone =>
string(6) "-05:00"
}
However, if I sent in another date after the DST switch (11-05 this year), the code dependent on that above function didn't fire. Why not?
class DateTime#4319 (3) {
public $date =>
string(26) "2017-11-06 15:00:00.000000"
public $timezone_type =>
int(1)
public $timezone =>
string(6) "-06:00"
}
The first one returns "0"
for the "is DST" check, and the second returns... "0"
??
It turns out, PHP has 3 different ways to represent a DateTimeZone object, represented by $timezone_type
in the var
dump above. You can create one with a UTC offset (type 1, ex. -0500
), a timezone abbreviation (type 2, ex. CDT
), or
a timezone name (type 3, ex. America/Chicago
). All 3 are valid, and all represent the same moment in time, but only
one of them contains enough context for PHP to understand DST. So while I knew it was CDT when I created the time
string, when the code under test received it, it was formatted with a UTC offset, so the consuming code couldn't tell if
DST had changed or not.
I ended up filling in the gaps using the context of the user, but when I initially tested it at the unit level, that wasn't there. Hence, the problem.