Skip to content

Commit

Permalink
Avoid formatting irrelevant parts of dateStyle/timeStyle for Temporal…
Browse files Browse the repository at this point in the history
… types

timeStyle: 'long' and timeStyle: 'full' include the time zone name for
legacy Date formatting. However, PlainTime and PlainDateTime don't include
a time zone in their data model, so they shouldn't format a time zone name
when using timeStyle. Similarly, PlainYearMonth and PlainMonthDay
shouldn't format a day or year respectively when using dateStyle. This was
already the consensus but somewhere along the line the spec text got out
of sync, probably in a rebase on latest ECMA-402.

In the polyfill, we already handled dateStyle for PlainYearMonth and
PlainMonthDay. Try to hack around this the same way for timeStyle.

Closes: #2795
  • Loading branch information
ptomato authored and Ms2ger committed Oct 8, 2024
1 parent c982717 commit f62aa26
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 6 deletions.
10 changes: 10 additions & 0 deletions polyfill/lib/intl.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,11 @@ function timeAmend(originalOptions) {
timeZoneName: false,
dateStyle: false
});
if (options.timeStyle === 'long' || options.timeStyle === 'full') {
// Try to fake what timeStyle should do if not printing the time zone name
delete options.timeStyle;
ObjectAssign(options, { hour: 'numeric', minute: '2-digit', second: '2-digit' });
}
if (!hasTimeOptions(options)) {
if (hasAnyDateTimeOptions(originalOptions)) {
throw new TypeError(`cannot format Temporal.PlainTime with options [${ObjectKeys(originalOptions)}]`);
Expand Down Expand Up @@ -428,6 +433,11 @@ function dateAmend(originalOptions) {

function datetimeAmend(originalOptions) {
const options = amend(originalOptions, { timeZoneName: false });
if (options.timeStyle === 'long' || options.timeStyle === 'full') {
// Try to fake what timeStyle should do if not printing the time zone name
delete options.timeStyle;
ObjectAssign(options, { hour: 'numeric', minute: '2-digit', second: '2-digit' });
}
if (!hasTimeOptions(options) && !hasDateOptions(options)) {
if (hasAnyDateTimeOptions(originalOptions)) {
throw new TypeError(`cannot format PlainDateTime with options [${ObjectKeys(originalOptions)}]`);
Expand Down
42 changes: 36 additions & 6 deletions spec/intl.html
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,7 @@ <h1>
1. Set _dateTimeFormat_.[[DateStyle]] to _dateStyle_.
1. Let _timeStyle_ be ? GetOption(_options_, *"timeStyle"*, ~string~, « *"full"*, *"long"*, *"medium"*, *"short"* », *undefined*).
1. Set _dateTimeFormat_.[[TimeStyle]] to _timeStyle_.
1. <ins>Let _formats_ be _resolvedLocaleData_.[[formats]].[[&lt;_resolvedCalendar_>]].</ins>
1. If _dateStyle_ is not *undefined* or _timeStyle_ is not *undefined*, then
1. If _hasExplicitFormatComponents_ is *true*, then
1. Throw a *TypeError* exception.
Expand All @@ -700,18 +701,18 @@ <h1>
1. Let _styles_ be _resolvedLocaleData_.[[styles]].[[&lt;_resolvedCalendar_>]].
1. Let _bestFormat_ be DateTimeStyleFormat(_dateStyle_, _timeStyle_, _styles_).
1. <ins>If _dateStyle_ is not *undefined*, then</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalPlainDateFormat]] to _bestFormat_.</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalPlainYearMonthFormat]] to _bestFormat_.</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalPlainMonthDayFormat]] to _bestFormat_.</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalPlainDateFormat]] to AdjustDateTimeStyleFormat(_formats_, _bestFormat_, _matcher_, « [[weekday]], [[era]], [[year]], [[month]], [[day]] »).</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalPlainYearMonthFormat]] to AdjustDateTimeStyleFormat(_formats_, _bestFormat_, _matcher_, « [[era]], [[year]], [[month]] »).</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalPlainMonthDayFormat]] to AdjustDateTimeStyleFormat(_formats_, _bestFormat_, _matcher_, « [[month]], [[day]] »).</ins>
1. <ins>Else,</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalPlainDateFormat]] to *null*.</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalPlainYearMonthFormat]] to *null*.</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalPlainMonthDayFormat]] to *null*.</ins>
1. <ins>If _timeStyle_ is not *undefined*, then</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalPlainTimeFormat]] to _bestFormat_.</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalPlainTimeFormat]] to AdjustDateTimeStyleFormat(_formats_, _bestFormat_, _matcher_, « [[dayPeriod]], [[hour]], [[minute]], [[second]], [[fractionalSecondDigits]] »).</ins>
1. <ins>Else,</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalPlainTimeFormat]] to *null*.</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalPlainDateTimeFormat]] to _bestFormat_.</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalPlainDateTimeFormat]] to AdjustDateTimeStyleFormat(_formats_, _bestFormat_, _matcher_, « [[weekday]], [[era]], [[year]], [[month]], [[day]], [[dayPeriod]], [[hour]], [[minute]], [[second]], [[fractionalSecondDigits]] »).</ins>
1. <ins>Set _dateTimeFormat_.[[TemporalInstantFormat]] to _bestFormat_.</ins>
1. Else,
1. <del>Let _needDefaults_ be *true*.</del>
Expand All @@ -729,7 +730,7 @@ <h1>
1. <del>If _needDefaults_ is *true* and _defaults_ is either ~time~ or ~all~, then</del>
1. <del>For each property name _prop_ of « *"hour"*, *"minute"*, *"second"* », do</del>
1. <del>Set _formatOptions_.[[&lt;_prop_>]] to *"numeric"*.</del>
1. Let _formats_ be _resolvedLocaleData_.[[formats]].[[&lt;_resolvedCalendar_>]].
1. <del>Let _formats_ be _resolvedLocaleData_.[[formats]].[[&lt;_resolvedCalendar_>]].</del>
1. <del>If _formatMatcher_ is *"basic"*, then</del>
1. <del>Let _bestFormat_ be BasicFormatMatcher(_formatOptions_, _formats_).</del>
1. <del>Else,</del>
Expand Down Expand Up @@ -876,6 +877,35 @@ <h1>
1. Return _bestFormat_.
</emu-alg>
</emu-clause>

