Problem/Motivation
Imagine an organisation WidgetCo with editors and users in a variety of different time zones. They commonly face 2 problems trying to use the Date module. Support for some of this was present in D7's date but lost as it went to D8 core.
A. When creating session entities as part of their annual conference in New York, the times of the sessions as input by the editor are interpreted by Drupal in terms of the time zone of the editor who is creating or updating it, not New York. In this case their sitebuilder needs to be able to control the time zone used by the widget to interpret the times the editors input.
B. When creating meeting entities to describe meetings held at various locations across the world, the same problem happens. But in this case the intended time zone needs to specified for each meeting by the editor, and that preference needs to be stored with the date/time.
Proposed resolution
This effort has become too large to be accomplished in a single issue.
#3185747: [META] Add timezone support to core date fields is the active plan issue to actually coordinate this effort in smaller pieces.
We should stop posting "composer-friendly" giant patches in here, too. It's important we have a place for folks to put the patches they're using on real sites while the dust settles on doing this properly, but we don't want those patches either in this issue, nor in the new meta. Those patches should now live at #3185750: Composer friendly patches adding timezones to core date fields
Ideally, no one else should comment here until #3185747 is marked fixed and we can close this.
General commentary on the new plan should happen at #3185747
Comments about specific pieces of the plan should go in the appropriate child issue.
Comments about the monster patches, re-rolls, conflicts, etc, should happen in #3185750
Remaining tasks
- Complete the plan described in #3185747: [META] Add timezone support to core date fields
- Mark this issue fixed to notify everyone.
User interface changes
TBD, see child issues.
API changes
TBD, see child issues.
Data model changes
TBD, see child issues.
Comment | File | Size | Author |
---|---|---|---|
#305 | 2632040-305.patch | 679 bytes | joseph.olstad |
#296 | interdiff-296-full--296-no-updates.txt | 8.53 KB | recrit |
#296 | 2632040-D9.2.x-296--no-updates.patch | 90.12 KB | recrit |
#296 | interdiff-2632040-296-full-293.txt | 670 bytes | recrit |
#296 | 2632040-D9.2.x-296--full.patch | 98.64 KB | recrit |
Issue fork drupal-2632040
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
mpdonadio+1 from me, but I'm not sure if we would be able to get this in 8.0.x (regressions for contrib that made it into core don't automatically count as bugs; it's up to the core maintainer's discretion).
Comment #3
andrewmacpherson CreditAttribution: andrewmacpherson as a volunteer commentedI agree this is a feature request, so bumping version.
Comment #4
jhedstromI was hoping to get further on this but ran out of time. Here's a very rough start. Current work takes heavily from the 7.x date module's timezone handling.
Comment #5
mpdonadioThanks. This will need upgrade path, but it will be easy to just add the default setting to all of the field instances.
Comment #6
jhedstromA start at tests.
Comment #7
swentel CreditAttribution: swentel commentedJust a thought here: wouldn't it be more interesting to add a new field type that stores a date + timezone.
That way we have a clear separation between two fields:
- one that stores dates always stores in UTC
- one that allows storing a date with timezone
That makes the
- the storage per field type very clear, no extra empty column - or worse having to update the tables in case you turn on/off timezone handling.
- it makes the upgrade path easier, as in, there shouldn't be one at all.
Comment #8
jhedstromUpdating IS.
Comment #9
jhedstromCross post there. I like the idea of #7 a lot.
Comment #10
mpdonadioNot sure if I like the idea of a different field type. Not totally against it, but would have to sleep on that one. The Drupal 7 Date module also stores the offset in the field table for the selected timezone. I believe it does this to allow date calculation to be handled at the SQL level when necessary.
Comment #11
swentel CreditAttribution: swentel commentedtldr: I now also think single field type is fine
----
So I thought some more about the split after I found #2161337: Add a Date Range field type with support for end date - theoretically we might end up with following scenario if we'd create different field types for all of them:
- single date
- single date with timezone
- single + end date
- single + end date with timezone
Now, more or less the same scenario exists for text (see #2313757: Remove text_processing option from text fields, expose existing string field types as plain text in UI) (which is where I got my 'inspiration' from) : plain vs formatted vs small vs long etc. In analogy with that patch it /could/ mean we'd expose TimestampItem as well in field UI some day (there is no reason to hide it imo) which would give us following field types exposed in Field UI
- single date (timestamp)
- single date + end date (timestamp)
- single date (iso8601)
- single date with timezone (iso8601)
- single + end date (iso8601)
- single + end date with timezone (iso8601)
Now, that looks a little silly, but then again, Field UI isn't perfect (ahum), but the field types and the API would be very clean, especially on the storage level, which in the end is probably my main concern as in: why have one (or more) column(s) that wouldn't store anything, right ? And with class inheritance, you call the parent, add a new column and property in the new class and you're done.
However, looking at the current datetime widgets and formatters, it'd especially mean a lot of new formatters and widgets per new field type, which on a first glance will lead to many duplicate code, or a lot of calls to the parent class in case of extending, let alone verbose names as well for the classes/files.
So, in the end, I think adding timezone in the same field type is fine, and the same for the end date too in that other issue.
Comment #12
mpdonadioWhat @swentel said. I spent a while thinking and working this out on paper yesterday, as well as reading the Drupal 7 Date module and issues, but didn't get a chance to write it up. It gets worse once you consider adding recurrences (which I think need to be in core, too; ugh). I just don't see how you can accomplish this w/o a really bad class hierarchy and bad (or less than proper) OO implementations.
Comment #13
mpdonadioJust reuploading the patch from #6 to get a TestBot run.
Comment #14
swentel CreditAttribution: swentel commentedI'm not sure anymore what happens in case you'd change the setting when there's no data yet and go from datetime to date: will the db column be added than or not, that's something to consider.
Comment #15
mikemiles86Comment #16
mpdonadioThanks for tagging this to be worked on this weekend, but we are going to postpone this on #2161337: Add a Date Range field type with support for end date. TZ support will be needed in some manner when we add end dates, and both patches are similar and touch the exact same portions of code.
Comment #17
mikemiles86Removing sprint tags, as this is postponed.
Comment #19
mpdonadioGiven the approach now in #2161337: Add a Date Range field type with support for end date, lets unpostpone this and see if we can work on both in parallel.
Let's go with the approach of adding a timezone property to the schema and always saving it in the field data. This will eliminate the dynamic schema.
?
Comment #20
jhedstromGoing to work on this a bit.
Comment #21
jhedstromStill more to do here. I added some
@todo
's in the patch, but additionally we will need more tests, and an upgrade path still.Comment #23
mpdonadioWas thinking about this today. Why do we need to do a schema update for storage? If this is really just about user entry, then why don't we just
- add the setting for the widget
- when we process the entry, warp the date to UTC based on the setting for storage; this is basically what we do now, we just don't give the user the option on how it happens per instance
- when the widget is used for editing, then we just need to use the setting to warp UTC back to what the setting uses
The upgrade path then just needs to add the default setting to add existing field instances (ie, just config), and not have to touch storage.
This has the added benefit that date storage is still sortable w/ simple string comparisons If we either update the storage string to add TZ or add another column for TZ, then things will get messy (especially for the Views plugins).
?
Comment #24
SKAUGHTjust to share my common use case for needing a timezone being collected (which almost always because a client 'wants visual timezone selection'):
content editor: -- event is going to be a video meeting.
end-user reviewing events (personalization)
@mpdonadio.
i will agree -- shouldn't need separate storage of the field as it should be a whole date stored. that can/will be easily converted come render time with somekind of personalizing to the end user.
it's always an issue of converting an original saved date/time in relation to location of the event it's being connected to... and the end user who's trying to match his schedule for it.
---------------------
or even (on the far side): date field should always have a location widget attached. HAHA.
Comment #25
SKAUGHTTimezone Picker
Comment #26
mpdonadio#24, thanks for outlining a use case. We may want to edit the authoring experience into the IS.
Just to clarify, we are talking about just the content authoring experience in this issue. I don't think there is a question of whether this is needed; we are just at the minutiae stage right now for how it gets implemented. We had originally thought that we would need to update how things get stored (which would bring it close to how the D7 Date module is implemented). I'm thinking now that we always store UTC, and that this new option just handles conversion before we store.
As for the user experience, we already have support for that. The field formatters support TZ overrides to force one for a field, else system default behavior is used (from how admin/config/regional/settings is set up).
IOW, handle entry and display as true inverses.
Comment #27
tstoecklerDon't want to hijack this issue (and maybe it is in fact a separate issue, but I don't think so), but I would argue that this is actually a bug report.
If you look into
\Drupal\Core\TypedData\Plugin\DataType\DateTimeIso8601::setDateTime()
you see that core itself uses PHP'sc
date format to store a date time. That, though, includes the timezone offest in the2004-02-12T15:19:21+00:00
format as can be seen on the linked PHP documentation page. So while it does not store the actual timezone identifier (which the patches here are about) it does store information that is in many cases (albeit not all) completely sufficient for timezone-aware date handling.However, the storage of the datestring is limited to 20 characters, so the timezone makes the string to long. So in fact using
DateTimeIso8601::setDateTime()
leads to unsaveable entities. Try it yourself:Given an entity with a
datetime
field with the IDdate
:Seems like proper API usage to me, but it yields:
Drupal\Core\Database\DatabaseExceptionWrapper: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'date'
That's what makes this a bug report. And solving the bug would involve supporting time zones as part of datetime fields - at least in the ISO8601-conform offset form. That's why I didn't open a new issue for this.
Thoughts?
Comment #28
tstoecklerAdditional problem:
Even setting aside the column length problem, if you have a date of the form
2004-02-12T15:19:21+00:00
in the database\Drupal\datetime\DateTimeComputed::getValue()
will never return a proper datetime object because it expects the formatY-m-d\TH:i:s
orY-m-d
depending on the storage setting of the date time field.Comment #29
mpdonadioI'm not convinced we have a problem, more of a happy accident? Maybe this was by design (before my time with this). Not ruling out a problem, thought, considering what I have dug up with TZ handling. However, with the changes we made to testing to run tests in non-UTC, I think we are OK.
Storage uses the ISO date w/o TZ suffix, w/ the implicit assumption that it is UTC.
The data type uses proper ISO dates w/ the TZ suffix as the value.
The field item uses the data type as the value, and then has a computed value for the actual DrupalDateTime object.
DateTimeComputed brokers this, and all is well.
I don't think this would be a problem with the approach I am proposing. I am thinking that we can take the settings form changes from the existing patch and then adjust the logic in DateTimeWidgetBase::formElement()
Instead of calling `drupal_get_user_timezone()` we would use the setting logic, and keep the non-widget code as-is.
?
Comment #30
tstoecklerOK, I will open a separate issue then. I still think #27 is a bug, but then I'll let you continue here without any further interruption. :-)
Comment #31
mpdonadio#30, I re-read your use case while looking core. It's a bug, and it looks like we are missing test coverage. It looks like all of the test are explicitly using the storage format string when setting values. That's on the public API, so that should work properly.
Comment #32
tstoecklerRe #31: Glad you agree. See you in #2716891: DateTimeIso8601::setDateTime() vs. DateTimeItem::schema(): (at least) one of them is broken then ;-)
Comment #33
jhedstromThe issue with this is that converting from a specified timezone (eg, America/Los_Angeles) to UTC loses data since it would just be stored with
-08:00
. The if the user creates a date formatter where they want the actual selected timezone to display, they cannot do so reliably. I verified the D7 module stores the textual representation of the timezone.Comment #34
mpdonadioSummary of IRC discussion.
- Keep value column in implicit UTC
- Add new widget setting for TZ entry handling
- Add new column for TZ name that was selected or computed by system behavior during input
- Keep logic that converts user entry to UTC for storage to allow simple string handling
- Add new field formatter option to TZ setting to allow for output using value at entry
- Possibly add some predefined date formatter strings that include TZ
Think that summarizes it?
Comment #35
jhedstromI think further work on this should hold off until #2739290: UTC+12 is broken on date only fields is in.
Comment #36
mpdonadioComment #37
jhedstromComment #38
jhedstromI made a bit of progress. This adds some options to the formatter configuration for which timezone to use.
Comment #40
anemirovsky CreditAttribution: anemirovsky at Giant Rabbit, LLC commentedThis adds support for date range fields as added by #2161337: Add a Date Range field type with support for end date, which looks close to completion. If we want to include support in this same patch, we should probably wait until that gets committed.
Comment #41
daffie CreditAttribution: daffie commentedFor the testbot.
Comment #43
mpdonadioA bot run of #40 doesn't make sense yet, because it references files that are only added by #2161337: Add a Date Range field type with support for end date.
Comment #44
jhedstromThanks @anemirovsky, but unfortunately since that issue isn't in yet, it will be nearly impossible to iterate with those changes included.
I'm working on some tests for this now, and hopefully #2161337: Add a Date Range field type with support for end date gets in soon so we can include support here (it could also be done in a follow-up since those are new field plugins).
Comment #45
jhedstromThis adds some additional testing and a few fixes. They are failing because there is still an issue where the timzone submitted by the user needs to be set before the
\Drupal\Core\Datetime\Element\Datetime::processDatetime()
method sets the timezone. As it is now, that gets called and sets the timezone to the site's timezone, which then gets converted to UTC on storage, and then when formatting, that gets converted to the submitted timezone, causing the date move around each time it is loaded into the form and saved.Comment #46
jhedstromUnassigning in case somebody else gets to this before I do again.
Comment #48
jhedstromWe somehow need to hook in before
Datetime::valueCallback
is called to set$element['#date_timezone']
with the user-selected timezone, since this is then used to construct the date object:As this patch stands now, that is set to NULL on new field values, and set to the previously selected timezone when editing.
Comment #49
jhedstromI had an idea that will resolve the issue detailed above, and also simplify implementation: we can add a
#expose_timezone
to thedatetime
form element itself. This will also make the reroll cleaner when #2161337: Add a Date Range field type with support for end date lands.Working on this now.
Comment #50
jhedstromThe new test is still failing, but I think this I've just overlooked something. I think this approach will work well, and it will have the added bonus of letting anybody using the core datetime form element to collect a timezone as needed.
Comment #52
jhedstromThis is why the date keeps processing. Since
messageFormValues()
is called twice (on form validate, and on form submit), the second time it is called, the timzeone on the date object has been set to UTC.I didn't immediately see a way to set this elsewhere since the only value passed in is the datetime object.
Once this detail is sorted, I think the only thing left here is to write the relatively simple upgrade hook.
I'm optimistically tagging this as a beta target since if we could knock this and the date range issue out, that would allow contrib to make calendars, etc.
Comment #53
mpdonadioFew quick comments, but not an in-depth look yet.
Probably want to keep the 'value' index and add a 'value_timezone' index instead.
Use $this->t() ?
Maybe use $form_state->isValidationComplete() to check the phase to avoid the problem you mention in #52?
This doesn't look too hard to merge into #2161337: Add a Date Range field type with support for end date this if lands first, but if that does happen the end date issue will need an upgrade path. Maybe we can get these added at same time to avoid that?
Comment #54
jhedstromThanks @mpdonadio for the
isValidationComplete()
suggestion! This gets the new test passing, and addresses #53. I think the remaining fails are upgrade path related.Comment #56
xjmOnly committers should add the beta target tag. In the case of this issue unfortunately it missed the deadline, and we generally avoid changes requiring upgrade paths in beta except for major and critical bugs. Thanks!
Comment #57
jhedstromThis update hook seems way too complex, but I couldn't find any other helpers that made it easier. If the update schema tests pass, I'll work on an final test for the upgrade path.
Comment #59
jhedstromThis will fix the undefined index tests.
Comment #61
jhedstromThis should fix that last failure. Will still need a dedicated upgrade path test, but this is close I think.
Comment #63
jhedstromAdding some related issues that are blocking this. Once those are in, I think this can be next.
Comment #64
nlisgo CreditAttribution: nlisgo commentedComment #65
nlisgo CreditAttribution: nlisgo commentedSince #2786583: Create a base class for DateTimeFieldTest and DateRangeFieldTest and move common code into it, this patch needs a re-roll.
Comment #66
nlisgo CreditAttribution: nlisgo commentedComment #67
nlisgo CreditAttribution: nlisgo commentedComment #69
nlisgo CreditAttribution: nlisgo commentedThe additional work that needs to be carried out is to support timezone for the datetime_range field.
Comment #70
bkosborneI think the issue summary can use some clarification as to the purpose of this feature, because as someone who's not super familiar with how timezone handling has worked in D7 with the Date module, I'm a little lost.
Here's what I've gathered:
WITHOUT this feature, any date/times entered into a date field are assumed to be in the user's timezone, or if that's not set, the site's default timezone. The date/time is converted to UTC before being stored in the database. When displaying the date/time, it will be converted to either the user's timezone or the site's default timezone, depending on how the field formatter is configured.
WITH this feature, a timezone can be selected when entering a date/time into a date field. Drupal will assume that the date/time entered is for that selected timezone. The date/time is still converted to UTC before being stored in the database. The timezone is also stored in the database. When displaying the date/time, the formatter can be configured to convert the date/time to the specific timezone that was selected when it was entered, or just convert it to the user's timezone or site's default.
===
It seems like the "win" that this brings is that it allows users to enter date/times for worldwide events in that event locations native timezone. For instance, let's say someone wanted to enter an event taking place at 7:00PM in Chicago (-6). The editor's timezone in Drupal is New York (-5). Without this patch, the editor would have to enter the time as 8:00PM to account for that difference, whereas with this patch, the editor can enter 7:00PM and also select the America/Chicago timezone.
Is that all correct?
Comment #71
mpdonadio#70, yes, that pretty much sums up the user experience when this lands.
Comment #72
bkosborneThere was a missing default_value for the widget settings form. I think there will be test failures since there were a bunch from the last re-roll that weren't fixed.
Comment #73
bkosborneHere's the interdiff from that last patch
Comment #74
bkosborneTwo problems found in manual testing:
1) The settings summary for the display formatter is not always accurate. If you select a timezone override, it will always display information relating to that override, even if you edit the settings and select a different display type.
2) Similarly, when the actual field data is rendered, the timezone override always takes precedence if you've previously configured one.
We could solve both problems by clearing the value set for "timezone_override" if the user de-selects timezone override from the display types, but probably a better fix it to adjust the logic that determines if the timezone override should be in effect so that it checks for the configured display type, instead of just checking if a value for override is set.
Comment #75
bkosborneAnother bug I found is that when a date field has a specific timezone filled in for it, and you configure the formatter to display it using the USER's timezone instead, it ignores that setting and still displays it with the date item's specific timezone.
I have a fix for that, and #74 above, but I'm going to wait until #2775669: Clean up redundant methods in datetime field formatters is committed since it all touches the same code.
Comment #78
mpdonadioOfficially postponing to avoid re-reroll purgatory.
Comment #79
mpdonadio#2775669: Clean up redundant methods in datetime field formatters is in, so I think we can work on this again.
Comment #80
SKAUGHTomit: sorry, wrong thread.
Comment #81
jhedstromI'll work on rebasing #72.
Comment #82
jhedstromThis is a reroll of #72 (the rebase diff is attached as
interdiff-2632040-72-82-rebase.txt
). I also fixed the php notice errors that were causing the daterange tests to fail. It doesn't address any of the other issues noted above.Comment #83
jhedstromOops, here's the rebase resolution diff noted above
Comment #84
bkosborneLet me see if I can fix the issues I brought up before.
Comment #85
bkosborneHere's the fixes to address #74.
I think the timezone logic in all the formatters can be refactored somehow to reduce this code duplication. I think as it stands, the timezone handling in the formatters is pretty confusing to understand. We have a method on DateTimeFormatterBase called "setTimeZone", but timezone overrides are not handled in this method, they are instead handled in each of the formatters formatDate method. I don't think those methods should need to deal with timezones at all.
May take a stab at that...
Comment #86
bkosborneAlso the name of the constant we use for specifying a timezone override is unfortunate. It makes code like this really confusing:
if ($this->getSetting('timezone_display') === DateTimeItem::TIMEZONE_NONE && $timezone_override) {
, but I don't think we can change the constant.Comment #87
mpdonadio#85, I haven't looked at this patch in a while, but yeah, ideally this should have minimal impact on formatters. We should all try to review what we have and what we need to do now that we are finally unblocked.
Comment #88
bkosborneHere's some refactoring based on reasoning I mentioned above.
Comment #91
bkosborneIgnore #88.
This fixes my test failures.
Comment #92
mpdonadioQuick look; I need to read this applied an play with it for a proper review.
Hmmm. I think we need to rethink this logic. Even if someone enters a timezone upon input, they may need a different timezone on output?
Ditto.
Not in love with these labels, but don't have better suggestions. We also have four constants; shouldn't all four be options here?
If the DateTimeItemInterface patch gets in first, we probably want to move these there.
Can we double check this against the TZ database for max length?
Comment #93
bkosborneRE: 1 and 2, the $date field there already has the proper timezone logic applied to it by the time that method is called. Your example of entering the time in a specific timezone and wanting it output in a different one works.
RE: 3, I think we can add some descriptions to both the widget settings and the field settings form that describes the impact of each choice a bit better. And yea, we probably should have all 4 constants there.
Comment #94
jonathanshawRerolled, a lot of collisions with the short array syntax changes. I hope to address #92 tomorrow.
Comment #95
jonathanshawI'm deep into working on this (reworking formatter settings and tests), hold off on reviewing.
Comment #96
mpdonadioThanks. Was #94 a straight reroll to account for the array issue, or was there anything else? When you wrap up, make sure you post an interdiff. This touches a lot of places, so seeing the incremental changes really helps.
Comment #97
jonathanshaw#94 is a straight reroll PLUS applying the short array syntax to the new patch code. There's 1 unrelated CS issue I fixed by mistake, reverted here.
The latest patch attached is a somewhat rough work in progress.
Responding to @mpdonadio's quick review #92:
#92.1 & 92.2: @bkosborne is right, the patch already allows for what you want.
#92.3 I added 'Site' which was the missing option.
#92.5 Various SO source demonstrate that the longest current timezone name is about 31 characters, the longest ever has been 38, so the specified storage length of 50 looks safe.
ALSO FIXED IN THIS PATCH
Site's default timezone
Issue: Per #92.3 'Site's default timezone' should be offered as an option alongside user's timezone or specific timezone.
Null per-date timezone values
Issue: The formatter needs robust handling for cases where per-date timezones are enabled in the field, but null for a particular date value. This mainly happens to a field with existing values (e.g. in a migration or when updating a field to have per-date timezones), but could also be set that way via the API or a widget.
Previously the patch used the user's timezone if there was no per-date timezone value. But this creates unexpected and undesired results when transitioning from using a manually specified timezone override to using per-date timezones - all existing dates would switch from the previously specified timezone to user timezone, until such time as they were edited and a timezone set for each one.
Solution: The current patch version splits the formatter timezone settings into 3:
- 'Default timezone': a select offering site, user or specified
- a select of timezones, if specifed is selected as the default
- a checkbox for 'Use stored timezone preference'
If the checkbox is checked, then the stored per-date timezone is used unless it is null, in which case it falls back to the default selected.
Need thorough tests of formatter's timezone logic
I added helper methods and used these to systematically test all combinations of settings and circumstances
WHAT'S STILL TO DO:
We face 2 unavoidably entangled issues:
(A) Interpreting user-inputted times in the widget. Previously we always assumed the user's timezone, but that can be problematic.
(B) Storing a timezone preference for each date This is a natural outflow of A), because one you allow people to specify a timezone that should be used to interpret their input of a certain time, it is unhelpful if you don't save that timezone. And once you've stored it, you need to allow for it in the formatter's rendering of the time too.
We've done a good job of (B), storing per-date timezones. But we've not yet fully worked through (A), the basics of how to determine the timezone used to interpret user-entered times.
What we need to do next are:
1) Add to the form element a 'timezone label' (the assumed timezone for time input) to the content editor, that is displayed when the timezone chooser is not. Have this always shown, but make sure it can be easily overridden by themers. With all this flexibility around timezones, it gets dangerously easy to trip up editors.
2) Change the field's per-date storage setting into a boolean 'Allow times to have a preferred timezone'.
3) Offer a setting on the widget, same as on the formatter: 'Default timezone' with site, user, and manually specified as the 3 options.
4) If per-date storage is set in the field's settings, offer a setting on the widget 'Allow users to choose a timezone'.
5) Pass to the form element 2 arguments:
-- '#expose_timezone'. Sets whether the element should show a timezone selector or timezone label, based on widget setting 'Allow user to choose'.
-- '#date_timezone'. The default value of the timezone selector, or the value of the timezone label. The value of this is based on the stored timezone value if present, or the default configured in the widget if the per-date is null or not enabled.
6) Exhaustively test the combinations of settings and circumstances.
7) Sort the terminology: create consistency between the settings labels, settings descriptions, variable names and code comments.
Current patch is good for reviewing the overall approach so far, but not for reviewing the fine details.
I will work on the todo's over the weekend.
Comment #99
mpdonadio@jonathanshaw, thanks for moving this forward. We are making good progress on this.
I took a quick look at this. I am concerned about a few things right now.
We are starting to change a decent amount of strings (labels, titles, etc). If possible, we need to minimize this.
The user facing term and in comments needs to be "time zone", two words. That is the preferred language from the docs team.
My main concern (which I could be wrong about, this is a little hard to review as a patch) is that we are starting to couple the intended output intent (ie, formatter behaviour) upon input, the (A) and (B) above. IOW, we are implying what the formatters should do based on widget input. We need to avoid that.
I will review this applied and play with this over the weekend.
Comment #100
jonathanshawUnderstood. I will think in terms of minimising this. I think it's only an issue in the formatters.
My bigger concern though is that it's very difficult to describe things clearly and set user expectations correctly, even with changing strings. I'm leaning towards coining the concept of a 'preferred time zone' or 'stored time zone preference' to refer to the time zone stored per-date in the field, but I need to play with this more, looking at all 3 settings contexts (field, widget and formatter) side by side.
Recent iterations of the patch make that coupling an optional (and non-default) behavior. If a timezone is set in the widget, you can choose in the formatter whether to use it or ignore it.
Comment #101
jonathanshawI think we should make addressing #2799987: Datetime and Datelist element's timezone handling is fragile, buggy and wrongly documented a prerequisite for this issue.
Comment #102
jonathanshawI'm close to having a heavily-revised patch ready, hold off on reviews on this issue for now.
Comment #103
mpdonadio#102, do you still think this is too coupled to 2799987? Should we postpone this properly until we figure that out? I haven't had much time to look into either of these issues this week.
Comment #104
jonathanshawRe #103, it's better to do #2799987: Datetime and Datelist element's timezone handling is fragile, buggy and wrongly documented for 2 reasons:
1) to have a good foundation before we add in more complexity
and
2) because of problem 2 in that issue, what I want to do in the widget here doesn't work: you can't get an exposed timezone selector to default (for new values) to something other the user timezone.
However, I don't suggest we need to formally postpone. This patch touches a lot of places, the element is just one small part of it, so there's a lot of reviewing and polishing that can be done here anyway even while that one is still being nailed down.
Comment #105
jonathanshawI have done a bunch more on this, and will upload new patch tomorrow once I've unpicked the merge conflicts with #2780063: Convert web tests to browser tests for datetime and datetime_range modules.
What I've done in this latest patch
A. Added widget settings for timezones, almost identical to those for the formatter and sharing a trait.
B. Reduce the field type setting down to a boolean (store / don't store), as the fancier question of what default you want to assume etc now lives on the widget/formatter.
C. Added widget timezone tests, and tidied up the formatter tests.
D. Mostly got all this timezone handling working for date range fields. The hard part of this was that the exposed timezone selector should only show up once (not on both date elements) but its value needs to be used to interpret the contents of both elements.
E. Harmonised the terminology of the UI text, code comments, array keys, constants and variables.
F. Moved the constants into an interface.
What still needs doing
1. Fix the date range formatters.
2. Extend the current tests to cover the daterange field/formatter/widget.
3. Extend the current tests to cover all widgets and formatters extending the DatetimeBase widget/formatter.
4. Check whether the logic in ConfigurableTimezoneTrait::getDefaultTimezone() is adequate for DateRange fields of the All day type.
5. Check whether we have adequate tests for all day and date-only fields, so that we know if our timezone changes are accidentally impacting them.
6. Add an update path for the formatter's timezone_override setting.
7. Remove -None- as an exposed value in the timezone_override selector (now called "fixed time zone").
8. Default timezone_override to the site's default timezone if there is the stored config setting is ''.
9. Add tests for all update paths.
10. Finish the datetime element once #2799987: Datetime and Datelist element's timezone handling is fragile, buggy and wrongly documented gets fixed.
11. Consider renaming the constant TIMEZONE_NONE to TIMEZONE_FIXED; consider changing its value to 'fixed' not 'none'. This may require an upgrade path if 'none' gets stored anywhere in config, but I don't think it does.
12. Bug: the field setting form allows you to change the timezone storage setting even after values are in the database, but it won;t save your change of setting. Make a test for this.
13. Make sure the date range validation that ensures the start time is before the end time is timezone intelligent - in particular it needs to handle the case where the exposed timezone on the start time is changed and that change needs to be applied to both start and end. Make sure we have tests for this.
14. Widgets and formatters seem to be forgetting their previous settings when disabled and then re-enabled. I'm not sure if this is the standard behavior or a bug in this patch.
15. Bug?: Make sure all the widgets and formatters are available in the UI when they should be. I've noticed an oddity here.
16. Bug: The formatter/widget timezone settings summary are not properly translatable, I think they don't use $this->t() correctly.
17. Bug: The formatter/widget timezone settings summaries are not behaving properly. The per-date settings summary doesn't show up at all for date_range fields, and only refreshes for normal date fields when the "Save" button is pressed, not when the "Update" button is pressed.
18. The field's timezone column description needs updating to reflect the new terminology, for the normal field and the daterange field.
19. The formatter/widget settings summaries may need updating to reflect new terminology.
20. Add tests for the formatter & widgets settings forms and summaries, and apply them to all widgets and formatters for both date and daterange fields.
Most of all, it's tests, tests, tests, tests. Timezones are really hard, and there are a lot of logic paths we're tampering with here all over the place. Unfortunately, I can't undertake to fix all this. I will focus on #2799987: Datetime and Datelist element's timezone handling is fragile, buggy and wrongly documented.
Comment #106
mpdonadio@jonathanshaw, thanks for your work with this, the TZ stuff is a pain. I think we need to see your in progress patch here to assess things (even if it doesn't apply b/c the BTB issue). It looks like you uncovered some new bugs, and identified some new ones. It also looks you may have done some needed work (eg, the interface thing) that we already have an issue for.
I think we need to look new stuff you uncovered, along with the queue, to see what we need to tackle first to make this more manageable.
The biggest thing would probably be refactoring the functional field tests to make them manageable. I also think we need to be sure we aren't making things overly complex; I don't want to get rid of any work that would benefit end users; we need to provide the essential building blocks in core (I think #70 is our MVP), and extra functionality can be punted to datetime_extras. I am still not sure what 'timezone_per_date' is providing us here, especially since exposes more test surface area.
Comment #107
jonathanshawHere's the rebased patch, and a further reroll of #94.
If you reckon this patch has become too sprawling too handle, I suggest the way to split it up would be into different issues like this:
1) Create a new TimezoneFieldTest class, which contains test methods that can be applied to any widget/formatter datetime/date_range to test timezone handling. So if we add some new timezone logic, we only have to touch a couple of places in the test and it magically gets tested on all widgets/formatters.
2) Refactor the formatters as suggested by @bkosborne in #88.
3) Move the formatters timezone settings into a trait, with the ['timezone_default] options of user, site and fixed; fixed allows you to choose (what we call for BC reasons) the ['timezone_override'].
4) Apply the trait to the widgets too. All the same options make sense for them. This addressed WidgetCo's first problem from the IS:
5) Add per-date time zone storage, to solve WidgetCo's second problem:
Trying to do 5) before 4) gives us earlier iterations of this patch which have things that should be formatter / widget settings being put as field settings, a mess that would be hard to unpick or build on. Trying to do 4) before 1) and 2) and 3) is painful and error-prone.
This would be 4 new issues and a meta to keep track of it all.
I don't think it's a sure thing either. It would be OK for core to default to always using the per-date if one existed. Especially if we put on the trait
as this would make it trivial to change this behavior.
However, there area few reasons I think it may be worth having the setting:
a) It will always be desirable to have the formatter setting to choose the default time zone, even if per-date is enabled in the field, because we have to handle fields with existing values that will have a NULL stored time zone. And having this setting, which will then be ignored most of the time, is slightly misleading for sitebuilders. It would make it more bluntly obvious how things worked if you have the additional checkbox for "If a preferred time zone is stored, use it instead of the default". This drives home the idea there are two different things at work here, a default and something that can override it per-date. The screenshots say it better than I can.
b) I suspect it's quite common to want to sometimes render a time in its canonical (venue) time zone and sometimes in the time zone of the user.
c) I imagine it might not be uncommon to want to hide the time zone selector on a "basic" form but have it exposed on an "advanced" form for superusers.
Comment #108
jonathanshawComment #110
jonathanshawThe reroll, interdiff and test-only in #105 are correct, but the main patch 2632040-105.patch only has about half of the work. Here is the full patch. Sorry about this.
Comment #112
rvillan CreditAttribution: rvillan as a volunteer and commented#110 had a print_r statement that was causing AJAX errors when trying to add entities using a complex inline entity form. Here it is with it removed.
Comment #113
jonathanshaw#112 is 10% smaller than #110, isn't that suspicious? Maybe a file is missing.
Comment #114
shawn_smiley CreditAttribution: shawn_smiley at Achieve Internet commentedI ran a diff on the 108 and 111 patches. The 111 patch is missing the updates to the files datetime.install, ConfigurableTimezoneInterface.php, and ConfigurableTimezoneTrait.php
Comment #115
rvillan CreditAttribution: rvillan as a volunteer and commentedYeah, that was my fault -- I didn't create the patch correctly. Here it is fixed along with an interdiff against #108.
Comment #116
jdleonardI'm not sure whether the screenshot below (stolen from the issue summary) is still representative of this issue's direction, but in case this hasn't already been considered, I wanted to throw out the possibility that the date range field should provide the ability for the start date and end date to have different timezones from one another (e.g. a travel site needs to store the departure and arrival times of a flight that crosses timezones).
Comment #117
tacituseu CreditAttribution: tacituseu commentedComment #119
jonathanshawRe #116 and the possibility of different timezones in date ranges I'm mindful of @mpdonadio's frequent injunction that core should provide the basics, not cover every use case.
The truth is that the 2nd timezone selector is naturally present in the widget and I actually had to do some ugly work to suppress it. So supporting it in the widget is easy.
But there's nothing at the moment to support it in the storage and formatter. Worst of all, because most sites would want to use the same timezone for both, we'd have to have setting and be constantly checking it and doing conditional logic based on it. The number of combinations of settings and formatters etc. is already painful, adding another permutation is not a very happy prospect.
On balance this seems like something that should be in datetime_extras, not core. But by all means review the patch and indicate if there is something that makes it unnecessarily hard to do this in contrib, if there's something that would make extending easier.
Comment #120
SKAUGHTRE@116. different end timezone.
That is an interesting use case. but could covered by simply using 2 separate combo date fields and a custom formatter..or even a secondary field capturing the expected length of flight..
Certainly an idea that would deserve it's own ticket.
Comment #121
jdleonardI completely understand the points raised in #119 and #120. I can see how the permutations could be getting a bit nuts.
While this use case could be solved per #120, it does seem cleaner to solve this in core. It is logical to me to defer the additional UI complication to a later date (or contrib) even if it's easy to expose the widget, but would it not make sense to address the storage aspect here to provide contrib with a simpler path to full implementation?
I'm not invested in this use case; I just thought it would be appropriate to address here.
Comment #122
jonathanshawHaving a field column sitting there that we never used would be very confusing to anyone looking at the code. If it's in the storage we need to use it.
Let's see what @mpdonadio thinks.
Comment #123
jhedstromNice progress here! A few items I found in reviewing the latest patch:
These changes look unrelated?
Whitespace errors.
While technically ok, this constant should probably reference the
ConfigurableTimezoneInterface
rather than the base class...Comment #124
mpdonadio@jhedstrom, what are your thoughts on separate TZ for start/end for daterange? I'm torn on this. I think it is an edge case, but don't want to design ourselves into a corner and end up with a nasty update path (though this wouldn't probably be that hard). My gut says that we should push that feature to contrib.
Comment #125
jhedstromSine we already have the widget forced to a single TZ selection, even though that isn't the default widget behavior, I think we can push the separate TZ per start/end to contrib and/or a follow-up. There would be additional formatter, widget options etc that we don't need to complicate this already complex issue further with I think. Folks making a site for multi-timezone races will have to wait ;)
Comment #126
jonathanshaw@mpdonadio / @jhedstrom I'm waiting for your take on #107, whether you want me to split this up or to proceed in just this issue?
Comment #127
mpdonadioI am not sure if we are going down the right path with this right now.
I am still not convinced about the timezone_storage setting on storage. I am leaning toward always storing the TZ; I have a feeling that the empty column is going to cause problems with REST and API usage, and possibly Views (not 100% sure, but empty values make me uneasy).
For the widgets, I think we can have an option to expose a TZ select, that defaults to drupal_get_user_timezone(). If the option is false, the just store drupal_get_user_timezone() with the field.
And then there would really not need to be any change to the formatters.
I think the current version couples storage / input / output too closely. I think the approach outlined in #34, which I think was was was the blueprint up to #94 or so is still the best bet.
@jhedstrom, thoughts?
Comment #128
jonathanshawI am leaning toward always storing the TZ; I have a feeling that the empty column is going to cause problems with REST and API usage, and possibly Views (not 100% sure, but empty values make me uneasy).
How would you handle existing fields? What value would you have the update path insert into the timezone column in these cases? If you don't want to have empty values presumably you'll have to force it to be the system's default timezone, but have the formatters default to not using the stored timezone?
Even if we don't allow this, perhaps there is still merit in having the timezone default (user/site/fixed) be a setting of the widgets, rather than a setting of the field and so forced to be the same in all widgets.
Comment #129
jhedstromI am still in favor of the approach outlined in #34.
Existing fields would get the site's timezone set I think, and since the prior to this, formatters only displayed in the site, or in the current user's timezone, this would be ignored by the formatters.
Comment #130
jonathanshawAlways storing the timezone
I'm understanding you guys to want the timezone column never empty. This requires AFAICS:
1) In the update hook, create a timezone column for all datetime fields,
2) In the update hook, put the site's default timezone as the value in all existing rows
3) Always store a timezone, including when saving via the API, regardless of the field's settings.
4) The FieldType needs to implement the getDefaultValue() method, so as to provide drupal_get_user_timezone() as the default value for timezone column when saving via the API.
This all seems fine to me. It requires some additions to the patch because so far no one has made the API or update path store a timezone.
The settings
#34 is not explicit about the details of what settings there are on the field, widgets and formatters.
Given you've specified the timezone column will never be empty, we now have 2 possible approaches:
The minimal option:
FieldType: have a checkbox for "Use per-date timezones"
Widget: If "Use per-date timezones" is checked on the FieldType, always have timezone selectors exposed by the widget, and always have these default to drupal_get_user_timezone()
Formatter: If "Use per-date timezones" is checked on the FieldType, always display dates using the stored timezone, do not allow overriding (hide the overrides setting).
More flexible options, which can be adopted in various combinations:
FieldType: Allow the user to choose the default timezone from "Site", "User", or "Fixed".
Widget: Have a select setting called "Timezone to use" with values "User's timezone", "Site default timezone", "Selected by user", and "Fixed". Timezone selectors are only exposed to the editor if the "Selected by User" option is shown. The "Fixed" option allows the sitebuilder to specify a particular timezone.
Formatter: Have a select setting called "Timezone to use" with values "User's timezone", "Site default timezone", "Stored timezone", and "Fixed".
If you have settings like this for the widgets and formatters, then you don't need a "Use per-date timezone" checkbox setting on the FieldType.
I think the idea of a default setting on the FieldType is worth considering seriously (and present in #94), because this affects the API behavior and can't easily be left to datetime_extras.
Overall when it comes to the widgets and formatters we have a choice between:
A) having a checkbox setting "Use per date timezones" on the FieldType, a (sometimes bypassed) "Timezone override" setting in the formatter, and nothing on the widget; OR
B) not having the checkbox setting on the FieldType, on the formatter replacing Timezone override with a broader selection of choices ("User's timezone", "Site default timezone", "Stored timezone", and "Fixed"), and reusing the same logic on widgets.
My sense is that B gives more power to sitebuilders while being not much more complex than A (possibly cleaner, depending on your tastes). But I can see there is a case for keeping core simple and leaving the formatter and widget settings to some more flexible widgets/formatters in datetime_extras.
Comment #131
benjy CreditAttribution: benjy at Unearthed commentedRe-rolled against 8.4.x head.
Comment #134
BrianLewisDesign CreditAttribution: BrianLewisDesign commentedThe 2632040-131.patch doesn't apply on core 8.4.2.
Looks like the patch is failing in core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php, Here is the rejected file I get from composer:
Comment #135
Tim Bozeman CreditAttribution: Tim Bozeman at CyberSolution for Achieve Internet commentedRe-rolled against 8.4.x head for people using this in production already and fixed an undefined index error.
Comment #136
mpdonadioNot sure if this will apply, but since this is a Feature Request, development should be against 8.5.x.
Comment #138
mpdonadioLooks like we need a reroll for 8.5.x.
Comment #139
jofitz CreditAttribution: jofitz at ComputerMinds commentedRe-rolled for 8.5.x.
Corrected some coding standard errors.
Comment #141
jofitz CreditAttribution: jofitz at ComputerMinds commentedCorrected a few test failures.
Removed a few more coding standards errors.
Comment #144
GoZ CreditAttribution: GoZ at Iosan, Barbe-Rousse commentedField name in database is not necessary suffixed by _value.
In case this field is created in an Entity thanks to BaseFieldDefinition::create(), the field name column will be named as defined in the key of array returned by baseFieldDefinitions.
Example:
Comment #145
HiMyNameIsSeb CreditAttribution: HiMyNameIsSeb commentedI'm wondering if saving all date and time fields as UTC is as designed. (I don't know enough about that in particular to know for sure).
We have a site that is used around the world, users can create events in their region. They are created using standard Drupal nodes with a date range field. Dates seem to all be stored in UTC within the database, and when rendered are formatted for the current users timezone, or defaults to UTC if the user has no timezone.
This works as expected in all cases where we are using the default node forms and rendering the fields using the default node field settings.
There is however 1 case where our events are created outside of the default Drupal forms. We considered our options, and they were;
- To store dates as the users timezone and flag this against the field value (as the patch above).
- To convert the date to UTC for storage in the database.
We decided to go with storing all dates in the database as UTC.
This is not necessarily a better way of doing this, it purely depends on your needs. However, I hope it helps someone in the future.
For our needs, it works nicely. Below is how we reverted the date selected by the user to UTC before saving the node.
Comment #146
mpdonadioYes, there are a few constants for this:
Re, your code, you can just create your date objects and use the `->setTimezone(DateTimeItemInterface::STORAGE_TIMEZONE)`, and then use `->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT)`.
Comment #147
brian.reese CreditAttribution: brian.reese commentedI had an issue using #141 when I had pre-existing datetime base fields defined.
Drupal\field\Entity\FieldStorageConfig::load()
used in the update hook won't loadDrupal\Core\Field\BaseFieldDefinition
and the update hook fails. A fresh site install doesn't have the same issue since the update hook doesn't runComment #148
sjancich CreditAttribution: sjancich commentedWith the patch in #141, I can confirm that the formatter does not respect the "Preferred time zone for each date" setting under Manage Display for date range fields. Date fields seem to respect it fine, though.
Comment #149
ekes CreditAttribution: ekes as a volunteer commentedJust noting I'm looking at this at Dev Days.
Comment #150
ekes CreditAttribution: ekes as a volunteer commentedStraight re-roll.
Comment #151
ekes CreditAttribution: ekes as a volunteer commentedChecking first work done. Fixes some tests, and other small items. Setting 'needs review' for tests.
Notes:-
Change to
datetime_range.schema.yml
: Fixes issue confirmed in #148. "Preferred time zone for each date" setting under Manage Display (widget), as it didn't have schema.In
DateTimeFieldTest
: Adds the configuration required Timezone fixed. This is also not obvious in the UI. Maybe wants javascript to make the Timezone override only appear when fixed is selected?In
EntityTestDateonlyTest::getExpectedNormalizedEntity()
: As expected there is additional output for the timezone. I assume for the API there could also be tests for setting via the API?Comment #153
Dane Powell CreditAttribution: Dane Powell at Acquia commentedHave you tested the upgrade path on a site with existing datetime fields? Patch #151 does not appear to address the concerns in #147 about the upgrade path.
Comment #154
ekes CreditAttribution: ekes as a volunteer commentedCorrect. 151 was just checking the work done, as explained.
Attached includes a test for datetime_update_8001(). I'm afraid I couldn't reproduce the issue mentioned in #147 either in the test or manually.
The patch also changes the check to see if it should store a timezone to use the storage setting specically for that (rather than if there is a fixed timezone option).
It also adds an additional test for the REST API for datetime with a timezone. This highlighted the need for additional validators. Also added.
Comment #157
Dane Powell CreditAttribution: Dane Powell at Acquia commented#154 does not apply cleanly to 8.7.x, which is the new target branch.
Additionally, for some reason Composer refuses to apply it to 8.6.x. I'll attach a version that seems to work with 8.6.x.
Comment #158
SKAUGHTComment #161
ekes CreditAttribution: ekes as a volunteer commentedRe-roll for 8.7.x to take into account changes from #2846963: Clean up DateRangeWidgetBase::massageFormValues(). Change is in the logic of the ::massageFormValues of both widgets. One of the new tests now fails (For scenario per-date 'not allowed' with default 'user': the time zone stored is expected to be '', actually is 'storage'.). I'll try and work out if that's the new logic or the test itself.
Interdiff is a diff of the two diffs (as the original doesn't apply).
Comment #162
SKAUGHTComment #164
nlisgo CreditAttribution: nlisgo commentedComment #165
ekes CreditAttribution: ekes as a volunteer commentedIt's this horrid fixture sql stuff that's not applying, maybe mangled already, but quickly what I have here at the moment --binary on.
Comment #167
ekes CreditAttribution: ekes as a volunteer commentedRolling the patch with
git diff --binary
solves the issue with the fixture sql applying.This adds back some code from #54 which got lost somewhere and was causing test fails. The timezone correction to storage should only be done once after validation.
It also changes the same test so that when timezone storage is enabled (on the field settings) but the widget does not allow the user to change it per-field, the test checks for the default timezone being stored (which is the case).
Comment #169
arsoman CreditAttribution: arsoman at FFW commentedHi, team! The patch is ok, but needs some UI change, in order to be perfect. In this file: core/lib/Drupal/Core/Datetime/Element/Datetime.php we are building select field, with list of all countries, but using machine names of the countries both as a keys, and as a values for that list. This is wrong, because leading to the effect, that the end user will see in the dropdown machine names of the city/timezone, with underscores, instead of spaces! Screenshot:
The problem comes from here, where the values of the select element is not OK for UI use: .
So i suggest the following fix:
.
Screenshot of the code base:
That way we will have the correct UI names of the timezones:
Comment #170
mpdonadioThanks for the review. This is still a Feature Request, though.
Comment #171
arsoman CreditAttribution: arsoman at FFW commentedHello again, according to the last comment, i will apply the patch also.Fix timezone names
Comment #172
lfilipov CreditAttribution: lfilipov commentedWe had an issue with the timezone names because they were *odd* according to the client so the solution that @arsoman has offered worked for us. #171
Comment #173
givanov CreditAttribution: givanov commentedI have used the patch proposed by arsoman and it worked as described for me. Thanks.
Comment #174
SKAUGHTchanging status to try to trigger test correctly.
Comment #175
jofitz CreditAttribution: jofitz at ComputerMinds commentedThe patch in #171 is an interdiff to be applied after the patch in #167. Here is the combination of the two.
Comment #177
jofitz CreditAttribution: jofitz at ComputerMinds commentedI forgot
--binary
.Comment #178
mpdonadioThis should use system_time_zones() instead of getting them directly from `\DateTimeZone::listIdentifiers()`. That has the improved UX and already does the nicer name display. See #2847651: Improve timezones selector with optgroups.
Comment #179
jofitz CreditAttribution: jofitz at ComputerMinds commentedReplaced
\DateTimeZone::listIdentifiers()
withsystem_time_zones ()
.Comment #180
jofitz CreditAttribution: jofitz at ComputerMinds commentedFix coding standards errors and one of the test failures.
Comment #183
John Cook CreditAttribution: John Cook at Creode commentedI've tested this with a datetime field in a paragraph type. The DB update fails on this line:
At this point, the
$field_changes
variable is as follows:The actual revision table should be
paragraph_revision__field_date
, so the update fails withComment #184
John Cook CreditAttribution: John Cook at Creode commentedI've changed the the way the revision table is determined. This patch uses
DefaultTableMapping::getDedicatedRevisionTableName()
to get the correct table name.Comment #185
John Cook CreditAttribution: John Cook at Creode commentedComment #187
John Cook CreditAttribution: John Cook at Creode commentedRe-uploaded patch #184 using
--binary
.Comment #188
wengerkFix Drupal coding standards from #187. Only on new added code.
Comment #191
wengerkReupload #188 with
--binary
.... sorry ...Also, about the 6 fails, I have 2 questions to help on these:
- Fail on
Drupal\Tests\layout_builder\FunctionalJavascript\FieldBlockTest
: Is it a side effect or an issue on layout_builder ?- Fail on
Drupal\Tests\node\Kernel\Migrate\d7\MigrateNodeTest
: same questions, as upper - side effect of reflecting changes ? Should we only update the expected results ?Waiting answers, I'm working on the Datetime Range missing upgrade path & Tests.
Comment #192
mpdonadioDid a quick look at the fails, but did not look at the patch yet.
I think the FieldBlockTest one is unrelated.
I think the fail in MigrateNodeTest is legit and a side effect of the patch. We can't just update the value in the test, we need to figure out what is causing it.
Comment #193
wengerkI struggle with the
datetime_range.post_update.php
which keeps failing on:Even after adding a new
datetime_range.install::datetime_range_update_8001
derived fromdatetime.install::datetime_update_8001
. which add the timezone field to the daterange field type.I think I miss a point, maybe from the
datetime_range.schema.yml
which should be updated with the new timezone storage.Someone with a global & better vision on datetime & daterange modules could found the solution.
To me, it seems the
datetime_range.post_update.php
don't see the updated schema from the previous update. But I'm maybe wrong.Comment #194
jonathanshaw@mpdonadio if you're ever ready to think about this more, #127 - #130 is the discussion that I think is still unresolved where I stalled waiting for direction.
Comment #195
jonathanshawGiven we've made little progress for 18 months, I suggest splitting the issue per #107 is the way forward.
Comment #196
mpdonadioI talked to @wengerk offline quickly and am going to review this patch again this weekend.
Re the test split, I will be making a meta about this. The existing tests are way too wieldy right now. There are a few in-progress patches are doing this.
Comment #197
jonathanshawIt's also the formatter refactoring that could be split out of this issue.
Comment #198
rgristroph CreditAttribution: rgristroph at Acquia commentedThis is an extension of the patch at #157, targeted at 8.5.6.
The fix I did was that when you have a datetime_range which is not using the default timezone, the timezone was being applied only to the start time in the validation function. That meant that if your site had a site timezone of Chicago, and you created an event that lasted 2 hours in the Los Angeles timezone, on saving the node you would get the "end time cannot be before start time" error.
As I am testing it, there is still at least one issue -- after saving the node, the time displays in UTC but the timezone displayed is the local one. I will try to do more testing of that over the weekend.
Comment #199
rgristroph CreditAttribution: rgristroph at Acquia commentedThis patch is a further re-working of #198 and #157, targeting 8.5.7.
The main change was in core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php in the buildDateWithIsoAttribute() method - it was presuming that the date could just be formatted and 'Z' appended to it, but if we are keeping track of a timezone that isn't the case. Also, I added a 'timezone' => $timezone element to the render array, because if you want to display the timezone on the theming end you will need that.
I think this patch needs more attention both on reviewing the code and tests. I'll try to re-work #191 and get something that passes tests and can be reviewed.
Comment #200
SKAUGHTComment #202
John Cook CreditAttribution: John Cook at Creode commentedThis issue seems to have been forked.
There's two versions of the patch; one in Comment #191 and one in Comment #199.
From the comments, I believe that #191 is actually ahead of #199. So the changes from #198 and #199 should be brought into #191 as a new patch.
Comment #203
recrit CreditAttribution: recrit at Phase2 commented- Added an update function for the datetime_range module.
- Added some checks for table exists, field exists, index exists.
Comment #204
recrit CreditAttribution: recrit at Phase2 commentedFixed the table names in the update functions. The original was getting the field table name and then creating the revision table as:
This does not work for all entity types.
Example: "paragraph" entity type, "field_example"
*Original patch <= 203* would create the table name of "paragraphs_item_revision_field_example", which is wrong and causes errors during the update. The field revision table name is "paragraph_revision__field_example".
*New patch 204" uses the correct "paragraph_revision__field_example".
Comment #205
akalata CreditAttribution: akalata commentedComment #207
recrit CreditAttribution: recrit at Phase2 commentedFix some bugs with original patch storing "" instead of NULL.
Comment #208
sjerdoSince #2799987: Datetime and Datelist element's timezone handling is fragile, buggy and wrongly documented is committed to 8.7.x-dev branch, this patch needs an update.
Comment #209
akalata CreditAttribution: akalata at Tag1 Consulting commentedHere is a reroll of #191 for 8.7.x.
I am ignoring patches #198, #199, #203, #204, and #207, since they are explicitly against 8.5.x.
I am not yet able to get the change to the field actually working, though, field data ends up set as UTC regardless of what I enter. I think this is because the data is getting looped through
massageValues()
multiple times, and the second loop ends up using the storage timezone as the selected timezone.Comment #210
akalata CreditAttribution: akalata at Tag1 Consulting commentedUpdated reroll.
Comment #211
akalata CreditAttribution: akalata at Tag1 Consulting commentedThis patch fixes the timezone handling for DatetimeRange fields.
Two additional issues I'm seeing:
Date range field validation: Since since the end_date is always communicated in UTC, it's possible for the start_date in a specific timezone to be after the end_date value in UTC.
This fails validation:
Start time entered: 2018-12-20 at 12:00:00 (12pm) America/Chicago (UTC-500)
End time entered: 2018-12-20 at 13:00:00 (1pm)
While this passes validation:
Start time entered: 2018-12-20 at 12:00:00 (12pm) Pacific/Wallis (UTC+1200)
End time entered: 2018-12-20 at 13:00:00 (1pm)
Timezone name validity: Timezone name values with spaces (ex America/New York) are not valid (should be America/New_York). The error message here is misleading/incomplete "The Start date date is invalid. Please enter a date in the format 2018-12-13 18:54:34. ".
Comment #213
akalata CreditAttribution: akalata at Tag1 Consulting commentedThis adds a fix for the timezone validity.
I'm guessing one of the changes in #211 made the date range field validation even wonkier than I had described, so I wanted to post this progress before continuing to dig into that.
Comment #215
akalata CreditAttribution: akalata at Tag1 Consulting commentedThis update adds a check to the datetime_range's validateStartEnd to ensure that the explict start_date/
value
timezone and the implicit end_date/end_value
timezone are the same before comparison.Comment #217
jhedstromHere's a quick review, by no means thorough, but just some nits and changes for the next version of the patch. It's looking really good, and once the tests are passing, I think it's very close! I'm also removing the upgrade path tests tag, as this now has those too :)
The word 'parse' seems overly specific. How about something a bit more user-facing?
PHP natively uses this message:
nit: extra spacing.
Just to be safe, this should probably use an
assertInstanceOf
here to to ensure there is a current user. Otherwise future uses of this will throw a non-useful fatal error if somebody calls this when there is no logged in user. Something like this perhaps:Comment #218
akalata CreditAttribution: akalata at Tag1 Consulting commentedThanks @jhedstrom!
I've addressed #1 and #3. I couldn't see the issue mentioned in #2.
I've also reverted the class name change in EntityTestDatetimeTest, and added the hook_update_N for datetime_range (daterange) fields.
Comment #220
dpiConfigurableTimezoneTrait
has a hidden dependency to the configuration factory (as ->config
).Im thinking the trait should implement a method returning the config factory from the
\Drupal::service()
helper.Implementing classes such as
DateTimeDefaultFormatter
can implement their own method that uses DI, overriding the traits new configfactory method.The patch also changes the constructor for
DateTimeDefaultFormatter
, it probably shouldnt do that. See Safely extending Drupal 8 plugin classes without fear of constructor changes for a rationale and workaround.Comment #221
akalata CreditAttribution: akalata at Tag1 Consulting commentedThanks @dpi,
Based on the blog post you've linked and the related comments/discussions linked from there, it appears that constructors for plugins are considered @internal and are allowed to change per https://www.drupal.org/core/d8-bc-policy#constructors.
While the "workaround" technique looks sound, I don't think we can tell core to override itself?
Some good discussion about breaking changes caused by core updates begins at https://www.drupal.org/project/drupal/issues/2856625#comment-11967635 on an issue that removed an unused service from a constructor. I am not currently aware of any similar discussion around adding a service to a constructor -- but we should definitely have a recommendation to avoid contrib breaks as much as possible.
Comment #223
koppie CreditAttribution: koppie as a volunteer commentedI've rerolled the patch from #199 against Drupal 8.6.4.
Comment #225
koppie CreditAttribution: koppie as a volunteer commentedNewb alert, sorry! I read the thread more carefully and I'm grabbing the patch from #218, and backporting against 8.6.x-dev.
Comment #226
SocialNicheGuru CreditAttribution: SocialNicheGuru commented225 is not working
git apply drupal-2632040-225.patch
fatal: invalid path '.'
Comment #227
nlisgo CreditAttribution: nlisgo commentedComment #228
savkaviktor16@gmail.com CreditAttribution: savkaviktor16@gmail.com at Skilld commentedI'm going to reroll it
Comment #229
savkaviktor16@gmail.com CreditAttribution: savkaviktor16@gmail.com at Skilld commentedactually, the patch #218 doesn't need to be rerolled. it applies cleanly
Comment #230
kkasson CreditAttribution: kkasson commentedI just got this error running database updates after testing the patch from #218:
Failed: Drupal\Core\Database\SchemaObjectDoesNotExistException: Cannot add field user_revision__field_MY_DATETIME_FIELD.field_MY_DATETIME_FIELD_timezone: table doesn't exist. in Drupal\Core\Database\Driver\mysql\Schema->addField()
The datetime field is on the user and it correctly updated the user__ table. It looks like it shouldn't be a problem because that table doesn't need to exist anyway. It looks like the update code is supposed to be checking if revisions exist or not, so I'm not sure exactly why it's trying to update it. I'm running the patch on 8.6.x - not sure if that makes a difference.
Comment #231
pcambraComment #232
captaindav CreditAttribution: captaindav commentedI tried the above patches for 8.6.x, they failed to apply. As a work-around I installed the https://www.drupal.org/project/datetime_range_timezone module which made it possible to create new fields with a new field type (based on the core date range field) that supports timezones. Unfortunately the only easy way we could find to switch to the new field type was to simply delete the existing fields with the core date/range type, and then make new fields with the same name. This of course breaks any views that referenced the original field, which is unfortunate and of course takes some time to fix, but it was the easiest way we could find to implement the new field type. I think from this respect the patch is preferable, in that the patch would alter the existing fields so they had timezone support, without requiring deletion of the existing date range fields first.
Comment #234
WidgetsBurritos CreditAttribution: WidgetsBurritos at Rackspace commentedThis is mostly just a reroll of #218 against 8.8.x with a couple exceptions.
The following change was made in that issue to the EntityTestDatetimeTest class:
The old value would have been '2017-03-01T20:02:00' where it's now '2017-03-02T07:02:00+11:00', which includes expected timezone. From what I understand from that issue it's supposed to be based on system default timezone. I dunno if that should affect strategy on this ticket in any way.
That said after running the test locally, looks like we got a new issue with this:
I didn't see that same error in the test error log for #218, so this will require further investigation.
I'm unsure as to the reasoning there. This didn't seem to be the case in #191, which that patch is based on and I didn't see any comments in between those two issues indicating the reason for it, so I don't really know why it was left out. As this portion of the file was in conflict as well, I put that bit of code back in that file because it seems like we don't want to lose important test context there.
Comment #235
WidgetsBurritos CreditAttribution: WidgetsBurritos at Rackspace commentedComment #236
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedThis patch attempts to rationalize some of the test behavior from #2926508: Add DateTimeNormalizer+TimestampNormalizer, deprecate TimestampItemNormalizer: @DataType-level normalizers are reusable by JSON:API with the new test behavior from this issue. I don't expect all tests to pass here, but we placing into review anyway to trigger the test runner.
Part of my logic in this patch was, instead of replacing the existing assertNormalizationEdgeCases test behavior like it seemed like we were doing in #218, is rather to just add additional test coverage for the timezone validation (although all other tests did need some sort of definition for timezone, even if that value was NULL).
^ Based on this though we're still only ever testing if timezone storage is true. We probably need a second test for when this value is false (which I imagine should behave almost exactly as it does now).
Comment #237
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedOddly the binary file got left out on that last patch. Attempting again. Interdiff from previous post is still correct, but posting again just to avoid confusion on numeric indexes.
Comment #239
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedAs I've been digging around, I discovered that EntityTestDateRangeTest won't be able to perform the same assertNormalizationEdgeCases() tests that EntityTestDateonlyTest does as DateTimeItem currently utilizes the DateTimeFormat constraint, but DateRangeItem does not, but there is open issue for that: #2847041: Add a format and start/end validation constraints to DateRangeItem to provide helpful REST/JSON:API error message. So I'm making note of it here, in the event that issue gets resolved before this one does, so we don't forget to update that test.
Comment #240
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedComment #241
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedThis patch should resolve a few more test failures, but still not all of them.
Specifically, in regard to comments in #191 and #192, I've identified what's causing the the Drupal\Tests\node\Kernel\Migrate\d7\MigrateNodeTest failures, but haven't been able to identify the fix quite yet:
The addition of the timezone value in field schema seems to be what's causing the failures. I'd presume that means we need to modify the corresponding fixture in core/modules/migrate_drupal/tests/fixtures/drupal7.php, but that's definitely not the easiest file to work with as it's over 52000 lines long. My initial attempts were fruitless so I did not include them in this patch, but I'll try again later if noone else beats me to it.
**Edit**
I forgot to include in my comment here, that it seems like the the change time is always getting set to the current system time. So whatever is happening there, is causing it to update the node again.
Comment #242
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedSo looking at the remaining test failures a couple things stand out to me:
Drupal\Tests\datetime\Functional\Update\DatetimeUpdateTest
is only failing because it's referencing deprecated code and should probably add@group legacy
to that new test. As such we'd need a follow up ticket to clean that up, but I presume we'd wait until this was actually merged in to see if it's necessary. If this doesn't make it in until D9 it may not be necessary. The included patch makes that change and I'm updating the IS to annotate that.Drupal\Tests\jsonapi\Functional\JsonApiRegressionTest
test is failing because it appears a data structure is changing:This seems like this could be a BC break here as it's affecting the way things are outputted in the jsonapi. I think this warrants further discussion. I think it's a change that probably needs to happen, but could potentially break a bunch of decoupled sites/apps.
Comment #243
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedMaking slight correction to my previous IS update
Comment #244
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedThis patch addresses my previous comment in in #236:
So what I've done is actually rolled back a few of the changes in the EntityTestDatetimeTest and created a new property called $timezoneStorage which indicates if timezone storage should be used. I've defaulted this to FALSE. The old test operates in much the same way it does now.
Then I created a new test called EntityTestDatetimeTimezoneStorageTest that extends EntityTestDatetimeTest. This class sets $timezoneStorage to TRUE instead, and runs all the parent tests, but then also runs its own additional checks on invalid timezones.
The only real issue I could see here is if we ever need to run specific tests only when timezoneStorage is FALSE, in which case the existing EntityTestDatetimeTest may need to get converted to an abstract EntityTestDatetimeTestBase class instead, and then two separate tests extend that instead. I didn't necessarily want to go that far without external feedback as to whether that is the best approach here or not.
Comment #245
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedIt took a bit of digging to figure out, a slight modification needed to be made to the DateField migration plugin to also account for timezone. I ended up not modifying the drupal7.php fixture (although I did learn that core/scripts/db-tools.php was a thing in the process of researching it).
That said, if we want test coverage around the actual migration of timezone data, it might be worth modifying that fixture to include a new "Date with timezone" field, or something like that. I have not done that in this patch, but wanted to annotate the potential need for that in this issue.
I'm assuming it's some environment difference there, but may need another set of eyes on that one.
Comment #246
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedWelp, just realized that's the wrong default value, which illustrates the need for a test here. I'm off for the night but that will need to be fixed in a subsequent patch.
Comment #247
heddnThis should probably block things. Can we get a migrate issue opened up specifically for this aspect? It will need tests, etc. Do we need the rest of this patch though to do that?
Comment #248
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commented@heddn,
Thanks for the feedback. This patch creates the necessary database columns to migrate into, so I think at least some portions of this patch would need to be required. Although maybe we could potentially split up this issue into multiple issues. One for all the database aspects and one for actually using the timezone field and one for the UI work. But that does create the potential for migrating in data that isn't actually being used anywhere, and causing some confusion (especially once the rest of this does get completed and starts changing timezone data on people unsuspectingly).
Comment #249
tim.plunkettThere's some timeout happening when opening the date field formatter form within the Layout Builder UI.
Couldn't track it down much further than there.
This is a HUGE patch. A lot of it seems necessary, but there are many things that seems extraneous or like they were just refactored while making the needed changes.
Even after removing all of the out of scope changes, it will still likely be a very large patch. Anything that can be done to reduce scope, I'd suggest you do it
This should add ConfigFactoryInterface to the end, allow it to be NULL, and add a @trigger_error when it's NULL and pull it from Drupal::service
Out of scope
One line. Going to stop highlighting these, but there are many more to fix
=== TRUE is one I haven't seen in a while
AFAIK t() doesn't support this
Misuse of camelCase
Out of scope
This change looks suspicious. Why is that second param no longer needed?
Same as before with the @trigger_error
This should go on one line. Also, + might be problematic here if there are clashing numeric keys. Consider
\Drupal\Component\Utility\NestedArray::mergeDeep()
"time zone" vs "timezone", here and elsewhere
One line, and same concern as above
Out of scope
Unneeded?
And again
Link to the full URL please
None of these parameters are used
Out of scope
Comment #250
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commented@tim.plunkett,
Thank you for your feedback. This patch is an initial stab at cleaning the items you addressed in #249. It is quite possible I missed an item or two though so I'll recheck in the morning with fresh eyes.
Also, I haven't had a chance to investigate the test failure yet, but based on our slack chat earlier my next steps will probably be to do some digging into system_time_zones() usage. I still need to figure out how to get my system failing.
**Edit**
Oh I didn't change this todo line to the URL format, because it appears #2799987: Datetime and Datelist element's timezone handling is fragile, buggy and wrongly documented has been fixed already, so we should revisit this functionality anyway.
Comment #251
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedThis is just another cleanup patch. It attempts to provide a bit more consistent "time zone" usage in comments/strings. I've opted to use "time zone" as it seems to the more universal option, if this stackexchange answer is to be believed. That said, there appears to be zero consistency within the rest of core of using "timezone" vs "time zone", but at least we can strive to be consistent here.
We did manage to chop of about 4KB off of this patch since #245.
** Edit **
Just saw this comment in #99 that is also advocating for the two word "time zone" here, so yeah, that's the way to go.
Comment #252
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedRegarding #249.8, I reverted that one change in a previous patch, but didn't realize that another part of the patch was getting rid of the getFormatSettings() method altogether, which means I broke the custom datetime formatter. Digging in a little further, I did identify the purpose of that code change. It was to address the issue brought up in #74.1:
So instead of removing the functionality altogether, what I've done, is restored the getFormatSettings() back to its previous glory, with one exception. Instead of:
It is:
This way, it's only overriding the timezone if it's not configurable per field instance. I think that is the desired behavior there, but maybe not. Let me know if anything thinks I misinterpreted that.
Comment #253
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedThis patch should hopefully resolve the layout builder mentioned in #245.2. That was a rather tricky issue to track down, but the gist of it is it was performing infinite recursion due to circular references in the form-building process.
Comment #254
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedThis patch resolves a minor issue with the changes #253 that was causing a few test failures.
Comment #255
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedSo with only one failing class remaining, I think we're at a good spot to summarize where I think this issue is at.
This @todo needs to be addressed as #2799987 is fixed now.
same here
Despite the remaining test failure, and the action items above, I'm gonna go ahead and move this issue into Needs review as I think it's a good time to get additional feedback here.
Comment #256
jonathanshawI thi k splitting up is vital. See #107 for some ideas.
Comment #257
dwwExcited to see this continuing to move forward, thanks everyone!
I think #107 looks like a very sensible way to split this into a meta with reviewable sub-issues, and a healthy order in which to do each step.
#255.2 makes a lot of sense as part of #107.1.
I don't think separating datetime and datetime_range from #255.3 is the way forward. That world is already a painfully fractured mess, and adding timezones for one but not the other, even "only for a couple of weeks" would be a fairly large-scale disaster. :( I'd much rather split this up and get it in along the lines of #107. If we do that, the datetime vs. datetime_range aspect of each piece won't be so bad, especially between #107.1 (shared tests) and #107.3 (shared trait) for most of this.
We're about to surpass 300 comments and this will be more clumsy to use, so either we need to quickly and efficiently make this a meta, or open a new "plan" issue to be the meta and postpone this issue on that. Given how often folks like to edit meta issues (and that each edit generates a new comment), I propose we create a new meta plan with new sub-issues for each of the 4-5 steps, and postpone this issue on all that. Folks who currently want to help get it done can follow / help the new issue(s). When it's all done we can mark this issue fixed to notify everyone following here. As a datetime_extras co-maintainer (and therefore quasi-datetime-in-core-provisional-co-maintainer), that's what I'd recommend and prefer as a strategy to get this done. Thoughts?
Thanks again!
-Derek
Comment #258
WidgetsBurritos CreditAttribution: WidgetsBurritos as a volunteer commentedAhh yeah, I remember seeing #107 when I first read through the issue, but it fell of my radar as I was working through some of the other issues. That definitely seems like a way better strategy than what I suggested with splitting up the datetime and datetime_range, so yes, let's definitely go that route. And I definitely agree that this issue has grown into a hard-to-follow behemoth so a separate meta issue makes a ton of sense here.
I'm gonna be a bit tied up the next couple days getting ready for DrupalCon and travelling, but if anybody is gonna be in Seattle and wants to find some time at the con to flesh out some of these issues, or wants to just go ahead and start creating the issues themselves, that would be greatly appreciated. Otherwise, I probably can find some time to start working through some of that next week.
Comment #259
baisong@jonathanshaw @dww @WidgetsBurritos I'm trying to phrase the proposed new issues titles & descriptions.
Does this look right? Once we make these new issues, do we mark this current issue closed?
Create TimezoneFieldTest class
Create `TimezoneFieldTest` class, to contain test methods that can be applied to any widget/formatter datetime/date_range in order to test timezone handling. This way if we add some new timezone logic, we only have to touch a couple of places in the test and it magically gets tested on all widgets/formatters.
This is a meta issue tracking the following four issues:
Refactor datetime formatters
Refactor to reduce code duplication and confusing code in the timezone handling for datetime formatters. We have a method on DateTimeFormatterBase called "setTimeZone", but timezone overrides are not handled in this method, they are instead handled in each of the formatters formatDate method. Those methods should not need to deal with timezones at all.
Move formatter timezone settings into a trait
Move the formatters timezone settings into a trait, with the ['timezone_default'] options: user, site and fixed; fixed allows you to choose (what we call for backward-compatibility reasons) the ['timezone_override'].
Apply timezone trait to datetime widgets
All the same options make sense for them. This addresses the problem when creating session entities, the times of the sessions as input by the editor are interpreted by Drupal in terms of the timezone of the editor who is creating or updating it, not the venue timezone. In this case their site builder needs to be able to control the timezone used by the widget to interpret the times the editors input.
Add per-instance datetime timezone storage
This solves the problem when creating meeting entities to describe meetings held at various locations across the world, the intended time zone needs to specified for each meeting by the editor, and that preference needs to be stored with the date/time.
A few more reasons for per-date settings.
a) We have to handle fields with existing values that will have a NULL stored time zone. And having this setting, which will then be ignored most of the time, is slightly misleading for site builders. It would make it more bluntly obvious how things worked if you have the additional checkbox for "If a preferred time zone is stored, use it instead of the default". This drives home the idea there are two different things at work here, a default and something that can override it per-date.
b) This would allow site builders to render a time in its canonical (venue) time zone and sometimes in the time zone of the user.
c) This would allow site builders to hide the time zone selector on a "basic" form but have it exposed on an "advanced" form for superusers.
Comment #260
jonathanshawLooks good @baisong!
Yes, I think it makes sense to create those 5 issues. We can then discuss the merits and scope of each more fully individually.
I'm not sure what you mean by "this" here. Do you mean converting the present issue into a meta? I share @dww's concern that at 300 comments it's become unwieldy and a new plan issue is probably better.
@mpdonadio the maintainer said in #196:
But I can't find it such a meta issue. I thought I did some factoring of existing tests in an earlier patch in this issue but can't see that code now when I look.
It's possible that this relates to the new tests we need, but maybe this feature will progress better if we simply create new tests rather than refactor the existing convoluted tangle.
Comment #261
Anonymous (not verified) CreditAttribution: Anonymous as a volunteer commentedTrying to catch up on this issue, as I'm building a media site that is referencing data from all over with varied time zones. Pretty necessary for what I'm trying to do to be able to specify at timezone alongside a date / time field.
Is the patch at #254 working? I see it has failing tests, but does it add the ability to specify a unique timezone per entry?
Is this something that will make it into 8.8.x?
Comment #262
ltrainRe-rolled 2632040-254.patch to work with 8.7.x.
Comment #263
ltrainComment #264
Kasey_MK CreditAttribution: Kasey_MK commented#262 fails to apply to 8.7.7 (I'm using cweagans composer-patches). I don't get any errors applying to patch, but none of my core files are changed.
Comment #265
Kasey_MK CreditAttribution: Kasey_MK commentedFWIW, this is what I'm doing in the meantime (Drupal 8.7.7). We use our site's time zone for all dates, and don't let users set their own time zones. We have events which we want to show in their own time zone; e.g., an event taking place in California should show its times in Pacific. (I spent some time trying to fix/figure out the latest patch on this branch but I could not get things working.)
Add a time zone field to the content type (https://www.drupal.org/project/tzfield) - field_time_zone.
In our case, field_event_date is our date field. Since we want to store accurate metadata, we'll convert the datetimes when they're entered, and then convert them back when they're displayed. That way what the user sees makes sense to them, and what's stored in the database is correct.
Views outputs require conversions too.
Comment #266
jhedstromThe patch in #262 is malformed and literally just creates a file named
632040-254.patch
. Reviews and testing should still happen against #254.Comment #268
jhedstromMoving to NW to address the failing test and feedback since the patch in #254.
Comment #269
recrit CreditAttribution: recrit at Phase2 commentedRolling patch in #254 for the latest 8.7.x.Use patch in #273.
Comment #270
Kasey_MK CreditAttribution: Kasey_MK commentedBless you, recrit. Thank you so much.
Comment #271
Martijn de WitComment #272
recrit CreditAttribution: recrit at Phase2 commentedRolling patch in #254 for the latest 8.7.x with a full index diff but without the new file "core/modules/datetime/tests/fixtures/update/datetime-date_8001-values.php".
If the new test file is not needed for your build, then use this patch 272.
Else, use the patch in #273 that needs to be manually applied with "git apply".
Comment #273
recrit CreditAttribution: recrit at Phase2 commentedRolling patch in #254 for the latest 8.7.x with a full index diff that includes the new binary files.
NOTE:
If the new test file is not needed for your build, then use path #272.
The patch #254 adds a new file for testing - "core/modules/datetime/tests/fixtures/update/datetime-date_8001-values.php".
When using composer + cweagans/composer-patches, this patch will fail when using a stable version of core since there will not be .git directory within the core directory. In this scenario, cweagans/composer-patches will use the local "patch" command instead of "git apply" which fails when using GNU Patch due to "Binary diffs are not supported yet". See https://savannah.gnu.org/forum/forum.php?forum_id=7361.
Test results:
- Patch is applied successfully.
- Fails for the same "Jsonapi.Drupal\Tests\jsonapi\Functional\JsonApiRegressionTest" as #254
Update needed:
Fix failing "Migrate.Drupal\Tests\datetime\Unit\Plugin\migrate\field\DateFieldTest"
Comment #275
Kasey_MK CreditAttribution: Kasey_MK commentedI think this is basically a copy of 2632040-254--8.7.x--full-index.patch in #272 but for 8.8.x.
Comment #276
awolfey CreditAttribution: awolfey at Capellic LLC commentedHere's an update that applies to 8.8.2. A minor edit to Kasey_MK's patch in #275.
Comment #277
japerryWhile the patch itself is coming along well, the update script has a bit of work needed. Specifically:
I've added the checks to the following patch and the update script works for me. Not setting to needs review because I think covering how we deal with basefields still needs some work.
Comment #279
iamdroid CreditAttribution: iamdroid at SystemSeed commentedRe-roll of #277 for 9.0.x
Comment #280
drewfranz CreditAttribution: drewfranz at Pac-12 Networks commentedRe-roll of #279 to remove the duplicate datetime schema key.
Comment #281
steinmb CreditAttribution: steinmb as a volunteer commentedComment #283
hussainwebFirst rerolling this to 9.1.x. There were conflicts because of #3112328: FormatterBase implements ContainerFactoryPluginInterface, so it's not necessary for its child classes to repeat that they do as well.
Comment #284
hussainwebFixing the errors found in #280.
Comment #287
amjad1233Is there anything we can do this ticket to move forward ?
Comment #288
jonathanshawSplit it up per #259 / #260 and earlier comments.
Comment #290
amjad1233@jonathanshaw & @baisong
As per your suggestion I have created 5 child issues.
Comment #291
dwwThanks for opening those child issues! 🙏
I opened #3185747: [META] Add timezone support to core date fields as a working meta plan issue to actually coordinate this effort. Trying to do that in this issue is going to be a mess.
We should stop posting "composer-friendly" giant patches in here, too. It's important we have a place for folks to put the patches they're using on real sites while the dust settles on doing this properly, but we don't want those patches either in this issue, nor in the new meta. So I also opened #3185750: Composer friendly patches adding timezones to core date fields for that.
Updating the summary here to clarify what's happening where. Removing tags for issue rescope and summary update.
Ideally, no one else should comment here until #3185747 is marked fixed and we can close this. 🤞
Thanks for all the effort here so far, and for your cooperation in keeping the scope manageable and the signal to noise ratio high. 😉
Cheers,
-Derek
Comment #293
recrit CreditAttribution: recrit at Phase2 commentedRolled the patch agains 9.2.x since the patch 284 does not apply cleanly to 9.2.x mainly due to the test "assert*" methods have changed.
Comment #294
BerdirI'm not a date system maintainer, but I feel quite strongly that extending the existing field type is adding an immense amount of complexity to this issue and patch that is IMHO not worth it.
I understand that people have some use cases for this, but this also has severe downsides.. sorting on such a field for example is impossible if you care about correct sort order by the hour, it can be mixed up by up to +/- 12h.
Wouldn't it be a lot easier to add a new field type that extends from the existing one and only that has a support for this new feature? The need for an update path would simply vanish then. There is an edge case of people that already have date fields that want them to be timezone specific, but is supporting that really worth the effort? There could be a contrib module or even just a script that people can run that would basically do what the update function does.
A new field type is something that could be implemented in a contrib module, I'm not sure if the need for this is strong enough that it has to be in core. The core date system is also barely maintained and and many issues have been stuck for years, I honestly think the chances of a patch with this level of complexity getting committed in the near future as very narrow. There might be small parts that are much easier to do in core, like the form element stuff, that could be split off and likely has a much bigger chance of getting in.
I also equally strongly advice against using this patch on production sites. Relying on patches with update functions is a time bomb. If another patch with a 8001 update function is committed then you have have a huge mess. Your installation thinks that 8001 will not need to run anymore, will skip that other update, this will be rerolled with 8002 and then it will instead try to run this update _again_.
Comment #295
dpiAs maintainer of Recurring Date Field I want to throw in some brief (late night) high level thoughts.
With both these points, we'd need to start over, no migration, no extending existing code, brand new views integration. Widgets and elements could possibly be adapted for use with both.
I think its a bit late to tack on time zone functionality to the existing datetime field.
Check out the Recurring Date Field field type, which is effectively the existing Datetime field + time zone + RRULE data. It does its best to extend as much from core as possible, making the switch from core's field easy. But I dont think the foundation is rock solid, and would certainly reconsider if starting the project over.
Its interesting that neither Smart Date nor Recurring Date Field has been brought up in this issue yet, both good examples of well utilized contrib implementations featuring time zone features. As mentioned above, Recurring Date Field suffers from legacy storage, and non-native database type. Smart Date is tied to using Timestamp/epoch, which has its own problems such as limited range (<1970) and database-level date math could be easier. Certainly some code could be borrowed and learnings informing this implementation could have been made.
Comment #296
recrit CreditAttribution: recrit at Phase2 commentedThe attached 2632040-D9.2.x-296--full.patch fixes a bug in the "core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDefaultWidget.php" which was missing "use Drupal\Core\Config\ConfigFactoryInterface;". See interdiff-2632040-296-full-293.txt.
@dpi,
Thanks for the contrib module suggestions. The Smart Date is perfect for this use case. Unfortunately, that module was created in April 2019 and this patch started way back in Dec 2015.
@Berdir,
I agree that this patch is not ideal, however it was a viable option for a site that needed to implement date entry with a timezone other than the site's time zone or user's timezone. Example: An editor creates an Event and sets the timezone of the date to that of the event's location, which is not the site's timezone or the editor's Drupal user timezone.
Sorting being off - This would be an issue for Database sorting. For a Solr search, then this is not an issue when indexing the field as a Date which indexes the date as GMT.
Suggestions
For new sites
Use Smart Date.
For existing sites that are using this patch
The datetime and datetime_range update has ran already to add the timezone field to the database table.
To support any future updates provide by core while continuing to use this patch:
Comment #297
dpi@recrit again and just to be clear, both projects solve the need for time zone. Not only Smart Date.
The point I'm making is that at any point we can stop, analyse, and evaluate, the solutions out there. A patch can be steered in a new direction or start from scratch. I'd encourage anyone keen on continuing this patch to look at the mentioned projects and write up something comparing the patch, outlining differences and pros/cons.
Comment #298
recrit CreditAttribution: recrit at Phase2 commented@dpi I steered away from Recurring Dates Field since its main goal is recurring dates with the majority of its code centered around handling the recurring dates. For this patch, we're only trying to add a timezone. A custom field widget could be created to exclude the recurring rule functionality, but it would have to be tested that the module work work without a recurring rule.
There is a module that only adds the timezone based on this patch - Datetime Range Timezone. However, the last commit was 3 years ago so it does not have any of the updates to the patch since then.
I agree that this should move to a contrib module since it's unlikely that it would make it into core. Then we would only need some upgrade code to convert over to the new field type.
Comment #303
c_archer CreditAttribution: c_archer as a volunteer and commentedPatch from #296 does not apply agains Drupal 9.5.7
Comment #305
joseph.olstadI suggest simplifying this to allow contrib to handle this.
In a Drupal classic approach we'd go ahead and add a new hook to alter the list of time zones.
This works quite well with the latest Drupal 10 and has been in use for a while without telling anyone.
Here in Canada for intranet sites we restrict the timezone selection down to 5 Canadian timezones.
Using the attached hook invokeAll patch to core and this example and an implements the said hook for example:
I imagine someone is going to suggest extending the TimeZoneFormHelper class and overriding the getOptionsListByRegion method instead?
Is there some Drupal 10 documentation for this sort of thing with examples if for say we wanted to adopt this approach in a contrib module?
I think this should be a contrib solution.
Are there some sort of informal or formal "white paper" with a performance analysis / benefits/risk to a list of various approaches to solve this?
Comment #306
joseph.olstadThis has been open 9 years, we should probably just leave this to contrib. With that said, given my example provided in comment #305, what is the highest performance /most practical way to handle this case?
Comment #307
joseph.olstadupdate to #305
https://www.drupal.org/files/issues/2024-01-30/2632040-307.patch