Problem/Motivation

Likely regression from #2778083: Default value for Date-Only fields is broken when UTC date is different than user current date

Given a date field, with the 'Date only' setting and 'Current date' as the default, the current date can be wrong for the configured time zone. It works as expected if the field is set to 'Date and time'

Screenshot of two date fields, one with Date only and one with Date and time, using Current date as the default, with timezone set to Los Angeles:

Same node, with the timezone set to UTC:

Steps to reproduce

  1. Install Drupal
  2. Add a Date field to the article content type, with 'Date only', and the default set to 'Current date'
  3. Add another date field with 'Date and time' and the default set to 'Current date'
  4. Set the site timezone to one that is ahead of UTC, where the current day is different (e.g. 7pm in LA)
  5. Create a node, see that the date is different between the fields
  6. Set the timezone to UTC
  7. See that the date is correct

It seems like this was caused by the changes in #2830094: Deprecate and remove usages of datetime_date_default_time()., specifically the changes in DateTimeWidgetBase.php around line 39.

When that code originally used datetime_date_default_time(), $date was first set to 12:00:00 and then the timezone was change. After the code was changed to not use datetime_date_default_time(), now the timezone is set first and then the time is set to 12:00:00. This doesn't produce the same result; it will now give the UTC date instead of the local time zone date.

Proposed resolution

Call $this->createDefaultValue() before calling $date->setTimezone() in line 39 of DateTimeWidgetBase.php

Remaining tasks

User interface changes

API changes

Data model changes

CommentFileSizeAuthor
#69 2993165-69.patch1.96 KBShubham Chandra
#56 2993165-56.patch5.64 KBpooja saraah
#55 2993165-date-only-field-shows-incorrect-default-value-55-d94.patch5.67 KBVladimirAus
#53 drupal_core-2993165-Date-Only-field-shows-incorrect-default-value-52.patch6.08 KBxurizaemon
#51 2993165-51.patch5.62 KBranjith_kumar_k_u
#49 2993165-49.patch827 bytestannguyenhn
#48 drupal_core-2993165-Date-Only-field-shows-incorrect-default-value.patch6.26 KBxurizaemon
#45 2993165-test-only-should-fail.patch4.52 KBSpokje
#39 2022-03-16_10-55-00.png520.29 KBjannakha
#31 2993165-31.patch974 byteswombatbuddy
#30 date-and-time.png20.74 KBMadhu kumar
#24 interdiff_16-24.txt1.67 KBraman.b
#24 2993165-24.patch6.05 KBraman.b
#24 2993165-24-FAIL.patch4.47 KBraman.b
#16 interdiff-14-16.txt1.17 KBkkasson
#16 2993165-16.patch5.92 KBkkasson
#14 interdiff-13-14.txt4.11 KBmpdonadio
#14 2993165-14.patch5.92 KBmpdonadio
#13 2993165-13.patch5.21 KBkkasson
#12 2993165-12.patch5.13 KBkkasson
#11 2993165-11.patch5.13 KBkkasson
#7 2993165-test-only.patch3.75 KBmpdonadio
#7 2993165-07.patch4.71 KBmpdonadio
#2 2993165.patch987 byteskkasson

Issue fork drupal-2993165

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

kkasson created an issue. See original summary.

kkasson’s picture

This patch seems to fix the problem for me, but I'm unsure of any potential downstream implications of this change.

kkasson’s picture

Version: 8.5.x-dev » 8.6.x-dev
mpdonadio’s picture

Version: 8.6.x-dev » 8.7.x-dev
Status: Active » Needs work
Issue tags: +Needs tests

Can we get a functional test (ie, a BrowserTestBase one) to demonstrate the problem? Kinda baffled that the TZ loop DatetimeFieldTest w/ dateonly fields doesn't catch this.

mpdonadio’s picture

Confirmed the bug. The problem is the initial default value, when the node is new.

In looking at DateTimeFieldTest::testDefaultValue(), it looks like we are missing an assertion of the form value for the 'Current date' setting. In

      // Create a new node to check that datetime field default value is +90
      // days.
      $new_node = Node::create(['type' => 'date_content']);
      $expected_date = new DrupalDateTime('+90 days', drupal_get_user_timezone());
      $this->assertEqual($new_node->get($field_name)->offsetGet(0)->value, $expected_date->format(DateTimeItemInterface::DATE_STORAGE_FORMAT));

we don't test that through the widget, just the field.

That test class needs to be burninated.

kkasson’s picture

Issue summary: View changes
mpdonadio’s picture

Here's a start at a test. Looks like the patch works, except for for Pacific/Tongatapu (which is UTC+13). Haven't looked at that yet.

