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
- Install Drupal
- Add a Date field to the article content type, with 'Date only', and the default set to 'Current date'
- Add another date field with 'Date and time' and the default set to 'Current date'
- Set the site timezone to one that is ahead of UTC, where the current day is different (e.g. 7pm in LA)
- Create a node, see that the date is different between the fields
- Set the timezone to UTC
- 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
Comment | File | Size | Author |
---|---|---|---|
#56 | 2993165-56.patch | 5.64 KB | pooja saraah |
#55 | 2993165-date-only-field-shows-incorrect-default-value-55-d94.patch | 5.67 KB | VladimirAus |
#49 | 2993165-49.patch | 827 bytes | tannguyenhn |
Issue fork drupal-2993165
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:
Comments
Comment #2
kkasson CreditAttribution: kkasson commentedThis patch seems to fix the problem for me, but I'm unsure of any potential downstream implications of this change.
Comment #3
kkasson CreditAttribution: kkasson commentedComment #4
mpdonadioCan 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.
Comment #5
mpdonadioConfirmed 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
we don't test that through the widget, just the field.
That test class needs to be burninated.
Comment #6
kkasson CreditAttribution: kkasson commentedComment #7
mpdonadioHere'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.
Comment #9
kkasson CreditAttribution: kkasson commentedSo 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:
Comment #10
mpdonadio#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.
Comment #11
kkasson CreditAttribution: kkasson commentedI 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!
Comment #12
kkasson CreditAttribution: kkasson commentedWhoops, trying that again.
Comment #13
kkasson CreditAttribution: kkasson commentedComment #14
mpdonadioNot sure if we have a valid solution. Right now (Tue Sep 11 00:52:56 UTC 2018), Pacific/Midway is failing locally.
Comment #16
kkasson CreditAttribution: kkasson commentedThis one is working for me. The date components have to be stored before the time zone is changed, or it causes the original problem.
Comment #17
mpdonadio#16 still fails for me locally (at Tue Sep 11 03:01:54 UTC 2018) at Pacific/Midway at
Comment #18
kkasson CreditAttribution: kkasson commentedVery 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.
Comment #19
BerdirNot 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
Comment #23
nicxvan CreditAttribution: nicxvan commented#19 didn't fix this, I'm on 8.9.6 and this issue is still occurring.
Applying 16 fixed it.
Comment #24
raman.b CreditAttribution: raman.b at OpenSense Labs commentedComment #27
edmonkey CreditAttribution: edmonkey commentedJust mentioning similar issue at https://www.drupal.org/project/drupal/issues/3069854
Comment #29
pameeela CreditAttribution: pameeela commentedUpdated 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.
Comment #30
Madhu kumar CreditAttribution: Madhu kumar as a volunteer and at Zyxware Technologies commentedI am unable to replicate the issue with timezone set to Los Angeles and working fine. Added Screenshot for the reference.
Comment #31
wombatbuddy CreditAttribution: wombatbuddy commentedShared the patch from #3069854 which was closed as duplicate.
Comment #37
tatianag CreditAttribution: tatianag commented9.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.
Comment #39
jannakha CreditAttribution: jannakha as a volunteer and at Tomato Elephant Studio for Australian Competition and Consumer Commission (ACCC) commentedNo, 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.
Comment #40
xurizaemon@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 patchesdownloaded 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).Comment #41
jannakha CreditAttribution: jannakha as a volunteer and at Tomato Elephant Studio for Australian Competition and Consumer Commission (ACCC) commentedWOW 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.
Comment #42
dwwPublic 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
Comment #43
dwwMeanwhile, the MR is currently failing tests, so this can’t be RTBC. 😉
Comment #45
SpokjeComment #46
Spokje- Merged latest commits from
9.4.x-dev
into MR- Fixed deprecations
- TLC
- Added test-only patch
Comment #47
xurizaemon@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.
Comment #48
xurizaemonAttaching a copy of MR !1575 as of ca2bdea3 as Gitlab MR URLs are subject to unexpected changes (ref #3204538).
Comment #49
tannguyenhn CreditAttribution: tannguyenhn at Lil Engine, Department of Customer Service, NSW for Department of Customer Service, NSW commentedComment #51
ranjith_kumar_k_u CreditAttribution: ranjith_kumar_k_u at Zyxware Technologies commentedComment #53
xurizaemonQuick re-roll for 9.5.x accounting for https://www.drupal.org/node/3168858
Back to NR
Comment #54
xurizaemonAnd back to NW, too quick :)
@ranjith do you want to update your patch to incorporate CR#3168858: drupalPostForm() in functional tests is deprecated instead?
Comment #55
VladimirAusUpdate dpatch for 9.4
Comment #56
pooja saraah CreditAttribution: pooja saraah at Srijan | A Material+ Company for Drupal India Association commentedFixed Failed Commands #55
Comment #57
dieuweNow 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.
Comment #58
alexpottI 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!
This shouldn't be added to the base class. Moved it to the new test.
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.
Comment #63
SpokjeCreated #3313838: Improve documentation on \Drupal\Component\Datetime\DateTimePlus::setDefaultDateTime() for the documentation update follow-up.
Comment #64
alexpottPretty sure this has introduced a random fail... see https://dispatcher.drupalci.org/job/drupal_patches/151663/
Comment #65
SpokjeCouldn't reproduce that error in 1500x run of
DateTimeWidgetTest
on several PHP/SQL combos.https://www.drupal.org/project/drupal/issues/3292008#comment-14723406
Comment #66
BerdirThat 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.
Comment #67
SpokjeOne 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! :)
Comment #68
BerdirFWIW, 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.
Comment #69
Shubham Chandra CreditAttribution: Shubham Chandra as a volunteer and at Dotsquares Ltd. commentedApplied patch #56 in drupal 10.0.x
Comment #70
Spokje@Shubham Chandra: I'm unsure why a committed patch needs a reroll?
Comment #71
Wim LeersCan this explain the failure at #3313473-26: CKEditor 5 plugin definitions should be derivable? 🤔 (@Berdir just pointed me here)