Skip to content

DateTimeNormalizer ignores format when denormalize #29030

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

Closed
benjamin-aubry opened this issue Oct 30, 2018 · 18 comments · Fixed by #43329
Closed

DateTimeNormalizer ignores format when denormalize #29030

benjamin-aubry opened this issue Oct 30, 2018 · 18 comments · Fixed by #43329

Comments

@benjamin-aubry
Copy link

benjamin-aubry commented Oct 30, 2018

Symfony version(s) affected: 4.1.6

Description
If I'm not mistaken, DateTimeNormalizer ignores format when denormalize

How to reproduce

<?php
require_once __DIR__.'/vendor/autoload.php';
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;

$format = 'd/m/Y';
$string = '01/10/2018';
$dateTimeNormalizer = new DateTimeNormalizer($format);
$date = \DateTime::createFromFormat($format, $string);

// Normalize OK, shows '01/10/2018'
var_dump($dateTimeNormalizer->normalize($date)); 

$date2 = $dateTimeNormalizer->denormalize($date->format($format),\DateTime::class);
// Denormalize KO, shows '10/01/2018' instead of '01/10/2018'
// when day is gretter than 12, this throw an PHP Fatal error
var_dump($date2->format($format)); 

Possible Solution
Use the format attribute of class DateTimeNormalizer in the denormalize method (line 79)

Additional context

@benjamin-aubry benjamin-aubry changed the title DateTimeNormalizer ignore format when denormalize DateTimeNormalizer ignores format when denormalize Oct 30, 2018
@Nek-
Copy link
Contributor

Nek- commented Oct 30, 2018

You forgot to specify the format as deserialization context:

$dateTimeNormalizer->denormalize(
    '01/10/2018', 
    \DateTime::class,
    [DateTimeNormalizer::FORMAT_KEY => $format]
);

See doc here: https://symfony.com/blog/new-in-symfony-3-1-datetime-normalizer

@ro0NL
Copy link
Contributor

ro0NL commented Oct 30, 2018

I think #28709 (comment) confirmed this behavior is broken :)

@CheapHasz
Copy link

Would you be interested in a PR fixing that ?

I'm guessing simply replacing $dateTimeFormat = $context[self::FORMAT_KEY] ?? null; by $dateTimeFormat = $context[self::FORMAT_KEY] ?? $this->defaultContext[self::FORMAT_KEY];
in Symfony\Component\Serializer\Normalizer\DateTimeNormalizer::93 is what would break the test mentioned in the comment #28709 (comment) , because it looks like a logical and easy fix.

I'm willing to work on it if the core team is willing to review the fixes

@Nek-
Copy link
Contributor

Nek- commented Oct 2, 2019

@CheapHasz I guess you can go for it yes. And add a test 😸 .

@carsonbot
Copy link

Hey, thanks for your report!
There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

@benjamin-aubry
Copy link
Author

benjamin-aubry commented Dec 18, 2020

HellO. If I'm not mistaken this bug is still relevant in version 5.2

<?php
require_once __DIR__ . '/vendor/autoload.php';
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;

$format = 'd/m/Y';
$string = '01/10/2018';
$defaultContext = [
    DateTimeNormalizer::FORMAT_KEY => $format
];
$dateTimeNormalizer = new DateTimeNormalizer($defaultContext);

$date = \DateTime::createFromFormat($format, $string);

// Normalize OK, shows '01/10/2018'
var_dump($dateTimeNormalizer->normalize($date));

$date2 = $dateTimeNormalizer->denormalize($date->format($format), \DateTime::class);
// Denormalize KO, shows '10/01/2018' instead of '01/10/2018'
// when day is gretter than 12, this throw an PHP Fatal error
var_dump($date2->format($format));

It seems that the default context is ignored on denormalize.
The easy workaround is to provide the context when calling denormalize.

Thanks.

@carsonbot carsonbot removed the Stalled label Dec 18, 2020
@wouterj
Copy link
Member

wouterj commented Dec 18, 2020

Hi @b-e-n-j-a-m-i-n! Thanks for your quick response. Are you up for a PR, implementing something like suggested in #28709 (comment) (to keep BC)? (feel free to ask questions if you're unsure how)

@benjamin-aubry
Copy link
Author

OK I'll do that, it might take a while as it is my first PR...

@carsonbot
Copy link

Hey, thanks for your report!
There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

@benjamin-aubry
Copy link
Author

This bug is still relevant in version 5.3 with the test above.

I tried to fix it but couldn't manage to keep BC and didn't have enough time to go futther...

@carsonbot carsonbot removed the Stalled label Jun 21, 2021
@wouterj
Copy link
Member

