Skip to content

[Serializer] DateTimeNormalizer throws NotNormalizableValueException if using datetime_format U #50236

@tgalcheva

Description

@tgalcheva

Symfony version(s) affected

6.2.10

Description

Since the changes for the DateTimeNormallizer in this PR I am getting a NotNormalizableValueException when using datetime_format U (Seconds since the Unix Epoch) for denormalization - our timestamp value comes via API. The error message we now get is "The data is either not an string, an empty string, or null; you should pass a string that can be parsed with the passed format or a valid DateTime string".

The value used for creating DateTime object from timestamp is integer, and now the validation is set to explicitly accept only string values.

How to reproduce

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
use Symfony\Component\Serializer\SerializerInterface;

class DateTimeNormalizerErrorController extends AbstractController
{
    #[Route('/normalizer-bug-example', name: 'normalizer_bug_example')]
    public function __invoke(SerializerInterface $serializer): JsonResponse
    {
        $data = '{"exampleDate":1685716333}';  // Use timestamp to create DateTime
        // $data = '{"exampleDate":"13-05-2023"}';  // When using string value - everything works as expected

        // Throws NotNormalizableValueException
        $triggerErrorObject = $serializer->deserialize($data, ExampleEntity::class, 'json', [
            DateTimeNormalizer::FORMAT_KEY => 'U',  // When using string value - change the format to 'd-m-Y'
        ]);

        // dd($triggerErrorObject->getExampleDate());  // When using string value - this dumps a normal DateTime object

        return new JsonResponse($data, 200, [], true);
    }
}

class ExampleEntity
{
    private \DateTime $exampleDate;

    public function getExampleDate(): \DateTimeInterface
    {
        return $this->exampleDate;
    }

    public function setExampleDate(\DateTime $exampleDate): void
    {
        $this->exampleDate = $exampleDate;
    }
}

Possible Solution

Maybe revert the changes in src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php:94:

-       if (null === $data || (\is_string($data) && '' === trim($data))) {
+       if (null === $data || !\is_string($data) || '' === trim($data)) {

Or cover the case for timestamps in the validation.

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions