brick / date-time

Date and time library for PHP
MIT License
337 stars 30 forks source link

isEqualTo(TimeZone::utc()) is not normalized #55

Open pscheit opened 2 years ago

pscheit commented 2 years ago

Hey there,

i got this:

$whenUtc = ZonedDateTime::parse('2021-07-18T07:00:00Z');
$whenUtc->getTimezone()->isEqualTo(TimeZone::utc()); // -> false

the timezone is then Z same with etc/UTC which represents the same TimeZone.

Do you want to harmonize those identifiers to represent a Timezone?

e.g.

TimeZone::utc()->isEqualTo(TimeZone::parse('UTC')) // true

would be happy to submit a PR

tigitz commented 2 years ago

Related to the PR I linked above, TimeZone::utc() is misleading in the first place because you don't know whether it will return the TimeZoneOffset of Z or the TimeZoneRegion of UTC

Now, should a TimeZoneOffset be equal to a TimeZoneRegion ?

Technically it is for Z and UTC but as soon as you have real offset like +02:00 you cannot map this offset to a singular TimeZoneRegion.

jiripudil commented 2 years ago

Hi, this is strange, your original code snippet

$whenUtc = ZonedDateTime::parse('2021-07-18T07:00:00Z');
$whenUtc->getTimezone()->isEqualTo(TimeZone::utc());

actually gives me true, at least on the latest master. TimeZone::utc() is always resolved to a TimeZoneOffset, as indicated by its return type, and so is parsing 'Z'.

pscheit commented 2 years ago

oh i am sorry, my code snippet was whack. Lets go with this:

$whenUtc = ZonedDateTime::fromDateTime(
    new \DateTimeImmutable('now', new \DateTimeZone('etc/UTC'))
);
self::assertTrue($whenUtc->getTimezone()->isEqualTo(TimeZone::utc()));
BenMorel commented 2 years ago

Indeed, timezones are compared on their getId(), which is Z for a TimeZoneOffset of UTC, and etc/UTC for a TimeZoneRegion of UTC.

Do you have suggestions on how we should handle this? Should we hardcode the special case of 'Z' == 'etc/UTC'?

By the way, you can get two representations of UTC in PHP as well:

$dt = new DateTime('2021-03-05T11:12:13Z');
echo $dt->getTimeZone()->getName(); // Z

$dt = new DateTime('2021-03-05T11:12:13', new DateTimeZone('etc/UTC'));
echo $dt->getTimeZone()->getName(); // etc/UTC
BenMorel commented 2 years ago

And now I'm realizing that DateTimeZone does not normalize the timezone names, so both etc/UTC and ETC/UTC are accepted, and isEqualTo() would fail to compare different cases as well. We need to take that into account when comparing them.

BenMorel commented 2 years ago

Sorry, closed by mistake.

pscheit commented 2 years ago

yep, i think it's a flaw in DateTimeZone. I dont understand the difference between region UTC and Offset0 UTC I understand that for regions where the offset might change due to whatever reasons, but utc?

Is there a reason that UTC and etc/UTC are not normalized in the php implementation?