Status: Needs review » Needs work

The last submitted patch, 7: 2993165-test-only.patch, failed testing. View results

kkasson’s picture

So actually when reviewing the code here, the

$date->setTimezone(new \DateTimeZone($element['value']['#date_timezone']));

at line 40 isn't necessary since

$date = $this->createDefaultValue($date, $element['value']['#date_timezone']);

right before that calls setTimezone() with that same parameter.

It looks like that test failure is because of how $date->setDefaultDateTime() works - it sets the time to noon, which when changed to UTC+13 gives the wrong value. The comment on setDefaultDateTime() seems to acknowledge this:

  /**
   * Sets the default time for an object built from date-only data.
   *
   * The default time for a date without time can be anything, so long as it is
   * consistently applied. If we use noon, dates in most timezones will have the
   * same value for in both the local timezone and UTC.
   */
mpdonadio’s picture

#9, yeah 'Pacific/Tongatapu' was specifically added the the date-only TZ test "loop" because it is permanent UTC+13 (extreme edge case, and Fiji is +12+13 depending on DST). I am just really baffled why we are seeing this now, and not when we fixed that mess in the first place.

kkasson’s picture

I think this is the desired behavior, from what I can understand from the comments in the datetime module.

There may be a more elegant way to do it, but I think the functionality is correct here. With this one the generated DateTime should always end up as noon UTC, on the date of the current date from the user's timezone. The existing code would set the time to noon in the user's timezone and then convert that to UTC, giving values like 2018-09-10 04:00:00 UTC or 2018-09-10 19:00:00 UTC. That gives you the same date-only portion, except for the extreme cases, but still doesn't seem very clean because you're actually generating a different value in different time zones. Since it's date-only it ends up being saved to the DB as only the date, so in the end it doesn't really matter that the times are different, but it seems to make more sense to always use noon UTC instead of noon in the user's timezone. That way you're more effectively eliminating the time potion.

Hopefully I'm understanding things right, and this patch passes!

kkasson’s picture

Whoops, trying that again.

kkasson’s picture

mpdonadio’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
FileSize
5.92 KB
4.11 KB

Not sure if we have a valid solution. Right now (Tue Sep 11 00:52:56 UTC 2018), Pacific/Midway is failing locally.

Status: Needs review » Needs work

The last submitted patch, 14: 2993165-14.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

kkasson’s picture

This one is working for me. The date components have to be stored before the time zone is changed, or it causes the original problem.

mpdonadio’s picture

#16 still fails for me locally (at Tue Sep 11 03:01:54 UTC 2018) at Pacific/Midway at

      $today_storage = $this->dateFormatter->format($request_time, 'html_date', NULL, DateTimeItemInterface::STORAGE_TIMEZONE);
      $this->assertEquals($today_storage, $node->field_dateonly->value);
kkasson’s picture

Very weird, I can't get it to happen locally. I even added an instance of every time zone to the test list, and all 46 assertions passed. The failure must be dependent on the system time[zone], or something like that?

Also interesting that the tests passed on #13 but failed on #16 - the code was the same except for adding a comment.

Berdir’s picture

Not sure, but this might be another issue that's fixed/improved with #3009377: Replace drupal_get_user_timezone with a date_default_timezone_get() and an event listener

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.

nicxvan’s picture

#19 didn't fix this, I'm on 8.9.6 and this issue is still occurring.

Applying 16 fixed it.

raman.b’s picture

The last submitted patch, 24: 2993165-24-FAIL.patch, failed testing. View results

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.

edmonkey’s picture

pameeela’s picture

Issue summary: View changes

Updated with info from #3069854: 'Current date' default for date only field can be off depending on time zone setting which I closed as a duplicate, and also adding credit from that issue.

Madhu kumar’s picture

FileSize
20.74 KB

I am unable to replicate the issue with timezone set to Los Angeles and working fine. Added Screenshot for the reference.

wombatbuddy’s picture

Status: Needs review » Needs work

The last submitted patch, 31: 2993165-31.patch, failed testing. View results

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.

tatianag made their first commit to this issue’s fork.

tatianag’s picture

Status: Needs work » Needs review

9.2.x: PHP 7.4 & MySQL 8
Regional settings: Pacific/Auckland (+13:00)

I checked 2993165-31.patch It removes the code that changes the timezone, but the issue is still there.

I've tested 2993165-24.patch and it fixes the issue. That patch has been re-rolled in MR!1575.

xurizaemon made their first commit to this issue’s fork.

jannakha’s picture

Status: Needs review » Needs work
FileSize
520.29 KB

