diff --git a/polyfill/test/validStrings.mjs b/polyfill/test/validStrings.mjs
index c3cd03c76..7c5f1f6d9 100644
--- a/polyfill/test/validStrings.mjs
+++ b/polyfill/test/validStrings.mjs
@@ -76,6 +76,7 @@ class Literal {
return this.str;
}
}
+const empty = new Literal('');
class Optional {
constructor(productionLike) {
@@ -189,6 +190,8 @@ function seq(...productions) {
// characters
const temporalSign = character('+-−');
+const dateSeparator = (extended) => (extended ? character('-') : empty);
+const timeSeparator = (extended) => (extended ? character(':') : empty);
const hour = zeroPaddedInclusive(0, 23, 2);
const minuteSecond = zeroPaddedInclusive(0, 59, 2);
const temporalDecimalSeparator = character('.,');
@@ -242,22 +245,28 @@ const timeFraction = withCode(temporalDecimalFraction, (data, result) => {
data.microsecond = +fraction.slice(3, 6);
data.nanosecond = +fraction.slice(6, 9);
});
+
function saveOffset(data, result) {
data.offset = ES.ParseDateTimeUTCOffset(result);
}
-const utcOffsetSubMinutePrecision = withCode(
- seq(
- temporalSign,
- hour,
+const utcOffset = (subMinutePrecision) =>
+ seq(temporalSign, hour, [
choice(
- [minuteSecond, [minuteSecond, [temporalDecimalFraction]]],
- seq(':', minuteSecond, [':', minuteSecond, [temporalDecimalFraction]])
+ seq(
+ timeSeparator(true),
+ minuteSecond,
+ subMinutePrecision ? [timeSeparator(true), minuteSecond, [temporalDecimalFraction]] : empty
+ ),
+ seq(
+ timeSeparator(false),
+ minuteSecond,
+ subMinutePrecision ? [timeSeparator(false), minuteSecond, [temporalDecimalFraction]] : empty
+ )
)
- ),
- saveOffset
-);
-const dateTimeUTCOffset = choice(utcDesignator, utcOffsetSubMinutePrecision);
-const timeZoneUTCOffsetName = seq(temporalSign, hour, choice([minuteSecond], seq(':', minuteSecond)));
+ ]);
+const dateTimeUTCOffset = (z) =>
+ z ? choice(utcDesignator, withCode(utcOffset(true), saveOffset)) : withCode(utcOffset(true), saveOffset);
+const timeZoneUTCOffsetName = utcOffset(false);
const timeZoneIANAName = choice(...timezoneNames);
const timeZoneIdentifier = withCode(
choice(timeZoneUTCOffsetName, timeZoneIANAName),
@@ -281,42 +290,48 @@ const annotations = withSyntaxConstraints(oneOrMore(choice(calendarAnnotation, a
throw new SyntaxError('more than one calendar annotation and at least one critical');
}
});
-const timeSpec = seq(
- timeHour,
- choice([':', timeMinute, [':', timeSecond, [timeFraction]]], seq(timeMinute, [timeSecond, [timeFraction]]))
-);
-const timeSpecWithOptionalOffsetNotAmbiguous = withSyntaxConstraints(seq(timeSpec, [dateTimeUTCOffset]), (result) => {
- if (/^(?:(?!02-?30)(?:0[1-9]|1[012])-?(?:0[1-9]|[12][0-9]|30)|(?:0[13578]|10|12)-?31)$/.test(result)) {
- throw new SyntaxError('valid PlainMonthDay');
- }
- if (/^(?![−-]000000)(?:[0-9]{4}|[+−-][0-9]{6})-?(?:0[1-9]|1[012])$/.test(result)) {
- throw new SyntaxError('valid PlainYearMonth');
- }
-});
+const timeSpec = (extended) =>
+ seq(timeHour, [timeSeparator(extended), timeMinute, [timeSeparator(extended), timeSecond, [timeFraction]]]);
+const time = choice(timeSpec(true), timeSpec(false));
function validateDayOfMonth(result, { year, month, day }) {
if (day > ES.ISODaysInMonth(year, month)) throw SyntaxError('retry if bad day of month');
}
-const dateSpecMonthDay = withSyntaxConstraints(seq(['--'], dateMonth, ['-'], dateDay), validateDayOfMonth);
-const dateSpecYearMonth = seq(dateYear, ['-'], dateMonth);
-const date = withSyntaxConstraints(
- choice(seq(dateYear, '-', dateMonth, '-', dateDay), seq(dateYear, dateMonth, dateDay)),
+const dateSpecMonthDay = withSyntaxConstraints(
+ seq(['--'], dateMonth, choice(dateSeparator(true), dateSeparator(false)), dateDay),
validateDayOfMonth
);
-const dateTime = seq(date, [dateTimeSeparator, timeSpec, [dateTimeUTCOffset]]);
+const dateSpecYearMonth = seq(dateYear, choice(dateSeparator(true), dateSeparator(false)), dateMonth);
+const dateSpec = (extended) =>
+ withSyntaxConstraints(
+ seq(dateYear, dateSeparator(extended), dateMonth, dateSeparator(extended), dateDay),
+ validateDayOfMonth
+ );
+const date = choice(dateSpec(true), dateSpec(false));
+const dateTime = (z, timeRequired) =>
+ seq(
+ date,
+ timeRequired
+ ? seq(dateTimeSeparator, time, [dateTimeUTCOffset(z)])
+ : [dateTimeSeparator, time, [dateTimeUTCOffset(z)]]
+ );
const annotatedTime = choice(
- seq(timeDesignator, timeSpec, [dateTimeUTCOffset], [timeZoneAnnotation], [annotations]),
- seq(timeSpecWithOptionalOffsetNotAmbiguous, [timeZoneAnnotation], [annotations])
-);
-const annotatedDateTime = seq(dateTime, [timeZoneAnnotation], [annotations]);
-const annotatedDateTimeTimeRequired = seq(
- date,
- dateTimeSeparator,
- timeSpec,
- [dateTimeUTCOffset],
- [timeZoneAnnotation],
- [annotations]
+ seq(timeDesignator, time, [dateTimeUTCOffset(false)], [timeZoneAnnotation], [annotations]),
+ seq(
+ withSyntaxConstraints(seq(time, [dateTimeUTCOffset(false)]), (result) => {
+ if (/^(?:(?!02-?30)(?:0[1-9]|1[012])-?(?:0[1-9]|[12][0-9]|30)|(?:0[13578]|10|12)-?31)$/.test(result)) {
+ throw new SyntaxError('valid PlainMonthDay');
+ }
+ if (/^(?![−-]000000)(?:[0-9]{4}|[+−-][0-9]{6})-?(?:0[1-9]|1[012])$/.test(result)) {
+ throw new SyntaxError('valid PlainYearMonth');
+ }
+ }),
+ [timeZoneAnnotation],
+ [annotations]
+ )
);
+const annotatedDateTime = (zoned, timeRequired) =>
+ seq(dateTime(zoned, timeRequired), zoned ? timeZoneAnnotation : [timeZoneAnnotation], [annotations]);
const annotatedYearMonth = withSyntaxConstraints(
seq(dateSpecYearMonth, [timeZoneAnnotation], [annotations]),
(result, data) => {
@@ -427,19 +442,19 @@ const duration = withSyntaxConstraints(
}
);
-const instant = seq(date, dateTimeSeparator, timeSpec, dateTimeUTCOffset, [timeZoneAnnotation], [annotations]);
-const zonedDateTime = seq(dateTime, timeZoneAnnotation, [annotations]);
+const instant = seq(date, dateTimeSeparator, time, dateTimeUTCOffset(true), [timeZoneAnnotation], [annotations]);
+const zonedDateTime = annotatedDateTime(true, false);
// goal elements
const goals = {
Instant: instant,
- Date: annotatedDateTime,
- DateTime: annotatedDateTime,
+ Date: annotatedDateTime(false, false),
+ DateTime: annotatedDateTime(false, false),
Duration: duration,
- MonthDay: choice(annotatedMonthDay, annotatedDateTime),
- Time: choice(annotatedTime, annotatedDateTimeTimeRequired),
+ MonthDay: choice(annotatedMonthDay, annotatedDateTime(false, false)),
+ Time: choice(annotatedTime, annotatedDateTime(false, true)),
TimeZone: choice(timeZoneIdentifier, zonedDateTime, instant),
- YearMonth: choice(annotatedYearMonth, annotatedDateTime),
+ YearMonth: choice(annotatedYearMonth, annotatedDateTime(false, false)),
ZonedDateTime: zonedDateTime
};
@@ -467,16 +482,12 @@ const comparisonItems = {
YearMonth: ['year', 'month', 'calendar'],
ZonedDateTime: [...dateItems, ...timeItems, 'offset', 'z', 'tzAnnotation', 'calendar']
};
-const plainModes = ['Date', 'DateTime', 'MonthDay', 'Time', 'YearMonth'];
function fuzzMode(mode) {
console.log('// starting to fuzz ' + mode);
for (let count = 0; count < 1000; count++) {
- let generatedData, fuzzed;
- do {
- generatedData = {};
- fuzzed = goals[mode].generate(generatedData);
- } while (plainModes.includes(mode) && /[0-9][zZ]/.test(fuzzed));
+ const generatedData = {};
+ const fuzzed = goals[mode].generate(generatedData);
try {
const parsingMethod = ES[`ParseTemporal${mode}StringRaw`] ?? ES[`ParseTemporal${mode}String`];
const parsed = parsingMethod(fuzzed);
diff --git a/spec/abstractops.html b/spec/abstractops.html
index 5e83e5c05..686e2ad13 100644
--- a/spec/abstractops.html
+++ b/spec/abstractops.html
@@ -1191,6 +1191,10 @@
ISO 8601 grammar
`a` `b` `c` `d` `e` `f` `g` `h` `i` `j` `k` `l` `m`
`n` `o` `p` `q` `r` `s` `t` `u` `v` `w` `x` `y` `z`
+ DateSeparator[Extended] :::
+ [+Extended] `-`
+ [~Extended] [empty]
+
DaysDesignator ::: one of
`D` `d`
@@ -1239,9 +1243,6 @@ ISO 8601 grammar
`11`
`12`
- DateMonthWithThirtyOneDays ::: one of
- `01` `03` `05` `07` `08` `10` `12`
-
DateDay :::
`0` NonZeroDigit
`1` DecimalDigit
@@ -1250,22 +1251,19 @@ ISO 8601 grammar
`31`
DateSpecYearMonth :::
- DateYear `-`? DateMonth
+ DateYear DateSeparator[+Extended] DateMonth
+ DateYear DateSeparator[~Extended] DateMonth
DateSpecMonthDay :::
- `--` DateMonth `-`? DateDay
- DateMonth `-`? DateDay
+ `--`? DateMonth DateSeparator[+Extended] DateDay
+ `--`? DateMonth DateSeparator[~Extended] DateDay
- ValidMonthDay :::
- DateMonth `-`? `0` NonZeroDigit
- DateMonth `-`? `1` DecimalDigit
- DateMonth `-`? `2` DecimalDigit
- DateMonth `-`? `30` but not one of `0230` or `02-30`
- DateMonthWithThirtyOneDays `-`? `31`
+ DateSpec[Extended] :::
+ DateYear DateSeparator[?Extended] DateMonth DateSeparator[?Extended] DateDay
Date :::
- DateYear `-` DateMonth `-` DateDay
- DateYear DateMonth DateDay
+ DateSpec[+Extended]
+ DateSpec[~Extended]
TimeHour :::
Hour
@@ -1280,28 +1278,22 @@ ISO 8601 grammar
TimeFraction :::
TemporalDecimalFraction
- UTCOffsetWithSubMinuteComponents[Extended] :::
- TemporalSign Hour TimeSeparator[?Extended] MinuteSecond TimeSeparator[?Extended] MinuteSecond TemporalDecimalFraction?
-
NormalizedUTCOffset :::
- ASCIISign Hour `:` MinuteSecond
+ ASCIISign Hour TimeSeparator[+Extended] MinuteSecond
- UTCOffsetMinutePrecision :::
+ UTCOffset[SubMinutePrecision] :::
TemporalSign Hour
TemporalSign Hour TimeSeparator[+Extended] MinuteSecond
TemporalSign Hour TimeSeparator[~Extended] MinuteSecond
+ [+SubMinutePrecision] TemporalSign Hour TimeSeparator[+Extended] MinuteSecond TimeSeparator[+Extended] MinuteSecond TemporalDecimalFraction?
+ [+SubMinutePrecision] TemporalSign Hour TimeSeparator[~Extended] MinuteSecond TimeSeparator[~Extended] MinuteSecond TemporalDecimalFraction?
- UTCOffsetSubMinutePrecision :::
- UTCOffsetMinutePrecision
- UTCOffsetWithSubMinuteComponents[+Extended]
- UTCOffsetWithSubMinuteComponents[~Extended]
-
- DateTimeUTCOffset :::
- UTCDesignator
- UTCOffsetSubMinutePrecision
+ DateTimeUTCOffset[Z] :::
+ [+Z] UTCDesignator
+ UTCOffset[+SubMinutePrecision]
TimeZoneUTCOffsetName :::
- UTCOffsetMinutePrecision
+ UTCOffset[~SubMinutePrecision]
TZLeadingChar :::
Alpha
@@ -1356,30 +1348,26 @@ ISO 8601 grammar
Annotations :::
Annotation Annotations?
- TimeSpec :::
+ TimeSpec[Extended] :::
TimeHour
- TimeHour `:` TimeMinute
- TimeHour TimeMinute
- TimeHour `:` TimeMinute `:` TimeSecond TimeFraction?
- TimeHour TimeMinute TimeSecond TimeFraction?
+ TimeHour TimeSeparator[?Extended] TimeMinute
+ TimeHour TimeSeparator[?Extended] TimeMinute TimeSeparator[?Extended] TimeSecond TimeFraction?
- TimeSpecWithOptionalOffsetNotAmbiguous :::
- TimeSpec DateTimeUTCOffset? but not one of ValidMonthDay or DateSpecYearMonth
+ Time :::
+ TimeSpec[+Extended]
+ TimeSpec[~Extended]
- DateTime :::
- Date
- Date DateTimeSeparator TimeSpec DateTimeUTCOffset?
+ DateTime[Z, TimeRequired] :::
+ [~TimeRequired] Date
+ Date DateTimeSeparator Time DateTimeUTCOffset[?Z]?
AnnotatedTime :::
- TimeDesignator TimeSpec DateTimeUTCOffset? TimeZoneAnnotation? Annotations?
- TimeSpecWithOptionalOffsetNotAmbiguous TimeZoneAnnotation? Annotations?
-
- AnnotatedDateTime[Zoned] :::
- [~Zoned] DateTime TimeZoneAnnotation? Annotations?
- [+Zoned] DateTime TimeZoneAnnotation Annotations?
+ TimeDesignator Time DateTimeUTCOffset[~Z]? TimeZoneAnnotation? Annotations?
+ Time DateTimeUTCOffset[~Z]? TimeZoneAnnotation? Annotations?
- AnnotatedDateTimeTimeRequired :::
- Date DateTimeSeparator TimeSpec DateTimeUTCOffset? TimeZoneAnnotation? Annotations?
+ AnnotatedDateTime[Zoned, TimeRequired] :::
+ [~Zoned] DateTime[~Z, ?TimeRequired] TimeZoneAnnotation? Annotations?
+ [+Zoned] DateTime[+Z, ?TimeRequired] TimeZoneAnnotation Annotations?
AnnotatedYearMonth :::
DateSpecYearMonth TimeZoneAnnotation? Annotations?
@@ -1460,29 +1448,93 @@ ISO 8601 grammar
TemporalSign? DurationDesignator DurationTime
TemporalInstantString :::
- Date DateTimeSeparator TimeSpec DateTimeUTCOffset TimeZoneAnnotation? Annotations?
+ Date DateTimeSeparator Time DateTimeUTCOffset[+Z] TimeZoneAnnotation? Annotations?
TemporalDateTimeString[Zoned] :::
- AnnotatedDateTime[?Zoned]
+ AnnotatedDateTime[?Zoned, ~TimeRequired]
TemporalDurationString :::
Duration
TemporalMonthDayString :::
AnnotatedMonthDay
- AnnotatedDateTime[~Zoned]
+ AnnotatedDateTime[~Zoned, ~TimeRequired]
TemporalTimeString :::
AnnotatedTime
- AnnotatedDateTimeTimeRequired
+ AnnotatedDateTime[~Zoned, +TimeRequired]
TemporalYearMonthString :::
AnnotatedYearMonth
- AnnotatedDateTime[~Zoned]
+ AnnotatedDateTime[~Zoned, ~TimeRequired]
+
+ Static Semantics: IsValidMonthDay ( ): a Boolean
+
+
+ DateSpec[Extended] :::
+ DateYear DateSeparator[?Extended] DateMonth DateSeparator[?Extended] DateDay
+
+ DateSpecMonthDay :::
+ `--`? DateMonth DateSeparator[+Extended] DateDay
+ `--`? DateMonth DateSeparator[~Extended] DateDay
+
+
+ 1. If |DateDay| is *"31"* and |DateMonth| is *"02"*, *"04"*, *"06"*, *"09"*, *"11"*, return *false*.
+ 1. If |DateMonth| is *"02"* and |DateDay| is *"30"*, return *false*.
+ 1. Return *true*.
+
+
+
+
+ Static Semantics: IsValidDate ( ): a Boolean
+
+
+ DateSpec[Extended] :::
+ DateYear DateSeparator[?Extended] DateMonth DateSeparator[?Extended] DateDay
+
+
+ 1. If IsValidMonthDay of |DateSpec| is *false*, return *false*.
+ 1. Let _year_ be ℝ(StringToNumber(CodePointsToString(|DateYear|))).
+ 1. If |DateMonth| is *"02"* and |DateDay| is *"29"* and MathematicalInLeapYear(EpochTimeForYear(_year_)) = 0, return *false*.
+ 1. Return *true*.
+
+
+
Static Semantics: Early Errors
+
+ AnnotatedTime :::
+ Time DateTimeUTCOffset[~Z]? TimeZoneAnnotation? Annotations?
+
+
+ -
+ It is a Syntax Error if IsValidMonthDay of ParseText(|Time| |DateTimeUTCOffset[~Z]|, |DateSpecMonthDay|) is *true*.
+
+ -
+ It is a Syntax Error if ParseText(|Time| |DateTimeUTCOffset[~Z]|, |DateSpecYearMonth|) is a Parse Node.
+
+
+
+ DateSpec[Extended] :::
+ DateYear DateSeparator[?Extended] DateMonth DateSeparator[?Extended] DateDay
+
+
+ -
+ It is a Syntax Error if IsValidDate of |DateSpec| is *false*.
+
+
+
+ DateSpecMonthDay :::
+ `--`? DateMonth DateSeparator[+Extended] DateDay
+ `--`? DateMonth DateSeparator[~Extended] DateDay
+
+
+ -
+ It is a Syntax Error if IsValidMonthDay of |DateSpecMonthDay| is *false*.
+
+
DateYear :::
TemporalSign DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
@@ -1565,16 +1617,16 @@
1. Let _millisecondMV_ be 0.
1. Let _microsecondMV_ be 0.
1. Let _nanosecondMV_ be 0.
- 1. If IsValidISODate(_yearMV_, _monthMV_, _dayMV_) is *false*, throw a *RangeError* exception.
- 1. If IsValidTime(_hourMV_, _minuteMV_, _secondMV_, _millisecondMV_, _microsecondMV_, _nanosecondMV_) is *false*, throw a *RangeError* exception.
+ 1. Assert: IsValidISODate(_yearMV_, _monthMV_, _dayMV_) is *true*.
+ 1. Assert: IsValidTime(_hourMV_, _minuteMV_, _secondMV_, _millisecondMV_, _microsecondMV_, _nanosecondMV_) is *true*.
1. Let _timeZoneResult_ be the Record { [[Z]]: *false*, [[OffsetString]]: *undefined*, [[TimeZoneAnnotation]]: *undefined* }.
1. If _parseResult_ contains a |TimeZoneIdentifier| Parse Node, then
1. Let _identifier_ be the source text matched by the |TimeZoneIdentifier| Parse Node contained within _parseResult_.
1. Set _timeZoneResult_.[[TimeZoneAnnotation]] to CodePointsToString(_identifier_).
1. If _parseResult_ contains a |UTCDesignator| Parse Node, then
1. Set _timeZoneResult_.[[Z]] to *true*.
- 1. Else if _parseResult_ contains a |UTCOffsetSubMinutePrecision| Parse Node, then
- 1. Let _offset_ be the source text matched by the |UTCOffsetSubMinutePrecision| Parse Node contained within _parseResult_.
+ 1. Else if _parseResult_ contains a |UTCOffset[+SubMinutePrecision]| Parse Node, then
+ 1. Let _offset_ be the source text matched by the |UTCOffset[+SubMinutePrecision]| Parse Node contained within _parseResult_.
1. Set _timeZoneResult_.[[OffsetString]] to CodePointsToString(_offset_).
1. Return the Record {
[[Year]]: _yearMV_,
@@ -1693,9 +1745,8 @@
It parses the argument as an ISO 8601 string and returns a Record representing each date and time component needed to construct a Temporal.PlainDateTime instance as a distinct field.
- 1. Let _parseResult_ be ParseText(StringToCodePoints(_isoString_), |TemporalDateTimeString|).
+ 1. Let _parseResult_ be ParseText(StringToCodePoints(_isoString_), |TemporalDateTimeString[~Zoned]|).
1. If _parseResult_ is a List of errors, throw a *RangeError* exception.
- 1. If _parseResult_ contains a |UTCDesignator| Parse Node, throw a *RangeError* exception.
1. Return ? ParseISODateTime(_isoString_).
@@ -1777,7 +1828,6 @@
1. Let _parseResult_ be ParseText(StringToCodePoints(_isoString_), |TemporalMonthDayString|).
1. If _parseResult_ is a List of errors, throw a *RangeError* exception.
- 1. If _parseResult_ contains a |UTCDesignator| Parse Node, throw a *RangeError* exception.
1. Let _result_ be ? ParseISODateTime(_isoString_).
1. Let _year_ be _result_.[[Year]].
1. If _parseResult_ does not contain a |DateYear| Parse Node, then
@@ -1804,7 +1854,6 @@
1. Let _parseResult_ be ParseText(StringToCodePoints(_isoString_), |TemporalDateTimeString|).
1. If _parseResult_ is a List of errors, throw a *RangeError* exception.
- 1. If _parseResult_ contains a |UTCDesignator| ParseNode but no |TimeZoneAnnotation| Parse Node, throw a *RangeError* exception.
1. Return ? ParseISODateTime(_isoString_).
@@ -1822,7 +1871,6 @@
1. Let _parseResult_ be ParseText(StringToCodePoints(_isoString_), |TemporalTimeString|).
1. If _parseResult_ is a List of errors, throw a *RangeError* exception.
- 1. If _parseResult_ contains a |UTCDesignator| Parse Node, throw a *RangeError* exception.
1. Let _result_ be ? ParseISODateTime(_isoString_).
1. Return the Record {
[[Hour]]: _result_.[[Hour]],
@@ -1889,7 +1937,6 @@
1. Let _parseResult_ be ParseText(StringToCodePoints(_isoString_), |TemporalYearMonthString|).
1. If _parseResult_ is a List of errors, throw a *RangeError* exception.
- 1. If _parseResult_ contains a |UTCDesignator| Parse Node, throw a *RangeError* exception.
1. Let _result_ be ? ParseISODateTime(_isoString_).
1. Return the Record {
[[Year]]: _result_.[[Year]],
diff --git a/spec/intl.html b/spec/intl.html
index ba25a18dd..1650b79e0 100644
--- a/spec/intl.html
+++ b/spec/intl.html
@@ -650,7 +650,7 @@
1. If _toLocaleStringTimeZone_ is present, throw a *TypeError* exception.
1. Set _timeZone_ to ? ToString(_timeZone_).
1. If IsTimeZoneOffsetString(_timeZone_) is *true*, then
- 1. Let _parseResult_ be ParseText(StringToCodePoints(_timeZone_), |UTCOffset||UTCOffsetMinutePrecision|).
+ 1. Let _parseResult_ be ParseText(StringToCodePoints(_timeZone_), |UTCOffset||UTCOffset[~SubMinutePrecision]|).
1. Assert: _parseResult_ is a Parse Node.
1. If _parseResult_ contains more than one |MinuteSecond| Parse Node, throw a *RangeError* exception.
1. Let _offsetNanoseconds_ be ParseTimeZoneOffsetString? ParseDateTimeUTCOffset(_timeZone_).
diff --git a/spec/mainadditions.html b/spec/mainadditions.html
index 977ce9b0a..5f9f1d28d 100644
--- a/spec/mainadditions.html
+++ b/spec/mainadditions.html
@@ -252,8 +252,8 @@ Time Zone Offset String FormatFormats
ECMAScript defines string interchange formats for UTC offsets, derived from ISO 8601.
- UTC offsets that represent offset time zone identifiers, or that are intended for interoperability with ISO 8601, use only hours and minutes and are specified by |UTCOffsetMinutePrecision|.
- UTC offsets that represent the offset of a named or custom time zone can be more precise, and are specified by |UTCOffsetSubMinutePrecision|.
+ UTC offsets that represent offset time zone identifiers, or that are intended for interoperability with ISO 8601, use only hours and minutes and are specified by |UTCOffset[~SubMinutePrecision]|.
+ UTC offsets that represent the offset of a named or custom time zone can be more precise, and are specified by |UTCOffset[+SubMinutePrecision]|.
These formats are described by the ISO String grammar in .
@@ -461,7 +461,7 @@
- 1. Let _parseResult_ be ParseText(StringToCodePoints(_offsetString_), |UTCOffset||UTCOffsetSubMinutePrecision|).
+ 1. Let _parseResult_ be ParseText(StringToCodePoints(_offsetString_), |UTCOffset||UTCOffset[+SubMinutePrecision]|).
1. Assert: _parseResult_ is not a List of errors.
1. If _parseResult_ is a List of errors, throw a *RangeError* exception.
1. Assert: _parseResult_ contains a |TemporalSign| Parse Node.