I’m using php8.2 and I have some trouble comparing dates inside a composer package running on my CI.
In short, the date comparison in php is failing because the timezone is not the expected one.
$timezone = new DateTimeZone(date_default_timezone_get());
$now = new DateTimeImmutable('now', $timezone);
$date = DateTimeImmutable::createFromFormat('U.u', $now->format('U.u'), $timezone);
var_dump($now, $date, $now === $date, $now > $date, $now < $date);
The code inside the package is creating a DateTimeImmutable Object for the current date and compares another DateTimeImmutable coming from a UNIX timestamp. However, the timezone for the DateTimeImmutable coming from a UNIX timestamp is ignoring the passed timezone Object.
The result looks like this:
...BearerTokenValidatorTest.php:61:
class DateTimeImmutable#445 (3) {
public $date =>
string(26) "2023-09-28 12:20:51.615050"
public $timezone_type =>
int(3)
public $timezone =>
string(13) "Europe/Berlin"
}
...BearerTokenValidatorTest.php:61:
class DateTimeImmutable#444 (3) {
public $date =>
string(26) "2023-09-28 10:20:51.615050"
public $timezone_type =>
int(1)
public $timezone =>
string(6) "+00:00"
}
...BearerTokenValidatorTest.php:61:
bool(false)
...BearerTokenValidatorTest.php:61:
bool(false)
...BearerTokenValidatorTest.php:61:
bool(false)
Interestingly, each comparison is false.
The original code I’m using and creates trouble can be found here: https://github.com/lcobucci/jwt/blob/5.1.x/src/Token/Parser.php#L160C69-L160C69
2
Answers
The issue you’re facing is related to how DateTimeImmutable objects are compared in PHP. When comparing two DateTimeImmutable objects using ===, PHP compares not only the date and time but also the timezone.
In your code, $now has the timezone set to "Europe/Berlin," and $date has the timezone set to "+00:00" (UTC). When you compare them using ===, PHP checks if both the date/time and the timezone are identical, which is why the comparison returns false.
If you want to compare DateTimeImmutable objects based on their date and time, ignoring the timezone, you can convert both objects to UTC before comparing them. Here’s how you can modify your code:
By setting both $now and $date to the UTC timezone before comparing them, you will ignore the timezone difference, and the comparison should work as expected.
Note that I used == for equality comparison instead of === because you want to compare the date and time values, and not necessarily the object references.
The
===
operator will always returnfalse
for even identical objects:Demo and reference.
You can use
==
, even though the definition suggest it wouldn’t work:Demo
Aside this, during my experience with date/time comparisons in PHP I’ve encountered a couple of rare bugs when dealing with daylight saving time boundaries, so if you want to be extra sure you can always normalise data convert everything to UTC before comparison, or extract the Unix time and compare that.