6

When attempting to perform a doctrine query and serialze it to json (not using JSM, using the symfony serializer) I get the following in the json:

""due":{"timezone":{"name":"Europe/Berlin","transitions":[{"ts":-2147483648,"time":"1901-12-13T20:45:52+0000","offset":3208,"isdst":false,"abbr":"LMT"},{"ts":-2147483648,"time":"1901-12-13T20:45:52+0000","offset":3600,"isdst":false,"abbr":"CET"},{"ts":-1693706400,"time":"1916-04-30T22:00:00+0000","offset":7200,"isdst":true,"abbr":"CEST"},{"ts":-1680483600,"time":"1916-09-30T23:00:00+0000","offset":3600,"isdst":false,"abbr":"CET"},{"ts":-1663455600,"time":"1917-04-16T01:00:00+0000","offset":7200,"isdst":true,"abbr":"CEST"},{"ts":-1650150000,"time":"1917-09-17T01:00:00+0000","offset":3600,"isdst":false,"abbr":"CET"},{"ts":-1632006000,"time":"1918-04-15T01:00:00+0000","offset":7200,"isdst":true,"abbr":"CEST"},{"ts":-1618700400,"time":"1918-09-16T01:00:00+0000","offset":3600,"isdst":false,"abbr":"CET"},{"ts":-938905200,"time":"1940-04-01T01:00:00+0000","offset":7200,"isdst":true,"abbr":"CEST"},{"ts":-857257200,"time":"1942-11-02T01:00:00+0000","offset":3600,"isdst":false,"abbr":"CET"},{"ts":-844556400,"time":"1943-03-29T01:00:00+0000","offset":7200,"isdst":true,"abbr":"CEST"},{"ts":-828226800,"time":"1943-10-04T01:00:00+0000","offset":3600,"isdst":false,"abbr":"CET"},{"ts":-812502000,"time":"1944-04-03T01:00:00+0000","offset":7200,"isdst":true,"abbr":"CEST"},{"ts":-796777200,"time":"1944-10-02T01:00:00+0000","offset":3600,"

When storing the due date, the timezone is saved and there is an additional timezone field stored. Is there a way to pull the date in a specific format or specify the timezone to use when retrieving?

 public function blahAction(Request $request)
{
    $currentUser = $this->getUser();
    $em = $this->getDoctrine()->getManager();
    $blahs = $em->getRepository('AppBundle:blah')->findAllByStatus($currentUser,'TODO');
    $encoders = array(new XmlEncoder(), new JsonEncoder());
    $normalizer = array(new ObjectNormalizer());
    $serializer = new Serializer($normalizer, $encoders);
    $response = new Response($serializer->serialize($blahs, 'json'));
    $response->headers->set('Content-Type', 'application/json');
    return $response;
}
3
  • Can you show "due" field definition? Commented Apr 8, 2018 at 13:37
  • /** * @ORM\Column(type="datetimetz", nullable=true) */ private $due; Commented Apr 11, 2018 at 8:59
  • Thanks. You must add DateTimeNormalizer. Check my answer. I prefer using Serializer service. Commented Apr 11, 2018 at 16:52

3 Answers 3

17

You have 2 ways to get RFC3339 Datetime format ...

Option 1:

Add DateTimeNormalizer as normalizer. An example is https://symfony.com/doc/current/components/serializer.html#recursive-denormalization-and-type-safety.

Change

$normalizer = array(new ObjectNormalizer());

by

$normalizer = array(new DateTimeNormalizer(), new ObjectNormalizer());

Option 2

More simple is using "serializer" container service ... your code will look like ...

public function blahAction(Request $request)
{
    $currentUser = $this->getUser();
    $em = $this->getDoctrine()->getManager();
    $blahs = $em->getRepository('AppBundle:blah')->findAllByStatus($currentUser,'TODO');
    $response = new Response($this->get('serializer')->serialize($blahs, 'json'));
    $response->headers->set('Content-Type', 'application/json');
    return $response;
}

.. or, if your prefer autowiring way (this code is unchecked)

public function blahAction(Request $request, \Symfony\Component\Serializer\SerializerInterface $serializer)
{
    $currentUser = $this->getUser();
    $em = $this->getDoctrine()->getManager();
    $blahs = $em->getRepository('AppBundle:blah')->findAllByStatus($currentUser,'TODO');
    $response = new Response($serializer->serialize($blahs, 'json'));
    $response->headers->set('Content-Type', 'application/json');
    return $response;
}
Sign up to request clarification or add additional context in comments.

1 Comment

Just note.. when defining $normalizer array, DateTimeNormalizer() should be first. Order matters.
4

In Symfony 5.1 it's recomended to add a callback function to specify datetime field format.For example:

use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;


$dateCallback = function ($innerObject, $outerObject, string $attributeName, string $format = null, array $context = []) {
        return $innerObject instanceof \DateTime ? $innerObject->format(\DateTime::ISO8601) : '';
    };

    $defaultContext = [
        AbstractNormalizer::CALLBACKS => [
            'created_at' => $dateCallback,
            'updated_at' => $dateCallback
        ],
        AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER =>
            function ($articles, $format, $context)  {
                return $articles->getId();
            }
    ];

    $encoders = [new JsonEncoder()];
    $normalizers = [
        new ObjectNormalizer(null, null, null,
            null, null, null,
            $defaultContext)
    ];

    $serializer = new Serializer(
        $normalizers, $encoders
    );

    $articles = $serializer->serialize($articles, 'json');

Where $articles = array of App\Entity\Article objects

You can specify datetime format you need in your callback function.

Comments

3

Another option is to pass arguments to the default DateTimeNormalizer in services.yaml:

  Symfony\Component\Serializer\Normalizer\DateTimeNormalizer:
    arguments:
      $defaultContext:
        datetime_format: 'Y-m-d\TH:i:s.v\Z'

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.