wouterj commented Jun 21, 2021

@benjamin-aubry if you have some time, you may open a PR with "WIP" (Work In Progress) in the title. We're happy to help you with keeping BC :)

@derrabus
Copy link
Member

Looking at the code, I'd say the actual bug is that the default context is not taken into account when denormalizing. Passing that setting via the context to the denormalize() call should work.

$dateTimeNormalizer->denormalize($date->format($format), \DateTime::class, null, [
    DateTimeNormalizer::FORMAT_KEY => $format,
]);

@benjamin-aubry
Copy link
Author

This bug is still relevant in version 5.3 with the test above.

I tried to fix it but couldn't manage to keep BC and didn't have enough time to go futther...

As I'm not used to symfony prosesses I won't have time do do it, I'm sorry.

@benjamin-aubry
Copy link
Author

Looking at the code, I'd say the actual bug is that the default context is not taken into account when denormalizing. Passing that setting via the context to the denormalize() call should work.

$dateTimeNormalizer->denormalize($date->format($format), \DateTime::class, null, [
    DateTimeNormalizer::FORMAT_KEY => $format,
]);

Yep, there is obvious workarounds that's why it is a minor bug.

@carsonbot
Copy link

Hey, thanks for your report!
There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

@benjamin-aubry
Copy link
Author

This bug is still relevant in version 5.4. Yep, I found a workaround 3 years ago, simply use the format as a parameter when denormalize.

@carsonbot carsonbot removed the Stalled label Dec 22, 2021
@carsonbot
Copy link

Hey, thanks for your report!
There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

@benjamin-aubry
Copy link
Author

If I'm not mistaken this bug is still relevant in version 5.4.9
The workaround is to use the format as a parameter when denormalize.

@carsonbot carsonbot removed the Stalled label Jul 7, 2022
nicolas-grekas added a commit that referenced this issue Jul 28, 2022
…::denormalize (hultberg)

This PR was merged into the 4.4 branch.

Discussion
----------

[Serializer] Respect default context in DateTimeNormalizer::denormalize

| Q             | A
| ------------- | ---
| Branch?       | 4.4 <!-- see below -->
| Bug fix?      | yes
| New feature?  |no <!-- please update src/**/CHANGELOG.md files -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets       | Fix #29030 <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead -->
| License       | MIT
| Doc PR        | <!-- required for new features -->
<!--
Replace this notice by a short README for your feature/bugfix. This will help people
understand your PR and can be used as a start for the documentation.

Additionally (see https://symfony.com/releases):
 - Always add tests and ensure they pass.
 - Never break backward compatibility (see https://symfony.com/bc).
 - Bug fixes must be submitted against the lowest maintained branch where they apply
   (lowest branches are regularly merged to upper ones so they get the fixes too.)
 - Features and deprecations must be submitted against branch 5.x.
 - Changelog entry should follow https://symfony.com/doc/current/contributing/code/conventions.html#writing-a-changelog-entry
-->

Hey there. 👋

I'm bringing my first code patch to symfony today and it's for fixing a bug I encountered today while working with DateTimeNormalizer. In my project I have set a default date format in the service container and I noticed that the denormalized date did not follow my set date format (I enforce time but the serialized date did not contain the time stamp which should have failed when using DateTime::createFromDate). After some debugging I discovered the issue described in issue #29030

`DateTimeNormalizer::normalize` respects the date time format in context or default context while `DateTimeNormalizer::denormalize` only respects the former. This patch adds logic to denormalize too attempt create a DateTime object from the default context format (by default set to `\DateTime::RFC3339`) with createFromFormat and then if that fails continue on with the current behaviour. In my opinion this patch does not break the symfony BC promise as it simply adds another way to denormalize the date time.

**One issue:** There are no error handling when creating the date time from default context as the logic just continues on which might give the impression to the developer that the denormalization with the specific format worked correctly. I was not able to find a way to handle any error and keeping BC.
**Future tough:** At some point the `new DateTime` call in denormalize should be deprecated since creating a date time with createFromFormat is considered "safer" in my eyes as it's very explicit while the call to `new DateTime` is implicit about the date format and must perform parsing and guessing of the intended format (explained over at https://www.php.net/manual/en/datetime.formats.php). Another thing about `new DateTime` is the terriable error handling as you must catch a `\Exception` which means you catch "what ever" exception that can exist, even `\ErrorException` since `\ErrorException extends \Exception`.

Fixes #29030
Alternative PR (closed) #33813

Commits
-------

763ea05 [Serializer] Respect default context in DateTimeNormalizer::denormalize
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants