Problem/Motivation
#2632040: [PP-1] Add ability to select a timezone for datetime field currently has 117 followers and we're on comment #290. The latest patch is 98k. It risks never being completed. The scope is too huge, there are too many moving pieces. It needs to be split up and tackled in smaller, more actionable pieces.
Proposed resolution
@jonathanshaw proposed a way to split it up into an actionable plan at #2632040-107: [PP-1] Add ability to select a timezone for datetime field, and other users (@dww, @WidgetsBurritos, @amjad1233, et al) support the approach.
This issue is a parent meta plan to coordinate the moving pieces. Once this is finally complete, we can reply at the parent and mark it fixed, notifying all the followers when the feature is working and committed.
High-level overview of the plan:
- Refactor datetime formatters to simplify the logic.
- Give settings to the datetime widgets (shared in common with the formatters, and date_range) that allow sitebuilders to control the time zone used to interpret input.
- Add a new (optional) property to the date field (and date_range) that stores the preferred time zone.
- Create thorough tests to verify that all this arcane time zone handling is working correctly everywhere.
Remaining tasks
Child issues
- #3185728: Create TimezoneFieldTest class
- #3185729: Refactor datetime formatters
- #3185730: Move formatter timezone settings into a trait
- #3185733: Apply timezone trait to datetime widgets
- #3185734: Add per-instance datetime timezone storage
General points (needs triage)
- Add tests for the widget and formatter settings forms
- Extend tests to cover date range
- Extend tests for the full range of formatters and widgets
- Debug the date_range formatter
- Various minor cleanups, debugging and testing per #105.
- Upgrade path tests
- Finish/reroll the datetime element once #2799987: Datetime and Datelist element's timezone handling is fragile, buggy and wrongly documented gets fixed
- Add constraint test coverage if #2847041: Add a format and start/end validation constraints to DateRangeItem to provide helpful REST/JSON:API error message gets resolved before this issue does
- Address deprecated tests per #242.1
- Resolve issue with JSON:API's handling of datetime data structure as described in #242.2
- Add migration-related test coverage per #245.1
User interface changes
A timezone handling configuration drop down on field storage configuration, and if configured for per-date storage, a timezone selector on the date widget. See child issues for details.
Screenshots






API changes
- The
datetimeform element will have an optional#expose_timezoneboolean, that if TRUE, will add a timezone selector to the element. - Date time widgets and formatters will have various new methods. Possibly getDefaultValue() should be public.
See child issues for details.
Data model changes
Datetime storage will store a timezone per date.
See child issues.
Release notes snippet
@todo
Comments
Comment #2
dwwMoving items from the parent summary to here.
The proposed resolution is a good overview of this plan.
These remaining tasks are copied from the parent. They should be triaged and moved into the appropriate child issue(s).
Comment #3
mpdonadioThanks @dww and others for taking the helm here to keep this moving. Reading the original post brought back a little PTSD, as that started the cascade of uncovering a lot of TZ related bugs.
Plan seems great.
Comment #4
pounardJust a ignorant set of questions, because I didn't follow any of the other issues, but:
timestamp with time zoneis SQL-92 standard, but as I recall, only PostgreSQL implements it, do you plan to use it ?timestamptype (which is different fromdatetime) is supposed to behave the same, i.e. converting all dates from the client set time zone to UTC when storing, do you plan on using this ?timestamptype, it will have the same limitations as UNIX timestamps (i.e. you can't set date before 1970's)My guess is that until the database layer doesn't handle the time zone itself, you will have bugs forever. PHP
\DateTime[Immutable]objects handle them well, the hardest part is to create the instances with the right time zones directly: you must always specify the time zone when creating your instances, or you'll have time shift bugs when converting.I just had to solve all those dates problems on a proprietary production project, spent 3 days working on the matter, with a custom (very close to Drupal's one) database access layer and query builder, MySQL and PostgreSQL support, many time zone related bugs, I'm quite sure you experienced all the same problems I had.
Comment #5
mpdonadioTimestamps (entity created / updates) and Unix timestamps as int. Datetime are ISO8601 strings w/o offset, and implicitly UTC. Both are legacy decisions.
Datetime are ISO8601 as strings b/c of this, and the lack of standardization across database backends. And the database backend adapter was added after this decision. This has the potential of being a huge contrib break because of the assumptions you can make with the strings.
Same as above.
Most time_t implementations are signed, which let you get back to about 1901 with a signed 32-bit. The 2038 problem is the rollover of a signed 32. Once you get into PHP, you are dealing w/ unix timestamps at the lowest level (\DateTime is a fancy wrapper for them). Core has test coverage for dates outside the 1901-2038 range.
A time machine would be great, but a lot of the these problems were discovered after Drupal 8 beta freeze, and BC support is very hard especially when a lot of these bugs are interconnected.
The biggest problem was realizing that testbot also ran in UTC, so a lot of test coverage was bad, which took a while to fix.
Yeah, but that isn't what this issue is about. Not storing the IANA TZ name w/ the value throws away information. An ISO string can give you the offset, but there are a myriad of quirks when you really care about wall time based on where you are (and the DST mess).
Comment #6
pounardThat's still a pretty rough limitation ! Timestamp should probably not be used, I know that it's a Drupal choice since the beginning so I will not argue about it, it's what it is for now, nevertheless in the long term, it should be good to get rid of those timestamps everywhere, including in node creation and update timestamp.
Wasn't it the goal to add interfaces and abstractions everywhere ? To be able to replace system parts without the need to rewrite all. But I agree, easier said than done.
I had to write those kind of unit tests too, preparing the environment by changing default time zone at runtime in tests is something doable.
That's a topic I had (very) long thoughts about, but in the end, it doesn't matter. Or should I say, it depends on your business, but most of the time, you don't care about storing the political zone name. It's a political information, not a time information, UTC is the absolute date the only thing you need to do proper conversions for display. After years worrying about this (I'm working on business proprietary software) storing the time zone has never been a requirement in the end. Storing a time zone or a time offset only gives you the information about where was the guy who input the date, but it doesn't give you anything more. Time zone is important for display, not for storage.
It took me a while to figure it out, but DST is not a mess. If you store UTC, every piece of library in the world will handle that for you, PostgreSQL does, PHP \DateTime objects do, etc. It works because those library will implement conversions using the IANA TZ database and standard. Of course, that's bugs put aside, but bugs should be fixed in your library you use, not in your code. Any attempt in writing workaround in your business code will eventually end up in catastrophic failure.
Comment #7
baysaa commentedHi, apologies if this is not the correct place to report bugs. We applied the patch in comment #277 of https://www.drupal.org/node/2632040 to my Drupal 8.9. But there seems to be an issue with DST and date range fields. We've set to allow overriding timezone per field instance on a specific date range field.
We are noticing that if we set the start date in daylight savings timezone (e.g. 1st January 2021 at 20:00:00 America/NewYork), the end date in Summer timezone (e.g. 1st May 2021 at 20:00:00 America/NewYork), and we're setting "America/New York" timezone for that specific field (issue is not exclusive to this TZ I imagine), then the end date is not converted correctly when saved to the database. The end date with above example should be saved as 2nd May 00:00:00 UTC (converted from 1st May 20:00:00 America/NewYork : +4 hours) but what we're seeing is it's saved as 2nd May 01:00:00 UTC (+5 hours : 1 extra hour wrongly added which seems to come from DST) in the database table. The start date is converted correctly.
If we set the start date to be in the summer time also, then both the dates are saved correctly with +4 hours offset added.
I tried to step through the code to find the cause but I'm not familiar enough with fields and where exactly they're converted and saved etc so ran out of time for this, and decided to leave a bug report.
At first it seemed like an issue when loading the data + converting timezones, but it looks like it's actually saved wrong into the database. What ends up happening is everytime a user edits a node with such date setup, 1 hour is added to the end date without user input/changing the dates. So 5 edits to the node, ends up adding 5 hours to the end date. This seems like a major bug
Currently the workaround seems to be to just use "UTC" timezone override for such a wide date range.
Comment #13
socialnicheguru commentedThere is this option: https://www.drupal.org/project/datetime_range_timezone