Problem/Motivation

DateTimePlus doesn't implement \JsonSerializable, so json_encode(new DateTimePlus()) just returns an empty object.

There are different reasons why it would be interesting to add this support to DateTimePlus

  • First, it would increase the compatibility of Drupal's special object DateTimePlus with PHP's DateTime object.
  • Furthermore, it would add the capacity for Drupal's Date Form field to have a JSON representation, like many other Drupal fields.

Proposed resolution

Implement \JsonSerializable and create a public function jsonSerialize

Remaining tasks

Tests.

User interface changes

None.

API changes

DateTimePlus will implement \JsonSerializable

Data model changes

None.

CommentFileSizeAuthor
#51 rerolled-2828835-51.patch3.89 KBVidushi Mehta
#35 interdiff.txt1.93 KBdenutkarsh
#35 2828835-35.patch3.83 KBdenutkarsh
#30 interdiff.txt2.71 KBdenutkarsh
#30 2828835-30.patch3.98 KBdenutkarsh
#24 interdiff-2828835-22-24.txt1.02 KBdenutkarsh
#24 2828835-22-24.patch4.13 KBdenutkarsh
#22 interdiff-2828835-19-22.txt1.89 KBdenutkarsh
#22 2828835-19-22.patch4.12 KBdenutkarsh
#19 interdiff-2828835-18-19.txt813 bytesdenutkarsh
#19 2828835-18-19.patch3.21 KBdenutkarsh
#18 interdiff-16-18.txt2.51 KBmpdonadio
#18 2828835-18.patch2.85 KBmpdonadio
#16 interdiff-2828835-9-16.txt1.22 KBdenutkarsh
#16 2828835-16-test-only.patch1018 bytesdenutkarsh
#9 Drupal_DateTime_have_no_render_to_json_encode-Test_Only_Patch-2828835-11789248-D_8_2_x.patch638 bytesdenutkarsh
#8 2828835-test-only1.patch638 bytesdenutkarsh
#7 2828835-test-only.patch638 bytesdenutkarsh
#5 drupal_datetime_have_no-2828835-5.patch931 bytesJulfabre
#2 edit_drupal_datetime-2828835-1.patch825 bytesJulfabre
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Julfabre created an issue. See original summary.

Julfabre’s picture

mpdonadio’s picture

Status: Active » Needs review
Issue tags: -json datetime improvement +Needs tests
mpdonadio’s picture

