Open kylekatarnls opened 1 month ago
It looks indeed that, when using the createFromFormat
, the timestamp is set and then the timezone is replaced without adapting the internal datetime.
Keeping in mind that I agree there is a bug here, some quick nit-picking:
I.E. I expect
DateTime::createFromFormat('U e', '1730597400 America/Toronto')
to be equivalent to:$date = DateTime::createFromFormat('U', '1730597400'); $date->setTimezone(new DateTimeZone('America/Toronto'));
Actually no, that's not quite how it works. Specifying a timezone indicates how to interpret the string, which could be very different from the default timezone, while setTimezone
will modify (the representation of) the date to match the given timezone.
// 12:00:00 according to the default timezone
$date = DateTime::createFromFormat('Y-m-d H:i:s', '2024-10-07 12:00:00');
var_dump($date); // 12:00:00 of the default timezone
// 12:00:00 according to America/Toronto
$date = DateTime::createFromFormat('Y-m-d H:i:s e', '2024-10-07 12:00:00 America/Toronto');
var_dump($date); // 12:00:00 of America/Toronto
// 12:00:00 according to the default timezone
$date = DateTime::createFromFormat('Y-m-d H:i:s', '2024-10-07 12:00:00');
$date->setTimezone(new DateTimeZone('America/Toronto'));
var_dump($date); // ??:00:00 of America/Toronto
As noted, the first and third example should use the same underlying timestamp, while the second should use a different timestamp (if the default timezone is in a different offset than America/Toronto, of course).
In the case of a Unix timestamp, which doesn't have a concept of a timezone, all three examples should be the same. Given UTC as the default timezone:
// 1730597400 = 01:30:00 according to UTC
$date = DateTime::createFromFormat('U', '1730597400');
var_dump($date); // 01:30:00 of UTC
// 1730597400 = 21:30:00 according to America/Toronto
$date = DateTime::createFromFormat('U e', '1730597400 America/Toronto');
var_dump($date); // 21:30:00 of America/Toronto
// 1730597400 = 01:30:00 according to UTC
$date = DateTime::createFromFormat('U', '1730597400');
$date->setTimezone(new DateTimeZone('America/Toronto'));
var_dump($date); // 21:30:00 of America/Toronto
And https://3v4l.org/e2eFe agrees that there is a bug: the second example is shifting the time when it shouldn't be. But the explanation of why it's a bug is not because "it isn't behaving the same as ->setTimezone".
@damianwadley I don't say it should be equivalent for any string, but it must be equivalent for U
because the doc explicitly states that U is a GMT timestamp, so putting Toronto after a timestamp must not give you a "Toronto timestamp" (timezeoned timestamps should probably not being considered as a thing).
And https://3v4l.org/e2eFe agrees that there is a bug: the second example is shifting the time when it shouldn't be.
I'm not sure I get this part. If you are saying that DateTime::createFromFormat('U', '1730597400')->setTimezone(new DateTimeZone('America/Toronto'))->format('U');
should output something else than 1730597400
, then I strongly disagree, changing timezone must not change the timestamp, it does not depend on the timezone since it's the number of seconds since January 1 1970 00:00:00 GMT
which is the same instant wherever you are in the world.
the doc explicitly states that U is a GMT timestamp
Unix timestamps do not have timezones. "A GMT [Unix] timestamp" isn't a thing. What the docs are saying is that it's a timestamp measured from "12am on January 1st, 1970" according to GMT. It could say "9pm on December 31st, 1969" according to US East, or "3am on January 1st, 1970" according to Uganda, and it would mean the same thing. (But it doesn't because nobody ever thinks that way about the epoch.)
I'm not sure I get this part.
The Unix timestamp for all three of them should be the same. Timezones are irrelevant when it comes a timestamp, so nothing you do with a DateTime's timezone should have any effect. However, the var_dump of a DateTime does not show timestamps - it shows string representations. Because it's easier for humans to understand those representations than raw 10-digit numbers. So timezones are relevant to that output.
That's what I said. And that's why the expected behavior in my original post is the correct one.
I don't get the point about var_dump
ing the object. The only output I'm talking in this issue is the result of ->format('U')
BTW your example:
$date = DateTime::createFromFormat('U e', '1730597400 America/Toronto');
var_dump($date); // 21:30:00 of America/Toronto
Is what I expect too but is not what is happening right now, as you can see https://3v4l.org/C1Tna it gives 01:30 of America/Toronto
and so this is part of the bug to be fixed.
The point about how setTimezone
works vs. how passing timezone in the constructor string is likely off-topic. I don't need to be convinced that they are working differently, I'm perfectly aligned with that, I don't say both should work the same way under the hood, I gave those 2 codes, as they both should return create DateTime
with America/Toronto
timezone and both should return 1730597400
out of ->getTimestamp()
, the end result for both snippets should then be equivalent.
But I didn't state anything about how it should produce this result, just that this is what it should produce.
I hope that we all agree on this result, as this is precisely because timezone is irrelevant when working with timestamp that it is the expected result.
If timezone is omitted or null and datetime contains no timezone, the current timezone will be used. Note:
The timezone parameter and the current timezone are ignored when the datetime parameter either contains a UNIX timestamp (e.g. 946684800) or specifies a timezone (e.g. 2010-01-28T15:00:00+02:00).
Yes, again, that's also the behavior that I expect, but as show in the exemple, this is not what PHP is currently doing/returning.
Description
The following code:
Resulted in this output:
It's 5 hours more than the input timestamp.
But I expected this output instead:
The difference matches the timezone offset.
But documentation on createFromFormat about
U
says:GMT is specified, so I expect the timestamp to be constant whatever is the timezone.
I.E. I expect
DateTime::createFromFormat('U e', '1730597400 America/Toronto')
to be equivalent to:PHP Version
PHP 8.3.12