-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Serializer] Provide option to always apply timezone of the DateTimeNormalizer context. #31256
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
src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php
Show resolved
Hide resolved
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.
Thank you for your contribution 👍🏻👍🏻
I left some minor comments
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php
Outdated
Show resolved
Hide resolved
As per #22444 the current behavior is the intended one, isnt it? cc @ogizanagi It's a BC break IMHO. |
@ro0NL the current behaviour only normalizes input if it's already normalized (everything in the same time zone or everything without a time zone). Having any sort of variance means your data will not be normalized in a way you'd expect, which is not something a normalizer should do by default. PHP itself has the same problem which is the root cause of this issue. See Twitter thread. So, technically yes, this changes the current behaviour, but the current behaviour is plainly buggy for the outlined reasons. If you explicitly specify a timezone, you should be able to rely on the output being in that timezone. |
this is mostly a matter of perspective isnt it, when denormalizing preserving the timezone as-given might be considered expected as well ... i agree some inconsistency comes with normalize(), where the timezone is always applied; as we don't know the user set it / or has a default timezone. Would a second context option be the better approach? E.g. |
@ro0NL doesn't seem like a matter of perspective to me. If you wish to preserve the timezone given in the input, you can omit specifying a timezone to the normalizer:
If you, on the other hand, wish to normalize the timezone (with the tool called |
i figure it's the most expected to cover timezone normalization consistently in both directions, esp. if one provides a timezone explicitly. I agree it should be omitted otherwise. Otherwise this option suffers poor naming (opposed to Should we migrate users from the current behavior to the new one using some flag? while deprecating not setting it to true. |
I was leaning towards the view @ro0NL that some type of flag be employed to capture BC. Remember that $defaultContext was only added to the DateTimeNormaliser in version 4.2.0, and as it has the ability to set the default_timezone, previous version of Symfony/Serializer are not impacted by this change. What should such a flag be called?
I have added a flag and tested at my end. I have use a deprecation message of:
Will commit when name and message consensus is reached. |
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php
Outdated
Show resolved
Hide resolved
@crayner i'm kinda convinced by #31256 (comment), we should avoid the variance between normalize() and denormalize()
that means when you omit it, you should set the DateTime timezone yourself and it's preserved in both directions (depending on the datetime format in this case) |
@crayner we need to deprecate the current behaviour (passing a timezone, but (by relying on the current buggy behaviour) expecting it to not be used. That means you deprecate that usecase, and in this case you do so by having the developer acknowledge they understand the new behaviour and opt-in to it. So,the new behaviour should be:
Symfony 5 should use the new behaviour by default without setting |
I confirm this was the expected behavior in #22444. The use-case was indeed to only fulfill the timezone info when none is provided in the input and preserve the ones explicitly provided. >>> new \DateTime('2016-01-27T16:39:26+01:00', new \DateTimezone('UTC'));
# => DateTime @1453909166 {#2313
# date: 2016-01-27 16:39:26.0 +01:00,
# } It ignores the second argument. Which surely has value, but perhaps a poor choice / suffers from a naming issue. So #31256 (comment):
is true, but the feature allows to explicitly choose the default timezone to use depending on the context while keeping provided timezone info from the input, if any.
Then it means the "keeping provided timezone from input" use-case is dropped in 5.0, as well as the Instead, we introduce a
This will keep both use-cases, and no flag to remove later. |
My reasoning for this being a bug was this can be achieved without any context flags with just
I feel this would again muddy the water here: if I'm explicitly specifying a timezone for the normalizer, why wouldn't it apply it when normalizing? The The most clean behaviour to me seems like described:
It has least possible use cases and things required to understand, least astonishment for the developer and no flags required. @ro0NL do you agree? If you don't consider this a bug, then the way to get there is different and this would need a relabel. |
Yes and no.
That'll become the default behavior in 5.0. So not an issue to me. |
I understand that, but this train of thought seems like it allows one app to handle many timezones, but the lack of this feature (or from my POV, this bug) doesn't allow the app to use a single chosen timezone, it's optimizing for the more complex and less common use case. 😄
I'm afraid I don't understand what you mean here: since the behaviour for both norm/denorm would change in 5.0, this still needs to be done in 4.4 for the current behaviour to be deprecated, no? 🤔 |
The idea is to introduce the
So the PR to get the expected behavior would just introduce the new flag in 4.4. |
Thanks for all the feedback @ogizanagi , @ro0NL and @dkarlovi . I think that @ogizanagi idea is an elegant solution that allows for both BC and forward to what you originally requested @dkarlovi in your issue #31232 . Full integration will be delayed till 5.0, but of 4.4 the system will work both ways, with a deprecation thrown if the context flag is not set. |
Question: Should the final behaviour of the denormaliser include an override of the TIMEZONE_KEY with the php_ini timezone setting, rather than the default UTC for timestamps, or provided timezone detail in the time parameter when TIMEZONE_KEY is null? |
My bad not correctly separating different PR's with appropriate branch names. Should I close both PR's and start again? |
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.
My bad not correctly separating different PR's with appropriate branch names. Should I close both PR's and start again?
@crayner : No need at all. Just keep the PR description, commit and title consistent with the code, that'll be enough ;)
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
|
rebased to a single commit |
…denormalizer of DateTimeNormalizer If timezone applied in context, then overwrite datetime timezone. Tests written Coding Standard Change Place new tests in testDenormalizeUsingTimezonePassedInDefaultContext Code Standard Changes Code Standard Changes Mk II Code Standard Changes Mk III Code Standard Changes Mk IV Added FORCE_TIMEZONE flag for BC changed flag to FORCE_CONTEXT_TIMEZONE Coding Standing Trip Coding Standing Trip Coding Standing Trip if null === TIMEZONE_KEY, then ignore deprecation warning as PHP default will apply to denormalization. Added test for null === TIMEZONE to show different TZ if null === TIMEZONE_KEY, then ignore deprecation warning as PHP default will apply to denormalization. Added test for null === TIMEZONE to show different TZ Format now used from $format in denormalizer. Created isForceContextTimezone method. throw deprecation in denormalizer if Timezone given and force is false. Add test for correct format use, and single context timezone. Coding Standard Changes Debug testDenormalize[Null,Empty]ThrowsException Handle Legacy Timezone correctly in Constructor Change Constructor test to remove deprecation. Change FORCE_CONTEXT_TIMEZONE to ALWAYS_USE_TIMEZONE_KEY Removed deprecation as the new behaviour is an option to be selected. Coding Standard Change Remove comment as per directive. Created PRESERVE_CONTEXT_TIMEZONE flag as a must set option in the context, that defaults to false and throws a deprecation warning if not set. Built in Legacy retirement of the PRESERVE_CONTEXT_TIMEZONE flag with version >= Symfony 5.0 Coding Standard Change Travis Testing on Symfony. Repair testDenormalizeRecusive in ObjectNormalizerTest Added Deprecation to legacy timezone import if defaultContext is partially used. Moved comment to PRESERVE_CONTEXT_TIMEZONE constant. Only throw flag deprecation if the context timezone is not null. Code Review Changes Debug call to getTimeZone()
Having new deprecations and new constants mean this should target master to me. |
Indeed. Base merge for PR changed to master |
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.
LGTM. 👍
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
Outdated
Show resolved
Hide resolved
Incorporate changes as suggested by @fabpot
I will be away till the 19th July. |
self::TIMEZONE_KEY => null, | ||
]; | ||
|
||
if (!\is_array($defaultContext)) { |
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.
$defaultContext
is always an array as there is a type hint in the constructor signature.
* | ||
* The denormalizer assumes that all DateTimeInterface object returned will have the timezone returned by the getTimezone() method. | ||
* Default PHP behavior will occur if the getTimezone() method returns null or context[self::PRESERVE_CONTEXT_TIMEZONE] is set to false. | ||
* This flag will be ignored in Symfony 5.0+ |
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.
6.0?
$defaultContext[self::TIMEZONE_KEY] = $timezone; | ||
} | ||
|
||
if (!isset($defaultContext[self::TIMEZONE_KEY]) && null !== $timezone) { |
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.
There is no $timezone
variable in the constructor.
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.
There was a $timezone and $defaultContext was not always an array when this was written.
Recommend Abandon these changes, as version in 5.1 has the required flexibility |
Let’s close then. Thank you |
If timezone applied in context, then overwrite datetime timezone.
Tests written
This PR ensures DateTimeNormalizer::denormalizer correctly applies context timezone when supplied by user.