No, patch #31 is not working correctly.

My timezone is +11hrs (Sydney)

Date-only date is loaded from UTC and converted to Sydney, so every time date is saved (before 11am local time) it's saved in UTC which is -1 day! See screenshot of saving a node twice changes the date.

Timezone of the date and of the widget should be always UTC to keep the date consistent.

It's a display issue of today's date (when server's date is on the next day from UTC).

I'll investigate further.

xurizaemon’s picture

@jannakha Your experience is noted I think by @tatianag in comment 37 - so you may find that the open MR!1575 addresses your situation.

@tatianag and I are way ahead of you - that's a joke, because we're in UTC+13 ;)

Note that MR!1575 is more recent than patch #31.

MR link "Plain diff" under the issue description can be used in composer patches downloaded to your project to provide a patch that won't change unexpectedly (see #3204538: GitLab Merge Requests Unable to Generate Incremental Patch Files on this).

jannakha’s picture

Status: Needs work » Reviewed & tested by the community

WOW cool! yes, I can see now!
perfect!
thank you, kiwi friends!

so patch #24 and MR!1575 is correct!

Tested and it works!
I hope it'll end up in the core soon.

dww’s picture

MR link "Plain diff" under the issue description can be used in composer patches.

Public service announcement: You should never do this. Anyone can push more code to the MR, and on the next deployment your site could all of a sudden be broken, or worse, vulnerable to a backdoor, hack, etc. The only safe thing to do is download such a plain diff, audit it / verify it’s the code you want, commit the known-good version of the patch to your site’s Git repo and have composer apply the local patch.

Safe site building,
-Derek

dww’s picture

Status: Reviewed & tested by the community » Needs work

Meanwhile, the MR is currently failing tests, so this can’t be RTBC. 😉

Spokje made their first commit to this issue’s fork.

Spokje’s picture

Status: Needs work » Needs review

- Merged latest commits from 9.4.x-dev into MR
- Fixed deprecations
- TLC
- Added test-only patch

xurizaemon’s picture

@spokje - thanks for the patch, nice work!

@dww - thanks for the clarification, agree and my comment intended to direct @jannakha to the availability of the patch was missing the additional guidance you added.

xurizaemon’s picture

Attaching a copy of MR !1575 as of ca2bdea3 as Gitlab MR URLs are subject to unexpected changes (ref #3204538).

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.

ranjith_kumar_k_u’s picture

Status: Needs review » Needs work

The last submitted patch, 51: 2993165-51.patch, failed testing. View results

xurizaemon’s picture

Quick re-roll for 9.5.x accounting for https://www.drupal.org/node/3168858

Back to NR

xurizaemon’s picture

Status: Needs review » Needs work

And back to NW, too quick :)

@ranjith do you want to update your patch to incorporate CR#3168858: drupalPostForm() in functional tests is deprecated instead?

pooja saraah’s picture

Fixed Failed Commands #55

dieuwe’s picture

Status: Needs review » Reviewed & tested by the community

Now that New Zealand is in daylight savings time (UTC+13) it's possible to test this patch properly in the wild. I have it running on several production sites and we'll be rolling this out to others as needed.

alexpott’s picture

Version: 9.5.x-dev » 9.4.x-dev
Status: Reviewed & tested by the community » Fixed
Issue tags: +Needs followup

I think we should reconsider the documentation of \Drupal\Component\Datetime\DateTimePlus::setDefaultDateTime() - on its own this method leads to this problem. It's called from a few places in core but this is the only place where the timezone on the date might not be UTC. The other runtime place is \Drupal\datetime\DateTimeComputed::getValue() - fwiw I'm not sure if implementation is correct. Dates and timezone stuff is hard to reason about. But this should be in a follow-up to improve the docs on setDefaultDateTime

Backported to 9.4.x because this is a non-disruptive bug fix.

Committed and pushed c9d63410bc to 10.1.x and e126af9cb0 to 10.0.x and 489730b19f to 9.5.x and b12a1586e3 to 9.4.x. Thanks!

