Skip to content

Commit 160e836

Browse files
committed
Normative: Allow annotations after YYYY-MM and MM-DD
In keeping with the IXDTF format which extends the grammar of RFC 3339 with any number of annotations, we should allow annotations after the short YYYY-MM PlainYearMonth and MM-DD PlainMonthDay forms. If we were to allow UTC offsets ±UU[:UU] alongside the time zone annotation, that would be ambiguous in one case: YYYY-MM-UU would be ambiguous with YYYY-MM-DD. This forced us to take another look at ISO 8601 and realize that YYYY-MM-DD-UU and YYYY-MM-DDZ are actually not defined by ISO 8601. Although they are not forbidden either, but we don't have any reason to introduce this notation given the set of Temporal types. Therefore, UTC offsets are disallowed after any date-only notation (that is, YYYY-MM-DD, YYYY-MM, and MM-DD.) Closes: #2379
1 parent 9cd448a commit 160e836

File tree

1 file changed

+29
-28
lines changed

1 file changed

+29
-28
lines changed

spec/abstractops.html

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,6 @@ <h1>ISO 8601 grammar</h1>
809809
Time zone and <a href="https://tools.ietf.org/html/bcp47#section-2.1">BCP 47 calendar</a> suffixes are the only recognized ones.
810810
Others are ignored, unless they are marked with a *!*, in which case they are rejected.
811811
</li>
812-
<li>A time zone suffix may be instead of or in addition to a UTC offset.</li>
813812
<li>A space may be used to separate the date and time in a combined date / time representation, but not in a duration.</li>
814813
<li>Alphabetic designators may be in lower or upper case.</li>
815814
<li>Period or comma may be used as the decimal separator.</li>
@@ -1032,19 +1031,9 @@ <h1>ISO 8601 grammar</h1>
10321031
TimeZoneIANAName
10331032
TimeZoneUTCOffsetName
10341033

1035-
TimeZoneBracketedAnnotation :
1034+
TimeZoneAnnotation :
10361035
`[` AnnotationCriticalFlag? TimeZoneIdentifier `]`
10371036

1038-
TimeZoneOffsetRequired :
1039-
TimeZoneUTCOffset TimeZoneBracketedAnnotation?
1040-
1041-
TimeZoneNameRequired :
1042-
TimeZoneUTCOffset? TimeZoneBracketedAnnotation
1043-
1044-
TimeZone :
1045-
TimeZoneUTCOffset TimeZoneBracketedAnnotation?
1046-
TimeZoneBracketedAnnotation
1047-
10481037
AKeyLeadingChar :
10491038
LowercaseAlpha
10501039
`_`
@@ -1087,24 +1076,28 @@ <h1>ISO 8601 grammar</h1>
10871076
TimeHour `:` TimeMinute `:` TimeSecond TimeFraction?
10881077
TimeHour TimeMinute TimeSecond TimeFraction?
10891078

1090-
TimeSpecWithOptionalTimeZoneNotAmbiguous :
1091-
TimeSpec TimeZone? but not one of ValidMonthDay or DateSpecYearMonth
1092-
1093-
TimeSpecSeparator :
1094-
DateTimeSeparator TimeSpec
1079+
TimeSpecWithOptionalOffsetNotAmbiguous :
1080+
TimeSpec TimeZoneUTCOffset? but not one of ValidMonthDay or DateSpecYearMonth
10951081

10961082
DateTime :
1097-
Date TimeSpecSeparator? TimeZone?
1083+
Date
1084+
Date DateTimeSeparator TimeSpec TimeZoneUTCOffset?
10981085

10991086
AnnotatedTime :
1100-
TimeDesignator TimeSpec TimeZone? Annotations?
1101-
TimeSpecWithOptionalTimeZoneNotAmbiguous Annotations?
1087+
TimeDesignator TimeSpec TimeZoneUTCOffset? TimeZoneAnnotation? Annotations?
1088+
TimeSpecWithOptionalOffsetNotAmbiguous TimeZoneAnnotation? Annotations?
11021089

11031090
AnnotatedDateTime:
1104-
DateTime Annotations?
1091+
DateTime TimeZoneAnnotation? Annotations?
11051092

11061093
AnnotatedDateTimeTimeRequired :
1107-
Date TimeSpecSeparator TimeZone? Annotations?
1094+
Date DateTimeSeparator TimeSpec TimeZoneUTCOffset? TimeZoneAnnotation? Annotations?
1095+
1096+
AnnotatedYearMonth:
1097+
DateSpecYearMonth TimeZoneAnnotation? Annotations?
1098+
1099+
AnnotatedMonthDay:
1100+
DateSpecMonthDay TimeZoneAnnotation? Annotations?
11081101