Thanks for identifying this. Really quick initial look.

  1. +++ b/core/lib/Drupal/Component/Datetime/DateTimePlus.php
    @@ -23,7 +23,7 @@
    +class DateTimePlus implements \JsonSerializable{
     
    

    Nit. Needs space before the opening brace.

  2. +++ b/core/lib/Drupal/Component/Datetime/DateTimePlus.php
    @@ -288,6 +288,15 @@ public function __construct($time = 'now', $timezone = NULL, $settings = array()
    +   * Renders the json format.
    

    How about "Returns a representation of the object for use in JSON serialization."

  3. +++ b/core/lib/Drupal/Component/Datetime/DateTimePlus.php
    @@ -288,6 +288,15 @@ public function __construct($time = 'now', $timezone = NULL, $settings = array()
    +  public function jsonSerialize() {
    +    return $this->render();
    +  }
    

    Not sure this is really the right thing to do, and it won't mirror the way json_encode(\new DateTime()) works, and it loses information about the object (like the langcode).

This will need test coverage when/if we decide if we want to do this. I think we need to do this, but I would prefer core extends the way json_encode(\new DateTime()) works, rather than just using a rendered string.

Julfabre’s picture

Hi @mpdonadio,

1. => Ok,
2. => Ok, I've change for : "Returns the DateTime object and langcode for use in JSON serialization"
3. => Ok, I try to understand the json encode method for \DateTime, but it's seems to be magic ;)
So I try to use it and add langcode from Drupal DateTimePlus.
for now it's like this :

{"datetime":{ "date":"2016-11-21 13:54:03.000000",
                     "timezone_type":3,
                     "timezone":"Europe\/Paris"},
  "langcode":null}
mpdonadio’s picture

Issue summary: View changes
Status: Needs review » Needs work

I think this format should be OK.

Setting to NW because we need tests to prevent a regression.

denutkarsh’s picture

FileSize
638 bytes

Here is my Test Patch that i have created.

denutkarsh’s picture

FileSize
638 bytes
denutkarsh’s picture

I have made the test patch for this issue which checks if serializing DateTimePlus returns empty object or not. Here is my code:-

 public function testIsSerilizable(){
    $t = json_decode(json_encode(new DateTimePlus()),true);
    $t = array_filter($t);
    $this->assertSame(empty($t),false);
  }
denutkarsh’s picture

Title: Drupal DateTime have no render to json_encode » Created a Test for this issue
Version: 8.3.x-dev » 8.2.x-dev
Category: Feature request » Task

A simple test for this could be checking weather the json_encode(new DateTimePlus()) is empty or not. Here is the code that i wrote for testing.

  public function testIsSerilizable(){
    $t = json_decode(json_encode(new DateTimePlus()),true);
    $t = array_filter($t);
    $this->assertSame(empty($t),false);
  }
denutkarsh’s picture

Title: Created a Test for this issue » Drupal DateTime have no render to json_encode
Version: 8.2.x-dev » 8.3.x-dev
Category: Task » Feature request

A simple test for this could be checking weather the json_encode(new DateTimePlus()) is empty or not. Here is the code that i wrote for testing.

  public function testIsSerilizable(){
    $t = json_decode(json_encode(new DateTimePlus()),true);
    $t = array_filter($t);
    $this->assertSame(empty($t),false);
  }
mpdonadio’s picture

Status: Needs work » Needs review

Thanks for the test. Setting NR for testbot. Will comment later. Also, make sure you post an interdiff with a new patch.

Status: Needs review » Needs work
mpdonadio’s picture

Issue tags: +Needs change record

Thanks for picking this up.

+++ b/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php
@@ -665,5 +665,12 @@ public function providerTestInvalidDateDiff() {
-
+   /*
+  Check if DateTimePlus is serilizable
+  */
+  public function testIsSerilizable(){
+    $t = json_decode(json_encode(new DateTimePlus()),true);
+    $t = array_filter($t);
+    $this->assertSame(empty($t),false);
+  }
 }

OK, ran this locally and it does fail on its own, and pass with #5, which does demonstrate the problem. However, I am uncomfortable with this approach for commit. If we change how JSON serialization works, then this will still pass. I think we should just do the `json_encode` on known DateTimePlus objects (probably want to use a provider), and check the results.

This also has multiple coding standard problems that need to be addressed (we can't commit any patches that violate them). From a quick look

- the deleted line needs to be there (blank link between methods)
- there needs to be a blank line after the last method in the class, and the closing brace
- there needs to be a space between the method () and the opening brace
- boolean literals need to be TRUE / FALSE (ie, capitalized).
- the method needs to be in proper docblock format

For new patches, let's post the test-only patch along with the fix+test. Just make sure the test-only one is added first, and the full one is added second. This will preserve the issue status, assuming all is OK. (see https://www.drupal.org/contributor-tasks/write-tests)

Once we have the nearly done, we will need a short change record to announce it and document the format.

denutkarsh’s picture

mpdonadio, Just wanted to know how can i access dateTimeObject, from my test function....

denutkarsh’s picture

Status: Needs work » Needs review
FileSize
1018 bytes
1.22 KB

Updated my test function, to check weather after serialization the data is correct. Also i tried to follow coding standards this time.

 public function testIsSerilizable() {
   $a = new DateTimePlus("1970-01-01 00:00:00","UTC",array("langcode"=>"EN"));
   $t = json_decode(json_encode($a),TRUE);
   $t = array_filter($t);
   $this->assertSame(empty($t),FALSE);
   $l = json_decode(json_encode($t),TRUE);
   $this->assertEquals("1970-01-01 00:00:00.000000", $l["datetime"]["date"]);
   $this->assertEquals("UTC", $l["datetime"]["timezone"]);
   $this->assertEquals("langcode","EN");
 }

I have also attached the interdiff

Status: Needs review » Needs work

The last submitted patch, 16: 2828835-16-test-only.patch, failed testing.

mpdonadio’s picture

Status: Needs work » Needs review
FileSize
2.85 KB
2.51 KB

@denutkarsh, this is what I was thinking of. Let's add some more combinations of timezone and langcode to the provider. Looks like core convention is for the langcode value to be lower case. Think we can just do a full patch at this point.

Hit me up on IRC (or anyone there) if you need help.

denutkarsh’s picture

@mpdonadio Something like this ( i have just added one more set right now), we have to add more sets like this to make this test more function, is that right?

Status: Needs review » Needs work

The last submitted patch, 19: 2828835-18-19.patch, failed testing.

denutkarsh’s picture

@mpdonadio Can you tell me why the path i posted is showing that it has 2 fails, while yours shows "PHP 5.5 & MySQL 5.5 21,372 pass".

denutkarsh’s picture

I have added more sets in this new test patch.

denutkarsh’s picture

Status: Needs work » Needs review
denutkarsh’s picture

There was php fatal error in previous patch, here is the new one..

The last submitted patch, 22: 2828835-19-22.patch, failed testing.

denutkarsh’s picture

Issue tags: +Needs reroll
mpdonadio’s picture

Issue tags: -Needs reroll

This doesn't need a reroll. That is just for when patches don't apply. The fails are from known spurious failures. I'll post a review of the latest patch soon.

mpdonadio’s picture

Status: Needs review » Needs work
Issue tags: +Google Code-in

OK, we only need to test against 8.3.x. This cannot go into 8.2.x per the change policy, since it is a feature request.

  1. +++ b/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php
    @@ -666,4 +666,101 @@ public function providerTestInvalidDateDiff() {
    +      [
    +        DateTimePlus::createFromTimestamp(1482876655),
    +        [
    +          'datetime' => [
    +            'date' => '2016-12-28 09:10:55.000000',
    +            'timezone_type' => 3,
    +            'timezone' => 'Australia/Sydney',
    +          ],
    +          'langcode' => NULL,
    +        ],
    +      ],
    +      [
    

    This section is redundant, can be deleted (it is tested above).

  2. +++ b/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php
    @@ -666,4 +666,101 @@ public function providerTestInvalidDateDiff() {
    +        DateTimePlus::createFromTimestamp(1300000000,'UTC'),
    

    I would prefer to us 1400000000 for all of the timestamps in the tests (here and below).

  3. +++ b/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php
    @@ -666,4 +666,101 @@ public function providerTestInvalidDateDiff() {
    +        DateTimePlus::createFromTimestamp(139000000,'Europe/Berlin',array('langcode' => 'EN')),
    

    Nits, but we need spaces after the comma between parameters. We can use array shorthand [] for the options, and I would prefer to use lowercase 'en' to be consistent with core usage. Actually, let's use a valid langcode other than 'en' to be safe (here and below).

  4. +++ b/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php
    @@ -666,4 +666,101 @@ public function providerTestInvalidDateDiff() {
    +        DateTimePlus::createFromTimestamp(1300000000,'UTC',array('langcode' => 'EN')),
    

    OK, for this test, we need to test the default timezone with a non-default langcode, so pass in NULL. Per #2498619: Unit tests should use a default timezone other that UTC, the expected TZ should be 'Australia/Sydney', just like with the first set returned.

If this fails anywhere else than DateTimePlusTest, hang tight and let me look at it; we have a bunch #2829040: [meta] Known intermittent, random, and environment-specific test failures going on right now.

gvso’s picture

Issue tags: -Google Code-in +GCI16

@mpdonadio, thanks for reviewing the patch.

denutkarsh’s picture

@mpdonadio, Ok, I have uploaded new improved patch. I have also checked it on simplytest.me and it seems to pass all the tests.

denutkarsh’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 30: 2828835-30.patch, failed testing.

mpdonadio’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests

Unrelated random fail b/c #2828559: UpdatePathTestBase tests randomly failing. Will look at it when I can, or someone else can review it.

mpdonadio’s picture

Status: Needs review » Needs work

Sorry to push this back again over formatting, but there is too much to fix on commit.

  1. +++ b/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php
    @@ -666,4 +666,103 @@ public function providerTestInvalidDateDiff() {
    +  function providerTestSerialization() {
    

    I missed this, but this should be explicitly `public function providerTestSerialization`

  2. +++ b/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php
    @@ -666,4 +666,103 @@ public function providerTestInvalidDateDiff() {
    +        DateTimePlus::createFromTimestamp(
    +          1400000000
    +        ),
    

    Looks like this crept in with this patch, but the constructor calls should all be on one line. Here and below. In general, only multi-element arrays can be spread across multiple lines.

If we can fix those, I'll RTBC it.

denutkarsh’s picture

Status: Needs work » Needs review
FileSize
3.83 KB
1.93 KB

@mpdonadio I just used multiline for the constructor to avoid 80 cols violations. Anyways here is the new patch

mpdonadio’s picture

Assigned: Unassigned » jhedstrom

Realized that I have work in this, so will get @jhedstrom to set if RTBC if he thinks it looks good.

jhedstrom’s picture

Status: Needs review » Reviewed & tested by the community

This looks really good. Great tests and a very straightforward implementation/fix.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

According to #14 we need a change record.

Also the issue summary is missing the reason why we need this. Not all objects have to be json serializable - so what's the advantage to doing this change?

mpdonadio’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record

Took a stab at the CR.

mpdonadio’s picture

Assigned: jhedstrom » Unassigned
Status: Needs review » Postponed (maintainer needs more info)

@Julfabre, can you update the Issue Summary with a use case that describes why this is needed beyond what Drupal provides for Serialization as part of core? Thanks.

Julfabre’s picture

Issue summary: View changes
Julfabre’s picture

@mpdonadio : Ok I've updated the summary section.

I'm trying to create an change record page, but I'm newbie on this.

I hope it's like good for all of us.

mpdonadio’s picture

@Julfabre, thanks. I already made a change record for this. I need to discuss the two bullet points with others before we can proceed here. I thought all of the datetime fields already worked with the REST system.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

jhedstrom’s picture

Status: Postponed (maintainer needs more info) » Needs review

First, it would increase the compatibility of Drupal's special object DateTimePlus with PHP's DateTime object.

This reason alone seems worth making this change for?

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

jhedstrom’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

Patch needs to be rerolled. I'm inclined to get this in, as from what I can tell, our custom date time class should be serializable.

I'm not clear on why this doesn't cause more issues with existing serialization. One thought is that it's possible computed fields are always unset prior to serialization, so perhaps this doesn't appear when serializing an entity with a datetime field on it...

mpdonadio’s picture

#49, another hypothesis is that all of our REST stuff uses the ISO string and not the serialized object.

Vidushi Mehta’s picture

Status: Needs work » Needs review
FileSize
3.89 KB

Patch rerolled.

Vidushi Mehta’s picture

Issue tags: -Needs reroll
jhedstrom’s picture

Status: Needs review » Reviewed & tested by the community

Since DateTimePlus is a component, and can theoretically be used completely independently of Drupal, our REST system, and other things, I think it makes sense to allow it to be serializable since PHP's \DateTime can be serialized.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/tests/Drupal/Tests/Component/Datetime/DateTimePlusTest.php
@@ -713,6 +713,92 @@ public function providerTestInvalidDateDiff() {
   /**
+   * Tests that DateTimePlus objects can be encoded as JSON.
+   */
+  public function testIsSerializable() {
+    // Create a DateTimePlus, and go through a encode/decode round-trip.
+    $date = DateTimePlus::createFromTimestamp(1400000000);
+    $decoded = json_decode(json_encode($date), TRUE);
+
+    // Make sure the decoded value isn't empty.
+    $decoded = array_filter($decoded);
+    $this->assertFalse(empty($decoded));
+  }
+
+  /**
+   * Tests the DateTimePlus JSON encoding format.
+   *
+   * @param \Drupal\Component\Datetime\DateTimePlus $date
+   *   The test date.
+   * @param object $expected
+   *   The expected value when $date undergoes a JSON encode/decode.
+   *
+   * @dataProvider providerTestSerialization
+   */
+  public function testSerialization($date, $expected) {
+    // Perform an encode/decode round trip so we can compare simple objects,
+    // rather than precise strings.
+    $actual = json_decode(json_encode($date), TRUE);
+    $this->assertEquals($expected, $actual);
+  }

I don't get why we need both testIsSerializable() and testSerialization(). testSerialization() is enough - the other test doesn't appear do anything new.

Also we should have a follow-up to fix the docs of \Drupal\Component\Datetime\DateTimePlus::__construct() - the debug option does not appear exist and the only thing that is used in $settings is $settings['langcode'] which all seems quite odd.

There's also an open question about what should happen if it's an object with errors. Ie. what happens if the creation of PHP's \Datetime object fails. I think the errors property should also be serialized.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.