-
-
Notifications
You must be signed in to change notification settings - Fork 36
Define time zone values and conversions #1078
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
> into a [floating](https://www.w3.org/TR/timezone/#floating) time value | ||
> (sometimes called a _plain_ or _local_ time value) by removing | ||
> the association with a specific time zone. | ||
The value `local` corresponds to the default time zone. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The value local
is meant to remove the time zone (it floats the value). This is different from the default time zone. Consider:
.local $event = {|2025-06-28T19
10000
:00:00Z| :datetime}
{{The Annual Barn Dance will be on {$event :date timeZone=local}.}}
The above formats as "June 28, 2025" regardless of where the message is viewed, vs. potentially formatting as "June 29, 2025" or "June 27, 2025" depending on the default time zone. The name local
I find misleading. The Temporal synonym is plain
, which I also find unhelpful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, so local
is effectively "local" to the input value, rather than being "local" to the time zone of the environment where the formatting is being done, yes? I had understood it the other way around.
We should probably use a different term that is more implicitly obvious about its meaning. Maybe input
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As expressed elsewhere, I hate the term local
for this. It makes more sense in HTML forms, where presumably the user in inputting local wall time, but no sense in a context like MF. Temporal uses the term plain
for this
If the _operand_ value does not include a time zone, | ||
it is presumed to use the default time zone. | ||
If the _operand_ value does include a time zone and the `timeZone` _option_ is set, | ||
an implementation SHOULD convert the value to the time zone indicated by the _option_. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this reads oddly, since the result of the first sentence would be that all operands end up with a time zone.
Lots of operands do not "include" a time zone--all classical date/time values, such as JS Date
, for example. It's not helpful to think of assigning a time zone to the value so much as it is to think of assigning a time zone to the expression (so that an incremental time stamp can be converted to wall time). Consider:
When it is {$d :datetime} for you
it is {$d :datetime timeZone=|America/Los_Angeles|} in L.A.
I would say:
If the _operand_ value does not include a time zone, | |
it is presumed to use the default time zone. | |
If the _operand_ value does include a time zone and the `timeZone` _option_ is set, | |
an implementation SHOULD convert the value to the time zone indicated by the _option_. | |
If the _expression_ includes a valid `timeZone` _option_ | |
and the _operand_'s value also includes a time zone, | |
an implementation SHOULD convert the _resolved value_ of the _operand_ | |
to the time zone indicated by the _option_. | |
Otherwise, the time zone indicated by the _option_ should be used to format the value. |
Note that it is unclear what "convert" means and the conversion means different things depending on the operand type. See here for examples of types. The conversion is one thing for a floating time or an incremental time/timestamp (you just add the time zone to the value) but requires calculation through a calendar for "zoned" values. The value local
for timeZone
exists to let the user remove the zone from a "zoned" value (so that the field values are no longer affected by the default--or any other--time zone).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The conversion is one thing for a floating time or an incremental time/timestamp (you just add the time zone to the value) but requires calculation through a calendar for "zoned" values.
This does not match my understanding of what would happen if a time without an explicit timezone (such as a JS Date
, which internally is handled as an incremental time/timestamp) would be formatted while explicitly setting timeZone
.
With the JS Intl.DateTimeFormat, this happens:
const now = new Date()
new Intl.DateTimeFormat('en-de',{timeStyle:'long'}).format(now)
// "11:10:55 CEST"
new Intl.DateTimeFormat('en-de',{timeZone:'America/Los_Angeles',timeStyle:'long'}).format(now)
// "02:10:55 GMT-7"
So effectively the date being formatted is always considered to use the local/system time zone, and setting timeZone
will format the date with conversion through a calendar.
My strong preference would be for the MF2 :datetime
to behave similarly to the current JS behaviour, where the input/operand value is always considered to have some timezone (by default, the system default), and for formatting to happen in some timezone (by default, the system default). Setting the timeZone
on the expression controls the timezone used for formatting, but does not change the timezone of the input.
Do the ICU datetime formatters use a similar approach, or do they do something different?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, you're right. And ICU does it the same way. It's my description that is somewhat wonky.
If you have a timestamp, you always need a calendar to format the value, but the application of a time zone (the default or some explicit value) doesn't change the timestamp itself. If you have a "zoned" value, you use a calendar to compute the instant and then modify the value by applying the explicitly provided time zone (you wouldn't use the default zone with a zoned value, presumably).
The value `local` corresponds to the default time zone. | ||
|
||
If the _operand_ value does not include a time zone, | ||
it is presumed to use the default time zone. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's not clear here if "the default time zone" is meant to be the result of accessing the system time zone setting, or a single default time zone (e.g. UTC).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The intent with the proposed language is to match the text from earlier in the same section:
message-format-wg/spec/functions/datetime.md
Lines 265 to 268 in 0028d17
**_<dfn>Date/time override options</dfn>_** are _options_ that allow an _expression_ to | |
override values set by the current locale, | |
or provided by the _formatting context_ (such as the default time zone), | |
or embedded in an implementation-defined date/time _operand_ value. |
Does that context clarify the meaning here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is presumed to use the default time zone. | |
it is presumed to use the default time zone specified by the formatting context. |
Ah, I missed that. How about this, then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fallback algorithm seems ok, since it has an out for an implementation that doesn't support time zone conversion
@@ -282,11 +282,14 @@ the functions `:datetime`, `:date`, and `:time`. | |||
- `local` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if I like the ident "local"; that word is way overloaded. I think "system" or "default" would be better.
This is proposed as a separate change from #1077, as it was not discussed on the call.
The intent with the text updated here is to clarify what happens when the
timeZone
option is set on a date/time function.The SHOULD/MAY language that's proposed is intended to allow for an implementation that does not support time zone conversions, which I believe matches the case in JS Temporal.
Is there prior art of
local
being used as a time zone value as we're proposing, or are there alternatives that other date/time formatters use?