11091102
DurationWholeSeconds :
11101103
DecimalDigits[~Sep]
@@ -1177,7 +1170,7 @@ <h1>ISO 8601 grammar</h1>
11771170
Sign? DurationDesignator DurationTime
11781171

11791172
TemporalInstantString :
1180-
Date TimeSpecSeparator? TimeZoneOffsetRequired Annotations?
1173+
Date DateTimeSeparator TimeSpec TimeZoneUTCOffset TimeZoneAnnotation? Annotations?
11811174

11821175
TemporalDateTimeString :
11831176
AnnotatedDateTime
@@ -1186,19 +1179,19 @@ <h1>ISO 8601 grammar</h1>
11861179
Duration
11871180

11881181
TemporalMonthDayString :
1189-
DateSpecMonthDay
1182+
AnnotatedMonthDay
11901183
AnnotatedDateTime
11911184

11921185
TemporalTimeString :
11931186
AnnotatedTime
11941187
AnnotatedDateTimeTimeRequired
11951188

11961189
TemporalYearMonthString :
1197-
DateSpecYearMonth
1190+
AnnotatedYearMonth
11981191
AnnotatedDateTime
11991192

12001193
TemporalZonedDateTimeString :
1201-
Date TimeSpecSeparator? TimeZoneNameRequired Annotations?
1194+
DateTime TimeZoneAnnotation Annotations?
12021195
</emu-grammar>
12031196

12041197
<emu-clause id="sec-temporal-iso8601grammar-early-errors">
@@ -1228,8 +1221,16 @@ <h1>
12281221
<emu-note>The value of ! ToIntegerOrInfinity(*undefined*) is 0.</emu-note>
12291222
<emu-alg>
12301223
1. Let _parseResult_ be ~empty~.
1231-
1. For each nonterminal _goal_ of &laquo; |TemporalDateTimeString|, |TemporalInstantString|, |TemporalMonthDayString|, |TemporalTimeString|, |TemporalYearMonthString|, |TemporalZonedDateTimeString| &raquo;, do
1224+
1. For each nonterminal _goal_ of &laquo; |TemporalDateTimeString|, |TemporalInstantString|, |TemporalTimeString|, |TemporalZonedDateTimeString| &raquo;, do
12321225
1. If _parseResult_ is not a Parse Node, set _parseResult_ to ParseText(StringToCodePoints(_isoString_), _goal_).
1226+
1. For each nonterminal _goal_ of &laquo; |TemporalMonthDayString|, |TemporalYearMonthString| &raquo;, do
1227+
1. If _parseResult_ is not a Parse Node, then
1228+
1. Set _parseResult_ to ParseText(StringToCodePoints(_isoString_), _goal_).
1229+
1. If _parseResult_ is a Parse Node, then
1230+
1. For each |Annotation| Parse Node _annotation_ contained within _parseResult_, do
1231+
1. Let _key_ be the source text matched by the |AnnotationKey| Parse Node contained within _annotation_.
1232+
1. Let _value_ be the source text matched by the |AnnotationValue| Parse Node contained within _annotation_.
1233+
1. If CodePointsToString(_key_) is *"u-ca"* and the ASCII-lowercase of CodePointsToString(_value_) is not *"iso8601"*, throw a *RangeError* exception.
12331234
1. If _parseResult_ is not a Parse Node, throw a *RangeError* exception.
12341235
1. Let each of _year_, _month_, _day_, _hour_, _minute_, _second_, and _fSeconds_ be the source text matched by the respective |DateYear|, |DateMonth|, |DateDay|, |TimeHour|, |TimeMinute|, |TimeSecond|, and |TimeFraction| Parse Node contained within _parseResult_, or an empty sequence of code points if not present.
12351236
1. If the first code point of _year_ is U+2212 (MINUS SIGN), replace the first code point with U+002D (HYPHEN-MINUS).
@@ -1500,7 +1501,7 @@ <h1>
15001501
<emu-alg>
15011502
1. Let _parseResult_ be ParseText(StringToCodePoints(_isoString_), |TemporalDateTimeString|).
15021503
1. If _parseResult_ is a List of errors, throw a *RangeError* exception.
1503-
1. If _parseResult_ contains a |UTCDesignator| ParseNode but no |TimeZoneBracketedAnnotation| Parse Node, throw a *RangeError* exception.
1504+
1. If _parseResult_ contains a |UTCDesignator| ParseNode but no |TimeZoneAnnotation| Parse Node, throw a *RangeError* exception.
15041505
1. Return ? ParseISODateTime(_isoString_).
15051506
</emu-alg>
15061507
</emu-clause>

0 commit comments

Comments
 (0)