<emu-clause id="sec-adjustdatetimestyleformat" type="abstract operation">
<h1>
AdjustDateTimeStyleFormat (
_formats_: a List of DateTime Format Records,
_baseFormat_: a DateTime Format Record,
_matcher_: *"basic"* or *"best fit"*,
_allowedOptions_: a List of field names,
): a DateTime Format Record
</h1>
<dl class="header">
<dt>description</dt>
<dd>
It inspects _baseFormat_ and determines the closest format to it that only includes fields from _allowedOptions_.
This is used for determining the best format for Temporal objects with the `"dateStyle"` or `"timeStyle"` options.
For example, a locale's best format for `"dateStyle": "full"` might include the weekday, which is not applicable when formatting a `Temporal.PlainYearMonth` object.
</dd>
</dl>
<emu-alg>
1. Let _formatOptions_ be a new Record.
1. For each field name _fieldName_ of _allowedOptions_, do
1. Set the field of _formatOptions_ whose name is _fieldName_ to the value of the field of _baseFormat_ whose name is _fieldName_.
1. If _matcher_ is *"basic"*, then
1. Let _bestFormat_ be BasicFormatMatcher(_formatOptions_, _formats_).
1. Else,
1. Let _bestFormat_ be BestFitFormatMatcher(_formatOptions_, _formats_).
1. Return _bestFormat_.
</emu-alg>
</emu-clause>
</ins>

<emu-clause id="sec-datetime-format-functions">
Expand Down

0 comments on commit f62aa26

Please sign in to comment.