diff --git a/core/modules/datetime/tests/src/Functional/DateTestBase.php b/core/modules/datetime/tests/src/Functional/DateTestBase.php
index ea76cd7898..57cc4cb641 100644
--- a/core/modules/datetime/tests/src/Functional/DateTestBase.php
+++ b/core/modules/datetime/tests/src/Functional/DateTestBase.php
@@ -23,11 +23,6 @@ abstract class DateTestBase extends BrowserTestBase {
    */
   protected static $modules = ['node', 'entity_test', 'datetime', 'field_ui'];
 
-  /**
-   * {@inheritdoc}
-   */
-  protected $defaultTheme = 'stark';
-
   /**
    * An array of display options.
    *
diff --git a/core/modules/datetime/tests/src/Functional/DateTimeWidgetTest.php b/core/modules/datetime/tests/src/Functional/DateTimeWidgetTest.php
index fe2399e96a..6f6e7449dc 100644
--- a/core/modules/datetime/tests/src/Functional/DateTimeWidgetTest.php
+++ b/core/modules/datetime/tests/src/Functional/DateTimeWidgetTest.php
@@ -13,6 +13,11 @@
  */
 class DateTimeWidgetTest extends DateTestBase {
 
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
   /**
    * The default display settings to use for the formatters.
    *

This shouldn't be added to the base class. Moved it to the new test.

diff --git a/core/modules/datetime/tests/src/Functional/DateTimeWidgetTest.php b/core/modules/datetime/tests/src/Functional/DateTimeWidgetTest.php
index 6f6e7449dc..529d06c96b 100644
--- a/core/modules/datetime/tests/src/Functional/DateTimeWidgetTest.php
+++ b/core/modules/datetime/tests/src/Functional/DateTimeWidgetTest.php
@@ -4,7 +4,6 @@
 
 use Drupal\field\Entity\FieldConfig;
 use Drupal\field\Entity\FieldStorageConfig;
-use Drupal\Node\Entity\Node;
 
 /**
  * Tests Datetime widgets functionality.
@@ -94,10 +93,7 @@ public function testDateonlyDefaultValue() {
       $this->submitForm($edit, 'Save');
       $this->assertSession()->pageTextContains('dateonly_content ' . $timezone . ' has been created');
 
-      preg_match('|node/(\d+)|', $this->getUrl(), $match);
-      $nid = $match[1];
-      $node = Node::load($nid);
-
+      $node = $this->drupalGetNodeByTitle($timezone);
       $today_storage = $this->dateFormatter->format($request_time, 'html_date', NULL, $timezone);
       $this->assertEquals($today_storage, $node->field_dateonly->value);
     }

Loaded the node in a better way that does not use a regular expression. Ran the test locally with this change and it works great.

  • alexpott committed c9d6341 on 10.1.x
    Issue #2993165 by kkasson, tatianag, Spokje, mpdonadio, xurizaemon,...

  • alexpott committed e126af9 on 10.0.x
    Issue #2993165 by kkasson, tatianag, Spokje, mpdonadio, xurizaemon,...

  • alexpott committed 489730b on 9.5.x
    Issue #2993165 by kkasson, tatianag, Spokje, mpdonadio, xurizaemon,...

  • alexpott committed b12a158 on 9.4.x
    Issue #2993165 by kkasson, tatianag, Spokje, mpdonadio, xurizaemon,...
Spokje’s picture

alexpott’s picture

Pretty sure this has introduced a random fail... see https://dispatcher.drupalci.org/job/drupal_patches/151663/

Spokje’s picture

Couldn't reproduce that error in 1500x run of DateTimeWidgetTest on several PHP/SQL combos.
https://www.drupal.org/project/drupal/issues/3292008#comment-14723406

Berdir’s picture

That might be because you didn't run it at the correct time of the day :)

Is it possible that we did run that _exactly_ as the day changed from one the other other? We do test a lot of timezones there, so if it runs around a full our, that seems totally possible. Especially as we use the request time of the test run process and not the current time. We can probably reduce it by changing it to getCurrentTime(), but there's still a slight chance of that happening.

Spokje’s picture

That might be because you didn't run it at the correct time of the day :)

One of these days I'm going to actually use my brain...
No guarantee that will change anything to the better side of things, since apparently it hasn't been used for a long time.

Thanks @Berdir, that must indeed be the problem.

I'll try to get a test up at the (infamous) "change-of-the-day" time-of-day by tomorrow.
Anybody that can beat me to it: Please do! :)

Berdir’s picture

FWIW, that's easier said than done. You need to calculate the time it takes from uploading the patch until it starts to run the test (which is not always the same as there are queues on both DrupalCI and drupal.org involved). If you run it thousands of times that helps a bit with the timeframe during which you can do that but it also depends on how the repeat option works. If that runs the test sequentially then you really will only have on run that might happen at the problematic time.

Shubham Chandra’s picture

Applied patch #56 in drupal 10.0.x

Spokje’s picture

@Shubham Chandra: I'm unsure why a committed patch needs a reroll?

Wim Leers’s picture

Can this explain the failure at #3313473-26: CKEditor 5 plugin definitions should be derivable? 🤔 (@Berdir just pointed me here)

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.