Let input be the string being parsed.
Let position be a pointer into input, initially pointing at the start of the string.
Collect a sequence of characters in the range
U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9). If the collected
sequence is not exactly four characters long, then fail. Otherwise,
interpret the resulting sequence as a base-ten integer. Let that number
be the year.
If position is beyond the end of input or if the character at position
is not a U+002D HYPHEN-MINUS character, then fail. Otherwise, move position forwards one character.
Collect a sequence of characters in the range
U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9). If the collected
sequence is not exactly two characters long, then fail. Otherwise,
interpret the resulting sequence as a base-ten integer. Let that number
be the month.
If month is not a number in the range
1 ≤ month ≤ 12, then fail.
If position is beyond the end of input or if the character at position
is not a U+002D HYPHEN-MINUS character, then fail. Otherwise, move position forwards one character.
Collect a sequence of characters in the range
U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9). If the collected
sequence is not exactly two characters long, then fail. Otherwise,
interpret the resulting sequence as a base-ten integer. Let that number
be the day.
If day is not a number in the range
1 ≤ month ≤ maxday, then fail.
Collect a sequence of characters that are
either U+0054 LATIN CAPITAL LETTER T characters or space characters. If the collected sequence
is zero characters long, or if it contains more than one U+0054 LATIN
CAPITAL LETTER T character, then fail.
Collect a sequence of characters in the range
U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9). If the collected
sequence is not exactly two characters long, then fail. Otherwise,
interpret the resulting sequence as a base-ten integer. Let that number
be the hour.
If hour is not a number in the range
0 ≤ hour ≤ 23, then fail.
If position is beyond the end of input or if the character at position
is not a U+003A COLON character, then fail. Otherwise, move position forwards one character.
Collect a sequence of characters in the range
U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9). If the collected
sequence is not exactly two characters long, then fail. Otherwise,
interpret the resulting sequence as a base-ten integer. Let that number
be the minute.
If minute is not a number in the range
0 ≤ minute ≤ 59, then fail.
Let second be a string with the value "0".
If position is beyond the end of input, then fail.
If the character at position is a U+003A COLON,
then:
Advance position to the next character in input.
If position is beyond the end of input, or at the last character in input, or if the next two characters in input starting at position are not
two characters both in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT
NINE (9), then fail.
Collect a sequence of characters that are
either characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT
NINE (9) or U+002E FULL STOP characters. If the collected sequence has
more than one U+002E FULL STOP characters, or if the last character in
the sequence is a U+002E FULL STOP character, then fail. Otherwise,
let the collected string be second instead of its
previous value.
Interpret second as a base-ten number (possibly
with a fractional part). Let that number be second
instead of the string version.
If second is not a number in the range
0 ≤ hour
(The values 60 and 61 are not allowed: leap seconds cannot be represented
by datetime values.)
If position is beyond the end of input, then fail.
If the character at position is a U+005A LATIN
CAPITAL LETTER Z, then:
Let timezonehours be 0.
Let timezoneminutes be 0.
Advance position to the next character in input.
Otherwise, if the character at position is either
a U+002B PLUS SIGN ("+") or a U+002D HYPHEN-MINUS ("-"), then:
If the character at position is a U+002B PLUS
SIGN ("+"), let sign be "positive". Otherwise,
it's a U+002D HYPHEN-MINUS ("-"); let sign be
"negative".
Advance position to the next character in input.
Collect a sequence of characters in the range
U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9). If the collected
sequence is not exactly two characters long, then fail. Otherwise,
interpret the resulting sequence as a base-ten integer. Let that
number be the timezonehours.
If timezonehours is not a
number in the range 0 ≤ timezonehours ≤ 23, then fail.
If sign is "negative", then negate timezonehours.
If position is beyond the end of input or if the character at position is not a U+003A COLON character, then fail.
Otherwise, move position forwards one character.
Collect a sequence of characters in the range
U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9). If the collected
sequence is not exactly two characters long, then fail. Otherwise,
interpret the resulting sequence as a base-ten integer. Let that
number be the timezoneminutes.
If timezoneminutes is not a
number in the range 0 ≤ timezoneminutes ≤ 59, then fail.
If sign is "negative", then negate timezoneminutes.
If position is not beyond the end of input, then fail.
Let time be the moment in time at year year, month month, day day, hours hour, minute minute, second second, subtracting
timezonehours hours and timezoneminutes minutes. That moment
in time is a moment in the UTC timezone.
Let timezone be timezonehours hours and timezoneminutes minutes from UTC.
Return time and timezone.