-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Form] DateTimeToLocalizedStringTransformer does not use timezone when using date only #21218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Beside my comment 👍
@@ -130,7 +130,10 @@ public function reverseTransform($value) | |||
try { | |||
if ($dateOnly) { | |||
// we only care about year-month-date, which has been delivered as a timestamp pointing to UTC midnight | |||
return new \DateTime(gmdate('Y-m-d', $timestamp), new \DateTimeZone($this->inputTimezone)); | |||
$dateTime = new \DateTime(gmdate('Y-m-d', $timestamp), new \DateTimeZone($this->outputTimezone)); | |||
$dateTime->setTimezone(new \DateTimeZone($this->inputTimezone)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line should be in the same if
as below https://github.com/symfony/symfony/pull/21218/files#diff-a13339ab3c3fcaba6009f82a2b77ae01R149.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in fact this looks correct here, see L146-149, isn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes these are the lines I'm talking about, but I don't get it what do you mean?
I'm not saying this is not correct here, but it may not be needed to set again the timezone, hence the check is missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
understood! Then what about this patch?
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php
@@ -129,11 +129,11 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
try {
if ($dateOnly) {
// we only care about year-month-date, which has been delivered as a timestamp pointing to UTC midnight
- return new \DateTime(gmdate('Y-m-d', $timestamp), new \DateTimeZone($this->inputTimezone));
+ $dateTime = new \DateTime(gmdate('Y-m-d', $timestamp), new \DateTimeZone($this->outputTimezone));
+ } else {
+ // read timestamp into DateTime object - the formatter delivers a timestamp
+ $dateTime = new \DateTime('@'.$timestamp);
}
-
- // read timestamp into DateTime object - the formatter delivers a timestamp
- $dateTime = new \DateTime(sprintf('@%s', $timestamp));
// set timezone separately, as it would be ignored if set via the constructor,
// see http://php.net/manual/en/datetime.construct.php
$dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
Thanks for the comments. I'll continue when the discussion about the related bug (#21217) is ended. |
@magnetik ready to update the PR? |
I'm willing to update it with the proposed change, but there are some ingoing discussion in #21217 about whether or not this PR is the good solution. |
The rational is purely local. The code logic is currently broken, the patch #21218 (comment) fixes the situation by handling TZ as in other places. |
Done. It slightly differ from your diff as I've let the |
@magnetik the setter must be called after the |
Well in the |
Yeah this is what the comment below is talking about ;) |
$dateTime = new \DateTime(sprintf('@%s', $timestamp)); | ||
// set timezone separately, as it would be ignored if set via the constructor, | ||
// see http://php.net/manual/en/datetime.construct.php | ||
$dateTime->setTimezone(new \DateTimeZone($this->outputTimezone)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nicolas-grekas @HeahDude I'm sorry to bother you with such trivial change but I really don't understand why this line should be moved outside the else.
The line 139 and the comment line 137 and 138 only applies to the construct of line 136 because it's created with the '@' with a timestamp. From the doc:
The $timezone parameter and the current timezone are ignored when the $time parameter either is a UNIX timestamp (e.g. @946684800) or specifies a timezone (e.g. 2010-01-28T15:00:00+02:00).
Line 133 the timezone is already applied when constructed.
If this something about limiting the number of instruction in the else
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
passing a TZ as constructor does not "set" it.
To set it, you need to call "setTimeZone".
passing a TZ as constructor does only tell the constructor that if the first arg contains no TZ info, then this should be the one to use while parsing.
That's why
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see why I'm confused: since we pass (gmdate('Y-m-d', $timestamp)
as first argument in the construct line 133 I'm assuming that there will never be a timezone there and you don't. (am I right?)
I'll change accordingly.
As i see the current fix you could still select 2017-01-10 and get back 2017-01-09, which seems very weird |
because of TZ config yes - not more weird than TZ themselves - just logical in fact. |
Not logical at all to me ... because there should not be any TZ config at all when working only with dates |
then that's a config issue. But when there is one, we must respect it. |
When there is a wrong one shouldn't we fix it ? |
@tkleinhakisa config is config, there is no way to tell if a TZ setting is wrong or false |
@@ -130,11 +130,11 @@ public function reverseTransform($value) | |||
try { | |||
if ($dateOnly) { | |||
// we only care about year-month-date, which has been delivered as a timestamp pointing to UTC midnight | |||
return new \DateTime(gmdate('Y-m-d', $timestamp), new \DateTimeZone($this->inputTimezone)); | |||
$dateTime = new \DateTime(gmdate('Y-m-d', $timestamp), new \DateTimeZone($this->outputTimezone)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wait, @tkleinhakisa is right! this should be inputTimezone instead of outputTimezone!
when dateOnly is true, the DateTime should not depend on the current hour!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's not my point ! for me it shoud be $dateTime = new \DateTime(gmdate('Y-m-d', $timestamp))
so that the date i write/select in my form is the same as the one i get back in the code
I'm sorry i don't want to be boring, but it's not about telling if the given TZ is right or wrong (there is no such thing) but it's about removing this setting (or at least deprecate it) TZ do not make sense when working with dates only, so why do we have these settings ? |
👍 again, I messed up with the previous comment :) |
the issue is that removing the timezone setting entirely was already attempted in the past, and it broke things for projects, because PHP still has a time in the object (because there is no Date object but a DateTime one). |
From what i've read on this bug tracker, TZ options do not make sense on that field, see #12404 #12380 #12239 #7187 the changes suggested here has the potential to break someone's app in a very isidious way because it won't be a fatal error break that can be easily spotted, it will be a change in the behavior of the app. @stof From what i've seen in the previous PR's the options were removed without any deprecation first, which should be the way to go so that people using it and relying on it have time to update their app
This PR has the same potential |
@tkleinhakisa a deprecation would not have helped much, as the issue was that stopping to take the timezone conversion into account for dates caused issues later when using the DateTime object in ways converting timezones. |
Well then maybe the deprecation should not only concern the options but the return type too. If we agree that DateTime is not a good object to represent a date only or time only then shouldn't we move onto something else (a string, a simple Date object or Time Object ?) |
Note that I don't see the issue you're talking about : if we have 12hours delta, "the day before" or "the day after" will always be accurate up to 12h. I like to think locally. And locally here, TZ handling is accurate. Changing for something else won't make things more accurate. |
@tkleinhakisa but we first need to have a standard for that, so that other libraries agree on using it (for instance the Doctrine ORM). If the ORM still use DateTime, it would just move the issue to the place where you convert between your Date object and DateTime, which does not solve anything |
Thank you @magnetik. |
…imezone when using date only (magnetik) This PR was merged into the 2.7 branch. Discussion ---------- [Form] DateTimeToLocalizedStringTransformer does not use timezone when using date only | Q | A | ------------- | --- | Branch? | 2.7 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #21217 | License | MIT The `DateTimeToLocalizedStringTransformer` when used with a pattern that have only date (in `DateType` for instance) does not convert the result in the desired output Reproduction steps: - Use `DateType` in a form - Set the `model_timezone` to `Pacific/Tahiti`, having default timezone to `Europe/Berlin`. - Enter the date `2017-01-10` - Submit the form - Notice that the received data is `2017-01-10 00:00 Europe/Berlin`, whereas it should be `2017-01-10 11:00 Europe/Berlin` Commits ------- 031d8c2 [Form] DateTimeToLocalizedStringTransformer does not use TZ when using only date
@stof i agree it's only pushing the pb away, it becomes the responsability of the developper to make the right conversion, for exemple using explicitly the transformer. This is not good at all for DX and third party lib integration. The issue could be raised at "higher" levels (php itself, fig, other ?) Having working intensively with a mix of date (only) and date-time i know very well how painfull it is, and how difficult it would be for someone to find spot a bug introduced by this change. As this PR is now merged, it seems that's the way to go and i don't think my app will suffer from it at all, then so be it. In the mean time is there anything that could be done to improve the situation ? dispite the fact that the implementation cannot be changed, there seems to be a consensus that these options do not really make sense, and that we're lacking some date-only and time-only objects |
The
DateTimeToLocalizedStringTransformer
when used with a pattern that have only date (inDateType
for instance) does not convert the result in the desired outputReproduction steps:
DateType
in a formmodel_timezone
toPacific/Tahiti
, having default timezone toEurope/Berlin
.2017-01-10
2017-01-10 00:00 Europe/Berlin
, whereas it should be2017-01-10 11:00 Europe/Berlin