ISO/IEC 10646, Information Technology — Universal Multiple-Octet Coded Character Set (UCS) plus Amendment 1:2005, Amendment 2:2006, Amendment 3:2008, Amendment 4:2008, and additional amendments and corrigenda, or successor.
ECMA-402, ECMAScript Internationalization API Specification, specifically the annual edition corresponding to this edition of this specification.
@@ -661,9 +665,13 @@
The Lexical and RegExp Grammars
-
The Numeric String Grammar
+
The Numeric String and ISO 8601 / RFC 9557 Grammars
A numeric string grammar appears in . It has as its terminal symbols |SourceCharacter|, and is used for translating Strings into numeric values starting from the goal symbol |StringNumericLiteral| (which is similar to but distinct from the lexical grammar for numeric literals).
-
Productions of the numeric string grammar are distinguished by having three colons “:::” as punctuation, and are never used for parsing source text.
+
+ A grammar for parsing strings representing dates, times, and durations, according to the formats specified in ISO 8601 and RFC 9557, is given in .
+ This grammar has as its terminal symbols Unicode code points that conform to the rules for |SourceCharacter|. It is used for parsing Strings in the context of various date, time, or duration-related functions, starting from one of the goal symbols |TemporalDateTimeString|, |TemporalDurationString|, |TemporalInstantString|, |TemporalMonthDayString|, |TemporalTimeString|, |TemporalYearMonthString|, |NormalizedUTCOffset|, or |TimeZoneIANAName|.
+
+
Productions of the numeric string and ISO 8601 / RFC 9557 grammars are distinguished by having three colons “:::” as punctuation, and are never used for parsing source text.
@@ -1181,13 +1189,14 @@
Mathematical Operations
The mathematical function ln(_x_) produces the natural logarithm of _x_. The mathematical function log10(_x_) produces the base 10 logarithm of _x_. The mathematical function log2(_x_) produces the base 2 logarithm of _x_.
The mathematical function min(_x1_, _x2_, … , _xN_) produces the mathematically smallest of _x1_ through _xN_. The mathematical function max(_x1_, _x2_, ..., _xN_) produces the mathematically largest of _x1_ through _xN_. The domain and range of these mathematical functions are the extended mathematical values.
The notation “_x_ modulo _y_” (_y_ must be finite and non-zero) computes a value _k_ of the same sign as _y_ (or zero) such that abs(_k_) < abs(_y_) and _x_ - _k_ = _q_ × _y_ for some integer _q_.
+
The mathematical function remainder(_x_, _y_) produces the mathematical value whose sign is the sign of _x_ and whose magnitude is abs(_x_) modulo _y_.
The phrase "the result of clamping _x_ between _lower_ and _upper_" (where _x_ is an extended mathematical value and _lower_ and _upper_ are mathematical values such that _lower_ ≤ _upper_) produces _lower_ if _x_ < _lower_, produces _upper_ if _x_ > _upper_, and otherwise produces _x_.
The mathematical function floor(_x_) produces the largest integer (closest to +∞) that is not larger than _x_.
floor(_x_) = _x_ - (_x_ modulo 1).
The mathematical function truncate(_x_) removes the fractional part of _x_ by rounding towards zero, producing -floor(-_x_) if _x_ < 0 and otherwise producing floor(_x_).
-
Mathematical functions min, max, abs, floor, and truncate are not defined for Numbers and BigInts, and any usage of those methods that have non-mathematical value arguments would be an editorial error in this specification.
+
Mathematical functions min, max, abs, remainder, floor, and truncate are not defined for Numbers and BigInts, and any usage of those methods that have non-mathematical value arguments would be an editorial error in this specification.
An interval from lower bound _a_ to upper bound _b_ is a possibly-infinite, possibly-empty set of numeric values of the same numeric type. Each bound will be described as either inclusive or exclusive, but not both. There are four kinds of intervals, as follows:
An interval from _a_ (inclusive) to _b_ (inclusive), also called an inclusive interval from _a_ to _b_, includes all values _x_ of the same numeric type such that _a_ ≤ _x_ ≤ _b_, and no others.
@@ -1263,6 +1272,9 @@
The String Type
*"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"*.
For historical reasons, it has significance to various algorithms.
+
The ASCII-uppercase of a String _S_ is the String derived from _S_ by replacing each occurrence of an ASCII lowercase letter code unit (0x0061 through 0x007A, inclusive) with the corresponding ASCII uppercase letter code unit (0x0041 through 0x005A, inclusive) while preserving all other code units.
+
The ASCII-lowercase of a String _S_ is the String derived from _S_ by replacing each occurrence of an ASCII uppercase letter code unit (0x0041 through 0x005A, inclusive) with the corresponding ASCII lowercase letter code unit (0x0061 through 0x007A, inclusive) while preserving all other code units.
+
A String _A_ is an ASCII-case-insensitive match for a String _B_ if the ASCII-lowercase of _A_ is the ASCII-lowercase of _B_.
@@ -4021,6 +4033,17 @@
Well-Known Intrinsic Objects
The SyntaxError constructor ()
+
+
+ %Temporal%
+
+
+ `Temporal`
+
+
+ The Temporal object ()
+
+
%ThrowTypeError%
@@ -5276,6 +5299,57 @@
+
+
+ ToIntegerIfIntegral (
+ _argument_: an ECMAScript language value,
+ ): either a normal completion containing an integer or a throw completion
+
+
+
description
+
It converts _argument_ to an integer representing its Number value, or throws a *RangeError* when that value is not integral.
+
+
+ 1. Let _number_ be ? ToNumber(_argument_).
+ 1. If _number_ is not an integral Number, throw a *RangeError* exception.
+ 1. Return ℝ(_number_).
+
+
+
+
+
+ ToIntegerWithTruncation (
+ _argument_: an ECMAScript language value,
+ ): either a normal completion containing an integer or a throw completion
+
+
+
description
+
It converts _argument_ to an integer representing its Number value with fractional part truncated, or throws a *RangeError* when that value is not finite.
+
+
+ 1. Let _number_ be ? ToNumber(_argument_).
+ 1. If _number_ is one of *NaN*, *+∞*𝔽, or *-∞*𝔽, throw a *RangeError* exception.
+ 1. Return truncate(ℝ(_number_)).
+
+
+
+
+
+ ToPositiveIntegerWithTruncation (
+ _argument_: an ECMAScript language value,
+ ): either a normal completion containing a positive integer or a throw completion
+
+
+
description
+
It converts _argument_ to an integer representing its Number value with fractional part truncated, or throws a *RangeError* when that value is not finite or not positive.
+
+
+ 1. Let _integer_ be ? ToIntegerWithTruncation(_argument_).
+ 1. If _integer_ ≤ 0, throw a *RangeError* exception.
+ 1. Return _integer_.
+
+
+
GetUTCEpochNanoseconds (
- _year_: an integer,
- _month_: an integer in the inclusive interval from 1 to 12,
- _day_: an integer in the inclusive interval from 1 to 31,
- _hour_: an integer in the inclusive interval from 0 to 23,
- _minute_: an integer in the inclusive interval from 0 to 59,
- _second_: an integer in the inclusive interval from 0 to 59,
- _millisecond_: an integer in the inclusive interval from 0 to 999,
- _microsecond_: an integer in the inclusive interval from 0 to 999,
- _nanosecond_: an integer in the inclusive interval from 0 to 999,
- ): a BigInt
+ _isoDateTime_: an ISO Date-Time Record,
+ ): an epoch nanoseconds value
description
The returned value represents a number of nanoseconds since the epoch that corresponds to the given ISO 8601 calendar date and wall-clock time in UTC.
- 1. Let _date_ be MakeDay(𝔽(_year_), 𝔽(_month_ - 1), 𝔽(_day_)).
- 1. Let _time_ be MakeTime(𝔽(_hour_), 𝔽(_minute_), 𝔽(_second_), 𝔽(_millisecond_)).
+ 1. Let _date_ be MakeDay(𝔽(_isoDateTime_.[[ISODate]].[[Year]]), 𝔽(_isoDateTime_.[[ISODate]].[[Month]] - 1), 𝔽(_isoDateTime_.[[ISODate]].[[Day]])).
+ 1. Let _time_ be MakeTime(𝔽(_isoDateTime_.[[Time]].[[Hour]]), 𝔽(_isoDateTime_.[[Time]].[[Minute]]), 𝔽(_isoDateTime_.[[Time]].[[Second]]), 𝔽(_isoDateTime_.[[Time]].[[Millisecond]])).
1. Let _ms_ be MakeDate(_date_, _time_).
1. Assert: _ms_ is an integral Number.
- 1. Return ℤ(ℝ(_ms_) × 106 + _microsecond_ × 103 + _nanosecond_).
-
-
-
-
-
Time Zone Identifiers
-
-
- Time zones in ECMAScript are represented by time zone identifiers, which are Strings composed entirely of code units in the inclusive interval from 0x0000 to 0x007F.
- Time zones supported by an ECMAScript implementation may be available named time zones, represented by the [[Identifier]] field of the Time Zone Identifier Records returned by AvailableNamedTimeZoneIdentifiers, or offset time zones, represented by Strings for which IsTimeZoneOffsetString returns *true*.
-
-
- A primary time zone identifier is the preferred identifier for an available named time zone.
- A non-primary time zone identifier is an identifier for an available named time zone that is not a primary time zone identifier.
- An available named time zone identifier is either a primary time zone identifier or a non-primary time zone identifier.
- Each available named time zone identifier is associated with exactly one available named time zone.
- Each available named time zone is associated with exactly one primary time zone identifier and zero or more non-primary time zone identifiers.
-
-
- ECMAScript implementations must support an available named time zone with the identifier *"UTC"*, which must be the primary time zone identifier for the UTC time zone.
- In addition, implementations may support any number of other available named time zones.
-
-
- Implementations that follow the requirements for time zones as described in the ECMA-402 Internationalization API specification are called time zone aware.
- Time zone aware implementations must support available named time zones corresponding to the Zone and Link names of the IANA Time Zone Database, and only such names.
- In time zone aware implementations, a primary time zone identifier is a Zone name, and a non-primary time zone identifier is a Link name, respectively, in the IANA Time Zone Database except as specifically overridden by AvailableNamedTimeZoneIdentifiers as specified in the ECMA-402 specification.
- Implementations that do not support the entire IANA Time Zone Database are still recommended to use IANA Time Zone Database names as identifiers to represent time zones.
-
-
-
-
-
- GetNamedTimeZoneEpochNanoseconds (
- _timeZoneIdentifier_: a String,
- _year_: an integer,
- _month_: an integer in the inclusive interval from 1 to 12,
- _day_: an integer in the inclusive interval from 1 to 31,
- _hour_: an integer in the inclusive interval from 0 to 23,
- _minute_: an integer in the inclusive interval from 0 to 59,
- _second_: an integer in the inclusive interval from 0 to 59,
- _millisecond_: an integer in the inclusive interval from 0 to 999,
- _microsecond_: an integer in the inclusive interval from 0 to 999,
- _nanosecond_: an integer in the inclusive interval from 0 to 999,
- ): a List of BigInts
-
-
-
description
-
- Each value in the returned List represents a number of nanoseconds since the epoch that corresponds to the given ISO 8601 calendar date and wall-clock time in the named time zone identified by _timeZoneIdentifier_.
-
-
-
- When the input represents a local time occurring more than once because of a negative time zone transition (e.g. when daylight saving time ends or the time zone offset is decreased due to a time zone rule change), the returned List will have more than one element and will be sorted by ascending numerical value.
- When the input represents a local time skipped because of a positive time zone transition (e.g. when daylight saving time begins or the time zone offset is increased due to a time zone rule change), the returned List will be empty.
- Otherwise, the returned List will have one element.
-
-
The default implementation of GetNamedTimeZoneEpochNanoseconds, to be used for ECMAScript implementations that do not include local political rules for any time zones, performs the following steps when called:
-
- 1. Assert: _timeZoneIdentifier_ is *"UTC"*.
- 1. Let _epochNanoseconds_ be GetUTCEpochNanoseconds(_year_, _month_, _day_, _hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_).
- 1. Return « _epochNanoseconds_ ».
-
-
-
It is required for time zone aware implementations (and recommended for all others) to use the time zone information of the IANA Time Zone Database https://www.iana.org/time-zones/.
-
1:30 AM on 5 November 2017 in America/New_York is repeated twice, so GetNamedTimeZoneEpochNanoseconds(*"America/New_York"*, 2017, 11, 5, 1, 30, 0, 0, 0, 0) would return a List of length 2 in which the first element represents 05:30 UTC (corresponding with 01:30 US Eastern Daylight Time at UTC offset -04:00) and the second element represents 06:30 UTC (corresponding with 01:30 US Eastern Standard Time at UTC offset -05:00).
-
2:30 AM on 12 March 2017 in America/New_York does not exist, so GetNamedTimeZoneEpochNanoseconds(*"America/New_York"*, 2017, 3, 12, 2, 30, 0, 0, 0, 0) would return an empty List.
-
-
-
-
-
- GetNamedTimeZoneOffsetNanoseconds (
- _timeZoneIdentifier_: a String,
- _epochNanoseconds_: a BigInt,
- ): an integer
-
-
-
-
The returned integer represents the offset from UTC of the named time zone identified by _timeZoneIdentifier_, at the instant corresponding with _epochNanoseconds_ relative to the epoch, both in nanoseconds.
-
The default implementation of GetNamedTimeZoneOffsetNanoseconds, to be used for ECMAScript implementations that do not include local political rules for any time zones, performs the following steps when called:
Time zone offset values may be positive or negative.
-
-
-
-
-
Time Zone Identifier Record
-
A Time Zone Identifier Record is a Record used to describe an available named time zone identifier and its corresponding primary time zone identifier.
-
Time Zone Identifier Records have the fields listed in .
-
-
-
-
-
Field Name
-
Value
-
Meaning
-
-
-
-
[[Identifier]]
-
a String
-
An available named time zone identifier that is supported by the implementation.
-
-
-
[[PrimaryIdentifier]]
-
a String
-
The primary time zone identifier that [[Identifier]] resolves to.
-
-
-
-
-
If [[Identifier]] is a primary time zone identifier, then [[Identifier]] is [[PrimaryIdentifier]].
-
-
-
-
-
AvailableNamedTimeZoneIdentifiers ( ): a List of Time Zone Identifier Records
-
-
description
-
- Its result describes all available named time zone identifiers in this implementation, as well as the primary time zone identifier corresponding to each available named time zone identifier.
- The List is ordered according to the [[Identifier]] field of each Time Zone Identifier Record.
-
-
-
- Time zone aware implementations, including all implementations that implement the ECMA-402 Internationalization API, must implement the AvailableNamedTimeZoneIdentifiers abstract operation as specified in the ECMA-402 specification.
- For implementations that are not time zone aware, AvailableNamedTimeZoneIdentifiers performs the following steps when called:
-
-
- 1. If the implementation does not include local political rules for any time zones, then
- 1. Return « the Time Zone Identifier Record { [[Identifier]]: *"UTC"*, [[PrimaryIdentifier]]: *"UTC"* } ».
- 1. Let _identifiers_ be the List of unique available named time zone identifiers, sorted according to lexicographic code unit order.
- 1. Let _result_ be a new empty List.
- 1. For each element _identifier_ of _identifiers_, do
- 1. Let _primary_ be _identifier_.
- 1. If _identifier_ is a non-primary time zone identifier in this implementation and _identifier_ is not *"UTC"*, then
- 1. Set _primary_ to the primary time zone identifier associated with _identifier_.
- 1. NOTE: An implementation may need to resolve _identifier_ iteratively to obtain the primary time zone identifier.
- 1. Let _record_ be the Time Zone Identifier Record { [[Identifier]]: _identifier_, [[PrimaryIdentifier]]: _primary_ }.
- 1. Append _record_ to _result_.
- 1. Assert: _result_ contains a Time Zone Identifier Record _r_ such that _r_.[[Identifier]] is *"UTC"* and _r_.[[PrimaryIdentifier]] is *"UTC"*.
- 1. Return _result_.
+ 1. Return ℝ(_ms_) × 106 + _isoDateTime_.[[Time]].[[Microsecond]] × 103 + _isoDateTime_.[[Time]].[[Nanosecond]].
-
-
SystemTimeZoneIdentifier ( ): a String
-
-
description
-
- It returns a String representing the host environment's current time zone, which is either a String representing a UTC offset for which IsTimeZoneOffsetString returns *true*, or a primary time zone identifier.
-
-
-
-
- 1. If the implementation only supports the UTC time zone, return *"UTC"*.
- 1. Let _systemTimeZoneString_ be the String representing the host environment's current time zone, either a primary time zone identifier or an offset time zone identifier.
- 1. Return _systemTimeZoneString_.
-
-
-
-
- To ensure the level of functionality that implementations commonly provide in the methods of the Date object, it is recommended that SystemTimeZoneIdentifier return an IANA time zone name corresponding to the host environment's time zone setting, if such a thing exists.
- GetNamedTimeZoneEpochNanoseconds and GetNamedTimeZoneOffsetNanoseconds must reflect the local political rules for standard time and daylight saving time in that time zone, if such rules exist.
-
-
For example, if the host environment is a browser on a system where the user has chosen US Eastern Time as their time zone, SystemTimeZoneIdentifier returns *"America/New_York"*.
-
-
-
LocalTime (
@@ -33809,8 +33713,9 @@
1. Let _systemTimeZoneIdentifier_ be SystemTimeZoneIdentifier().
- 1. If IsTimeZoneOffsetString(_systemTimeZoneIdentifier_) is *true*, then
- 1. Let _offsetNs_ be ParseTimeZoneOffsetString(_systemTimeZoneIdentifier_).
+ 1. Let _parseResult_ be ! ParseTimeZoneIdentifier(_systemTimeZoneIdentifier_).
+ 1. If _parseResult_.[[OffsetMinutes]] is not ~empty~, then
+ 1. Let _offsetNs_ be _parseResult_.[[OffsetMinutes]] × (60 × 109).
1. Else,
1. Let _offsetNs_ be GetNamedTimeZoneOffsetNanoseconds(_systemTimeZoneIdentifier_, ℤ(ℝ(_t_) × 106)).
1. Let _offsetMs_ be truncate(_offsetNs_ / 106).
@@ -33844,16 +33749,18 @@
1. If _t_ is not finite, return *NaN*.
1. Let _systemTimeZoneIdentifier_ be SystemTimeZoneIdentifier().
- 1. If IsTimeZoneOffsetString(_systemTimeZoneIdentifier_) is *true*, then
- 1. Let _offsetNs_ be ParseTimeZoneOffsetString(_systemTimeZoneIdentifier_).
+ 1. Let _parseResult_ be ! ParseTimeZoneIdentifier(_systemTimeZoneIdentifier_).
+ 1. If _parseResult_.[[OffsetMinutes]] is not ~empty~, then
+ 1. Let _offsetNs_ be _parseResult_.[[OffsetMinutes]] × (60 × 109).
1. Else,
- 1. Let _possibleInstants_ be GetNamedTimeZoneEpochNanoseconds(_systemTimeZoneIdentifier_, ℝ(YearFromTime(_t_)), ℝ(MonthFromTime(_t_)) + 1, ℝ(DateFromTime(_t_)), ℝ(HourFromTime(_t_)), ℝ(MinFromTime(_t_)), ℝ(SecFromTime(_t_)), ℝ(msFromTime(_t_)), 0, 0).
+ 1. Let _isoDateTime_ be TimeValueToISODateTimeRecord(_t_).
+ 1. Let _possibleInstants_ be GetNamedTimeZoneEpochNanoseconds(_systemTimeZoneIdentifier_, _isoDateTime_).
1. NOTE: The following steps ensure that when _t_ represents local time repeating multiple times at a negative time zone transition (e.g. when the daylight saving time ends or the time zone offset is decreased due to a time zone rule change) or skipped local time at a positive time zone transition (e.g. when the daylight saving time starts or the time zone offset is increased due to a time zone rule change), _t_ is interpreted using the time zone offset before the transition.
1. If _possibleInstants_ is not empty, then
1. Let _disambiguatedInstant_ be _possibleInstants_[0].
1. Else,
1. NOTE: _t_ represents a local time skipped at a positive time zone transition (e.g. due to daylight saving time starting or a time zone rule change increasing the UTC offset).
- 1. [declared="tBefore"] Let _possibleInstantsBefore_ be GetNamedTimeZoneEpochNanoseconds(_systemTimeZoneIdentifier_, ℝ(YearFromTime(_tBefore_)), ℝ(MonthFromTime(_tBefore_)) + 1, ℝ(DateFromTime(_tBefore_)), ℝ(HourFromTime(_tBefore_)), ℝ(MinFromTime(_tBefore_)), ℝ(SecFromTime(_tBefore_)), ℝ(msFromTime(_tBefore_)), 0, 0), where _tBefore_ is the largest integral Number < _t_ for which _possibleInstantsBefore_ is not empty (i.e., _tBefore_ represents the last local time before the transition).
+ 1. [declared="tBefore"] Let _possibleInstantsBefore_ be GetNamedTimeZoneEpochNanoseconds(_systemTimeZoneIdentifier_, TimeValueToISODateTimeRecord(_tBefore_)), where _tBefore_ is the largest integral Number < _t_ for which _possibleInstantsBefore_ is not empty (i.e., _tBefore_ represents the last local time before the transition).
1. Let _disambiguatedInstant_ be the last element of _possibleInstantsBefore_.
1. Let _offsetNs_ be GetNamedTimeZoneOffsetNanoseconds(_systemTimeZoneIdentifier_, _disambiguatedInstant_).
1. Let _offsetMs_ be truncate(_offsetNs_ / 106).
@@ -33989,7 +33896,7 @@
Date Time String Format
-
ECMAScript defines a string interchange format for date-times based upon a simplification of the ISO 8601 calendar date extended format. The format is as follows: `YYYY-MM-DDTHH:mm:ss.sssZ`
+
ECMAScript defines a string interchange format for date-times which is adapted from the ISO 8601 calendar date extended format. The format is as follows: `YYYY-MM-DDTHH:mm:ss.sssZ`
Where the elements are as follows:
@@ -34105,10 +34012,10 @@
Date Time String Format
A string containing out-of-bounds or nonconforming elements is not a valid instance of this format.
-
As every day both starts and ends with midnight, the two notations `00:00` and `24:00` are available to distinguish the two midnights that can be associated with one date. This means that the following two notations refer to exactly the same point in time: `1995-02-04T24:00` and `1995-02-05T00:00`. This interpretation of the latter form as "end of a calendar day" is consistent with ISO 8601, even though that specification reserves it for describing time intervals and does not permit it within representations of single points in time.
+
As every day both starts and ends with midnight, the two notations `00:00` and `24:00` are available to distinguish the two midnights that can be associated with one date. This means that the following two notations refer to exactly the same point in time: `1995-02-04T24:00` and `1995-02-05T00:00`.
-
There exists no international standard that specifies abbreviations for civil time zones like CET, EST, etc. and sometimes the same abbreviation is even used for two very different time zones. For this reason, both ISO 8601 and this format specify numeric representations of time zone offsets.
+
This format does not support annotations with a time zone name as defined in RFC 9557, only a numeric representation of the time zone offset. For strings with a time zone annotation, see .
@@ -34156,89 +34063,45 @@
Expanded Years
Time Zone Offset String Format
- ECMAScript defines a string interchange format for UTC offsets, derived from ISO 8601.
- The format is described by the following grammar.
+ 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 |UTCOffset[~SubMinutePrecision]|.
+ UTC offsets that represent the offset of a named time zone can be more precise, and are specified by |UTCOffset[+SubMinutePrecision]|.
- IsTimeZoneOffsetString (
+ IsOffsetTimeZoneIdentifier (
_offsetString_: a String,
): a Boolean
description
-
The return value indicates whether _offsetString_ conforms to the grammar given by |UTCOffset|.
+
The return value indicates whether _offsetString_ conforms to the grammar given by |UTCOffset[~SubMinutePrecision]|.
- 1. Let _parseResult_ be ParseText(_offsetString_, |UTCOffset|).
+ 1. Let _parseResult_ be ParseText(_offsetString_, |UTCOffset[~SubMinutePrecision]|).
1. If _parseResult_ is a List of errors, return *false*.
1. Return *true*.
-
+
- ParseTimeZoneOffsetString (
+ ParseDateTimeUTCOffset (
_offsetString_: a String,
- ): an integer
+ ): either a normal completion containing an integer in the interval from -86400 × 109 (exclusive) to 86400 × 109 (exclusive), or a throw completion
description
-
The return value is the UTC offset, as a number of nanoseconds, that corresponds to the String _offsetString_.
+
+ The return value is the UTC offset, as a number of nanoseconds, that corresponds to the String _offsetString_.
+ If _offsetString_ is invalid, a *RangeError* is thrown.
+
- 1. Let _parseResult_ be ParseText(_offsetString_, |UTCOffset|).
- 1. Assert: _parseResult_ is not a List of errors.
+ 1. Let _parseResult_ be ParseText(StringToCodePoints(_offsetString_), |UTCOffset[+SubMinutePrecision]|).
+ 1. If _parseResult_ is a List of errors, throw a *RangeError* exception.
1. Assert: _parseResult_ contains a |ASCIISign| Parse Node.
1. Let _parsedSign_ be the source text matched by the |ASCIISign| Parse Node contained within _parseResult_.
1. If _parsedSign_ is the single code point U+002D (HYPHEN-MINUS), then
@@ -34270,6 +34133,51 @@
+
+
+
+ HostSystemUTCEpochNanoseconds (
+ _global_: a global object,
+ ): an epoch nanoseconds value
+
+
+
description
+
+ It allows host environments to reduce the precision of the result.
+ In particular, web browsers artificially limit it to prevent abuse of security flaws
+ (e.g., Spectre) and to avoid certain methods of fingerprinting.
+
+
+
An implementation of HostSystemUTCEpochNanoseconds must conform to the following requirements:
+
+
Its result must be between minEpochNanoseconds and maxEpochNanoseconds.
+
+
+
+ This requirement is necessary if the system clock is set to a time outside the range that Temporal.Instant can represent.
+ This is not expected to affect implementations in practice.
+
+
+
The default implementation of HostSystemUTCEpochNanoseconds performs the following steps when called:
+
+ 1. Let _epochNanoseconds_ be the approximate current UTC date and time, in nanoseconds since the epoch.
+ 1. Return the result of clamping _epochNanoseconds_ between minEpochNanoseconds and maxEpochNanoseconds.
+
+
ECMAScript hosts that are not web browsers must use the default implementation of HostSystemUTCEpochNanoseconds.
+
+
+
+
SystemUTCEpochMilliseconds ( ): an integral Number
+
+
description
+
+
+
+ 1. Let _global_ be GetGlobalObject().
+ 1. Let _nowNs_ be HostSystemUTCEpochNanoseconds(_global_).
+ 1. Return 𝔽(floor(_nowNs_ / 106)).
+
+
@@ -34288,12 +34196,10 @@
The Date Constructor
Date ( ..._values_ )
This function performs the following steps when called:
- 1. If NewTarget is *undefined*, then
- 1. Let _now_ be the time value (UTC) identifying the current time.
- 1. Return ToDateString(_now_).
+ 1. If NewTarget is *undefined*, return ToDateString(SystemUTCEpochMilliseconds()).
1. Let _numberOfArgs_ be the number of elements in _values_.
1. If _numberOfArgs_ = 0, then
- 1. Let _dv_ be the time value (UTC) identifying the current time.
+ 1. Let _dv_ be SystemUTCEpochMilliseconds().
1. Else if _numberOfArgs_ = 1, then
1. Let _value_ be _values_[0].
1. If _value_ is an Object and _value_ has a [[DateValue]] internal slot, then
@@ -34336,7 +34242,10 @@
Properties of the Date Constructor
Date.now ( )
-
This function returns the time value designating the UTC date and time of the occurrence of the call to it.
+
This function performs the following steps when called:
- 1. Let _hour_ be ToZeroPaddedDecimalString(ℝ(HourFromTime(_tv_)), 2).
- 1. Let _minute_ be ToZeroPaddedDecimalString(ℝ(MinFromTime(_tv_)), 2).
- 1. Let _second_ be ToZeroPaddedDecimalString(ℝ(SecFromTime(_tv_)), 2).
- 1. Return the string-concatenation of _hour_, *":"*, _minute_, *":"*, _second_, the code unit 0x0020 (SPACE), and *"GMT"*.
+ 1. Let _timeString_ be FormatTimeString(ℝ(HourFromTime(_tv_)), ℝ(MinFromTime(_tv_)), ℝ(SecFromTime(_tv_)), 0, 0).
+ 1. Return the string-concatenation of _timeString_, the code unit 0x0020 (SPACE), and *"GMT"*.
@@ -35236,21 +35143,13 @@
1. Let _systemTimeZoneIdentifier_ be SystemTimeZoneIdentifier().
- 1. If IsTimeZoneOffsetString(_systemTimeZoneIdentifier_) is *true*, then
- 1. Let _offsetNs_ be ParseTimeZoneOffsetString(_systemTimeZoneIdentifier_).
- 1. Else,
+ 1. Let _offsetMinutes_ be ! ParseTimeZoneIdentifier(_systemTimeZoneIdentifier_).[[OffsetMinutes]].
+ 1. If _offsetMinutes_ is ~empty~, then
1. Let _offsetNs_ be GetNamedTimeZoneOffsetNanoseconds(_systemTimeZoneIdentifier_, ℤ(ℝ(_tv_) × 106)).
- 1. Let _offset_ be 𝔽(truncate(_offsetNs_ / 106)).
- 1. If _offset_ is *+0*𝔽 or _offset_ > *+0*𝔽, then
- 1. Let _offsetSign_ be *"+"*.
- 1. Let _absOffset_ be _offset_.
- 1. Else,
- 1. Let _offsetSign_ be *"-"*.
- 1. Let _absOffset_ be -_offset_.
- 1. Let _offsetMin_ be ToZeroPaddedDecimalString(ℝ(MinFromTime(_absOffset_)), 2).
- 1. Let _offsetHour_ be ToZeroPaddedDecimalString(ℝ(HourFromTime(_absOffset_)), 2).
+ 1. Set _offsetMinutes_ to truncate(_offsetNs_ / (60 × 109)).
+ 1. Let _offsetString_ be FormatOffsetTimeZoneIdentifier(_offsetMinutes_, ~unseparated~).
1. Let _tzName_ be an implementation-defined string that is either the empty String or the string-concatenation of the code unit 0x0020 (SPACE), the code unit 0x0028 (LEFT PARENTHESIS), an implementation-defined timezone name, and the code unit 0x0029 (RIGHT PARENTHESIS).
- 1. Return the string-concatenation of _offsetSign_, _offsetHour_, _offsetMin_, and _tzName_.
+ 1. Return the string-concatenation of _offsetString_ and _tzName_.
@@ -35270,6 +35169,18 @@
+
+
Date.prototype.toTemporalInstant ( )
+
This method performs the following steps when called:
+
+ 1. Let _dateObject_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_dateObject_, [[DateValue]]).
+ 1. Let _t_ be _dateObject_.[[DateValue]].
+ 1. Let _epochNanoseconds_ be ? NumberToBigInt(_t_) × ℤ(106).
+ 1. Return ! CreateTemporalInstant(_epochNanoseconds_).
+
+
+
Date.prototype.toTimeString ( )
This method performs the following steps when called:
@@ -35337,6 +35248,22 @@
Properties of Date Instances
Date instances are ordinary objects that inherit properties from the Date prototype object. Date instances also have a [[DateValue]] internal slot. The [[DateValue]] internal slot is the time value represented by this Date.
- ISO 8601:2004(E) Data elements and interchange formats — Information interchange — Representation of dates and times
+ ISO 8601-1:2019(E) Date and time — Representations for information interchange — Part 1: Basic rules
Definitions and Abstract Operations for Temporal Objects
+
+
+
Calendar Date Records and Calendar Fields Records
+
+
+
Calendar Date Records
+
+ A Calendar Date Record is a Record value used to represent a valid calendar date, which may or may not be the ISO 8601 calendar.
+ Calendar Date Records are produced by the abstract operation CalendarISOToDate.
+
+
Calendar Date Records have the fields listed in .
+
+
+
+
Field Name
+
Value
+
Meaning
+
+
+
[[Era]]
+
a String or *undefined*
+
+ A lowercase String representing the date's era, or *undefined* for calendars that do not have eras.
+
+
+
+
[[EraYear]]
+
an integer or *undefined*
+
+ The ordinal position of the date's year within its era, or *undefined* for calendars that do not have eras.
+
+ Era years are 1-indexed for many calendars, but not all (e.g., the eras of the Burmese calendar, not currently available in CLDR, each start with a year 0). Years can also advance opposite the flow of time (as for BCE years in the Gregorian calendar).
+
+
+
+
+
[[Year]]
+
an integer
+
+ The date's year relative to the first day of a calendar-specific "epoch year".
+ The year is relative to the first day of the calendar's epoch year, so if the epoch era starts in the middle of the year, the year will be the same value before and after the start date of the era.
+
+
+
+
[[Month]]
+
a positive integer
+
+ The 1-based ordinal position of the date's month within its year.
+
+ When the number of months in a year of the calendar is variable, a different value can be returned for dates that are part of the same month in different years. For example, in the Hebrew calendar, 1 Nisan 5781 is associated with value 7 while 1 Nisan 5782 is associated with value 8 because 5782 is a leap year and Nisan follows the insertion of Adar I.
+
+
+
+
+
[[MonthCode]]
+
a month code
+
+ The month code of the date's month.
+
+
+
+
[[Day]]
+
a positive integer
+
+ The 1-based ordinal position of the date's day within its month.
+
+
+
+
[[DayOfWeek]]
+
a positive integer
+
+ The day of the week corresponding to the date. The value should be 1-based, where 1 is the day corresponding to Monday in the given calendar.
+
+
+
+
[[DayOfYear]]
+
a positive integer
+
+ The 1-based ordinal position of the date's day within its year.
+
+
+
+
[[WeekOfYear]]
+
a Year-Week Record
+
+
The date's calendar week of year, and the corresponding week calendar year.
+
The Year-Week Record's [[Week]] field should be 1-based.
+
The Year-Week Record's [[Year]] field is relative to the first day of a calendar-specific "epoch year", as in the Calendar Date Record's [[Year]] field, not relative to an era as in [[EraYear]].
+
+ Usually the Year-Week Record's [[Year]] field will contain the same value as the Calendar Date Record's [[Year]] field, but may contain the previous or next year if the week number in the Year-Week Record's [[Week]] field overlaps two different years.
+ See also ISOWeekOfYear.
+
+
The Year-Week Record contains *undefined* in [[Week]] and [[Year]] field for calendars that do not have a well-defined week calendar system.
+
+
+
+
[[DaysInWeek]]
+
a positive integer
+
The number of days in the date's week.
+
+
+
[[DaysInMonth]]
+
a positive integer
+
The number of days in the date's month.
+
+
+
[[DaysInYear]]
+
a positive integer
+
The number of days in the date's year.
+
+
+
[[MonthsInYear]]
+
a positive integer
+
The number of months in the date's year.
+
+
+
[[InLeapYear]]
+
a Boolean
+
+ *true* if the date falls within a leap year, and *false* otherwise.
+
+ A "leap year" is a year that contains more days than other years (for solar or lunar calendars) or more months than other years (for lunisolar calendars like Hebrew or Chinese).
+ Some calendars, especially lunisolar ones, have further variation in year length that is not represented in the output of this operation (e.g., the Hebrew calendar includes common years with 353, 354, or 355 days and leap years with 383, 384, or 385 days).
+
+
+
+
+
+
+
+
+
Calendar Fields Records
+
+ A Calendar Fields Record is a Record value used to represent full or partial input for a calendar date in a non-ISO 8601 calendar.
+ Calendar Fields Records are produced by several abstract operations, such as ISODateToFields and PrepareCalendarFields, and are passed to abstract operations such as CalendarDateFromFields.
+
+
Many of the fields in a Calendar Fields Record have the same meaning as the fields of the same name in Calendar Date Records, but each field in a Calendar Fields Record may additionally be ~unset~ to indicate partial input.
+
+ Each field has a corresponding property key.
+ These property keys correspond to the properties that are read from user input objects to populate the field, in methods such as `Temporal.PlainDate.prototype.with()`.
+
+
+ Each field has a corresponding enumeration key.
+ Lists of these enumeration keys are passed to abstract operations such as PrepareCalendarFields and CalendarFieldKeysToIgnore to denote a subset of fields to operate on.
+
+
Calendar Fields Records have the fields listed in .
+
+
+
+
Field Name
+
Value
+
Default
+
Property Key
+
Enumeration Key
+
Conversion
+
Meaning
+
+
+
[[Era]]
+
a String or ~unset~
+
~unset~
+
*"era"*
+
~era~
+
~to-string~
+
+ A lowercase String representing the era.
+
+
+
+
[[EraYear]]
+
an integer or ~unset~
+
~unset~
+
*"eraYear"*
+
~era-year~
+
~to-integer-with-truncation~
+
+ The ordinal position of the year within the era.
+
+
+
+
[[Year]]
+
an integer or ~unset~
+
~unset~
+
*"year"*
+
~year~
+
~to-integer-with-truncation~
+
+ The year relative to the first day of a calendar-specific "epoch year".
+
+
+
+
[[Month]]
+
a positive integer or ~unset~
+
~unset~
+
*"month"*
+
~month~
+
~to-positive-integer-with-truncation~
+
+ The 1-based ordinal position of the month within the year.
+
+
+
+
[[MonthCode]]
+
a month code or ~unset~
+
~unset~
+
*"monthCode"*
+
~month-code~
+
~to-month-code~
+
+ The month code of the month.
+
+
+
+
[[Day]]
+
a positive integer or ~unset~
+
~unset~
+
*"day"*
+
~day~
+
~to-positive-integer-with-truncation~
+
+ The 1-based ordinal position of the day within the month.
+
+
+
+
[[Hour]]
+
an integer in the inclusive interval from 0 to 23 or ~unset~
+
0
+
*"hour"*
+
~hour~
+
~to-integer-with-truncation~
+
+ The number of the hour within the day.
+
+
+
+
[[Minute]]
+
an integer in the inclusive interval from 0 to 59 or ~unset~
+
0
+
*"minute"*
+
~minute~
+
~to-integer-with-truncation~
+
+ The number of the minute within the hour.
+
+
+
+
[[Second]]
+
an integer in the inclusive interval from 0 to 59 or ~unset~
+
0
+
*"second"*
+
~second~
+
~to-integer-with-truncation~
+
+ The number of the second within the minute.
+
+
+
+
[[Millisecond]]
+
an integer in the inclusive interval from 0 to 999 or ~unset~
+
0
+
*"millisecond"*
+
~millisecond~
+
~to-integer-with-truncation~
+
+ The number of the millisecond within the second.
+
+
+
+
[[Microsecond]]
+
an integer in the inclusive interval from 0 to 999 or ~unset~
+
0
+
*"microsecond"*
+
~microsecond~
+
~to-integer-with-truncation~
+
+ The number of the microsecond within the millisecond.
+
+
+
+
[[Nanosecond]]
+
an integer in the inclusive interval from 0 to 999 or ~unset~
+
0
+
*"nanosecond"*
+
~nanosecond~
+
~to-integer-with-truncation~
+
+ The number of the nanosecond within the microsecond.
+
+
+
+
[[OffsetString]]
+
a String or ~unset~
+
~unset~
+
*"offset"*
+
~offset~
+
~to-offset-string~
+
+ A string of the form `±HH:MM[:SS.SSSSSSSSS]` that can be parsed by ParseDateTimeUTCOffset.
+
+
+
+
[[TimeZone]]
+
a String or ~unset~
+
~unset~
+
*"timeZone"*
+
~time-zone~
+
~to-temporal-time-zone-identifier~
+
+ An available time zone identifier.
+
+
+
+
+
+
+
+
+ PrepareCalendarFields (
+ _calendar_: a calendar type,
+ _fields_: an Object,
+ _calendarFieldNames_: a List of values from the Enumeration Key column of ,
+ _nonCalendarFieldNames_: a List of values from the Enumeration Key column of ,
+ _requiredFieldNames_: either a List of values from the Enumeration Key column of or ~partial~,
+ ): either a normal completion containing a Calendar Fields Record, or a throw completion
+
+
+
description
+
+ It returns the result of reading from _fields_ all of the property names corresponding to _calendarFieldNames_ and _nonCalendarFieldNames_, plus any extra fields required by the calendar.
+ The returned Record has a non-~unset~ value for each element of _fieldNames_ that corresponds with a non-*undefined* property on _fields_ used as the input for relevant conversion.
+ When _requiredFields_ is ~partial~, this operation throws if none of the properties are present with a non-*undefined* value.
+ When _requiredFields_ is a List, this operation throws if any of the properties named by it are absent or *undefined*.
+
+
+
+ 1. Assert: If _requiredFieldNames_ is a List, _requiredFieldNames_ contains zero or one of each of the elements of _calendarFieldNames_ and _nonCalendarFieldNames_.
+ 1. Let _fieldNames_ be the list-concatenation of _calendarFieldNames_ and _nonCalendarFieldNames_.
+ 1. Let _extraFieldNames_ be CalendarExtraFields(_calendar_, _calendarFieldNames_).
+ 1. Set _fieldNames_ to the list-concatenation of _fieldNames_ and _extraFieldNames_.
+ 1. Assert: _fieldNames_ contains no duplicate elements.
+ 1. Let _result_ be a Calendar Fields Record with all fields equal to ~unset~.
+ 1. Let _any_ be *false*.
+ 1. Let _sortedPropertyNames_ be a List whose elements are the values in the Property Key column of corresponding to the elements of _fieldNames_, sorted according to lexicographic code unit order.
+ 1. For each property name _property_ of _sortedPropertyNames_, do
+ 1. Let _key_ be the value in the Enumeration Key column of corresponding to the row whose Property Key value is _property_.
+ 1. Let _value_ be ? Get(_fields_, _property_).
+ 1. If _value_ is not *undefined*, then
+ 1. Set _any_ to *true*.
+ 1. Let _Conversion_ be the Conversion value of the same row.
+ 1. If _Conversion_ is ~to-integer-with-truncation~, then
+ 1. Set _value_ to ? ToIntegerWithTruncation(_value_).
+ 1. Set _value_ to 𝔽(_value_).
+ 1. Else if _Conversion_ is ~to-positive-integer-with-truncation~, then
+ 1. Set _value_ to ? ToPositiveIntegerWithTruncation(_value_).
+ 1. Set _value_ to 𝔽(_value_).
+ 1. Else if _Conversion_ is ~to-string~, then
+ 1. Set _value_ to ? ToString(_value_).
+ 1. Else if _Conversion_ is ~to-temporal-time-zone-identifier~, then
+ 1. Set _value_ to ? ToTemporalTimeZoneIdentifier(_value_).
+ 1. Else if _Conversion_ is ~to-month-code~, then
+ 1. Let _parsed_ be ? ParseMonthCode(_value_).
+ 1. Set _value_ to CreateMonthCode(_parsed_.[[MonthNumber]], _parsed_.[[IsLeapMonth]]).
+ 1. Else,
+ 1. Assert: _Conversion_ is ~to-offset-string~.
+ 1. Set _value_ be ? ToPrimitive(_value_, ~string~).
+ 1. If _value_ is not a String, throw a *TypeError* exception.
+ 1. Perform ? ParseDateTimeUTCOffset(_value_).
+ 1. Set _result_'s field whose name is given in the Field Name column of the same row to _value_.
+ 1. Else if _requiredFieldNames_ is a List, then
+ 1. If _requiredFieldNames_ contains _key_, throw a *TypeError* exception.
+ 1. Set _result_'s field whose name is given in the Field Name column of the same row to the corresponding Default value of the same row.
+ 1. If _requiredFieldNames_ is ~partial~ and _any_ is *false*, throw a *TypeError* exception.
+ 1. Return _result_.
+
+
+
+
+
+ CalendarFieldKeysPresent (
+ _fields_: a Calendar Fields Record,
+ ): a List of values from the Enumeration Key column of
+
+
+
description
+
The returned List contains the enumeration keys for all fields of _fields_ that are not ~unset~.
+
+
+ 1. Let _list_ be « ».
+ 1. For each row of , except the header row, do
+ 1. Let _value_ be _fields_' field whose name is given in the Field Name column of the row.
+ 1. Let _enumerationKey_ be the value in the Enumeration Key column of the row.
+ 1. If _value_ is not ~unset~, append _enumerationKey_ to _list_.
+ 1. Return _list_.
+
+
+
+
+
+ CalendarMergeFields (
+ _calendar_: a calendar type,
+ _fields_: a Calendar Fields Record,
+ _additionalFields_: a Calendar Fields Record,
+ ): a Calendar Fields Record
+
+
+
description
+
It merges the properties of _fields_ and _additionalFields_.
+
+
+ 1. Let _additionalKeys_ be CalendarFieldKeysPresent(_additionalFields_).
+ 1. Let _overriddenKeys_ be CalendarFieldKeysToIgnore(_calendar_, _additionalKeys_).
+ 1. Let _merged_ be a Calendar Fields Record with all fields set to ~unset~.
+ 1. Let _fieldsKeys_ be CalendarFieldKeysPresent(_fields_).
+ 1. For each row of , except the header row, do
+ 1. Let _key_ be the value in the Enumeration Key column of the row.
+ 1. If _fieldsKeys_ contains _key_ and _overriddenKeys_ does not contain _key_, then
+ 1. Let _propValue_ be _fields_' field whose name is given in the Field Name column of the row.
+ 1. Set _merged_'s field whose name is given in the Field Name column of the row to _propValue_.
+ 1. If _additionalKeys_ contains _key_, then
+ 1. Let _propValue_ be _additionalFields_' field whose name is given in the Field Name column of the row.
+ 1. Set _merged_'s field whose name is given in the Field Name column of the row to _propValue_.
+ 1. Return _merged_.
+
+
+
+
+
+
Calendar Identifiers
+
+
+ At a minimum, ECMAScript implementations must support a built-in calendar named *"iso8601"*, representing the ISO 8601 calendar.
+ In addition, implementations may support any number of other built-in calendars corresponding with those of the Unicode Common Locale Data Repository (CLDR).
+
+
+ ECMAScript implementations identify built-in calendars using a calendar type that is a Unicode Calendar Identifier as defined in Unicode Technical Standard #35 Part 1 Core, Key and Type Definitions.
+ Their canonical form is a string containing only Unicode Basic Latin lowercase letters (U+0061 LATIN SMALL LETTER A through U+007A LATIN SMALL LETTER Z, inclusive) and/or digits (U+0030 DIGIT ZERO through U+0039 DIGIT NINE, inclusive), with zero or more medial hyphens (U+002D HYPHEN-MINUS).
+
+
+
+
AvailableCalendars ( ): a List of calendar types
+
+
description
+
The returned List is sorted according to lexicographic code unit order, and contains unique calendar types in canonical form () identifying the calendars for which the implementation provides the functionality of Temporal objects, including any aliases.
+
+
The default implementation of AvailableCalendars, to be used for ECMAScript implementations that do not support any calendar types other than *"iso8601"*, performs the following steps when called:
+
+ 1. Return « *"iso8601"* ».
+
+
+
+
+
+ CanonicalizeCalendar (
+ _id_: a String,
+ ): either a normal completion containing a calendar type, or a throw completion
+
+
+
description
+
It returns the canonical form of the calendar type denoted by _id_, or throws an exception if there is no such built-in calendar.
+
+
The default implementation of CanonicalizeCalendar, to be used for ECMAScript implementations that do not support any calendar types other than *"iso8601"*, performs the following steps when called:
+
+ 1. If the ASCII-lowercase of _id_ is not *"iso8601"*, throw a *RangeError* exception.
+ 1. Return *"iso8601"*.
+
+
+
+
+
+ ToTemporalCalendarIdentifier (
+ _temporalCalendarLike_: an ECMAScript value,
+ ): either a normal completion containing a calendar type or a throw completion
+
+
+
description
+
+ It attempts to derive a calendar type from _temporalCalendarLike_, and returns that value if found or throws an exception if not.
+
+
+
+ 1. If _temporalCalendarLike_ is an Object and _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, return _temporalCalendarLike_.[[Calendar]].
+ 1. If _temporalCalendarLike_ is not a String, throw a *TypeError* exception.
+ 1. Let _identifier_ be ? ParseTemporalCalendarString(_temporalCalendarLike_).
+ 1. Return ? CanonicalizeCalendar(_identifier_).
+
+
+
+
+
+ GetTemporalCalendarIdentifierWithISODefault (
+ _item_: an Object,
+ ): either a normal completion containing a calendar type or a throw completion
+
+
+
description
+
+ It looks for a `calendar` property on the given _item_ and converts its value into a calendar identifier.
+ If no such property is present, the built-in ISO 8601 calendar is returned.
+
+
+
+ 1. If _item_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ 1. Return _item_.[[Calendar]].
+ 1. Let _calendarLike_ be ? Get(_item_, *"calendar"*).
+ 1. If _calendarLike_ is *undefined*, return *"iso8601"*.
+ 1. Return ? ToTemporalCalendarIdentifier(_calendarLike_).
+
+
+
+
+
+ CalendarEquals (
+ _one_: a calendar type,
+ _two_: a calendar type,
+ ): a Boolean
+
+
+
description
+
It returns *true* if its arguments represent calendars using the same identifier.
+ CalendarDateAdd (
+ _calendar_: a calendar type,
+ _isoDate_: an ISO Date Record,
+ _duration_: a Date Duration Record,
+ _overflow_: either ~constrain~ or ~reject~,
+ ): either a normal completion containing an ISO Date Record or a throw completion
+
+
+
description
+
+ It adds _dateDuration_ to _isoDate_ using the years, months, and weeks reckoning of _calendar_.
+ If addition of years or months results in a nonexistent date, depending on _overflow_ it will be coerced to an existing date or the operation will throw.
+
+
+
+ 1. If _calendar_ is *"iso8601"*, then
+ 1. Let _intermediate_ be BalanceISOYearMonth(_isoDate_.[[Year]] + _duration_.[[Years]], _isoDate_.[[Month]] + _duration_.[[Months]]).
+ 1. Set _intermediate_ to ? RegulateISODate(_intermediate_.[[Year]], _intermediate_.[[Month]], _isoDate_.[[Day]], _overflow_).
+ 1. Let _days_ be _duration_.[[Days]] + 7 × _duration_.[[Weeks]].
+ 1. Let _result_ be AddDaysToISODate(_intermediate_, _days_).
+ 1. Else,
+ 1. Let _result_ be ? NonISODateAdd(_calendar_, _isoDate_, _duration_, _overflow_).
+ 1. If ISODateWithinLimits(_result_) is *false*, throw a *RangeError* exception.
+ 1. Return _result_.
+
+
+
+
+
+ NonISODateAdd (
+ _calendar_: a calendar type that is not *"iso8601"*,
+ _isoDate_: an ISO Date Record,
+ _duration_: a Date Duration Record,
+ _overflow_: either ~constrain~ or ~reject~,
+ ): either a normal completion containing an ISO Date Record or a throw completion
+
+
+
description
+
+ The operation performs implementation-defined processing to add _duration_ to _date_ in the context of the calendar represented by _calendar_ and returns the corresponding day, month and year of the result in the ISO 8601 calendar values as an ISO Date Record.
+ It may throw a *RangeError* exception if _overflow_ is ~reject~ and the resulting month or day would need to be clamped in order to form a valid date in _calendar_.
+
+
+
+
+
+
+ CalendarDateUntil (
+ _calendar_: a calendar type,
+ _one_: an ISO Date Record,
+ _two_: an ISO Date Record,
+ _largestUnit_: a date unit,
+ ): a Date Duration Record
+
+
+
description
+
+ It determines the difference between the dates _one_ and _two_ using the years, months, and weeks reckoning of _calendar_.
+ No fields larger than _largestUnit_ will be non-zero in the resulting Date Duration Record.
+
+
+
+ 1. Let _sign_ be CompareISODate(_one_, _two_).
+ 1. If _sign_ = 0, return ZeroDateDuration().
+ 1. If _calendar_ is *"iso8601"*, then
+ 1. Set _sign_ to -sign.
+ 1. Let _years_ be 0.
+ 1. If _largestUnit_ is ~year~, then
+ 1. Let _candidateYears_ be _sign_.
+ 1. Repeat, while ISODateSurpasses(_sign_, _one_, _two_, _candidateYears_, 0, 0, 0) is *false*,
+ 1. Set _years_ to _candidateYears_.
+ 1. Set _candidateYears_ to _candidateYears_ + _sign_.
+ 1. Let _months_ be 0.
+ 1. If _largestUnit_ is either ~year~ or ~month~, then
+ 1. Let _candidateMonths_ be _sign_.
+ 1. Repeat, while ISODateSurpasses(_sign_, _one_, _two_, _years_, _candidateMonths_, 0, 0) is *false*,
+ 1. Set _months_ to _candidateMonths_.
+ 1. Set _candidateMonths_ to _candidateMonths_ + _sign_.
+ 1. Let _weeks_ be 0.
+ 1. If _largestUnit_ is ~week~, then
+ 1. Let _candidateWeeks_ be _sign_.
+ 1. Repeat, while ISODateSurpasses(_sign_, _one_, _two_, _years_, _months_, _candidateWeeks_, 0) is *false*,
+ 1. Set _weeks_ to _candidateWeeks_.
+ 1. Set _candidateWeeks_ to _candidateWeeks_ + sign.
+ 1. Let _days_ be 0.
+ 1. Let _candidateDays_ be _sign_.
+ 1. Repeat, while ISODateSurpasses(_sign_, _one_, _two_, _years_, _months_, _weeks_, _candidateDays_) is *false*,
+ 1. Set _days_ to _candidateDays_.
+ 1. Set _candidateDays_ to _candidateDays_ + _sign_.
+ 1. Return ! CreateDateDurationRecord(_years_, _months_, _weeks_, _days_).
+ 1. Return NonISODateUntil(_calendar_, _one_, _two_, _largestUnit_).
+
+
+
+
+
+ NonISODateUntil (
+ _calendar_: a calendar type that is not *"iso8601"*,
+ _one_: an ISO Date Record,
+ _two_: an ISO Date Record,
+ _largestUnit_: a date unit,
+ ): a Date Duration Record
+
+
+
description
+
+ It performs implementation-defined processing to determine the difference between the dates _one_ and _two_ using the years, months, and weeks reckoning of _calendar_.
+ No fields larger than _largestUnit_ will be non-zero in the resulting Date Duration Record.
+
+
+
+
+
+
+ CalendarDateToISO (
+ _calendar_: a calendar type,
+ _fields_: a Calendar Fields Record,
+ _overflow_: either ~constrain~ or ~reject~,
+ ): either a normal completion containing an ISO Date Record or a throw completion
+
+
+
description
+
+ It converts _fields_, which represents either a date or a year and month in the built-in calendar identified by _calendar_, to a corresponding representative date in the ISO 8601 calendar, subject to overflow correction specified by _overflow_.
+ For ~reject~, values that do not form a valid date cause an exception to be thrown, as described below.
+ For ~constrain~, values that do not form a valid date are clamped to their respective valid range.
+
+
+
+ 1. If _calendar_ is *"iso8601"*, then
+ 1. Assert: _fields_.[[Year]], _fields_.[[Month]], and _fields_.[[Day]] are not ~unset~.
+ 1. Return ? RegulateISODate(_fields_.[[Year]], _fields_.[[Month]], _fields_.[[Day]], _overflow_).
+ 1. Return ? NonISOCalendarDateToISO(_calendar_, _fields_, _overflow_).
+
+
+
+
+
+ NonISOCalendarDateToISO (
+ _calendar_: a calendar type that is not *"iso8601"*,
+ _fields_: a Calendar Fields Record,
+ _overflow_: either ~constrain~ or ~reject~,
+ ): either a normal completion containing an ISO Date Record or a throw completion
+
+
+
description
+
+ It performs implementation-defined processing to convert _fields_, which represents either a date or a year and month in the built-in calendar identified by _calendar_, to a corresponding representative date in the ISO 8601 calendar, subject to overflow correction specified by _overflow_.
+ For ~reject~, values that do not form a valid date cause an exception to be thrown, as described below.
+ For ~constrain~, values that do not form a valid date are clamped to their respective valid range.
+
+
+
Like RegulateISODate, the operation throws a *RangeError* exception when _overflow_ is ~reject~ and the date described by _fields_ does not exist.
+
Clamping an invalid date to the correct range when _overflow_ is ~constrain~ is a behaviour specific to each calendar other than *"iso8601"*, but all calendars follow this guideline:
+
+
Pick the closest day in the same month. If there are two equally-close dates in that month, pick the later one.
+
If the month is a leap month that doesn't exist in the year, pick another date according to the cultural conventions of that calendar's users. Usually this will result in the same day in the month before or after where that month would normally fall in a leap year.
+
Otherwise, pick the closest date that is still in the same year. If there are two equally-close dates in that year, pick the later one.
+
If the entire year doesn't exist, pick the closest date in a different year. If there are two equally-close dates, pick the later one.
+
+
+
+
+
+ CalendarMonthDayToISOReferenceDate (
+ _calendar_: a calendar type,
+ _fields_: a Calendar Fields Record,
+ _overflow_: either ~constrain~ or ~reject~,
+ ): either a normal completion containing an ISO Date Record or a throw completion
+
+
+
description
+
+ It converts _fields_, which represents a calendar date without a year (i.e., month code and day pair, or equivalent) in the built-in calendar identified by _calendar_, to a corresponding reference date in the ISO 8601 calendar as described below, subject to overflow correction specified by _overflow_.
+ For ~reject~, values that do not form a valid date cause an exception to be thrown.
+ For ~constrain~, values that do not form a valid date are clamped to their respective valid range as in CalendarDateToISO.
+
+
+
+ 1. If _calendar_ is *"iso8601"*, then
+ 1. Assert: _fields_.[[Month]] and _fields_.[[Day]] are not ~unset~.
+ 1. Let _referenceISOYear_ be 1972 (the first ISO 8601 leap year after the epoch).
+ 1. If _fields_.[[Year]] is ~unset~, let _year_ be _referenceISOYear_; else let _year_ be _fields_.[[Year]].
+ 1. Let _result_ be ? RegulateISODate(_year_, _fields_.[[Month]], _fields_.[[Day]], _overflow_).
+ 1. Return CreateISODateRecord(_referenceISOYear_, _result_.[[Month]], _result_.[[Day]]).
+ 1. Return ? NonISOMonthDayToISOReferenceDate(_calendar_, _fields_, _overflow_).
+
+
+ The fields of the returned ISO Date Record represent a reference date in the ISO 8601 calendar that, when converted to _calendar_, corresponds to the month code and day of _fields_ in an arbitrary but deterministically chosen reference year.
+ For the ISO 8601 calendar, the reference year is always 1972. For other calendars, see the note in NonISOMonthDayToISOReferenceDate.
+
+
Like RegulateISODate, the operation throws a *RangeError* exception if _overflow_ is ~reject~ and the month and day described by _fields_ does not exist (or does not exist within the year described by _fields_ when there is such a year).
+
Also like RegulateISODate, if _overflow_ is ~constrain~ and the date or month and day described by _fields_ does not exist (or does not exist within the year described by _fields_ when there is such a year), the values of those fields are clamped to their respective valid range. As in CalendarDateToISO, such clamping is calendar-specific.
+
+
+
+
+ NonISOMonthDayToISOReferenceDate (
+ _calendar_: a calendar type that is not *"iso8601"*,
+ _fields_: a Calendar Fields Record,
+ _overflow_: either ~constrain~ or ~reject~,
+ ): either a normal completion containing an ISO Date Record or a throw completion
+
+
+
description
+
+ It performs implementation-defined processing to convert _fields_, which represents a calendar date without a year (i.e., month code and day pair, or equivalent) in the built-in calendar identified by _calendar_, to a corresponding reference date in the ISO 8601 calendar as described below, subject to overflow correction specified by _overflow_.
+ For ~reject~, values that do not form a valid date cause an exception to be thrown.
+ For ~constrain~, values that do not form a valid date are clamped to their respective valid range as in CalendarDateToISO.
+
+
+
+ The fields of the returned ISO Date Record represent a reference date in the ISO 8601 calendar that, when converted to _calendar_, corresponds to the month code and day of _fields_ in an arbitrary but deterministically chosen reference year.
+ The reference date is the latest ISO 8601 date corresponding to the calendar date that is between January 1, 1900 and December 31, 1972 inclusive. If there is no such date, it is the earliest ISO 8601 date corresponding to the calendar date between January 1, 1973 and December 31, 2035 inclusive.
+
+
The reference year is almost always 1972 (the first ISO 8601 leap year after the epoch), with exceptions for calendars where some dates (e.g. leap days or days in leap months) didn't occur during that ISO 8601 year. For example, Hebrew calendar leap month Adar I occurred in calendar years 5730 and 5733 (respectively overlapping ISO 8601 February/March 1970 and February/March 1973), but did not occur between them, so the reference year for days of that month is 1970.
+
+ Like RegulateISODate, the operation throws a *RangeError* exception if _overflow_ is ~reject~ and the month and day described by _fields_ does not exist (or does not exist within the year described by _fields_ when there is such a year).
+ For example, when _calendar_ is *"gregory"* and _overflow_ is ~reject~, _fields_ values of { [[MonthCode]]: *"M01"*, [[Day]]: 32 } and { [[Year]]: 2001, [[Month]]: 2, [[Day]]: 29 } would both cause a *RangeError* to be thrown.
+ In the latter case, even though February 29 is a date in leap years of the Gregorian calendar, 2001 was not a leap year and a month code cannot be determined from the nonexistent date 2001-02-29 with the specified month index.
+
+
+ Also like RegulateISODate, if _overflow_ is ~constrain~ and the date or month and day described by _fields_ does not exist (or does not exist within the year described by _fields_ when there is such a year), the values of those fields are clamped to their respective valid range. As in CalendarDateToISO, such clamping is calendar-specific.
+ For example, when _calendar_ is *"gregory"* and _overflow_ is ~constrain~, a _fields_ value of { [[MonthCode]]: *"M02"*, [[Day]]: 30 } is clamped to { [[Year]]: 1972, [[Month]]: 2, [[Day]]: 29 } (because 29 is the maximum valid day for February) while _fields_ values of { [[Year]]: 2001, [[MonthCode]]: *"M02"*, [[Day]]: 30 } and { [[Era]]: *"ce"*, [[EraYear]]: 2001, [[Month]]: 2, [[Day]]: 30 } (or an equivalent with a supported value for [[Era]] representing the Common Era beginning in ISO 8601 year 1) are clamped to { [[Year]]: 1972, [[Month]]: 2, [[Day]]: 28 } (because 28 is the maximum valid day for February 2001, which did not include a leap day).
+
+
+ The operation throws a *RangeError* if _fields_.[[Year]] is not ~unset~ and the ISO 8601 year _year_ corresponding to _fields_.[[Year]] would cause ISODateWithinLimits to return *false* (i.e., _year_ is not in the inclusive interval from -271,821 to 275,760.)
+ This is so as not to require calculating whether the month and day described in _fields_ exist in years arbitrarily far in the future or past.
+ Note this restriction does not apply to CalendarMonthDayToISOReferenceDate when _calendar_ is *"iso8601"*.
+
+
+
+
+
+ CalendarISOToDate (
+ _calendar_: a calendar type,
+ _isoDate_: an ISO Date Record,
+ ): a Calendar Date Record
+
+
+
description
+
It finds the date corresponding to _isoDate_ in the context of the calendar represented by _calendar_ and returns a Calendar Date Record representing that calendar date, with its fields filled in according to their descriptions.
+
+
+ 1. If _calendar_ is *"iso8601"*, then
+ 1. If MathematicalInLeapYear(EpochTimeForYear(_isoDate_.[[Year]])) = 1, let _inLeapYear_ be *true*; else let _inLeapYear_ be *false*.
+ 1. Return Calendar Date Record {
+ [[Era]]: *undefined*,
+ [[EraYear]]: *undefined*,
+ [[Year]]: _isoDate_.[[Year]],
+ [[Month]]: _isoDate_.[[Month]],
+ [[MonthCode]]: CreateMonthCode(_isoDate_.[[Month]], *false*),
+ [[Day]]: _isoDate_.[[Day]],
+ [[DayOfWeek]]: ISODayOfWeek(_isoDate_),
+ [[DayOfYear]]: ISODayOfYear(_isoDate_),
+ [[WeekOfYear]]: ISOWeekOfYear(_isoDate_),
+ [[DaysInWeek]]: 7,
+ [[DaysInMonth]]: ISODaysInMonth(_isoDate_.[[Year]], _isoDate_.[[Month]]),
+ [[DaysInYear]]: MathematicalDaysInYear(_isoDate_.[[Year]]),
+ [[MonthsInYear]]: 12,
+ [[InLeapYear]]: _inLeapYear_
+ }.
+ 1. Return NonISOCalendarISOToDate(_calendar_, _isoDate_).
+
+
+
Implementations are encouraged to elide fields that are not read by the caller.
+
+
+
+
+
+ NonISOCalendarISOToDate (
+ _calendar_: a calendar type that is not *"iso8601"*,
+ _isoDate_: an ISO Date Record,
+ ): a Calendar Date Record
+
+
+
description
+
It performs implementation-defined processing to find the date corresponding to _isoDate_ in the context of the calendar represented by _calendar_ and returns a Calendar Date Record representing that calendar date, with its fields filled in according to their descriptions in .
+
+
+
Implementations are encouraged to elide fields that are not read by the caller.
+
+
+
+
+
+ CalendarExtraFields (
+ _calendar_: a calendar type,
+ _fields_: a List of values from the Enumeration Key column of ,
+ ): a List of values from the Enumeration Key column of
+
+
+
description
+
It characterizes calendar-specific fields that are relevant for the provided _fields_ in the built-in calendar identified by _calendar_. For example, « ~era~, ~era-year~ » is returned when _calendar_ is *"gregory"* or *"japanese"* and _fields_ is a List containing ~year~.
+
+
+ 1. If _calendar_ is *"iso8601"*, return a new empty List.
+ 1. Return an implementation-defined List as described above.
+
+
+
+
+
+ CalendarFieldKeysToIgnore (
+ _calendar_: a calendar type,
+ _keys_: a List of values from the Enumeration Key column of ,
+ ): a List of values from the Enumeration Key column of
+
+
+
description
+
+ It determines which calendar date fields changing any of the fields named in _keys_ can potentially conflict with or invalidate, for the given _calendar_.
+ A field always invalidates at least itself.
+
+
+
+ 1. If _calendar_ is *"iso8601"*, then
+ 1. Let _ignoredKeys_ be a new empty List.
+ 1. For each element _key_ of _keys_, do
+ 1. Append _key_ to _ignoredKeys_.
+ 1. If _key_ is ~month~, append ~month-code~ to _ignoredKeys_.
+ 1. Else if _key_ is ~month-code~, append ~month~ to _ignoredKeys_.
+ 1. NOTE: While _ignoredKeys_ can have duplicate elements, this is not intended to be meaningful. This specification only checks whether particular keys are or are not members of the list.
+ 1. Return _ignoredKeys_.
+ 1. Return NonISOFieldKeysToIgnore(_calendar_, _keys_).
+
+
+
+
+
+ NonISOFieldKeysToIgnore (
+ _calendar_: a calendar type that is not *"iso8601"*,
+ _keys_: a List of values from the Enumeration Key column of ,
+ ): a List of values from the Enumeration Key column of
+
+
+
description
+
+ It performs implementation-defined processing to determine which calendar date fields changing any of the fields named in _keys_ can potentially conflict with or invalidate, for the given _calendar_.
+ A field always invalidates at least itself.
+
+
+
This operation is relevant for calendars which accept fields other than the standard set of ISO 8601 calendar fields, in order to implement the Temporal objects' `with()` methods in such a way that the result is free of ambiguity or conflicts.
+
+ For example, given a _calendar_ that uses eras, such as *"gregory"*, a key in _keys_ being any one of ~year~, ~era~, or ~era-year~ would exclude all three.
+ Passing any one of the three to a `with()` method might conflict with either of the other two properties on the receiver object, so those properties of the receiver object should be ignored.
+ Given this, in addition to the ISO 8601 mutual exclusion of ~month~ and ~month-code~, a possible implementation might produce the following results when _calendar_ is *"gregory"*:
+
+
+ Example results of CalendarFieldKeysToIgnore
+
+
+
+ In a _calendar_ such as *"japanese"* where eras do not start and end at year and/or month boundaries, note that the returned List should contain ~era~ and ~era-year~ if _keys_ contains ~day~, ~month~, or ~month-code~ (not only if it contains ~era~, ~era-year~, or ~year~, as in the example above) because it's possible for changing the day or month to cause a conflict with the era.
+
+
+
+
+
+ CalendarResolveFields (
+ _calendar_: a calendar type,
+ _fields_: a Calendar Fields Record,
+ _type_: one of ~date~, ~year-month~, or ~month-day~,
+ ): either a normal completion containing ~unused~ or a throw completion
+
+
+
description
+
+ It validates that _fields_ (which describes a date or partial date in the built-in calendar identified by _calendar_) is sufficiently complete to satisfy _type_ and not internally inconsistent, and mutates _fields_ into acceptable input for or by merging data that can be represented in multiple forms into standard fields and removing redundant fields (for example, merging [[Era]] and [[EraYear]] into [[Year]]).
+
+
+
+ 1. If _calendar_ is *"iso8601"*, then
+ 1. Let _needsYear_ be *false*.
+ 1. If _type_ is either ~date~ or ~year-month~, set _needsYear_ to *true*.
+ 1. Let _needsDay_ be *false*.
+ 1. If _type_ is either ~date~ or ~month-day~, set _needsDay_ to *true*.
+ 1. If _needsYear_ is *true* and _fields_.[[Year]] is ~unset~, throw a *TypeError* exception.
+ 1. If _needsDay_ is *true* and _fields_.[[Day]] is ~unset~, throw a *TypeError* exception.
+ 1. If _fields_.[[Month]] is ~unset~ and _fields_.[[MonthCode]] is ~unset~, throw a *TypeError* exception.
+ 1. If _fields_.[[MonthCode]] is not ~unset~, then
+ 1. Let _parsedMonthCode_ be ! ParseMonthCode(_fields_.[[MonthCode]]).
+ 1. If _parsedMonthCode_.[[IsLeapMonth]] is *true*, throw a *RangeError* exception.
+ 1. Let _month_ be _parsedMonthCode_.[[MonthNumber]].
+ 1. If _month_ > 12, throw a *RangeError* exception.
+ 1. If _fields_.[[Month]] is not ~unset~ and _fields_.[[Month]] ≠ _month_, throw a *RangeError* exception.
+ 1. Set _fields_.[[Month]] to _month_.
+ 1. Else,
+ 1. Perform ? NonISOResolveFields(_calendar_, _fields_, _type_).
+ 1. Return ~unused~.
+
+
+
+
+
+ NonISOResolveFields (
+ _calendar_: a calendar type that is not *"iso8601"*,
+ _fields_: a Calendar Fields Record,
+ _type_: one of ~date~, ~year-month~, or ~month-day~,
+ ): either a normal completion containing ~unused~ or a throw completion
+
+
+
description
+
+ It performs implementation-defined processing to validate that _fields_ (which describes a date or partial date in the built-in calendar identified by _calendar_) is sufficiently complete to satisfy _type_ and not internally inconsistent, and mutates _fields_ into acceptable input for or by merging data that can be represented in multiple forms into standard fields and removing redundant fields (for example, merging [[Era]] and [[EraYear]] into [[Year]]).
+
+
+
The operation throws a *TypeError* exception if the non-~unset~ fields of _fields_ are insufficient to identify a unique instance of _type_ in the calendar (e.g., when at least one field in each combination capable of determining some part of its data is ~unset~) or a *RangeError* exception if the fields are sufficient but their values are internally inconsistent within the calendar (e.g., when fields such as [[Month]] and [[MonthCode]] have conflicting non-~unset~ values). For example:
+
+
If _type_ is either ~date~ or ~month-day~, and "day" in the calendar has an interpretation similar to ISO 8601 and _fields_.[[Day]] is ~unset~.
+
If _fields_.[[MonthCode]] identifies a month code that is not valid in any year of the calendar.
+
If _fields_.[[Month]] and _fields_.[[MonthCode]] are both ~unset~ or neither value is ~unset~ but they do not identify the same month.
+
If _type_ is ~month-day~ and _fields_.[[MonthCode]] is ~unset~ and a specific year cannot be determined from _fields_.
+
If the calendar supports the usual partitioning of years into eras with their own year counting as represented by "year", "era", and "era year" (as in the Gregorian or traditional Japanese calendars) and any of the following cases apply:
+
+
_type_ is ~date~ or ~year-month~ and each of _fields_.[[Year]], _fields_.[[Era]], and _fields_.[[EraYear]] is ~unset~.
+
_fields_.[[Era]] is ~unset~ but _fields_.[[EraYear]] is not.
+
_fields_.[[EraYear]] is ~unset~ but _fields_.[[Era]] is not.
+
None of the three values are ~unset~ but _fields_.[[Era]] and _fields_.[[EraYear]] do not together identify the same year as _fields_.[[Year]].
+
+
+
+
+ The ISODateWithinLimits assertion holds because the result of CalendarMonthDayToISOReferenceDate should return a reference year that falls within the representable range.
+
+ In some cases, verifying the internal consistency of two fields requires the data from other fields, such as checking _fields_.[[MonthCode]] *"M06"* against _fields_.[[Month]] 7 in the Hebrew calendar (which are consistent if and only if _fields_ identifies a year that includes leap month Adar I).
+
+
+
When the fields of _fields_ are inconsistent with respect to a non-~unset~ _fields_.[[Era]], it is recommended that _fields_.[[Era]] and _fields_.[[EraYear]] be updated to resolve the inconsistency by lenient interpretation of out-of-bounds values (rather than throwing a *RangeError*), which is particularly useful for consistent interpretation of dates in calendars with regnal eras.
+
+
In the Gregorian calendar, a zero or negative _fields_.[[EraYear]] should be replaced with a positive [[EraYear]] corresponding with extension of the era into its complement and _fields_.[[Era]] should be updating accordingly (such that Common Era [[EraYear]] 0 is updated to Before Common Era [[EraYear]] 1, Before Common Era [[EraYear]] -1 is updated to Common Era [[EraYear]] 2, etc.).
+
In the Japanese calendar, when _fields_.[[Era]] is not ~unset~ and the date represented by _fields_ is not within the bounds of that era, _fields_.[[Era]] should be updated to the appropriate containing era for that date (for example, because the transition from Heisei era [[EraYear]] 31 to Reiwa era [[EraYear]] 1 took place on May 1 of [[Year]] 2019, Heisei era [[EraYear]] 32 should be updated to Reiwa era [[EraYear]] 2, Reiwa era [[EraYear]] 1 [[Month]] 1 should be updated to Heisei era [[EraYear]] 31 [[Month]] 1, etc.).
+
+
+
+ When _type_ is ~month-day~ and _fields_.[[Month]] is not ~unset~, it is recommended that all built-in calendars other than the ISO 8601 calendar require a disambiguating year (e.g., either _fields_.[[Year]] or _fields_.[[Era]] and _fields_.[[EraYear]]) to avoid a *TypeError*, regardless of whether or not _fields_.[[MonthCode]] is also ~unset~. The ISO 8601 calendar allows _fields_.[[Year]] to be ~unset~ in this case because it is a special default calendar that is permanently stable for automated processing.
+
+
+
+
+
+ CalendarDateFromFields (
+ _calendar_: a calendar type,
+ _fields_: a Calendar Fields Record,
+ _overflow_: either ~constrain~ or ~reject~,
+ ): either a normal completion containing an ISO Date Record or a throw completion
+
+
+
description
+
It converts a calendar date in the reckoning of _calendar_, if it is uniquely determined by the fields of _fields_, into an ISO Date Record.
+
+
+ 1. Perform ? CalendarResolveFields(_calendar_, _fields_, ~date~).
+ 1. Let _result_ be ? CalendarDateToISO(_calendar_, _fields_, _overflow_).
+ 1. If ISODateWithinLimits(_result_) is *false*, throw a *RangeError* exception.
+ 1. Return _result_.
+
+
+
+
+
+ CalendarYearMonthFromFields (
+ _calendar_: a calendar type,
+ _fields_: a Calendar Fields Record,
+ _overflow_: either ~constrain~ or ~reject~,
+ ): either a normal completion containing an ISO Date Record or a throw completion
+
+
+
description
+
It converts a calendar month in the reckoning of _calendar_, if it is uniquely determined by the properties on _fields_, into an ISO Date Record denoting the first day of that month.
+
+
+ 1. Set _fields_.[[Day]] to 1.
+ 1. Perform ? CalendarResolveFields(_calendar_, _fields_, ~year-month~).
+ 1. Let _result_ be ? CalendarDateToISO(_calendar_, _fields_, _overflow_).
+ 1. If ISOYearMonthWithinLimits(_result_) is *false*, throw a *RangeError* exception.
+ 1. Return _result_.
+
+
+
+
+
+ CalendarMonthDayFromFields (
+ _calendar_: a calendar type,
+ _fields_: a Calendar Fields Record,
+ _overflow_: either ~constrain~ or ~reject~,
+ ): either a normal completion containing an ISO Date Record or a throw completion
+
+
+
description
+
It converts a calendar month-day in the reckoning of _calendar_, if it is uniquely determined by the properties on _fields_, into an ISO Date Record denoting that day in an appropriate reference year.
+
+
+ 1. Perform ? CalendarResolveFields(_calendar_, _fields_, ~month-day~).
+ 1. Let _result_ be ? CalendarMonthDayToISOReferenceDate(_calendar_, _fields_, _overflow_).
+ 1. Assert: ISODateWithinLimits(_result_) is *true*.
+ 1. Return _result_.
+
+
+ The ISODateWithinLimits assertion holds because the result of CalendarMonthDayToISOReferenceDate should return a reference year that falls within the representable range.
+
+
+
+
+
+
Date Duration Records
+
+ A Date Duration Record is a Record value used to represent the portion of a Temporal.Duration object that deals with calendar date units.
+ Date Duration Records are produced by the abstract operation CreateDateDurationRecord, among others.
+
+
Date Duration Records have the fields listed in .
+
+
+
+
Field Name
+
Value
+
Meaning
+
+
+
[[Years]]
+
a float64-representable integer
+
+ The number of years in the duration.
+
+
+
+
[[Months]]
+
a float64-representable integer
+
+ The number of months in the duration.
+
+
+
+
[[Weeks]]
+
a float64-representable integer
+
+ The number of weeks in the duration.
+
+
+
+
[[Days]]
+
a float64-representable integer
+
+ The number of days in the duration.
+
+
+
+
+
+
+
+ AdjustDateDurationRecord (
+ _dateDuration_: a Date Duration Record,
+ _days_: an integer,
+ optional _weeks_: an integer,
+ optional _months_: an integer,
+ ): either a normal completion containing a Date Duration Record or a throw completion
+
+
+
description
+
It creates a new Date Duration Record that is a copy of _dateDuration_, with one or more fields replaced with new values.
+
+
+ 1. If _weeks_ is not present, set _weeks_ to _dateDuration_.[[Weeks]].
+ 1. If _months_ is not present, set _months_ to _dateDuration_.[[Months]].
+ 1. Return ? CreateDateDurationRecord(_dateDuration_.[[Years]], _months_, _weeks_, _days_).
+
+
+
+
+
+ CreateDateDurationRecord (
+ _years_: an integer,
+ _months_: an integer,
+ _weeks_: an integer,
+ _days_: an integer,
+ ): either a normal completion containing a Date Duration Record or a throw completion
+
+
+
description
+
+
+
+ 1. If IsValidDuration(_years_, _months_, _weeks_, _days_, 0, 0, 0, 0, 0, 0) is *false*, throw a *RangeError* exception.
+ 1. Return Date Duration Record {
+ [[Years]]: ℝ(𝔽(_years_)),
+ [[Months]]: ℝ(𝔽(_months_)),
+ [[Weeks]]: ℝ(𝔽(_weeks_)),
+ [[Days]]: ℝ(𝔽(_days_))
+ }.
+
+
+
+
+
+ DateDurationDays (
+ _dateDuration_: a Date Duration Record,
+ _plainRelativeTo_: a Temporal.PlainDate,
+ ): either a normal completion containing an integer or a throw completion
+
+
+
description
+
It converts the calendar units of a duration into a number of days, and returns the result.
+
+
+ 1. Let _yearsMonthsWeeksDuration_ be ! AdjustDateDurationRecord(_dateDuration_, 0).
+ 1. If DateDurationSign(_yearsMonthsWeeksDuration_) = 0, return _dateDuration_.[[Days]].
+ 1. Let _later_ be ? CalendarDateAdd(_plainRelativeTo_.[[Calendar]], _plainRelativeTo_.[[ISODate]], _yearsMonthsWeeksDuration_, ~constrain~).
+ 1. Let _epochDays1_ be ISODateToEpochDays(_plainRelativeTo_.[[ISODate]].[[Year]], _plainRelativeTo_.[[ISODate]].[[Month]] - 1, _plainRelativeTo_.[[ISODate]].[[Day]]).
+ 1. Let _epochDays2_ be ISODateToEpochDays(_later_.[[Year]], _later_.[[Month]] - 1, _later_.[[Day]]).
+ 1. Let _yearsMonthsWeeksInDays_ be _epochDays2_ - _epochDays1_.
+ 1. Return _dateDuration_.[[Days]] + _yearsMonthsWeeksInDays_.
+
+
+
+
+
+ DateDurationSign (
+ _dateDuration_: a Date Duration Record,
+ ): one of -1, 0, or 1
+
+
+
description
+
It returns 1 if the most significant non-zero field in the _dateDuration_ argument is positive, and -1 if the most significant non-zero field is negative. If all of _dateDuration_'s fields are zero, it returns 0.
+
+
+ 1. For each value _v_ of « _dateDuration_.[[Years]], _dateDuration_.[[Months]], _dateDuration_.[[Weeks]], _dateDuration_.[[Days]] », do
+ 1. If _v_ < 0, return -1.
+ 1. If _v_ > 0, return 1.
+ 1. Return 0.
+
+
+
+
+
ZeroDateDuration ( ): a Date Duration Record
+
+
description
+
The returned Record represents a duration with length 0.
A weekday value of 0 specifies Sunday; 1 specifies Monday; 2 specifies Tuesday; 3 specifies Wednesday; 4 specifies Thursday; 5 specifies Friday; and 6 specifies Saturday. Note that EpochTimeToWeekDay(0) = 4, corresponding to Thursday, 1 January 1970.
+
+
+
+ CheckISODaysRange (
+ _isoDate_: an ISO Date Record,
+ ): either a normal completion containing ~unused~ or a throw completion
+
+
+
description
+
It checks that the given date is within the range of 108 days from the epoch.
+
+
+ 1. If abs(ISODateToEpochDays(_isoDate_.[[Year]], _isoDate_.[[Month]] - 1, _isoDate_.[[Day]])) > 108, throw a *RangeError* exception.
+ 1. Return ~unused~.
+
+
+ This operation ensures that GetUTCEpochNanoseconds is not called with numbers that are too large, and can be removed when issue gh-1087 is fixed. It is distinct from ISODateWithinLimits.
+
+
+
+
+
+ EpochDaysToEpochMs (
+ _day_: an integer,
+ _time_: an integer,
+ ): an integer
+
+
+
description
+
It calculates a number of milliseconds as in MakeDate, using mathematical values.
+ ISODateToEpochDays (
+ _year_: an integer,
+ _month_: an integer,
+ _date_: an integer,
+ ): an integer
+
+
+
description
+
It calculates a number of days as in MakeDay, using mathematical values.
+
+
+ 1. Let _resolvedYear_ be _year_ + floor(_month_ / 12).
+ 1. Let _resolvedMonth_ be _month_ modulo 12.
+ 1. Find a time _t_ such that EpochTimeToEpochYear(_t_) = _resolvedYear_, EpochTimeToMonthInYear(_t_) = _resolvedMonth_, and EpochTimeToDate(_t_) = 1.
+ 1. Return EpochTimeToDayNumber(_t_) + _date_ - 1.
+
+
+
+
+
+
Epoch Nanoseconds and Range
+
+
An instant in time to nanosecond precision, or epoch nanoseconds value, as stored in the [[EpochNanoseconds]] internal slot of Temporal.Instant and Temporal.ZonedDateTime, is represented by an integer. It supports a range of exactly -100,000,000 to 100,000,000 days relative to midnight at the beginning of 1 January 1970 UTC, the same range as a time value. There is no nanosecond equivalent of the time value *NaN*; there is no representation for no specific instant.
+
+
The exact moment of midnight at the beginning of 1 January 1970 UTC is represented by the value 0. The maximum value is maxEpochNanoseconds, and the minimum value is minEpochNanoseconds.
+
+
+
+ AddEpochNanoseconds (
+ _epochNanoseconds_: an epoch nanoseconds value,
+ _timeDuration_: a time duration,
+ ): either a normal completion containing an epoch nanoseconds value or a throw completion
+
+
+
description
+
It adds a duration to a number of nanoseconds since the epoch.
+
+
+ 1. Let _result_ be AddTimeDurationToEpochNanoseconds(_timeDuration_, _epochNanoseconds_).
+ 1. If IsValidEpochNanoseconds(_result_) is *false*, throw a *RangeError* exception.
+ 1. Return _result_.
+
+
+
+
+
+ CompareEpochNanoseconds (
+ _epochNanosecondsOne_: an epoch nanoseconds value,
+ _epochNanosecondsTwo_: an epoch nanoseconds value,
+ ): either -1, 0, or 1
+
+ DifferenceEpochNanoseconds (
+ _ns1_: an epoch nanoseconds value,
+ _ns2_: an epoch nanoseconds value,
+ _roundingIncrement_: a positive integer,
+ _smallestUnit_: a time unit,
+ _roundingMode_: a rounding mode,
+ ): an Internal Duration Record
+
+
+
description
+
It computes the difference between two exact times _ns1_ and _ns2_ expressed in nanoseconds since the epoch, and rounds the result according to the parameters _roundingIncrement_, _smallestUnit_, and _roundingMode_.
+
+
+ 1. Let _timeDuration_ be TimeDurationFromEpochNanosecondsDifference(_ns2_, _ns1_).
+ 1. Set _timeDuration_ to ! RoundTimeDuration(_timeDuration_, _roundingIncrement_, _smallestUnit_, _roundingMode_).
+ 1. Return CombineDateAndTimeDuration(ZeroDateDuration(), _timeDuration_).
+
+
+
+
+
+ IsValidEpochNanoseconds (
+ _epochNanoseconds_: an epoch nanoseconds value,
+ ): a Boolean
+
+
+
description
+
It returns *true* if its argument is within the allowed range of nanoseconds since the epoch for a Temporal.Instant and Temporal.ZonedDateTime, and *false* otherwise.
+ RoundEpochNanoseconds (
+ _epochNanoseconds_: an epoch nanoseconds value,
+ _increment_: a positive integer,
+ _unit_: a time unit,
+ _roundingMode_: a rounding mode,
+ ): an epoch nanoseconds value
+
+
+
description
+
It rounds a number of nanoseconds _epochNanoseconds_ since the epoch to the given rounding increment.
+
+
+ 1. Let _unitLength_ be the value in the "Length in Nanoseconds" column of the row of whose "Value" column contains _unit_.
+ 1. Let _incrementNs_ be _increment_ × _unitLength_.
+ 1. Return RoundNumberToIncrementAsIfPositive(_epochNanoseconds_, _incrementNs_, _roundingMode_).
+
+
+
+
+
+
Internal Duration Records
+
+
+ A Internal Duration Record is a Record value used to represent the combination of a Date Duration Record with a time duration.
+ Such Records are used by operations that deal with both date and time portions of durations, such as RoundTimeDuration.
+
+
+
Internal Duration Records have the fields listed in .
+
+
+
+
Field Name
+
Value
+
Meaning
+
+
+
[[Date]]
+
a Date Duration Record
+
+ The date portion of the duration.
+
+
+
+
[[Time]]
+
a time duration
+
+ The time portion of the duration.
+
+
+
+
+
+
+
+ CombineDateAndTimeDuration (
+ _dateDuration_: a Date Duration Record,
+ _timeDuration_: a time duration,
+ ): an Internal Duration Record
+
+
+
description
+
+
+
+ 1. Let _dateSign_ be DateDurationSign(_dateDuration_).
+ 1. Let _timeSign_ be TimeDurationSign(_timeDuration_).
+ 1. Assert: If _dateSign_ ≠ 0 and _timeSign_ ≠ 0, _dateSign_ = _timeSign_.
+ 1. Return Internal Duration Record {
+ [[Date]]: _dateDuration_,
+ [[Time]]: _timeDuration_
+ }.
+
+
+
+
+
+ InternalDurationSign (
+ _internalDuration_: an Internal Duration Record,
+ ): one of -1, 0, or 1
+
+
+
description
+
It returns 1 if the most significant non-zero field in the _internalDuration_ argument is positive, and -1 if the most significant non-zero field is negative. If all of _internalDuration_'s fields are zero, it returns 0.
+
+
+ 1. Let _dateSign_ be DateDurationSign(_internalDuration_.[[Date]]).
+ 1. If _dateSign_ ≠ 0, return _dateSign_.
+ 1. Return TimeDurationSign(_internalDuration_.[[Time]]).
+
+
+
+
+
+ ToInternalDurationRecord (
+ _duration_: a Temporal.Duration,
+ ): an Internal Duration Record
+
+
+
description
+
It converts _duration_ into its internal form, for use in duration calculations that may involve time zones. The duration's days are kept separate and not converted into the [[Time]] field.
+
+
+ 1. Let _dateDuration_ be ! CreateDateDurationRecord(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]]).
+ 1. Let _timeDuration_ be TimeDurationFromComponents(_duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]]).
+ 1. Return CombineDateAndTimeDuration(_dateDuration_, _timeDuration_).
+
+
+
+
+
+ ToInternalDurationRecordWith24HourDays (
+ _duration_: a Temporal.Duration,
+ ): an Internal Duration Record
+
+
+
description
+
It converts _duration_ into its internal form, for use in duration calculations that do not involve time zones. The duration's days are assumed to be uniformly 24 hours, and the [[Date]].[[Days]] field of the returned Record is set to 0, while the [[Time]] field includes the days.
+
+
+ 1. Let _timeDuration_ be TimeDurationFromComponents(_duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]]).
+ 1. Set _timeDuration_ to ! Add24HourDaysToTimeDuration(_timeDuration_, _duration_.[[Days]]).
+ 1. Let _dateDuration_ be ! CreateDateDurationRecord(_duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], 0).
+ 1. Return CombineDateAndTimeDuration(_dateDuration_, _timeDuration_).
+
+
+
+
+
+
The ISO 8601 Calendar
+
+
+ The only calendar type that a conforming ECMA-262 implementation is required to support, is the ISO 8601 calendar.
+ This section contains definitions specific to calendrical calculations in the ISO 8601 calendar.
+
+
+
+
+ CompareSurpasses (
+ _sign_: either -1 or 1,
+ _year_: an integer,
+ _monthOrCode_: either an integer or a month code,
+ _day_: an integer,
+ _target_: a Calendar Date Record,
+ ): a Boolean
+
+
+
description
+
+ The return value indicates whether the ISO 8601 calendar date formed by _year_, _monthOrCode_, and _day_, which need not exist, surpasses _target_ in the direction denoted by _sign_.
+
+
+
+ 1. If _year_ ≠ _target_.[[Year]], then
+ 1. If _sign_ × (_year_ - _target_.[[Year]]) > 0, return *true*.
+ 1. Else if _monthOrCode_ is a month code and _monthOrCode_ is not _target_.[[MonthCode]], then
+ 1. If _sign_ > 0, then
+ 1. If _monthOrCode_ is lexicographically greater than _target_.[[MonthCode]], return *true*.
+ 1. Else,
+ 1. If _target_.[[MonthCode]] is lexicographically greater than _monthOrCode_, return *true*.
+ 1. Else if _monthOrCode_ is an integer and _monthOrCode_ ≠ _target_.[[Month]], then
+ 1. If _sign_ × (_monthOrCode_ - _target_.[[Month]]) > 0, return *true*.
+ 1. Else if _day_ ≠ _target_.[[Day]], then
+ 1. If _sign_ × (_day_ - _target_.[[Day]]) > 0, return *true*.
+ 1. Return *false*.
+
+
+
+
+
+ ISODateSurpasses (
+ _sign_: either -1 or 1,
+ _baseDate_: an ISO Date Record,
+ _isoDate2_: an ISO Date Record,
+ _years_: an integer,
+ _months_: an integer,
+ _weeks_: an integer,
+ _days_: an integer,
+ ): a Boolean
+
+
+
description
+
+ The return value indicates whether the date _isoDate1_, the result of adding the duration denoted by _years_, _months_, _weeks_, and _days_ to _baseDate_, surpasses _isoDate2_ in the direction denoted by _sign_.
+ If _weeks_ and _days_ are both zero, then _isoDate1_ need not exist (for example, it could be February 30).
+ Note that this operation is specific to date difference calculations and is not the same as CompareISODate.
+
+
+
+ 1. Let _parts_ be CalendarISOToDate(*"iso8601"*, _baseDate_).
+ 1. Let _target_ be CalendarISOToDate(*"iso8601"*, _isoDate2_).
+ 1. Let _y0_ be _parts_.[[Year]] + _years_.
+ 1. If CompareSurpasses(_sign_, _y0_, _parts_.[[MonthCode]], _parts_.[[Day]], _target_) is *true*, return *true*.
+ 1. If _months_ = 0, _weeks_ = 0, and _days_ = 0, return *false*.
+ 1. Let _m0_ be _parts_.[[Month]] + _months_.
+ 1. Let _monthsAdded_ be BalanceISOYearMonth(_y0_, _m0_).
+ 1. If CompareSurpasses(_sign_, _monthsAdded_.[[Year]], _monthsAdded_.[[Month]], _parts_.[[Day]], _target_) is *true*, return *true*.
+ 1. If _weeks_ = 0 and _days_ = 0, return *false*.
+ 1. Let _regulatedDate_ be ! RegulateISODate(_monthsAdded_.[[Year]], _monthsAdded_.[[Month]], _parts_.[[Day]], ~constrain~).
+ 1. Let _daysInWeek_ be 7.
+ 1. Let _balancedDate_ be AddDaysToISODate(_regulatedDate_, _daysInWeek_ * _weeks_ + _days_).
+ 1. Return CompareSurpasses(_sign_, _balancedDate_.[[Year]], _balancedDate_.[[Month]], _balancedDate_.[[Day]], _target_).
+
+
+
This operation intentionally uses overflow ~constrain~ when regulating the year-month. As a result, adding the duration returned by `.since` or `.until` to _baseDate_ may cause a *RangeError* exception when _overflow_ is ~reject~.
+
+
+
+
+
+ ISODaysInMonth (
+ _year_: an integer,
+ _month_: an integer in the inclusive interval from 1 to 12,
+ ): a positive integer
+
+
+
description
+
It returns the number of days in the given year and month in the ISO 8601 calendar.
+
+
+ 1. If _month_ is one of 1, 3, 5, 7, 8, 10, or 12, return 31.
+ 1. If _month_ is one of 4, 6, 9, or 11, return 30.
+ 1. Assert: _month_ = 2.
+ 1. Return 28 + MathematicalInLeapYear(EpochTimeForYear(_year_)).
+
+
+
+
+
Year-Week Records
+
+ The Year-Week Record specification type is returned by the week number calculation in ISOWeekOfYear, and the corresponding calculations for other calendars if applicable.
+ It comprises a calendar week of year with the corresponding week calendar year.
+
+
Year-Week Records have the fields listed in table .
+
+ Year-Week Record Fields
+
+
+
+
Field Name
+
Value
+
Meaning
+
+
+
+
[[Week]]
+
a positive integer or *undefined*
+
The calendar week of year.
+
+
+
[[Year]]
+
an integer or *undefined*
+
The week calendar year.
+
+
+
+
+
+
+
+ ISOWeekOfYear (
+ _isoDate_: an ISO Date Record,
+ ): a Year-Week Record
+
+
+
description
+
It determines where a calendar day falls in the ISO 8601 week calendar and calculates its calendar week of year, which is the 1-based ordinal number of its calendar week within the corresponding week calendar year (which may differ from _year_ by up to 1 in either direction).
+
+
+ 1. Let _year_ be _isoDate_.[[Year]].
+ 1. Let _wednesday_ be 3.
+ 1. Let _thursday_ be 4.
+ 1. Let _friday_ be 5.
+ 1. Let _saturday_ be 6.
+ 1. Let _daysInWeek_ be 7.
+ 1. Let _maxWeekNumber_ be 53.
+ 1. Let _dayOfYear_ be ISODayOfYear(_isoDate_).
+ 1. Let _dayOfWeek_ be ISODayOfWeek(_isoDate_).
+ 1. Let _week_ be floor((_dayOfYear_ + _daysInWeek_ - _dayOfWeek_ + _wednesday_) / _daysInWeek_).
+ 1. If _week_ < 1, then
+ 1. NOTE: This is the last week of the previous year.
+ 1. Let _jan1st_ be CreateISODateRecord(_year_, 1, 1).
+ 1. Let _dayOfJan1st_ be ISODayOfWeek(_jan1st_).
+ 1. If _dayOfJan1st_ = _friday_, then
+ 1. Return Year-Week Record { [[Week]]: _maxWeekNumber_, [[Year]]: _year_ - 1 }.
+ 1. If _dayOfJan1st_ = _saturday_, and MathematicalInLeapYear(EpochTimeForYear(_year_ - 1)) = 1, then
+ 1. Return Year-Week Record { [[Week]]: _maxWeekNumber_. [[Year]]: _year_ - 1 }.
+ 1. Return Year-Week Record { [[Week]]: _maxWeekNumber_ - 1, [[Year]]: _year_ - 1 }.
+ 1. If _week_ = _maxWeekNumber_, then
+ 1. Let _daysInYear_ be MathematicalDaysInYear(_year_).
+ 1. Let _daysLaterInYear_ be _daysInYear_ - _dayOfYear_.
+ 1. Let _daysAfterThursday_ be _thursday_ - _dayOfWeek_.
+ 1. If _daysLaterInYear_ < _daysAfterThursday_, then
+ 1. Return Year-Week Record { [[Week]]: 1, [[Year]]: _year_ + 1 }.
+ 1. Return Year-Week Record { [[Week]]: _week_, [[Year]]: _year_ }.
+
+ In the ISO 8601 week calendar, calendar week number 1 of a calendar year is the week including the first Thursday of that year (based on the principle that a week belongs to the same calendar year as the majority of its calendar days), which always includes January 4 and starts on the Monday on or immediately before then. Because of this, some calendar days of the first calendar week of a calendar year may be part of the _preceding_ [proleptic Gregorian] date calendar year, and some calendar days of the last calendar week of a calendar year may be part of the _following_ [proleptic Gregorian] date calendar year. See ISO 8601 for details.
+ For example, week calendar year 2020 includes both 31 December 2019 (a Tuesday belonging to its calendar week 1) and 1 January 2021 (a Friday belonging to its calendar week 53).
+
+
+
+
+ ISODayOfYear (
+ _isoDate_: an ISO Date Record,
+ ): an integer
+
+
+
description
+
It returns the ISO 8601 calendar day of year of a calendar day, which is its 1-based ordinal number within its ISO 8601 calendar year.
+ ISODayOfWeek (
+ _isoDate_: an ISO Date Record,
+ ): an integer
+
+
+
description
+
It returns the ISO 8601 calendar day of week of a calendar day, which is its 1-based ordinal position within the sequence of week calendar days that starts with Monday at 1 and ends with Sunday at 7.
+
+
+ 1. Let _epochDays_ be ISODateToEpochDays(_isoDate_.[[Year]], _isoDate_.[[Month]] - 1, _isoDate_.[[Day]]).
+ 1. Let _dayOfWeek_ be EpochTimeToWeekDay(EpochDaysToEpochMs(_epochDays_, 0)).
+ 1. If _dayOfWeek_ = 0, return 7.
+ 1. Return _dayOfWeek_.
+
+
+
+
+
+
ISO Date Records
+
+ An ISO Date Record is a Record value used to represent a valid calendar date in the ISO 8601 calendar, although the year may be outside of the allowed range for Temporal.
+ ISO Date Records are produced by the abstract operation CreateISODateRecord.
+ For any ISO Date Record _d_, IsValidISODate(_d_.[[Year]], _d_.[[Month]], _d_.[[Day]]) must return *true*.
+
+
ISO Date Records have the fields listed in .
+
+
+
+
Field Name
+
Value
+
Meaning
+
+
+
[[Year]]
+
an integer
+
+ The year in the ISO 8601 calendar.
+
+
+
+
[[Month]]
+
an integer between 1 and 12, inclusive
+
+ The number of the month in the ISO 8601 calendar.
+
+
+
+
[[Day]]
+
an integer between 1 and 31, inclusive
+
+ The number of the day of the month in the ISO 8601 calendar.
+
+
+
+
+
+
+
+ AddDaysToISODate (
+ _isoDate_: an ISO Date Record,
+ _days_: an integer,
+ ): an ISO Date Record
+
+
+
description
+
+ It adds _days_ to _isoDate_ into a valid calendar date in the ISO 8601 calendar as given by IsValidISODate, by overflowing out-of-range month or day values into the next-highest unit.
+ This date may be outside the range given by ISODateTimeWithinLimits.
+
+
+
+ 1. Let _epochDays_ be ISODateToEpochDays(_isoDate_.[[Year]], _isoDate_.[[Month]] - 1, _isoDate_.[[Day]]) + _days_.
+ 1. Let _epochMilliseconds_ be EpochDaysToEpochMs(_epochDays_, 0).
+ 1. Return CreateISODateRecord(EpochTimeToEpochYear(_epochMilliseconds_), EpochTimeToMonthInYear(_epochMilliseconds_) + 1, EpochTimeToDate(_epochMilliseconds_)).
+
+
+
+
+
+ CompareISODate (
+ _isoDate1_: an ISO Date Record,
+ _isoDate2_: an ISO Date Record,
+ ): one of -1, 0, or 1
+
+
+
description
+
+ It performs a comparison of the two dates denoted by _isoDate1_ and _isoDate2_ according to ISO 8601 calendar arithmetic.
+
+
+
+ 1. If _isoDate1_.[[Year]] > _isoDate2_.[[Year]], return 1.
+ 1. If _isoDate1_.[[Year]] < _isoDate2_.[[Year]], return -1.
+ 1. If _isoDate1_.[[Month]] > _isoDate2_.[[Month]], return 1.
+ 1. If _isoDate1_.[[Month]] < _isoDate2_.[[Month]], return -1.
+ 1. If _isoDate1_.[[Day]] > _isoDate2_.[[Day]], return 1.
+ 1. If _isoDate1_.[[Day]] < _isoDate2_.[[Day]], return -1.
+ 1. Return 0.
+
+
+
+
+
+ CreateISODateRecord (
+ _year_: an integer,
+ _month_: an integer between 1 and 12 inclusive,
+ _day_: an integer between 1 and 31 inclusive,
+ ): an ISO Date Record
+
+
+
description
+
+
+
+ 1. Assert: IsValidISODate(_year_, _month_, _day_) is *true*.
+ 1. Return ISO Date Record { [[Year]]: _year_, [[Month]]: _month_, [[Day]]: _day_ }.
+
+
+
+
+
+ ISODateToFields (
+ _calendar_: a calendar type,
+ _isoDate_: an ISO Date Record,
+ _type_: one of ~date~, ~year-month~, or ~month-day~,
+ ): a Calendar Fields Record
+
+
+
description
+
+
+
+ 1. Let _fields_ be an empty Calendar Fields Record with all fields set to ~unset~.
+ 1. Let _calendarDate_ be CalendarISOToDate(_calendar_, _isoDate_).
+ 1. Set _fields_.[[MonthCode]] to _calendarDate_.[[MonthCode]].
+ 1. If _type_ is either ~month-day~ or ~date~, then
+ 1. Set _fields_.[[Day]] to _calendarDate_.[[Day]].
+ 1. If _type_ is either ~year-month~ or ~date~, then
+ 1. Set _fields_.[[Year]] to _calendarDate_.[[Year]].
+ 1. Return _fields_.
+
+
+
+
+
+ ISODateWithinLimits (
+ _isoDate_: an ISO Date Record,
+ ): a Boolean
+
+
+
description
+
The return value is *true* if the date in the ISO 8601 calendar given by the argument is within the representable range of `Temporal.PlainDate`, and *false* otherwise.
+
+
+
Deferring to ISODateTimeWithinLimits with an hour of 12 avoids trouble at the extremes of the representable range of Temporal.PlainDateTime, which stops just before midnight on each end.
+
+
+ 1. Let _isoDateTime_ be CombineISODateAndTimeRecord(_isoDate_, NoonTimeRecord()).
+ 1. Return ISODateTimeWithinLimits(_isoDateTime_).
+
+
+
+
+
+ IsValidISODate (
+ _year_: an integer,
+ _month_: an integer,
+ _day_: an integer,
+ ): a Boolean
+
+
+
description
+
+ The return value is *true* if its arguments form a valid date in the ISO 8601 calendar, and *false* otherwise.
+ This includes dates that may fall outside of the allowed range for Temporal.
+
+
+
+ 1. If _month_ < 1 or _month_ > 12, return *false*.
+ 1. Let _daysInMonth_ be ISODaysInMonth(_year_, _month_).
+ 1. If _day_ < 1 or _day_ > _daysInMonth_, return *false*; else return *true*.
+
+
+
+
+
+ RegulateISODate (
+ _year_: an integer,
+ _month_: an integer,
+ _day_: an integer,
+ _overflow_: either ~constrain~ or ~reject~,
+ ): either a normal completion containing an ISO Date Record or a throw completion
+
+
+
description
+
+ It performs the overflow correction specified by _overflow_ on the values _year_, _month_, and _day_, in order to arrive at a valid date in the ISO 8601 calendar, as determined by IsValidISODate.
+ For ~reject~, values that do not form a valid date cause an exception to be thrown.
+ For ~constrain~, values that do not form a valid date are independently clamped to their respective valid range in order of descending unit magnitude.
+
+
+
+ 1. If _overflow_ is ~constrain~, then
+ 1. Set _month_ to the result of clamping _month_ between 1 and 12.
+ 1. Let _daysInMonth_ be ISODaysInMonth(_year_, _month_).
+ 1. Set _day_ to the result of clamping _day_ between 1 and _daysInMonth_.
+ 1. Else,
+ 1. Assert: _overflow_ is ~reject~.
+ 1. If IsValidISODate(_year_, _month_, _day_) is *false*, throw a *RangeError* exception.
+ 1. Return CreateISODateRecord(_year_, _month_, _day_).
+
+
+
+
+
+
ISO Date-Time Records
+
+ An ISO Date-Time Record is a Record value used to represent a valid calendar date in the ISO 8601 calendar together with a clock time.
+ For any ISO Date-Time Record _r_, IsValidISODate(_r_.[[ISODate]].[[Year]], _r_.[[ISODate]].[[Month]], _r_.[[ISODate]].[[Day]]) must return *true*, and IsValidTime(_r_.[[Time]].[[Hour]], _r_.[[Time]].[[Minute]], _r_.[[Time]].[[Second]], _r_.[[Time]].[[Millisecond]], _r_.[[Time]].[[Microsecond]], _r_.[[Time]].[[Nanosecond]]) must return *true*.
+ It is not necessary for ISODateTimeWithinLimits(_r__) to return *true*.
+
+
ISO Date-Time Records have the fields listed in .
+
+
+
+
Field Name
+
Value
+
Meaning
+
+
+
[[ISODate]]
+
an ISO Date Record
+
+ The date in the ISO 8601 calendar.
+
+
+
+
[[Time]]
+
a Time Record
+
The time. The [[Days]] field is ignored.
+
+
+
+
+
+
+ BalanceISODateTime (
+ _year_: an integer,
+ _month_: an integer,
+ _day_: an integer,
+ _hour_: an integer,
+ _minute_: an integer,
+ _second_: an integer,
+ _millisecond_: an integer,
+ _microsecond_: an integer,
+ _nanosecond_: an integer,
+ ): an ISO Date-Time Record
+
+
+
description
+
+
+
+ 1. Let _balancedTime_ be BalanceTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_).
+ 1. Let _balancedDate_ be AddDaysToISODate(CreateISODateRecord(_year_, _month_, _day_), _balancedTime_.[[Days]]).
+ 1. Return CombineISODateAndTimeRecord(_balancedDate_, _balancedTime_).
+
+
+
+
+
+ CombineISODateAndTimeRecord (
+ _isoDate_: an ISO Date Record,
+ _time_: a Time Record,
+ ): an ISO Date-Time Record
+
+
+
description
+
+ It combines a date and a time into one ISO Date-Time Record.
+
+
+
+ 1. NOTE: _time_.[[Days]] is ignored.
+ 1. Return ISO Date-Time Record { [[ISODate]]: _isoDate_, [[Time]]: _time_ }.
+
+
+
+
+
+ CompareISODateTime (
+ _isoDateTime1_: an ISO Date-Time Record,
+ _isoDateTime2_: an ISO Date-Time Record,
+ ): one of -1, 0, or 1
+
+
+
description
+
It performs a comparison of two date-times according to ISO 8601 calendar arithmetic.
+
+
+ 1. Let _dateResult_ be CompareISODate(_isoDateTime1_.[[ISODate]], _isoDateTime2_.[[ISODate]]).
+ 1. If _dateResult_ ≠ 0, return _dateResult_.
+ 1. Return CompareTimeRecord(_isoDateTime1_.[[Time]], _isoDateTime2_.[[Time]]).
+
+
+
+
+
+ DifferenceISODateTime (
+ _isoDateTime1_: an ISO Date-Time Record,
+ _isoDateTime2_: an ISO Date-Time Record,
+ _calendar_: a calendar type,
+ _largestUnit_: a Temporal unit,
+ ): an Internal Duration Record
+
+
+
description
+
+ The returned Internal Duration Record contains the elapsed duration from a first date and time, until a second date and time, according to the reckoning of the given calendar.
+ The given date and time units are all in the ISO 8601 calendar.
+
+
+
+ 1. Assert: ISODateTimeWithinLimits(_isoDateTime1_) is *true*.
+ 1. Assert: ISODateTimeWithinLimits(_isoDateTime2_) is *true*.
+ 1. Let _timeDuration_ be DifferenceTime(_isoDateTime1_.[[Time]], _isoDateTime2_.[[Time]]).
+ 1. Let _timeSign_ be TimeDurationSign(_timeDuration_).
+ 1. Let _dateSign_ be CompareISODate(_isoDateTime1_.[[ISODate]], _isoDateTime2_.[[ISODate]]).
+ 1. Let _adjustedDate_ be _isoDateTime2_.[[ISODate]].
+ 1. If _timeSign_ = _dateSign_, then
+ 1. Set _adjustedDate_ to AddDaysToISODate(_adjustedDate_, _timeSign_).
+ 1. Set _timeDuration_ to ! Add24HourDaysToTimeDuration(_timeDuration_, -_timeSign_).
+ 1. Let _dateLargestUnit_ be LargerOfTwoTemporalUnits(~day~, _largestUnit_).
+ 1. Let _dateDifference_ be CalendarDateUntil(_calendar_, _isoDateTime1_.[[ISODate]], _adjustedDate_, _dateLargestUnit_).
+ 1. If _largestUnit_ is not _dateLargestUnit_, then
+ 1. Set _timeDuration_ to ! Add24HourDaysToTimeDuration(_timeDuration_, _dateDifference_.[[Days]]).
+ 1. Set _dateDifference_.[[Days]] to 0.
+ 1. Return CombineDateAndTimeDuration(_dateDifference_, _timeDuration_).
+
+
+
+
+
+ ISODateTimeWithinLimits (
+ _isoDateTime_: an ISO Date-Time Record,
+ ): a Boolean
+
+
+
description
+
The return value is *true* if the combination of a date in the ISO 8601 calendar with a wall-clock time, given by the arguments, is within the representable range of `Temporal.PlainDateTime`, and *false* otherwise.
+
+
+
+ Temporal.PlainDateTime objects can represent points in time within 24 hours (8.64 × 1013 nanoseconds) of the Temporal.Instant boundaries.
+ This ensures that a Temporal.Instant object can be converted into a Temporal.PlainDateTime object using any time zone.
+
+ RoundISODateTime (
+ _isoDateTime_: an ISO Date-Time Record,
+ _increment_: a positive integer,
+ _unit_: either a time unit or ~day~,
+ _roundingMode_: a rounding mode,
+ ): an ISO Date-Time Record
+
+
+
description
+
It rounds the time part of a combined date and time, carrying over any excess into the date part.
+
+
+ 1. Assert: ISODateTimeWithinLimits(_isoDateTime_) is *true*.
+ 1. Let _roundedTime_ be RoundTime(_isoDateTime_.[[Time]], _increment_, _unit_, _roundingMode_).
+ 1. Let _balanceResult_ be AddDaysToISODate(_isoDateTime_.[[ISODate]], _roundedTime_.[[Days]]).
+ 1. Return CombineISODateAndTimeRecord(_balanceResult_, _roundedTime_).
+
+
+
+
+
+ TimeValueToISODateTimeRecord (
+ _t_: a finite time value,
+ ): an ISO Date-Time Record
+
+
+
description
+
+ It converts a time value into an ISO Date-Time Record.
+
+
+
+ 1. Let _isoDate_ be CreateISODateRecord(ℝ(YearFromTime(_t_)), ℝ(MonthFromTime(_t_)) + 1, ℝ(DateFromTime(_t_))).
+ 1. Let _time_ be CreateTimeRecord(ℝ(HourFromTime(_t_)), ℝ(MinFromTime(_t_)), ℝ(SecFromTime(_t_)), ℝ(msFromTime(_t_)), 0, 0).
+ 1. Return CombineISODateAndTimeRecord(_isoDate_, _time_).
+
+
+
+
+
+
Month Codes
+
+
+ Lunisolar calendars may insert leap months into certain years, in order to reconcile the discrepancy between lunar cycles and the solar year.
+ For this reason, a particular month may not have the same ordinal number every year if a leap month is inserted before it.
+
+
+ A month code is a String that refers uniquely to a particular month, even one that is not present every year.
+ Month codes are lexicographically ordered according to the notional order of months in the year, even though not all may be present in any given year.
+ They conform to the following string format:
+
+
+ The month code for a month that is not a leap month and whose 1-based ordinal position in a common year of the calendar (i.e., a year that is not a leap year) is _n_ is the string-concatenation of *"M"* and ToZeroPaddedDecimalString(_n_, 2).
+ The month code for a leap month inserted after a month whose 1-based ordinal position in a common year of the calendar is _p_, is the string-concatenation of *"M"*, ToZeroPaddedDecimalString(_p_, 2), and *"L"*.
+
+
The month codes in the ISO 8601 calendar, which does not have leap months, are *"M01"* for January through *"M12"* for December.
+
+ For example, in the Hebrew calendar, the month code of Adar (and Adar II, in leap years) is *"M06"* and the month code of Adar I (the leap month inserted before Adar II) is *"M05L"*.
+ Theoretically, in a calendar with a leap month at the start of some years, the month code of that month would be *"M00L"*.
+
+
+
+
+ CreateMonthCode (
+ _monthNumber_: an integer in the inclusive interval from 0 to 99,
+ _isLeapMonth_: a Boolean,
+ ): a month code
+
+
+
description
+
+ It creates a month code with the given month number and leap month flag.
+
+
+
It performs the following steps when called:
+
+ 1. Assert: If _isLeapMonth_ is *false*, _monthNumber_ > 0.
+ 1. Let _numberPart_ be ToZeroPaddedDecimalString(_monthNumber_, 2).
+ 1. If _isLeapMonth_ is *true*, then
+ 1. Return the string-concatenation of the code unit 0x004D (LATIN CAPITAL LETTER M), _numberPart_, and the code unit 0x004C (LATIN CAPITAL LETTER L).
+ 1. Return the string-concatenation of the code unit 0x004D (LATIN CAPITAL LETTER M) and _numberPart_.
+
+
+
+
+
+ ParseMonthCode (
+ _argument_: an ECMAScript language value,
+ ): either a normal completion containing a Record with fields [[MonthNumber]] (an integer) and [[IsLeapMonth]] (a Boolean) or a throw completion
+
+
+
description
+
+ It converts _argument_ to a month code and parses it into its parts, or throws a *TypeError* if conversion to String fails, or throws a *RangeError* if the result is not a syntactically valid month code.
+ The month code is not guaranteed to be correct in the context of any particular calendar; for example, some calendars do not have leap months.
+
+
+
It performs the following steps when called:
+
+ 1. Let _monthCode_ be ? ToPrimitive(_argument_, ~string~).
+ 1. If _monthCode_ is not a String, throw a *TypeError* exception.
+ 1. If ParseText(StringToCodePoints(_monthCode_), |MonthCode|) is a List of errors, throw a *RangeError* exception.
+ 1. Let _isLeapMonth_ be *false*.
+ 1. If the length of _monthCode_ = 4, then
+ 1. Assert: The fourth code unit of _monthCode_ is 0x004C (LATIN CAPITAL LETTER L).
+ 1. Set _isLeapMonth_ to *true*.
+ 1. Let _monthCodeDigits_ be the substring of _monthCode_ from 1 to 3.
+ 1. Let _monthNumber_ be ℝ(StringToNumber(_monthCodeDigits_)).
+ 1. Return the Record { [[MonthNumber]]: _monthNumber_, [[IsLeapMonth]]: _isLeapMonth_ }.
+
+
+ MonthCode :::
+ `M00L`
+ `M0` NonZeroDigit `L`?
+ `M` NonZeroDigit DecimalDigit `L`?
+
+
+
+
+
+
Operations for Reading Options
+
+
+ This section defines abstract operations for reading the properties of options Objects passed to Temporal functions.
+ For example, GetTemporalOverflowOption accesses the *"overflow"* property of an Object, ensures that it is one of the allowed values *"constrain"* or *"reject"*, and returns one of the corresponding Enum specification types ~constrain~ or ~reject~.
+
+
+
+
+ GetDifferenceSettings (
+ _operation_: either ~since~ or ~until~,
+ _options_: an Object,
+ _unitGroup_: one of ~date~, ~time~, or ~datetime~,
+ _disallowedUnits_: a List of Temporal units,
+ _fallbackSmallestUnit_: a Temporal unit,
+ _smallestLargestDefaultUnit_: a Temporal unit,
+ ): either a normal completion containing a Record with fields [[SmallestUnit]] (a Temporal unit), [[LargestUnit]] (a Temporal unit), [[RoundingMode]] (a rounding mode), and [[RoundingIncrement]] (an integer in the inclusive interval from 1 to 109), or a throw completion
+
+
+
description
+
It reads unit and rounding options needed by difference operations.
+
+
+ 1. NOTE: The following steps read options and perform independent validation in alphabetical order.
+ 1. Let _largestUnit_ be ? GetTemporalUnitValuedOption(_options_, *"largestUnit"*, ~unset~).
+ 1. Let _roundingIncrement_ be ? GetRoundingIncrementOption(_options_).
+ 1. Let _roundingMode_ be ? GetRoundingModeOption(_options_, ~trunc~).
+ 1. Let _smallestUnit_ be ? GetTemporalUnitValuedOption(_options_, *"smallestUnit"*, ~unset~).
+ 1. Perform ? ValidateTemporalUnitValue(_largestUnit_, _unitGroup_, « ~auto~ »).
+ 1. If _largestUnit_ is ~unset~, then
+ 1. Set _largestUnit_ to ~auto~.
+ 1. If _disallowedUnits_ contains _largestUnit_, throw a *RangeError* exception.
+ 1. Perform ? ValidateTemporalUnitValue(_smallestUnit_, _unitGroup_).
+ 1. If _smallestUnit_ is ~unset~, then
+ 1. Set _smallestUnit_ to _fallbackSmallestUnit_.
+ 1. If _disallowedUnits_ contains _smallestUnit_, throw a *RangeError* exception.
+ 1. Let _defaultLargestUnit_ be LargerOfTwoTemporalUnits(_smallestLargestDefaultUnit_, _smallestUnit_).
+ 1. If _largestUnit_ is ~auto~, set _largestUnit_ to _defaultLargestUnit_.
+ 1. If LargerOfTwoTemporalUnits(_largestUnit_, _smallestUnit_) is not _largestUnit_, throw a *RangeError* exception.
+ 1. Let _maximum_ be MaximumTemporalDurationRoundingIncrement(_smallestUnit_).
+ 1. If _maximum_ is not ~unset~, perform ? ValidateTemporalRoundingIncrement(_roundingIncrement_, _maximum_, *false*).
+ 1. If _operation_ is ~since~, then
+ 1. Set _roundingMode_ to NegateRoundingMode(_roundingMode_).
+ 1. Return the Record {
+ [[SmallestUnit]]: _smallestUnit_,
+ [[LargestUnit]]: _largestUnit_,
+ [[RoundingMode]]: _roundingMode_,
+ [[RoundingIncrement]]: _roundingIncrement_,
+ }.
+
+
+
+
+
+ GetDirectionOption (
+ _options_: an Object,
+ ): either a normal completion containing either ~next~ or ~previous~, or a throw completion
+
+
+
description
+
It fetches and validates the *"direction"* property from _options_, throwing if absent.
+
+
+ 1. Let _value_ be ? Get(_options_, *"direction"*).
+ 1. If _value_ is *undefined*, throw a *RangeError* exception.
+ 1. Let _stringValue_ be ? ToString(_value_).
+ 1. If _stringValue_ is *"next"*, return ~next~.
+ 1. If _stringValue_ is *"previous"*, return ~previous~.
+ 1. Throw a *RangeError* exception.
+
+
+
+
+
+ GetRoundingIncrementOption (
+ _options_: an Object,
+ ): either a normal completion containing a positive integer in the inclusive interval from 1 to 109, or a throw completion
+
+
+
description
+
+ It fetches and validates the *"roundingIncrement"* property from _options_, returning a default if absent.
+
+
+
+ 1. Let _value_ be ? Get(_options_, *"roundingIncrement"*).
+ 1. If _value_ is *undefined*, return *1*𝔽.
+ 1. Let _integerIncrement_ be ? ToIntegerWithTruncation(_value_).
+ 1. If _integerIncrement_ < 1 or _integerIncrement_ > 109, throw a *RangeError* exception.
+ 1. Return _integerIncrement_.
+
+
+
+
+
+ GetRoundingModeOption (
+ _options_: an Object,
+ _fallback_: a rounding mode,
+ ): either a normal completion containing a rounding mode, or a throw completion
+
+
+
description
+
It fetches and validates the *"roundingMode"* property from _options_, returning _fallback_ as a default if absent.
+
+
+ 1. Let _value_ be ? Get(_options_, *"roundingMode"*).
+ 1. If _value_ is *undefined*, return _fallback_.
+ 1. Let _stringValue_ be ? ToString(_value_).
+ 1. If _stringValue_ is not one of the Strings from the "String Identifier" column of , throw a *RangeError*.
+ 1. Return the value from the "Rounding Mode" column of the row with _stringValue_ in its "String Identifier" column.
+
+
+
+
+
+ GetTemporalDisambiguationOption (
+ _options_: an Object,
+ ): either a normal completion containing either ~compatible~, ~earlier~, ~later~, or ~reject~, or a throw completion
+
+
+
description
+
It fetches and validates the *"disambiguation"* property of _options_, returning a default if absent.
+
+
+ 1. Let _value_ be ? Get(_options_, *"disambiguation"*).
+ 1. If _value_ is *undefined*, return ~compatible~.
+ 1. Let _stringValue_ be ? ToString(_value_).
+ 1. If _stringValue_ is *"compatible"*, return ~compatible~.
+ 1. If _stringValue_ is *"earlier"*, return ~earlier~.
+ 1. If _stringValue_ is *"later"*, return ~later~.
+ 1. If _stringValue_ is *"reject"*, return ~reject~.
+ 1. Throw a *RangeError* exception.
+
+
+
+
+
+ GetTemporalFractionalSecondDigitsOption (
+ _options_: an Object,
+ ): either a normal completion containing either ~auto~ or an integer in the inclusive interval from 0 to 9, or a throw completion
+
+
+
description
+
It fetches and validates the *"fractionalSecondDigits"* property from _options_, returning a default if absent.
+
+
+ 1. Let _digitsValue_ be ? Get(_options_, *"fractionalSecondDigits"*).
+ 1. If _digitsValue_ is *undefined*, return ~auto~.
+ 1. If _digitsValue_ is not a Number, then
+ 1. If ? ToString(_digitsValue_) is not *"auto"*, throw a *RangeError* exception.
+ 1. Return ~auto~.
+ 1. If _digitsValue_ is one of *NaN*, *+∞*𝔽, or *-∞*𝔽, throw a *RangeError* exception.
+ 1. Let _digitCount_ be floor(ℝ(_digitsValue_)).
+ 1. If _digitCount_ < 0 or _digitCount_ > 9, throw a *RangeError* exception.
+ 1. Return _digitCount_.
+
+
+
+
+
+ GetTemporalOffsetOption (
+ _options_: an Object,
+ _fallback_: one of ~prefer~, ~use~, ~ignore~, or ~reject~,
+ ): either a normal completion containing either ~prefer~, ~use~, ~ignore~, or ~reject~, or a throw completion
+
+
+
description
+
It fetches and validates the *"offset"* property of _options_, returning _fallback_ as a default if absent.
+
+
+ 1. Let _value_ be ? Get(_options_, *"offset"*).
+ 1. If _value_ is *undefined*, return _fallback_.
+ 1. Let _stringValue_ be ? ToString(_value_).
+ 1. If _stringValue_ is *"prefer"*, return ~prefer~.
+ 1. If _stringValue_ is *"use"*, return ~use~.
+ 1. If _stringValue_ is *"ignore"*, return ~ignore~.
+ 1. If _stringValue_ is *"reject"*, return ~reject~.
+ 1. Throw a *RangeError* exception.
+
+
+
+
+
+ GetTemporalOverflowOption (
+ _options_: an Object,
+ ): either a normal completion containing either ~constrain~ or ~reject~, or a throw completion
+
+
+
description
+
It fetches and validates the *"overflow"* property of _options_, returning a default if absent.
+
+
+ 1. Let _value_ be ? Get(_options_, *"overflow"*).
+ 1. If _value_ is *undefined*, return ~constrain~.
+ 1. Let _stringValue_ be ? ToString(_value_).
+ 1. If _stringValue_ is *"constrain"*, return ~constrain~.
+ 1. If _stringValue_ is *"reject"*, return ~reject~.
+ 1. Throw a *RangeError* exception.
+
+
+
+
+
+ GetTemporalRelativeToOption (
+ _options_: an Object,
+ ): either a normal completion containing a Record with fields [[PlainRelativeTo]] (a Temporal.PlainDate or *undefined*) and [[ZonedRelativeTo]] (a Temporal.ZonedDateTime or *undefined*), or a throw completion
+
+
+
description
+
+ It examines the value of the `relativeTo` property of its _options_ argument.
+ If the value is *undefined*, both the [[PlainRelativeTo]] and [[ZonedRelativeTo]] fields of the returned Record are *undefined*.
+ If the value is not a String or an Object, it throws a *TypeError*.
+ Otherwise, it attempts to return a Temporal.ZonedDateTime instance in the [[ZonedRelativeTo]] field, or a Temporal.PlainDate instance in the [[PlainRelativeTo]] field, in order of preference, by converting the value.
+ If neither of those are possible, it throws a *RangeError*.
+
+
+
+ 1. Let _value_ be ? Get(_options_, *"relativeTo"*).
+ 1. If _value_ is *undefined*, return the Record { [[PlainRelativeTo]]: *undefined*, [[ZonedRelativeTo]]: *undefined* }.
+ 1. Let _offsetBehaviour_ be ~option~.
+ 1. Let _matchBehaviour_ be ~match-exactly~.
+ 1. If _value_ is an Object, then
+ 1. If _value_ has an [[InitializedTemporalZonedDateTime]] internal slot, then
+ 1. Return the Record { [[PlainRelativeTo]]: *undefined*, [[ZonedRelativeTo]]: _value_ }.
+ 1. If _value_ has an [[InitializedTemporalDate]] internal slot, then
+ 1. Return the Record { [[PlainRelativeTo]]: _value_, [[ZonedRelativeTo]]: *undefined* }.
+ 1. If _value_ has an [[InitializedTemporalDateTime]] internal slot, then
+ 1. Let _plainDate_ be ! CreateTemporalDate(_value_.[[ISODateTime]].[[ISODate]], _value_.[[Calendar]]).
+ 1. Return the Record { [[PlainRelativeTo]]: _plainDate_, [[ZonedRelativeTo]]: *undefined* }.
+ 1. Let _calendar_ be ? GetTemporalCalendarIdentifierWithISODefault(_value_).
+ 1. Let _fields_ be ? PrepareCalendarFields(_calendar_, _value_, « ~year~, ~month~, ~month-code~, ~day~ », « ~hour~, ~minute~, ~second~, ~millisecond~, ~microsecond~, ~nanosecond~, ~offset~, ~time-zone~ », «»).
+ 1. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, ~constrain~).
+ 1. Let _timeZone_ be _fields_.[[TimeZone]].
+ 1. Let _offsetString_ be _fields_.[[OffsetString]].
+ 1. If _offsetString_ is ~unset~, then
+ 1. Set _offsetBehaviour_ to ~wall~.
+ 1. Let _isoDate_ be _result_.[[ISODate]].
+ 1. Let _time_ be _result_.[[Time]].
+ 1. Else,
+ 1. If _value_ is not a String, throw a *TypeError* exception.
+ 1. Let _result_ be ? ParseISODateTime(_value_, « |TemporalDateTimeString[+Zoned]|, |TemporalDateTimeString[~Zoned]| »).
+ 1. Let _offsetString_ be _result_.[[TimeZone]].[[OffsetString]].
+ 1. Let _annotation_ be _result_.[[TimeZone]].[[TimeZoneAnnotation]].
+ 1. If _annotation_ is ~empty~, then
+ 1. Let _timeZone_ be ~unset~.
+ 1. Else,
+ 1. Let _timeZone_ be ? ToTemporalTimeZoneIdentifier(_annotation_).
+ 1. If _result_.[[TimeZone]].[[Z]] is *true*, then
+ 1. Set _offsetBehaviour_ to ~exact~.
+ 1. Else if _offsetString_ is ~empty~, then
+ 1. Set _offsetBehaviour_ to ~wall~.
+ 1. Set _matchBehaviour_ to ~match-minutes~.
+ 1. If _offsetString_ is not ~empty~, then
+ 1. Let _offsetParseResult_ be ParseText(StringToCodePoints(_offsetString_), |UTCOffset[+SubMinutePrecision]|).
+ 1. Assert: _offsetParseResult_ is a Parse Node.
+ 1. If _offsetParseResult_ contains more than one |MinuteSecond| Parse Node, set _matchBehaviour_ to ~match-exactly~.
+ 1. Let _calendar_ be _result_.[[Calendar]].
+ 1. If _calendar_ is ~empty~, set _calendar_ to *"iso8601"*.
+ 1. Set _calendar_ to ? CanonicalizeCalendar(_calendar_).
+ 1. Let _isoDate_ be CreateISODateRecord(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]]).
+ 1. Let _time_ be _result_.[[Time]].
+ 1. If _timeZone_ is ~unset~, then
+ 1. Let _plainDate_ be ? CreateTemporalDate(_isoDate_, _calendar_).
+ 1. Return the Record { [[PlainRelativeTo]]: _plainDate_, [[ZonedRelativeTo]]: *undefined* }.
+ 1. If _offsetBehaviour_ is ~option~, then
+ 1. Let _offsetNs_ be ! ParseDateTimeUTCOffset(_offsetString_).
+ 1. Else,
+ 1. Let _offsetNs_ be 0.
+ 1. Let _epochNanoseconds_ be ? InterpretISODateTimeOffset(_isoDate_, _time_, _offsetBehaviour_, _offsetNs_, _timeZone_, ~compatible~, ~reject~, _matchBehaviour_).
+ 1. Let _zonedRelativeTo_ be ! CreateTemporalZonedDateTime(_epochNanoseconds_, _timeZone_, _calendar_).
+ 1. Return the Record { [[PlainRelativeTo]]: *undefined*, [[ZonedRelativeTo]]: _zonedRelativeTo_ }.
+
+
+
+
+
+ GetTemporalShowCalendarNameOption (
+ _options_: an Object,
+ ): either a normal completion containing either ~auto~, ~always~, ~never~, or ~critical~, or a throw completion
+
+
+
description
+
It fetches and validates the *"calendarName"* property from _options_, returning a default if absent.
+
+
+ This property is used in `toString` methods in Temporal to control whether a calendar annotation should be output.
+
+
+ 1. Let _value_ be ? Get(_options_, *"calendarName"*).
+ 1. If _value_ is *undefined*, return ~auto~.
+ 1. Let _stringValue_ be ? ToString(_value_).
+ 1. If _stringValue_ is *"always"*, return ~always~.
+ 1. If _stringValue_ is *"never"*, return ~never~.
+ 1. If _stringValue_ is *"critical"*, return ~critical~.
+ 1. If _stringValue_ is *"auto"*, return ~auto~.
+ 1. Throw a *RangeError* exception.
+
+
+
+
+
+ GetTemporalShowOffsetOption (
+ _options_: an Object,
+ ): either a normal completion containing either ~auto~ or ~never~, or a throw completion
+
+
+
description
+
It fetches and validates the *"offset"* property from _options_, returning a default if absent.
+
+
+ This property is used in `Temporal.ZonedDateTime.prototype.toString()`.
+ It is different from the `offset` property passed to `Temporal.ZonedDateTime.from()`.
+
+
+ 1. Let _value_ be ? Get(_options_, *"offset"*).
+ 1. If _value_ is *undefined*, return ~auto~.
+ 1. Let _stringValue_ be ? ToString(_value_).
+ 1. If _stringValue_ is *"never"*, return ~never~.
+ 1. If _stringValue_ is *"auto"*, return ~auto~.
+ 1. Throw a *RangeError* exception.
+
+
+
+
+
+ GetTemporalShowTimeZoneNameOption (
+ _options_: an Object,
+ ): either a normal completion containing either ~auto~, ~never~, or ~critical~, or a throw completion
+
+
+
description
+
It fetches and validates the *"timeZoneName"* property from _options_, returning a default if absent.
+
+
+ This property is used in `Temporal.ZonedDateTime.prototype.toString()`.
+ It is different from the `timeZone` property passed to `Temporal.ZonedDateTime.from()` and from the `timeZone` property in the options passed to `Temporal.Instant.prototype.toString()`.
+
+
+ 1. Let _value_ be ? Get(_options_, *"timeZoneName"*).
+ 1. If _value_ is *undefined*, return ~auto~.
+ 1. Let _stringValue_ be ? ToString(_value_).
+ 1. If _stringValue_ is *"never"*, return ~never~.
+ 1. If _stringValue_ is *"critical"*, return ~critical~.
+ 1. If _stringValue_ is *"auto"*, return ~auto~.
+ 1. Throw a *RangeError* exception.
+
+
+
+
+
+ GetTemporalUnitValuedOption (
+ _options_: an Object,
+ _key_: a property key,
+ _default_: either ~required~ or ~unset~,
+ ): either a normal completion containing either a Temporal unit, ~unset~, or ~auto~, or a throw completion
+
+
+
description
+
It attempts to read a Temporal unit from the specified property of _options_.
+
+
Both singular and plural unit names are accepted, but only the singular form is used internally.
+
+ 1. Let _value_ be ? Get(_options_, _key_).
+ 1. If _value_ is *undefined*, then
+ 1. If _default_ is ~required~, throw a *RangeError* exception.
+ 1. Return ~unset~.
+ 1. Let _stringValue_ be ? ToString(_value_).
+ 1. If _stringValue_ is *"auto"*, return ~auto~.
+ 1. If _stringValue_ is not listed in the "Singular property name" or "Plural property name" columns of , throw a *RangeError* exception.
+ 1. Return the value in the "Value" column of corresponding to the row with _stringValue_ in its "Singular property name" or "Plural property name" column.
+
+
+
+
+
+
Rounding Modes and Increments
+
+
+ This section contains definitions pertaining to rounding increments and rounding modes.
+ Several Temporal Objects provide the capability of rounding a quantity to a given increment, following different rounding rules.
+
+
+ A rounding mode is one of the values in the "Rounding Mode" column of .
+ An unsigned rounding mode is one of the values in the "Unsigned Rounding Mode" column of .
+
+
+
+ Rounding modes
+
+
+
+
Rounding Mode
+
String Identifier
+
Description
+
Examples: Round to 0 fraction digits
+
+
+
-1.5
+
0.4
+
0.5
+
0.6
+
1.5
+
+
+
+
~ceil~
+
*"ceil"*
+
Toward positive infinity
+
⬆️ [-1]
+
⬆️ [1]
+
⬆️ [1]
+
⬆️ [1]
+
⬆️ [2]
+
+
+
~floor~
+
*"floor"*
+
Toward negative infinity
+
⬇️ [-2]
+
⬇️ [0]
+
⬇️ [0]
+
⬇️ [0]
+
⬇️ [1]
+
+
+
~expand~
+
*"expand"*
+
Away from zero
+
⬇️ [-2]
+
⬆️ [1]
+
⬆️ [1]
+
⬆️ [1]
+
⬆️ [2]
+
+
+
~trunc~
+
*"trunc"*
+
Toward zero
+
⬆️ [-1]
+
⬇️ [0]
+
⬇️ [0]
+
⬇️ [0]
+
⬇️ [1]
+
+
+
~half-ceil~
+
*"halfCeil"*
+
Ties toward positive infinity
+
⬆️ [-1]
+
⬇️ [0]
+
⬆️ [1]
+
⬆️ [1]
+
⬆️ [2]
+
+
+
~half-floor~
+
*"halfFloor"*
+
Ties toward negative infinity
+
⬇️ [-2]
+
⬇️ [0]
+
⬇️ [0]
+
⬆️ [1]
+
⬇️ [1]
+
+
+
~half-expand~
+
*"halfExpand"*
+
Ties away from zero
+
⬇️ [-2]
+
⬇️ [0]
+
⬆️ [1]
+
⬆️ [1]
+
⬆️ [2]
+
+
+
~half-trunc~
+
*"halfTrunc"*
+
Ties toward zero
+
⬆️ [-1]
+
⬇️ [0]
+
⬇️ [0]
+
⬆️ [1]
+
⬇️ [1]
+
+
+
~half-even~
+
*"halfEven"*
+
Ties toward an even rounding increment multiple
+
⬇️ [-2]
+
⬇️ [0]
+
⬇️ [0]
+
⬆️ [1]
+
⬆️ [2]
+
+
+ The examples are illustrative of the unique behaviour of each option. ⬆️ means "resolves toward positive infinity"; ⬇️ means "resolves toward negative infinity".
+
+
+
+ Conversion from rounding mode to unsigned rounding mode
+
+
+
+
Rounding Mode
+
Sign
+
Unsigned Rounding Mode
+
+
+
+
~ceil~
+
~positive~
+
~infinity~
+
+
+
~negative~
+
~zero~
+
+
+
~floor~
+
~positive~
+
~zero~
+
+
+
~negative~
+
~infinity~
+
+
+
~expand~
+
~positive~
+
~infinity~
+
+
+
~negative~
+
~infinity~
+
+
+
~trunc~
+
~positive~
+
~zero~
+
+
+
~negative~
+
~zero~
+
+
+
~half-ceil~
+
~positive~
+
~half-infinity~
+
+
+
~negative~
+
~half-zero~
+
+
+
~half-floor~
+
~positive~
+
~half-zero~
+
+
+
~negative~
+
~half-infinity~
+
+
+
~half-expand~
+
~positive~
+
~half-infinity~
+
+
+
~negative~
+
~half-infinity~
+
+
+
~half-trunc~
+
~positive~
+
~half-zero~
+
+
+
~negative~
+
~half-zero~
+
+
+
~half-even~
+
~positive~
+
~half-even~
+
+
+
~negative~
+
~half-even~
+
+
+
+
+
+
+ ApplyUnsignedRoundingMode (
+ _x_: a mathematical value,
+ _r1_: a mathematical value,
+ _r2_: a mathematical value,
+ _unsignedRoundingMode_: either a specification type from the "Unsigned Rounding Mode" column of or *undefined*,
+ ): a mathematical value
+
+
+
description
+
It considers _x_, bracketed below by _r1_ and above by _r2_, and returns either _r1_ or _r2_ according to _unsignedRoundingMode_.
+
+
+ 1. If _x_ = _r1_, return _r1_.
+ 1. Assert: _r1_ < _x_ < _r2_.
+ 1. Assert: _unsignedRoundingMode_ is not *undefined*.
+ 1. If _unsignedRoundingMode_ is ~zero~, return _r1_.
+ 1. If _unsignedRoundingMode_ is ~infinity~, return _r2_.
+ 1. Let _d1_ be _x_ – _r1_.
+ 1. Let _d2_ be _r2_ – _x_.
+ 1. If _d1_ < _d2_, return _r1_.
+ 1. If _d2_ < _d1_, return _r2_.
+ 1. Assert: _d1_ is equal to _d2_.
+ 1. If _unsignedRoundingMode_ is ~half-zero~, return _r1_.
+ 1. If _unsignedRoundingMode_ is ~half-infinity~, return _r2_.
+ 1. Assert: _unsignedRoundingMode_ is ~half-even~.
+ 1. Let _cardinality_ be (_r1_ / (_r2_ – _r1_)) modulo 2.
+ 1. If _cardinality_ = 0, return _r1_.
+ 1. Return _r2_.
+
+
+
+
+
+ GetUnsignedRoundingMode (
+ _roundingMode_: a rounding mode,
+ _sign_: either ~negative~ or ~positive~,
+ ): an unsigned rounding mode
+
+
+
description
+
It returns the rounding mode that should be applied to the absolute value of a number to produce the same result as if _roundingMode_ were applied to the signed value of the number (negative if _sign_ is ~negative~, or positive otherwise).
+
+
+ 1. Return the specification type in the "Unsigned Rounding Mode" column of for the row where the value in the "Rounding Mode" column is _roundingMode_ and the value in the "Sign" column is _sign_.
+
+
+
+
+
+ MaximumTemporalDurationRoundingIncrement (
+ _unit_: a Temporal unit,
+ ): one of 24, 60, 1000, or ~unset~
+
+
+
description
+
Given a string representing a Temporal.Duration unit, it returns the maximum rounding increment for that unit, or ~unset~ if there is no maximum.
+
+
+ 1. Return the value from the "Maximum duration rounding increment" column of the row of in which _unit_ is in the "Value" column.
+
+
+
+
+
+ NegateRoundingMode (
+ _roundingMode_: a rounding mode,
+ ): a rounding mode
+
+
+
description
+
It returns the correct rounding mode to use when rounding the negative of a value that was originally given with _roundingMode_.
+
+
+ 1. If _roundingMode_ is ~ceil~, return ~floor~.
+ 1. If _roundingMode_ is ~floor~, return ~ceil~.
+ 1. If _roundingMode_ is ~half-ceil~, return ~half-floor~.
+ 1. If _roundingMode_ is ~half-floor~, return ~half-ceil~.
+ 1. Return _roundingMode_.
+
+
+
+
+
+ RoundNumberToIncrement (
+ _x_: a mathematical value,
+ _increment_: a positive integer,
+ _roundingMode_: a rounding mode,
+ ): an integer
+
+
+
description
+
It rounds _x_ to the nearest multiple of _increment_, up or down according to _roundingMode_.
+
+
+ 1. Let _quotient_ be _x_ / _increment_.
+ 1. If _quotient_ < 0, then
+ 1. Let _isNegative_ be ~negative~.
+ 1. Set _quotient_ to -_quotient_.
+ 1. Else,
+ 1. Let _isNegative_ be ~positive~.
+ 1. Let _unsignedRoundingMode_ be GetUnsignedRoundingMode(_roundingMode_, _isNegative_).
+ 1. Let _r1_ be the largest integer such that _r1_ ≤ _quotient_.
+ 1. Let _r2_ be the smallest integer such that _r2_ > _quotient_.
+ 1. Let _rounded_ be ApplyUnsignedRoundingMode(_quotient_, _r1_, _r2_, _unsignedRoundingMode_).
+ 1. If _isNegative_ is ~negative~, set _rounded_ to -_rounded_.
+ 1. Return _rounded_ × _increment_.
+
+
+
+
+
+ RoundNumberToIncrementAsIfPositive (
+ _x_: a mathematical value,
+ _increment_: a positive integer,
+ _roundingMode_: a rounding mode,
+ ): an integer
+
+
+
description
+
+ It rounds _x_ to the nearest multiple of _increment_, up or down according to _roundingMode_, but always as if _x_ were positive.
+ For example, ~floor~ and ~trunc~ behave identically.
+ This is used when rounding exact times, where "rounding down" conceptually always means towards the beginning of time, even if the time is expressed as a negative amount of time relative to an epoch.
+
+
+
+ 1. Let _quotient_ be _x_ / _increment_.
+ 1. Let _unsignedRoundingMode_ be GetUnsignedRoundingMode(_roundingMode_, ~positive~).
+ 1. Let _r1_ be the largest integer such that _r1_ ≤ _quotient_.
+ 1. Let _r2_ be the smallest integer such that _r2_ > _quotient_.
+ 1. Let _rounded_ be ApplyUnsignedRoundingMode(_quotient_, _r1_, _r2_, _unsignedRoundingMode_).
+ 1. Return _rounded_ × _increment_.
+
+
+
+
+
+ ValidateTemporalRoundingIncrement (
+ _increment_: a positive integer,
+ _dividend_: a positive integer,
+ _inclusive_: a Boolean,
+ ): either a normal completion containing ~unused~ or a throw completion
+
+
+
description
+
+ It verifies that _increment_ evenly divides _dividend_, otherwise throwing a *RangeError*.
+ _dividend_ must be divided into more than one part unless _inclusive_ is *true*.
+
+
+
+ 1. If _inclusive_ is *true*, then
+ 1. Let _maximum_ be _dividend_.
+ 1. Else,
+ 1. Assert: _dividend_ > 1.
+ 1. Let _maximum_ be _dividend_ - 1.
+ 1. If _increment_ > _maximum_, throw a *RangeError* exception.
+ 1. If _dividend_ modulo _increment_ ≠ 0, throw a *RangeError* exception.
+ 1. Return ~unused~.
+
+
+
+
+
+
Time Durations
+
+
+ A time duration is an integer in the inclusive interval from -maxTimeDuration to maxTimeDuration, where
+
+ maxTimeDuration = 253 × 109 - 1 = 9,007,199,254,740,991,999,999,999
+
+ It represents the portion of a Temporal.Duration object that deals with time units, but as a combined value of total nanoseconds.
+
+
+
+
+ Add24HourDaysToTimeDuration (
+ _d_: a time duration,
+ _days_: an integer,
+ ): either a normal completion containing a time duration or a throw completion
+
+
+
description
+
+ It returns a time duration that is the sum of _d_ and the number of 24-hour days indicated by _days_, throwing an exception if the result is greater than the maximum time duration.
+ This operation should not be used when adding days relative to a Temporal.ZonedDateTime, since the days may not be 24 hours long.
+
+
+
+ 1. Let _result_ be _d_ + _days_ × nsPerDay.
+ 1. If abs(_result_) > maxTimeDuration, throw a *RangeError* exception.
+ 1. Return _result_.
+
+
+
+
+
+ AddTimeDuration (
+ _one_: a time duration,
+ _two_: a time duration,
+ ): either a normal completion containing a time duration or a throw completion
+
+
+
description
+
It returns a time duration that is the sum of _one_ and _two_, throwing an exception if the result is greater than the maximum time duration.
+
+
+ 1. Let _result_ be _one_ + _two_.
+ 1. If abs(_result_) > maxTimeDuration, throw a *RangeError* exception.
+ 1. Return _result_.
+
+
+
+
+
+ AddTimeDurationToEpochNanoseconds (
+ _d_: a time duration,
+ _epochNs_: an epoch nanoseconds value,
+ ): an epoch nanoseconds value
+
+
+
description
+
+ It adds a time duration _d_ to an exact time in nanoseconds since the epoch, _epochNs_, and returns a new exact time.
+ The returned exact time is not required to be valid according to IsValidEpochNanoseconds.
+
+
+
+ 1. Return _d_ + _epochNs_.
+
+
+
+
+
+ RoundTimeDuration (
+ _timeDuration_: a time duration,
+ _increment_: a positive integer,
+ _unit_: a time unit,
+ _roundingMode_: a rounding mode,
+ ): either a normal completion containing a time duration, or a throw completion
+
+
+
description
+
+ It rounds a _timeDuration_ according to the rounding parameters _unit_, _increment_, and _roundingMode_, and returns the time duration result.
+
+
+
+ 1. Let _divisor_ be the value in the "Length in Nanoseconds" column of the row of whose "Value" column contains _unit_.
+ 1. Return ? RoundTimeDurationToIncrement(_timeDuration_, _divisor_ × _increment_, _roundingMode_).
+
+
+
+
+
+ RoundTimeDurationToIncrement (
+ _d_: a time duration,
+ _increment_: a positive integer,
+ _roundingMode_: a rounding mode,
+ ): either a normal completion containing a time duration or a throw completion
+
+
+
description
+
It rounds the total number of nanoseconds in the time duration _d_ to the nearest multiple of _increment_, up or down according to _roundingMode_.
+
+
+ 1. Let _rounded_ be RoundNumberToIncrement(_d_, _increment_, _roundingMode_).
+ 1. If abs(_rounded_) > maxTimeDuration, throw a *RangeError* exception.
+ 1. Return _rounded_.
+
+
+
+
+
+ TimeDurationFromComponents (
+ _hours_: an integer,
+ _minutes_: an integer,
+ _seconds_: an integer,
+ _milliseconds_: an integer,
+ _microseconds_: an integer,
+ _nanoseconds_: an integer,
+ ): a time duration
+
+
+
description
+
+ From the given units, it computes a time duration consisting of total nanoseconds.
+ The time duration can be stored losslessly in two 64-bit floating point numbers consisting of truncate(_nanoseconds_ / 109) and remainder(_nanoseconds_, 109).
+ Alternatively, _nanoseconds_ can be stored as a 96-bit integer.
+
+
+
+ 1. Set _minutes_ to _minutes_ + _hours_ × 60.
+ 1. Set _seconds_ to _seconds_ + _minutes_ × 60.
+ 1. Set _milliseconds_ to _milliseconds_ + _seconds_ × 1000.
+ 1. Set _microseconds_ to _microseconds_ + _milliseconds_ × 1000.
+ 1. Set _nanoseconds_ to _nanoseconds_ + _microseconds_ × 1000.
+ 1. Assert: abs(_nanoseconds_) ≤ maxTimeDuration.
+ 1. Return _nanoseconds_.
+
+
+
+
+
+ TimeDurationFromEpochNanosecondsDifference (
+ _one_: an epoch nanoseconds value,
+ _two_: an epoch nanoseconds value,
+ ): a time duration
+
+
+
description
+
The returned time duration is the difference between two exact times in nanoseconds since the epoch, which must not be greater than the maximum time duration.
+ TotalTimeDuration (
+ _timeDuration_: a time duration,
+ _unit_: either a time unit or ~day~,
+ ): a mathematical value
+
+
+
description
+
It returns the total number of _unit_ in _duration_.
+
+
+ 1. Let _divisor_ be the value in the "Length in Nanoseconds" column of the row of whose "Value" column contains _unit_.
+ 1. NOTE: The following step cannot be implemented directly using floating-point arithmetic when 𝔽(_timeDuration_) is not a safe integer. The division can be implemented in C++ with the `__float128` type if the compiler supports it, or with software emulation such as in the SoftFP library.
+ 1. Return _timeDuration_ / _divisor_.
+
+
+
+
+
+
Time Records
+
+ A Time Record is a Record value used to represent a valid clock time, together with a number of overflow days such as might occur in BalanceTime.
+ For any Time Record _t_, IsValidTime(_t_.[[Hour]], _t_.[[Minute]], _t_.[[Second]], _t_.[[Millisecond]], _t_.[[Microsecond]], _t_.[[Nanosecond]]) must return *true*.
+
+
Time Records have the fields listed in .
+
+
+
+
Field Name
+
Value
+
Meaning
+
+
+
[[Days]]
+
an integer
+
A number of overflow days.
+
+
+
[[Hour]]
+
an integer in the inclusive interval from 0 to 23
+
The number of the hour.
+
+
+
[[Minute]]
+
an integer in the inclusive interval from 0 to 59
+
The number of the minute.
+
+
+
[[Second]]
+
an integer in the inclusive interval from 0 to 59
+
The number of the second.
+
+
+
[[Millisecond]]
+
an integer in the inclusive interval from 0 to 999
+
The number of the millisecond.
+
+
+
[[Microsecond]]
+
an integer in the inclusive interval from 0 to 999
+
The number of the microsecond.
+
+
+
[[Nanosecond]]
+
an integer in the inclusive interval from 0 to 999
+
The number of the nanosecond.
+
+
+
+
+
+
+ AddTime (
+ _time_: a Time Record,
+ _timeDuration_: a time duration,
+ ): a Time Record
+
+
+
description
+
+
+
+ 1. Return BalanceTime(_time_.[[Hour]], _time_.[[Minute]], _time_.[[Second]], _time_.[[Millisecond]], _time_.[[Microsecond]], _time_.[[Nanosecond]] + _timeDuration_).
+ 1. NOTE: If using floating points to implement this operation, add the time components separately before balancing to avoid errors with unsafe integers.
+
+
+
+
+
+ BalanceTime (
+ _hour_: an integer,
+ _minute_: an integer,
+ _second_: an integer,
+ _millisecond_: an integer,
+ _microsecond_: an integer,
+ _nanosecond_: an integer,
+ ): a Time Record
+
+
+
description
+
+
+
+ 1. Set _microsecond_ to _microsecond_ + floor(_nanosecond_ / 1000).
+ 1. Set _nanosecond_ to _nanosecond_ modulo 1000.
+ 1. Set _millisecond_ to _millisecond_ + floor(_microsecond_ / 1000).
+ 1. Set _microsecond_ to _microsecond_ modulo 1000.
+ 1. Set _second_ to _second_ + floor(_millisecond_ / 1000).
+ 1. Set _millisecond_ to _millisecond_ modulo 1000.
+ 1. Set _minute_ to _minute_ + floor(_second_ / 60).
+ 1. Set _second_ to _second_ modulo 60.
+ 1. Set _hour_ to _hour_ + floor(_minute_ / 60).
+ 1. Set _minute_ to _minute_ modulo 60.
+ 1. Let _deltaDays_ be floor(_hour_ / 24).
+ 1. Set _hour_ to _hour_ modulo 24.
+ 1. Return CreateTimeRecord(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_, _deltaDays_).
+
+
+
+
+
+ CompareTimeRecord (
+ _time1_: a Time Record,
+ _time2_: a Time Record,
+ ): one of -1, 0, or 1
+
+
+
description
+
It compares the two given times and returns -1 if the second comes earlier in the day than the first, 1 if the first comes earlier in the day than the second, and 0 if they are the same.
+
+
+ 1. If _time1_.[[Hour]] > _time2_.[[Hour]], return 1.
+ 1. If _time1_.[[Hour]] < _time2_.[[Hour]], return -1.
+ 1. If _time1_.[[Minute]] > _time2_.[[Minute]], return 1.
+ 1. If _time1_.[[Minute]] < _time2_.[[Minute]], return -1.
+ 1. If _time1_.[[Second]] > _time2_.[[Second]], return 1.
+ 1. If _time1_.[[Second]] < _time2_.[[Second]], return -1.
+ 1. If _time1_.[[Millisecond]] > _time2_.[[Millisecond]], return 1.
+ 1. If _time1_.[[Millisecond]] < _time2_.[[Millisecond]], return -1.
+ 1. If _time1_.[[Microsecond]] > _time2_.[[Microsecond]], return 1.
+ 1. If _time1_.[[Microsecond]] < _time2_.[[Microsecond]], return -1.
+ 1. If _time1_.[[Nanosecond]] > _time2_.[[Nanosecond]], return 1.
+ 1. If _time1_.[[Nanosecond]] < _time2_.[[Nanosecond]], return -1.
+ 1. Return 0.
+
+
+
+
+
+ CreateTimeRecord (
+ _hour_: an integer in the inclusive interval from 0 to 23,
+ _minute_: an integer in the inclusive interval from 0 to 59,
+ _second_: an integer in the inclusive interval from 0 to 59,
+ _millisecond_: an integer in the inclusive interval from 0 to 999,
+ _microsecond_: an integer in the inclusive interval from 0 to 999,
+ _nanosecond_: an integer in the inclusive interval from 0 to 999,
+ optional _deltaDays_: an integer,
+ ): a Time Record
+
+
+
description
+
Most uses of Time Records do not require the _deltaDays_ parameter.
+
+
+ 1. If _deltaDays_ is not present, set _deltaDays_ to 0.
+ 1. Assert: IsValidTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_).
+ 1. Return Time Record { [[Days]]: _deltaDays_, [[Hour]]: _hour_, [[Minute]]: _minute_, [[Second]]: _second_, [[Millisecond]]: _millisecond_, [[Microsecond]]: _microsecond_, [[Nanosecond]]: _nanosecond_ }.
+
+
+
+
+
+ DifferenceTime (
+ _time1_: a Time Record,
+ _time2_: a Time Record,
+ ): a time duration
+
+
+
description
+
It returns the elapsed duration from a first wall-clock time, until a second wall-clock time.
+
+
+ 1. Let _hours_ be _time2_.[[Hour]] - _time1_.[[Hour]].
+ 1. Let _minutes_ be _time2_.[[Minute]] - _time1_.[[Minute]].
+ 1. Let _seconds_ be _time2_.[[Second]] - _time1_.[[Second]].
+ 1. Let _milliseconds_ be _time2_.[[Millisecond]] - _time1_.[[Millisecond]].
+ 1. Let _microseconds_ be _time2_.[[Microsecond]] - _time1_.[[Microsecond]].
+ 1. Let _nanoseconds_ be _time2_.[[Nanosecond]] - _time1_.[[Nanosecond]].
+ 1. Let _timeDuration_ be TimeDurationFromComponents(_hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_).
+ 1. Assert: abs(_timeDuration_) < nsPerDay.
+ 1. Return _timeDuration_.
+
+
+
+
+
+ IsValidTime (
+ _hour_: an integer,
+ _minute_: an integer,
+ _second_: an integer,
+ _millisecond_: an integer,
+ _microsecond_: an integer,
+ _nanosecond_: an integer,
+ ): a Boolean
+
+
+
description
+
+ The return value is *true* if its arguments form a valid time of day, and *false* otherwise.
+ Leap seconds are not taken into account.
+
+
+
+ 1. If _hour_ < 0 or _hour_ > 23, return *false*.
+ 1. If _minute_ < 0 or _minute_ > 59, return *false*.
+ 1. If _second_ < 0 or _second_ > 59, return *false*.
+ 1. If _millisecond_ < 0 or _millisecond_ > 999, return *false*.
+ 1. If _microsecond_ < 0 or _microsecond_ > 999, return *false*.
+ 1. If _nanosecond_ < 0 or _nanosecond_ > 999, return *false*.
+ 1. Return *true*.
+
+
+
+
+
MidnightTimeRecord ( ): a Time Record
+
+
description
+
The returned Record denotes the wall-clock time of midnight.
+ RegulateTime (
+ _hour_: an integer,
+ _minute_: an integer,
+ _second_: an integer,
+ _millisecond_: an integer,
+ _microsecond_: an integer,
+ _nanosecond_: an integer,
+ _overflow_: either ~constrain~ or ~reject~,
+ ): either a normal completion containing a Time Record or a throw completion
+
+
+
description
+
+ It applies the correction given by _overflow_ to the given time.
+ If _overflow_ is ~constrain~, out-of-range values are clamped.
+ If _overflow_ is ~reject~, a *RangeError* is thrown if any values are out of range.
+
+
+
+ 1. If _overflow_ is ~constrain~, then
+ 1. Set _hour_ to the result of clamping _hour_ between 0 and 23.
+ 1. Set _minute_ to the result of clamping _minute_ between 0 and 59.
+ 1. Set _second_ to the result of clamping _second_ between 0 and 59.
+ 1. Set _millisecond_ to the result of clamping _millisecond_ between 0 and 999.
+ 1. Set _microsecond_ to the result of clamping _microsecond_ between 0 and 999.
+ 1. Set _nanosecond_ to the result of clamping _nanosecond_ between 0 and 999.
+ 1. Else,
+ 1. Assert: _overflow_ is ~reject~.
+ 1. If IsValidTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_) is *false*, throw a *RangeError* exception.
+ 1. Return CreateTimeRecord(_hour_, _minute_, _second_, _millisecond_, _microsecond_,_nanosecond_).
+
+
+
+
+
+ RoundTime (
+ _time_: a Time Record,
+ _increment_: a positive integer,
+ _unit_: either a time unit or ~day~,
+ _roundingMode_: a rounding mode,
+ ): a Time Record
+
+
+
description
+
It rounds a time to the given increment.
+
+
+ 1. If _unit_ is either ~day~ or ~hour~, then
+ 1. Let _quantity_ be ((((_time_.[[Hour]] × 60 + _time_.[[Minute]]) × 60 + _time_.[[Second]]) × 1000 + _time_.[[Millisecond]]) × 1000 + _time_.[[Microsecond]]) × 1000 + _time_.[[Nanosecond]].
+ 1. Else if _unit_ is ~minute~, then
+ 1. Let _quantity_ be (((_time_.[[Minute]] × 60 + _time_.[[Second]]) × 1000 + _time_.[[Millisecond]]) × 1000 + _time_.[[Microsecond]]) × 1000 + _time_.[[Nanosecond]].
+ 1. Else if _unit_ is ~second~, then
+ 1. Let _quantity_ be ((_time_.[[Second]] × 1000 + _time_.[[Millisecond]]) × 1000 + _time_.[[Microsecond]]) × 1000 + _time_.[[Nanosecond]].
+ 1. Else if _unit_ is ~millisecond~, then
+ 1. Let _quantity_ be (_time_.[[Millisecond]] × 1000 + _time_.[[Microsecond]]) × 1000 + _time_.[[Nanosecond]].
+ 1. Else if _unit_ is ~microsecond~, then
+ 1. Let _quantity_ be _time_.[[Microsecond]] × 1000 + _time_.[[Nanosecond]].
+ 1. Else,
+ 1. Assert: _unit_ is ~nanosecond~.
+ 1. Let _quantity_ be _time_.[[Nanosecond]].
+ 1. Let _unitLength_ be the value in the "Length in Nanoseconds" column of the row of whose "Value" column contains _unit_.
+ 1. Let _result_ be RoundNumberToIncrement(_quantity_, _increment_ × _unitLength_, _roundingMode_) / _unitLength_.
+ 1. If _unit_ is ~day~, return CreateTimeRecord(0, 0, 0, 0, 0, 0, _result_).
+ 1. If _unit_ is ~hour~, return BalanceTime(_result_, 0, 0, 0, 0, 0).
+ 1. If _unit_ is ~minute~, return BalanceTime(_time_.[[Hour]], _result_, 0, 0, 0, 0).
+ 1. If _unit_ is ~second~, return BalanceTime(_time_.[[Hour]], _time_.[[Minute]], _result_, 0, 0, 0).
+ 1. If _unit_ is ~millisecond~, return BalanceTime(_time_.[[Hour]], _time_.[[Minute]], _time_.[[Second]], _result_, 0, 0).
+ 1. If _unit_ is ~microsecond~, return BalanceTime(_time_.[[Hour]], _time_.[[Minute]], _time_.[[Second]], _time_.[[Millisecond]], _result_, 0).
+ 1. Assert: _unit_ is ~nanosecond~.
+ 1. Return BalanceTime(_time_.[[Hour]], _time_.[[Minute]], _time_.[[Second]], _time_.[[Millisecond]], _time_.[[Microsecond]], _result_).
+
+
+
+
+
+ TimeRecordToString (
+ _time_: a Time Record,
+ _precision_: either an integer in the inclusive interval from 0 to 9, ~minute~, or ~auto~,
+ ): a String
+
+
+
description
+
It formats the given time as an ISO 8601 string, to the precision specified by _precision_.
+ ToTemporalTimeRecord (
+ _temporalTimeLike_: an Object,
+ optional _completeness_: either ~partial~ or ~complete~,
+ ): either a normal completion containing a TemporalTimeLike Record or a throw completion
+
+
+
+
+ 1. If _completeness_ is not present, set _completeness_ to ~complete~.
+ 1. If _completeness_ is ~complete~, then
+ 1. Let _result_ be a new TemporalTimeLike Record with each field set to 0.
+ 1. Else,
+ 1. Let _result_ be a new TemporalTimeLike Record with each field set to ~unset~.
+ 1. Let _any_ be *false*.
+ 1. Let _hour_ be ? Get(_temporalTimeLike_, *"hour"*).
+ 1. If _hour_ is not *undefined*, then
+ 1. Set _result_.[[Hour]] to ? ToIntegerWithTruncation(_hour_).
+ 1. Set _any_ to *true*.
+ 1. Let _microsecond_ be ? Get(_temporalTimeLike_, *"microsecond"*).
+ 1. If _microsecond_ is not *undefined*, then
+ 1. Set _result_.[[Microsecond]] to ? ToIntegerWithTruncation(_microsecond_).
+ 1. Set _any_ to *true*.
+ 1. Let _millisecond_ be ? Get(_temporalTimeLike_, *"millisecond"*).
+ 1. If _millisecond_ is not *undefined*, then
+ 1. Set _result_.[[Millisecond]] to ? ToIntegerWithTruncation(_millisecond_).
+ 1. Set _any_ to *true*.
+ 1. Let _minute_ be ? Get(_temporalTimeLike_, *"minute"*).
+ 1. If _minute_ is not *undefined*, then
+ 1. Set _result_.[[Minute]] to ? ToIntegerWithTruncation(_minute_).
+ 1. Set _any_ to *true*.
+ 1. Let _nanosecond_ be ? Get(_temporalTimeLike_, *"nanosecond"*).
+ 1. If _nanosecond_ is not *undefined*, then
+ 1. Set _result_.[[Nanosecond]] to ? ToIntegerWithTruncation(_nanosecond_).
+ 1. Set _any_ to *true*.
+ 1. Let _second_ be ? Get(_temporalTimeLike_, *"second"*).
+ 1. If _second_ is not *undefined*, then
+ 1. Set _result_.[[Second]] to ? ToIntegerWithTruncation(_second_).
+ 1. Set _any_ to *true*.
+ 1. If _any_ is *false*, throw a *TypeError* exception.
+ 1. Return _result_.
+
+
+
+ TemporalTimeLike Record Fields
+
+
+
+
Field Name
+
Property Name
+
+
+
+
[[Hour]]
+
*"hour"*
+
+
+
+
[[Minute]]
+
*"minute"*
+
+
+
+
[[Second]]
+
*"second"*
+
+
+
+
[[Millisecond]]
+
*"millisecond"*
+
+
+
+
[[Microsecond]]
+
*"microsecond"*
+
+
+
+
[[Nanosecond]]
+
*"nanosecond"*
+
+
+
+
+
+
+
+ ToTimeRecordOrMidnight (
+ _item_: an ECMAScript language value,
+ ): either a normal completion containing a Time Record or a throw completion
+
+
+
description
+
Converts _item_ to a Time Record if possible, considering *undefined* to be the same as midnight, and throws otherwise.
+
+
+ 1. If _item_ is *undefined*, return MidnightTimeRecord().
+ 1. Let _plainTime_ be ? ToTemporalTime(_item_).
+ 1. Return _plainTime_.[[Time]].
+
+
+
+
+
+
Units
+
+ Time is reckoned using multiple units.
+ These units are listed in .
+
+
+ A Temporal unit is a value listed in the "Value" column of .
+ A calendar unit is a Temporal unit for which IsCalendarUnit returns *true*.
+ A date unit is a Temporal unit for which the corresponding "Category" value in is ~date~, and a time unit is a Temporal unit for which the corresponding "Category" value is ~time~.
+
+
+ Temporal units by descending magnitude
+
+
+
+
Value
+
Singular property name
+
Plural property name
+
Category
+
Length in nanoseconds
+
Maximum duration rounding increment
+
+
+
+
~year~
+
*"year"*
+
*"years"*
+
~date~
+
calendar-dependent
+
~unset~
+
+
+
+
~month~
+
*"month"*
+
*"months"*
+
~date~
+
calendar-dependent
+
~unset~
+
+
+
+
~week~
+
*"week"*
+
*"weeks"*
+
~date~
+
calendar-dependent
+
~unset~
+
+
+
+
~day~
+
*"day"*
+
*"days"*
+
~date~
+
nsPerDay
+
~unset~
+
+
+
+
~hour~
+
*"hour"*
+
*"hours"*
+
~time~
+
3.6 × 1012
+
24
+
+
+
+
~minute~
+
*"minute"*
+
*"minutes"*
+
~time~
+
6 × 1010
+
60
+
+
+
+
~second~
+
*"second"*
+
*"seconds"*
+
~time~
+
109
+
60
+
+
+
+
~millisecond~
+
*"millisecond"*
+
*"milliseconds"*
+
~time~
+
106
+
1000
+
+
+
+
~microsecond~
+
*"microsecond"*
+
*"microseconds"*
+
~time~
+
103
+
1000
+
+
+
+
~nanosecond~
+
*"nanosecond"*
+
*"nanoseconds"*
+
~time~
+
1
+
1000
+
+
+
+
+ The length of a day is given as nsPerDay in the table.
+ Note that changes in the UTC offset of a time zone may result in longer or shorter days, so care should be taken when using this value in the context of `Temporal.ZonedDateTime`.
+
+
+
+
+ DefaultTemporalLargestUnit (
+ _duration_: a Temporal.Duration,
+ ): a Temporal unit
+
+
+
description
+
It implements the logic used in the `Temporal.Duration.prototype.round()` method and elsewhere, where the `largestUnit` option, if not given explicitly, is set to the largest-magnitude non-zero unit.
+
+
+ 1. If _duration_.[[Years]] ≠ 0, return ~year~.
+ 1. If _duration_.[[Months]] ≠ 0, return ~month~.
+ 1. If _duration_.[[Weeks]] ≠ 0, return ~week~.
+ 1. If _duration_.[[Days]] ≠ 0, return ~day~.
+ 1. If _duration_.[[Hours]] ≠ 0, return ~hour~.
+ 1. If _duration_.[[Minutes]] ≠ 0, return ~minute~.
+ 1. If _duration_.[[Seconds]] ≠ 0, return ~second~.
+ 1. If _duration_.[[Milliseconds]] ≠ 0, return ~millisecond~.
+ 1. If _duration_.[[Microseconds]] ≠ 0, return ~microsecond~.
+ 1. Return ~nanosecond~.
+
+
+
+
+
+ IsCalendarUnit (
+ _unit_: a Temporal unit,
+ ): a Boolean
+
+
+
description
+
It returns whether _unit_ is a Temporal unit for which rounding would require calendar calculations.
+
+
+ 1. If _unit_ is ~year~, return *true*.
+ 1. If _unit_ is ~month~, return *true*.
+ 1. If _unit_ is ~week~, return *true*.
+ 1. Return *false*.
+
+
+
+
+
+ LargerOfTwoTemporalUnits (
+ _u1_: a Temporal unit,
+ _u2_: a Temporal unit,
+ ): a Temporal unit
+
+
+
description
+
Given two Temporal units, it returns the larger of the two units.
+
+
+ 1. For each row of , except the header row, in table order, do
+ 1. Let _unit_ be the value in the "Value" column of the row.
+ 1. If _u1_ is _unit_, return _unit_.
+ 1. If _u2_ is _unit_, return _unit_.
+
+
+
+
+
+ TemporalUnitCategory (
+ _unit_: a Temporal unit,
+ ): either ~date~ or ~time~
+
+
+
description
+
It returns the category (date or time) of the Temporal unit _unit_.
+
+
+ 1. Return the value from the "Category" column of the row of in which _unit_ is in the "Value" column.
+
+
+
+
+
+ ValidateTemporalUnitValue (
+ _value_: either a Temporal unit, ~unset~, or ~auto~,
+ _unitGroup_: one of ~date~, ~time~, or ~datetime~,
+ optional _extraValues_: a List of either Temporal units or ~auto~,
+ ): either a normal completion containing ~unused~ or a throw completion
+
+
+
description
+
It validates that the result of GetTemporalUnitValuedOption is covered by the union of _unitGroup_, _extraValues_, and « ~unset~ ».
+
+
+ 1. If _value_ is ~unset~, return ~unused~.
+ 1. If _extraValues_ is present and _extraValues_ contains _value_, return ~unused~.
+ 1. Let _category_ be the value in the “Category” column of the row of whose “Value” column contains _value_. If there is no such row, throw a *RangeError* exception.
+ 1. If _category_ is ~date~ and _unitGroup_ is either ~date~ or ~datetime~, return ~unused~.
+ 1. If _category_ is ~time~ and _unitGroup_ is either ~time~ or ~datetime~, return ~unused~.
+ 1. Throw a *RangeError* exception.
+
+
+
+
+
+
+ IsPartialTemporalObject (
+ _value_: an ECMAScript language value,
+ ): either a normal completion containing a Boolean or a throw completion
+
+
+
description
+
It determines whether _value_ is a suitable input for one of the Temporal objects' `with()` methods: it must be an Object, it must not be an instance of one of the time-related or date-related Temporal types, and it must not have a `calendar` or `timeZone` property.
+
+
+ 1. If _value_ is not an Object, return *false*.
+ 1. If _value_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, return *false*.
+ 1. Let _calendarProperty_ be ? Get(_value_, *"calendar"*).
+ 1. If _calendarProperty_ is not *undefined*, return *false*.
+ 1. Let _timeZoneProperty_ be ? Get(_value_, *"timeZone"*).
+ 1. If _timeZoneProperty_ is not *undefined*, return *false*.
+ 1. Return *true*.
+
+
+
diff --git a/temporal/duration.emu b/temporal/duration.emu
new file mode 100644
index 0000000000..9d365640e1
--- /dev/null
+++ b/temporal/duration.emu
@@ -0,0 +1,1464 @@
+
+
+
+
+
Temporal.Duration Objects
+
+
+ A Temporal.Duration object describes the difference in elapsed time between
+ two other Temporal objects of the same type: Temporal.Instant, Temporal.PlainDate,
+ Temporal.PlainDateTime, Temporal.PlainTime, Temporal.PlainYearMonth, or Temporal.ZonedDateTime.
+
+
+
+
The Temporal.Duration Constructor
+
The Temporal.Duration constructor:
+
+
+ creates and initializes a new Temporal.Duration object when called as a constructor.
+
+
+ is not intended to be called as a function and will throw an exception when called in that manner.
+
+
+ may be used as the value of an `extends` clause of a class definition.
+ Subclass constructors that intend to inherit the specified Temporal.Duration behaviour must
+ include a super call to the %Temporal.Duration% constructor to create and initialize subclass
+ instances with the necessary internal slots.
+
The `Temporal.Duration` function performs the following steps when called:
+
+ 1. If NewTarget is *undefined*, throw a *TypeError* exception.
+ 1. If _years_ is *undefined*, let _y_ be 0; else let _y_ be ? ToIntegerIfIntegral(_years_).
+ 1. If _months_ is *undefined*, let _mo_ be 0; else let _mo_ be ? ToIntegerIfIntegral(_months_).
+ 1. If _weeks_ is *undefined*, let _w_ be 0; else let _w_ be ? ToIntegerIfIntegral(_weeks_).
+ 1. If _days_ is *undefined*, let _d_ be 0; else let _d_ be ? ToIntegerIfIntegral(_days_).
+ 1. If _hours_ is *undefined*, let _h_ be 0; else let _h_ be ? ToIntegerIfIntegral(_hours_).
+ 1. If _minutes_ is *undefined*, let _m_ be 0; else let _m_ be ? ToIntegerIfIntegral(_minutes_).
+ 1. If _seconds_ is *undefined*, let _s_ be 0; else let _s_ be ? ToIntegerIfIntegral(_seconds_).
+ 1. If _milliseconds_ is *undefined*, let _ms_ be 0; else let _ms_ be ? ToIntegerIfIntegral(_milliseconds_).
+ 1. If _microseconds_ is *undefined*, let _mis_ be 0; else let _mis_ be ? ToIntegerIfIntegral(_microseconds_).
+ 1. If _nanoseconds_ is *undefined*, let _ns_ be 0; else let _ns_ be ? ToIntegerIfIntegral(_nanoseconds_).
+ 1. Return ? CreateTemporalDuration(_y_, _mo_, _w_, _d_, _h_, _m_, _s_, _ms_, _mis_, _ns_, NewTarget).
+
+
+
+
+
+
Properties of the Temporal.Duration Constructor
+
+ The value of the [[Prototype]] internal slot of the Temporal.Duration
+ constructor is the intrinsic object %Function.prototype%.
+
+
The Temporal.Duration constructor has the following properties:
+
+
+
Temporal.Duration.prototype
+
+ The initial value of `Temporal.Duration.prototype` is
+ %Temporal.Duration.prototype%.
+
+
+ This property has the attributes { [[Writable]]: *false*, [[Enumerable]]:
+ *false*, [[Configurable]]: *false* }.
+
+
+
+
+
Temporal.Duration.from ( _item_ )
+
The `Temporal.Duration.from` function performs the following steps when called:
The `Temporal.Duration.compare` function performs the following steps when called:
+
+ 1. Set _one_ to ? ToTemporalDuration(_one_).
+ 1. Set _two_ to ? ToTemporalDuration(_two_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _relativeToRecord_ be ? GetTemporalRelativeToOption(_resolvedOptions_).
+ 1. If _one_.[[Years]] = _two_.[[Years]], and _one_.[[Months]] = _two_.[[Months]], and _one_.[[Weeks]] = _two_.[[Weeks]], and _one_.[[Days]] = _two_.[[Days]], and _one_.[[Hours]] = _two_.[[Hours]], and _one_.[[Minutes]] = _two_.[[Minutes]], and _one_.[[Seconds]] = _two_.[[Seconds]], and _one_.[[Milliseconds]] = _two_.[[Milliseconds]], and _one_.[[Microseconds]] = _two_.[[Microseconds]], and _one_.[[Nanoseconds]] = _two_.[[Nanoseconds]], then
+ 1. Return *+0*𝔽.
+ 1. Let _zonedRelativeTo_ be _relativeToRecord_.[[ZonedRelativeTo]].
+ 1. Let _plainRelativeTo_ be _relativeToRecord_.[[PlainRelativeTo]].
+ 1. Let _largestUnit1_ be DefaultTemporalLargestUnit(_one_).
+ 1. Let _largestUnit2_ be DefaultTemporalLargestUnit(_two_).
+ 1. Let _duration1_ be ToInternalDurationRecord(_one_).
+ 1. Let _duration2_ be ToInternalDurationRecord(_two_).
+ 1. If _zonedRelativeTo_ is not *undefined*, and TemporalUnitCategory(_largestUnit1_) is ~date~ or TemporalUnitCategory(_largestUnit2_) is ~date~, then
+ 1. Let _timeZone_ be _zonedRelativeTo_.[[TimeZone]].
+ 1. Let _calendar_ be _zonedRelativeTo_.[[Calendar]].
+ 1. Let _after1_ be ? AddZonedDateTime(_zonedRelativeTo_.[[EpochNanoseconds]], _timeZone_, _calendar_, _duration1_, ~constrain~).
+ 1. Let _after2_ be ? AddZonedDateTime(_zonedRelativeTo_.[[EpochNanoseconds]], _timeZone_, _calendar_, _duration2_, ~constrain~).
+ 1. If _after1_ > _after2_, return *1*𝔽.
+ 1. If _after1_ < _after2_, return *-1*𝔽.
+ 1. Return *+0*𝔽.
+ 1. If IsCalendarUnit(_largestUnit1_) is *true* or IsCalendarUnit(_largestUnit2_) is *true*, then
+ 1. If _plainRelativeTo_ is *undefined*, throw a *RangeError* exception.
+ 1. Let _days1_ be ? DateDurationDays(_duration1_.[[Date]], _plainRelativeTo_).
+ 1. Let _days2_ be ? DateDurationDays(_duration2_.[[Date]], _plainRelativeTo_).
+ 1. Else,
+ 1. Let _days1_ be _one_.[[Days]].
+ 1. Let _days2_ be _two_.[[Days]].
+ 1. Let _timeDuration1_ be ? Add24HourDaysToTimeDuration(_duration1_.[[Time]], _days1_).
+ 1. Let _timeDuration2_ be ? Add24HourDaysToTimeDuration(_duration2_.[[Time]], _days2_).
+ 1. If _timeDuration1_ > _timeDuration2_, return *1*𝔽.
+ 1. If _timeDuration1_ < _timeDuration2_, return *-1*𝔽.
+ 1. Return *+0*𝔽.
+
+
+
+
+
+
Properties of the Temporal.Duration Prototype Object
+
+
The Temporal.Duration prototype object
+
+
is itself an ordinary object.
+
is not a Temporal.Duration instance and doesn't have an [[InitializedTemporalDuration]] internal slot.
+
has a [[Prototype]] internal slot whose value is %Object.prototype%.
+
+
+
+
Temporal.Duration.prototype.constructor
+
The initial value of `Temporal.Duration.prototype.constructor` is %Temporal.Duration%.
The initial value of the %Symbol.toStringTag% property is the String *"Temporal.Duration"*.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.
+
+
+
+
get Temporal.Duration.prototype.years
+
+ `Temporal.Duration.prototype.years` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return 𝔽(_duration_.[[Years]]).
+
+
+
+
+
get Temporal.Duration.prototype.months
+
+ `Temporal.Duration.prototype.months` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return 𝔽(_duration_.[[Months]]).
+
+
+
+
+
get Temporal.Duration.prototype.weeks
+
+ `Temporal.Duration.prototype.weeks` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return 𝔽(_duration_.[[Weeks]]).
+
+
+
+
+
get Temporal.Duration.prototype.days
+
+ `Temporal.Duration.prototype.days` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return 𝔽(_duration_.[[Days]]).
+
+
+
+
+
get Temporal.Duration.prototype.hours
+
+ `Temporal.Duration.prototype.hours` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return 𝔽(_duration_.[[Hours]]).
+
+
+
+
+
get Temporal.Duration.prototype.minutes
+
+ `Temporal.Duration.prototype.minutes` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return 𝔽(_duration_.[[Minutes]]).
+
+
+
+
+
get Temporal.Duration.prototype.seconds
+
+ `Temporal.Duration.prototype.seconds` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return 𝔽(_duration_.[[Seconds]]).
+
+
+
+
+
get Temporal.Duration.prototype.milliseconds
+
+ `Temporal.Duration.prototype.milliseconds` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return 𝔽(_duration_.[[Milliseconds]]).
+
+
+
+
+
get Temporal.Duration.prototype.microseconds
+
+ `Temporal.Duration.prototype.microseconds` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return 𝔽(_duration_.[[Microseconds]]).
+
+
+
+
+
get Temporal.Duration.prototype.nanoseconds
+
+ `Temporal.Duration.prototype.nanoseconds` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return 𝔽(_duration_.[[Nanoseconds]]).
+
+
+
+
+
get Temporal.Duration.prototype.sign
+
+ `Temporal.Duration.prototype.sign` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return 𝔽(DurationSign(_duration_)).
+
+
+
+
+
get Temporal.Duration.prototype.blank
+
+ `Temporal.Duration.prototype.blank` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. If DurationSign(_duration_) = 0, return *true*.
+ 1. Return *false*.
+
+
+
+
+
The `Temporal.Duration.prototype.with` method performs the following steps when called:
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Let _partial_ be ? ToPartialDurationRecord(_temporalDurationLike_).
+ 1. If _partial_.[[Years]] is not *undefined*, let _years_ be _partial_.[[Years]]; else, let _years_ be _duration_.[[Years]].
+ 1. If _partial_.[[Months]] is not *undefined*, let _months_ be _partial_.[[Months]]; else, let _months_ be _duration_.[[Months]].
+ 1. If _partial_.[[Weeks]] is not *undefined*, let _weeks_ be _partial_.[[Weeks]]; else, let _weeks_ be _duration_.[[Weeks]].
+ 1. If _partial_.[[Days]] is not *undefined*, let _days_ be _partial_.[[Days]]; else, let _days_ be _duration_.[[Days]].
+ 1. If _partial_.[[Hours]] is not *undefined*, let _hours_ be _partial_.[[Hours]]; else, let _hours_ be _duration_.[[Hours]].
+ 1. If _partial_.[[Minutes]] is not *undefined*, let _minutes_ be _partial_.[[Minutes]]; else, let _minutes_ be _duration_.[[Minutes]].
+ 1. If _partial_.[[Seconds]] is not *undefined*, let _seconds_ be _partial_.[[Seconds]]; else, let _seconds_ be _duration_.[[Seconds]].
+ 1. If _partial_.[[Milliseconds]] is not *undefined*, let _milliseconds_ be _partial_.[[Milliseconds]]; else, let _milliseconds_ be _duration_.[[Milliseconds]].
+ 1. If _partial_.[[Microseconds]] is not *undefined*, let _microseconds_ be _partial_.[[Microseconds]]; else, let _microseconds_ be _duration_.[[Microseconds]].
+ 1. If _partial_.[[Nanoseconds]] is not *undefined*, let _nanoseconds_ be _partial_.[[Nanoseconds]]; else, let _nanoseconds_ be _duration_.[[Nanoseconds]].
+ 1. Return ? CreateTemporalDuration(_years_, _months_, _weeks_, _days_, _hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_).
+
+
+
+
+
Temporal.Duration.prototype.negated ( )
+
The `Temporal.Duration.prototype.negated` method performs the following steps when called:
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return CreateNegatedTemporalDuration(_duration_).
+
+
+
+
+
Temporal.Duration.prototype.abs ( )
+
The `Temporal.Duration.prototype.abs` method performs the following steps when called:
The `Temporal.Duration.prototype.add` method performs the following steps when called:
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return ? AddDurations(~add~, _duration_, _other_).
+
+
+
+
+
Temporal.Duration.prototype.subtract ( _other_ )
+
The `Temporal.Duration.prototype.subtract` method performs the following steps when called:
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return ? AddDurations(~subtract~, _duration_, _other_).
+
+
+
+
+
Temporal.Duration.prototype.round ( _roundTo_ )
+
The `Temporal.Duration.prototype.round` method performs the following steps when called:
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. If _roundTo_ is *undefined*, throw a *TypeError* exception.
+ 1. If _roundTo_ is a String, then
+ 1. Let _paramString_ be _roundTo_.
+ 1. Set _roundTo_ to OrdinaryObjectCreate(*null*).
+ 1. Perform ! CreateDataPropertyOrThrow(_roundTo_, *"smallestUnit"*, _paramString_).
+ 1. Else,
+ 1. Set _roundTo_ to ? GetOptionsObject(_roundTo_).
+ 1. Let _smallestUnitPresent_ be *true*.
+ 1. Let _largestUnitPresent_ be *true*.
+ 1. NOTE: The following steps read options and perform independent validation in alphabetical order (GetTemporalRelativeToOption reads *"relativeTo"*, GetRoundingIncrementOption reads *"roundingIncrement"* and GetRoundingModeOption reads *"roundingMode"*).
+ 1. Let _largestUnit_ be ? GetTemporalUnitValuedOption(_roundTo_, *"largestUnit"*, ~unset~).
+ 1. Let _relativeToRecord_ be ? GetTemporalRelativeToOption(_roundTo_).
+ 1. Let _zonedRelativeTo_ be _relativeToRecord_.[[ZonedRelativeTo]].
+ 1. Let _plainRelativeTo_ be _relativeToRecord_.[[PlainRelativeTo]].
+ 1. Let _roundingIncrement_ be ? GetRoundingIncrementOption(_roundTo_).
+ 1. Let _roundingMode_ be ? GetRoundingModeOption(_roundTo_, ~half-expand~).
+ 1. Let _smallestUnit_ be ? GetTemporalUnitValuedOption(_roundTo_, *"smallestUnit"*, ~unset~).
+ 1. Perform ? ValidateTemporalUnitValue(_smallestUnit_, ~datetime~).
+ 1. If _smallestUnit_ is ~unset~, then
+ 1. Set _smallestUnitPresent_ to *false*.
+ 1. Set _smallestUnit_ to ~nanosecond~.
+ 1. Let _existingLargestUnit_ be DefaultTemporalLargestUnit(_duration_).
+ 1. Let _defaultLargestUnit_ be LargerOfTwoTemporalUnits(_existingLargestUnit_, _smallestUnit_).
+ 1. If _largestUnit_ is ~unset~, then
+ 1. Set _largestUnitPresent_ to *false*.
+ 1. Set _largestUnit_ to _defaultLargestUnit_.
+ 1. Else if _largestUnit_ is ~auto~, then
+ 1. Set _largestUnit_ to _defaultLargestUnit_.
+ 1. If _smallestUnitPresent_ is *false* and _largestUnitPresent_ is *false*, throw a *RangeError* exception.
+ 1. If LargerOfTwoTemporalUnits(_largestUnit_, _smallestUnit_) is not _largestUnit_, throw a *RangeError* exception.
+ 1. Let _maximum_ be MaximumTemporalDurationRoundingIncrement(_smallestUnit_).
+ 1. If _maximum_ is not ~unset~, perform ? ValidateTemporalRoundingIncrement(_roundingIncrement_, _maximum_, *false*).
+ 1. If _roundingIncrement_ > 1, and _largestUnit_ is not _smallestUnit_, and TemporalUnitCategory(_smallestUnit_) is ~date~, throw a *RangeError* exception.
+ 1. If _zonedRelativeTo_ is not *undefined*, then
+ 1. Let _internalDuration_ be ToInternalDurationRecord(_duration_).
+ 1. Let _timeZone_ be _zonedRelativeTo_.[[TimeZone]].
+ 1. Let _calendar_ be _zonedRelativeTo_.[[Calendar]].
+ 1. Let _relativeEpochNs_ be _zonedRelativeTo_.[[EpochNanoseconds]].
+ 1. Let _targetEpochNs_ be ? AddZonedDateTime(_relativeEpochNs_, _timeZone_, _calendar_, _internalDuration_, ~constrain~).
+ 1. Set _internalDuration_ to ? DifferenceZonedDateTimeWithRounding(_relativeEpochNs_, _targetEpochNs_, _timeZone_, _calendar_, _largestUnit_, _roundingIncrement_, _smallestUnit_, _roundingMode_).
+ 1. If TemporalUnitCategory(_largestUnit_) is ~date~, set _largestUnit_ to ~hour~.
+ 1. Return ? TemporalDurationFromInternal(_internalDuration_, _largestUnit_).
+ 1. If _plainRelativeTo_ is not *undefined*, then
+ 1. Let _internalDuration_ be ToInternalDurationRecordWith24HourDays(_duration_).
+ 1. Let _targetTime_ be AddTime(MidnightTimeRecord(), _internalDuration_.[[Time]]).
+ 1. Let _calendar_ be _plainRelativeTo_.[[Calendar]].
+ 1. Let _dateDuration_ be ! AdjustDateDurationRecord(_internalDuration_.[[Date]], _targetTime_.[[Days]]).
+ 1. Let _targetDate_ be ? CalendarDateAdd(_calendar_, _plainRelativeTo_.[[ISODate]], _dateDuration_, ~constrain~).
+ 1. Let _isoDateTime_ be CombineISODateAndTimeRecord(_plainRelativeTo_.[[ISODate]], MidnightTimeRecord()).
+ 1. Let _targetDateTime_ be CombineISODateAndTimeRecord(_targetDate_, _targetTime_).
+ 1. Set _internalDuration_ to ? DifferencePlainDateTimeWithRounding(_isoDateTime_, _targetDateTime_, _calendar_, _largestUnit_, _roundingIncrement_, _smallestUnit_, _roundingMode_).
+ 1. Return ? TemporalDurationFromInternal(_internalDuration_, _largestUnit_).
+ 1. If IsCalendarUnit(_existingLargestUnit_) is *true* or IsCalendarUnit(_largestUnit_) is *true*, throw a *RangeError* exception.
+ 1. Assert: IsCalendarUnit(_smallestUnit_) is *false*.
+ 1. Let _internalDuration_ be ToInternalDurationRecordWith24HourDays(_duration_).
+ 1. If _smallestUnit_ is ~day~, then
+ 1. Let _fractionalDays_ be TotalTimeDuration(_internalDuration_.[[Time]], ~day~).
+ 1. Let _days_ be RoundNumberToIncrement(_fractionalDays_, _roundingIncrement_, _roundingMode_).
+ 1. Let _dateDuration_ be ? CreateDateDurationRecord(0, 0, 0, _days_).
+ 1. Set _internalDuration_ to CombineDateAndTimeDuration(_dateDuration_, 0).
+ 1. Else,
+ 1. Let _timeDuration_ be ? RoundTimeDuration(_internalDuration_.[[Time]], _roundingIncrement_, _smallestUnit_, _roundingMode_).
+ 1. Set _internalDuration_ to CombineDateAndTimeDuration(ZeroDateDuration(), _timeDuration_).
+ 1. Return ? TemporalDurationFromInternal(_internalDuration_, _largestUnit_).
+
+
+
+
+
Temporal.Duration.prototype.total ( _totalOf_ )
+
The `Temporal.Duration.prototype.total` method performs the following steps when called:
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. If _totalOf_ is *undefined*, throw a *TypeError* exception.
+ 1. If _totalOf_ is a String, then
+ 1. Let _paramString_ be _totalOf_.
+ 1. Set _totalOf_ to OrdinaryObjectCreate(*null*).
+ 1. Perform ! CreateDataPropertyOrThrow(_totalOf_, *"unit"*, _paramString_).
+ 1. Else,
+ 1. Set _totalOf_ to ? GetOptionsObject(_totalOf_).
+ 1. NOTE: The following steps read options and perform independent validation in alphabetical order (GetTemporalRelativeToOption reads *"relativeTo"*).
+ 1. Let _relativeToRecord_ be ? GetTemporalRelativeToOption(_totalOf_).
+ 1. Let _zonedRelativeTo_ be _relativeToRecord_.[[ZonedRelativeTo]].
+ 1. Let _plainRelativeTo_ be _relativeToRecord_.[[PlainRelativeTo]].
+ 1. Let _unit_ be ? GetTemporalUnitValuedOption(_totalOf_, *"unit"*, ~required~).
+ 1. Perform ? ValidateTemporalUnitValue(_unit_, ~datetime~).
+ 1. If _zonedRelativeTo_ is not *undefined*, then
+ 1. Let _internalDuration_ be ToInternalDurationRecord(_duration_).
+ 1. Let _timeZone_ be _zonedRelativeTo_.[[TimeZone]].
+ 1. Let _calendar_ be _zonedRelativeTo_.[[Calendar]].
+ 1. Let _relativeEpochNs_ be _zonedRelativeTo_.[[EpochNanoseconds]].
+ 1. Let _targetEpochNs_ be ? AddZonedDateTime(_relativeEpochNs_, _timeZone_, _calendar_, _internalDuration_, ~constrain~).
+ 1. Let _total_ be ? DifferenceZonedDateTimeWithTotal(_relativeEpochNs_, _targetEpochNs_, _timeZone_, _calendar_, _unit_).
+ 1. Else if _plainRelativeTo_ is not *undefined*, then
+ 1. Let _internalDuration_ be ToInternalDurationRecordWith24HourDays(_duration_).
+ 1. Let _targetTime_ be AddTime(MidnightTimeRecord(), _internalDuration_.[[Time]]).
+ 1. Let _calendar_ be _plainRelativeTo_.[[Calendar]].
+ 1. Let _dateDuration_ be ! AdjustDateDurationRecord(_internalDuration_.[[Date]], _targetTime_.[[Days]]).
+ 1. Let _targetDate_ be ? CalendarDateAdd(_calendar_, _plainRelativeTo_.[[ISODate]], _dateDuration_, ~constrain~).
+ 1. Let _isoDateTime_ be CombineISODateAndTimeRecord(_plainRelativeTo_.[[ISODate]], MidnightTimeRecord()).
+ 1. Let _targetDateTime_ be CombineISODateAndTimeRecord(_targetDate_, _targetTime_).
+ 1. Let _total_ be ? DifferencePlainDateTimeWithTotal(_isoDateTime_, _targetDateTime_, _calendar_, _unit_).
+ 1. Else,
+ 1. Let _largestUnit_ be DefaultTemporalLargestUnit(_duration_).
+ 1. If IsCalendarUnit(_largestUnit_) is *true* or IsCalendarUnit(_unit_) is *true*, throw a *RangeError* exception.
+ 1. Let _internalDuration_ be ToInternalDurationRecordWith24HourDays(_duration_).
+ 1. Let _total_ be TotalTimeDuration(_internalDuration_.[[Time]], _unit_).
+ 1. Return 𝔽(_total_).
+
+
+
+
+
The `Temporal.Duration.prototype.toString` method performs the following steps when called:
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. NOTE: The following steps read options and perform independent validation in alphabetical order (GetTemporalFractionalSecondDigitsOption reads *"fractionalSecondDigits"* and GetRoundingModeOption reads *"roundingMode"*).
+ 1. Let _digits_ be ? GetTemporalFractionalSecondDigitsOption(_resolvedOptions_).
+ 1. Let _roundingMode_ be ? GetRoundingModeOption(_resolvedOptions_, ~trunc~).
+ 1. Let _smallestUnit_ be ? GetTemporalUnitValuedOption(_resolvedOptions_, *"smallestUnit"*, ~unset~).
+ 1. Perform ? ValidateTemporalUnitValue(_smallestUnit_, ~time~).
+ 1. If _smallestUnit_ is either ~hour~ or ~minute~, throw a *RangeError* exception.
+ 1. Let _precision_ be ToSecondsStringPrecisionRecord(_smallestUnit_, _digits_).
+ 1. If _precision_.[[Unit]] is ~nanosecond~ and _precision_.[[Increment]] = 1, then
+ 1. Return TemporalDurationToString(_duration_, _precision_.[[Precision]]).
+ 1. Let _largestUnit_ be DefaultTemporalLargestUnit(_duration_).
+ 1. Let _internalDuration_ be ToInternalDurationRecord(_duration_).
+ 1. Let _timeDuration_ be ? RoundTimeDuration(_internalDuration_.[[Time]], _precision_.[[Increment]], _precision_.[[Unit]], _roundingMode_).
+ 1. Set _internalDuration_ to CombineDateAndTimeDuration(_internalDuration_.[[Date]], _timeDuration_).
+ 1. Let _roundedLargestUnit_ be LargerOfTwoTemporalUnits(_largestUnit_, ~second~).
+ 1. Let _roundedDuration_ be ? TemporalDurationFromInternal(_internalDuration_, _roundedLargestUnit_).
+ 1. Return TemporalDurationToString(_roundedDuration_, _precision_.[[Precision]]).
+
+
+
+
+
Temporal.Duration.prototype.toJSON ( )
+
The `Temporal.Duration.prototype.toJSON` method performs the following steps when called:
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return TemporalDurationToString(_duration_, ~auto~).
+
+
+
+
+
+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `Temporal.Duration.prototype.toLocaleString` method as specified in the ECMA-402 specification.
+ If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `Temporal.Duration.prototype.toLocaleString` method is used.
+
+
The `Temporal.Duration.prototype.toLocaleString` method performs the following steps when called:
+
+ 1. Let _duration_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_duration_, [[InitializedTemporalDuration]]).
+ 1. Return TemporalDurationToString(_duration_, ~auto~).
+
+
+
+
+
Temporal.Duration.prototype.valueOf ( )
+
The `Temporal.Duration.prototype.valueOf` method performs the following steps when called:
+
+ 1. Throw a *TypeError* exception.
+
+
+
+ This method always throws, because in the absence of `valueOf()`, expressions with arithmetic operators such as `duration1 > duration2` would fall back to being equivalent to `duration1.toString() > duration2.toString()`.
+ Lexicographical comparison of serialized strings might not seem obviously wrong, because the result would sometimes be correct.
+ Implementations are encouraged to phrase the error message to point users to `Temporal.Duration.compare()` and/or `Temporal.Duration.prototype.toString()`.
+
+
+
+
+
+
+
Properties of Temporal.Duration Instances
+
+ Temporal.Duration instances are ordinary objects that inherit properties from the %Temporal.Duration.prototype% intrinsic object.
+ Temporal.Duration instances are initially created with the internal slots described in .
+
+
+ A float64-representable integer is an integer that is exactly representable as a Number.
+ That is, for a float64-representable integer _x_, it must hold that ℝ(𝔽(_x_)) = _x_.
+
+
+ The use of float64-representable integers here is intended so that implementations can store and do arithmetic on Duration fields using 64-bit floating-point values.
+
+
+
+
+
+ Internal Slot
+
+
+ Description
+
+
+
+
+ [[InitializedTemporalDuration]]
+
+
+ The only specified use of this slot is for distinguishing Temporal.Duration instances from other objects.
+
+
+
+
+ [[Years]]
+
+
+ A float64-representable integer representing the number of years in the duration.
+
+
+
+
+ [[Months]]
+
+
+ A float64-representable integer representing the number of months in the duration.
+
+
+
+
+ [[Weeks]]
+
+
+ A float64-representable integer representing the number of weeks in the duration.
+
+
+
+
+ [[Days]]
+
+
+ A float64-representable integer representing the number of days in the duration.
+
+
+
+
+ [[Hours]]
+
+
+ A float64-representable integer representing the number of hours in the duration.
+
+
+
+
+ [[Minutes]]
+
+
+ A float64-representable integer representing the number of minutes in the duration.
+
+
+
+
+ [[Seconds]]
+
+
+ A float64-representable integer representing the number of seconds in the duration.
+
+
+
+
+ [[Milliseconds]]
+
+
+ A float64-representable integer representing the number of milliseconds in the duration.
+
+
+
+
+ [[Microseconds]]
+
+
+ A float64-representable integer representing the number of microseconds in the duration.
+
+
+
+
+ [[Nanoseconds]]
+
+
+ A float64-representable integer representing the number of nanoseconds in the duration.
+
+
+
+
+
+
+
+
Abstract Operations for Temporal.Duration Objects
+
+
+
+ CreateTemporalDuration (
+ _years_: an integer,
+ _months_: an integer,
+ _weeks_: an integer,
+ _days_: an integer,
+ _hours_: an integer,
+ _minutes_: an integer,
+ _seconds_: an integer,
+ _milliseconds_: an integer,
+ _microseconds_: an integer,
+ _nanoseconds_: an integer,
+ optional _newTarget_: a constructor,
+ ): either a normal completion containing a Temporal.Duration or a throw completion
+
+
+
description
+
It creates a Temporal.Duration instance and fills the internal slots with valid values.
+
+
+ 1. If IsValidDuration(_years_, _months_, _weeks_, _days_, _hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_) is *false*, throw a *RangeError* exception.
+ 1. If _newTarget_ is not present, set _newTarget_ to %Temporal.Duration%.
+ 1. Let _object_ be ? OrdinaryCreateFromConstructor(_newTarget_, *"%Temporal.Duration.prototype%"*, « [[InitializedTemporalDuration]], [[Years]], [[Months]], [[Weeks]], [[Days]], [[Hours]], [[Minutes]], [[Seconds]], [[Milliseconds]], [[Microseconds]], [[Nanoseconds]] »).
+ 1. Set _object_.[[Years]] to ℝ(𝔽(_years_)).
+ 1. Set _object_.[[Months]] to ℝ(𝔽(_months_)).
+ 1. Set _object_.[[Weeks]] to ℝ(𝔽(_weeks_)).
+ 1. Set _object_.[[Days]] to ℝ(𝔽(_days_)).
+ 1. Set _object_.[[Hours]] to ℝ(𝔽(_hours_)).
+ 1. Set _object_.[[Minutes]] to ℝ(𝔽(_minutes_)).
+ 1. Set _object_.[[Seconds]] to ℝ(𝔽(_seconds_)).
+ 1. Set _object_.[[Milliseconds]] to ℝ(𝔽(_milliseconds_)).
+ 1. Set _object_.[[Microseconds]] to ℝ(𝔽(_microseconds_)).
+ 1. Set _object_.[[Nanoseconds]] to ℝ(𝔽(_nanoseconds_)).
+ 1. Return _object_.
+
+
+
+
+
+ CreateNegatedTemporalDuration (
+ _duration_: a Temporal.Duration,
+ ): a Temporal.Duration
+
+
+
description
+
It returns a new Temporal.Duration instance that is the negation of _duration_.
+ TemporalDurationFromInternal (
+ _internalDuration_: an Internal Duration Record,
+ _largestUnit_: a Temporal unit,
+ ): either a normal completion containing a Temporal.Duration, or a throw completion
+
+
+
description
+
+ It converts _internalDuration_ back into the form of a `Temporal.Duration` object, with each component stored separately.
+ The time units are balanced up to _largestUnit_.
+ The conversion may be lossy if _largestUnit_ is ~millisecond~, ~microsecond~, or ~nanosecond~.
+ In that case, the internal slots of the returned Temporal.Duration may contain unsafe (but float64-representable) integers.
+ The result of a lossy conversion may be outside the allowed range for Durations, even if the input was not.
+
+
+
+ 1. Let _days_, _hours_, _minutes_, _seconds_, _milliseconds_, and _microseconds_ be 0.
+ 1. Let _sign_ be TimeDurationSign(_internalDuration_.[[Time]]).
+ 1. Let _nanoseconds_ be abs(_internalDuration_.[[Time]]).
+ 1. If TemporalUnitCategory(_largestUnit_) is ~date~, then
+ 1. Set _microseconds_ to floor(_nanoseconds_ / 1000).
+ 1. Set _nanoseconds_ to _nanoseconds_ modulo 1000.
+ 1. Set _milliseconds_ to floor(_microseconds_ / 1000).
+ 1. Set _microseconds_ to _microseconds_ modulo 1000.
+ 1. Set _seconds_ to floor(_milliseconds_ / 1000).
+ 1. Set _milliseconds_ to _milliseconds_ modulo 1000.
+ 1. Set _minutes_ to floor(_seconds_ / 60).
+ 1. Set _seconds_ to _seconds_ modulo 60.
+ 1. Set _hours_ to floor(_minutes_ / 60).
+ 1. Set _minutes_ to _minutes_ modulo 60.
+ 1. Set _days_ to floor(_hours_ / 24).
+ 1. Set _hours_ to _hours_ modulo 24.
+ 1. Else if _largestUnit_ is ~hour~, then
+ 1. Set _microseconds_ to floor(_nanoseconds_ / 1000).
+ 1. Set _nanoseconds_ to _nanoseconds_ modulo 1000.
+ 1. Set _milliseconds_ to floor(_microseconds_ / 1000).
+ 1. Set _microseconds_ to _microseconds_ modulo 1000.
+ 1. Set _seconds_ to floor(_milliseconds_ / 1000).
+ 1. Set _milliseconds_ to _milliseconds_ modulo 1000.
+ 1. Set _minutes_ to floor(_seconds_ / 60).
+ 1. Set _seconds_ to _seconds_ modulo 60.
+ 1. Set _hours_ to floor(_minutes_ / 60).
+ 1. Set _minutes_ to _minutes_ modulo 60.
+ 1. Else if _largestUnit_ is ~minute~, then
+ 1. Set _microseconds_ to floor(_nanoseconds_ / 1000).
+ 1. Set _nanoseconds_ to _nanoseconds_ modulo 1000.
+ 1. Set _milliseconds_ to floor(_microseconds_ / 1000).
+ 1. Set _microseconds_ to _microseconds_ modulo 1000.
+ 1. Set _seconds_ to floor(_milliseconds_ / 1000).
+ 1. Set _milliseconds_ to _milliseconds_ modulo 1000.
+ 1. Set _minutes_ to floor(_seconds_ / 60).
+ 1. Set _seconds_ to _seconds_ modulo 60.
+ 1. Else if _largestUnit_ is ~second~, then
+ 1. Set _microseconds_ to floor(_nanoseconds_ / 1000).
+ 1. Set _nanoseconds_ to _nanoseconds_ modulo 1000.
+ 1. Set _milliseconds_ to floor(_microseconds_ / 1000).
+ 1. Set _microseconds_ to _microseconds_ modulo 1000.
+ 1. Set _seconds_ to floor(_milliseconds_ / 1000).
+ 1. Set _milliseconds_ to _milliseconds_ modulo 1000.
+ 1. Else if _largestUnit_ is ~millisecond~, then
+ 1. Set _microseconds_ to floor(_nanoseconds_ / 1000).
+ 1. Set _nanoseconds_ to _nanoseconds_ modulo 1000.
+ 1. Set _milliseconds_ to floor(_microseconds_ / 1000).
+ 1. Set _microseconds_ to _microseconds_ modulo 1000.
+ 1. Else if _largestUnit_ is ~microsecond~, then
+ 1. Set _microseconds_ to floor(_nanoseconds_ / 1000).
+ 1. Set _nanoseconds_ to _nanoseconds_ modulo 1000.
+ 1. Else,
+ 1. Assert: _largestUnit_ is ~nanosecond~.
+ 1. NOTE: When _largestUnit_ is ~millisecond~, ~microsecond~, or ~nanosecond~, _milliseconds_, _microseconds_, or _nanoseconds_ may be an unsafe integer. In this case, care must be taken when implementing the calculation using floating point arithmetic. It can be implemented in C++ using `std::fma()`. String manipulation will also give an exact result, since the multiplication is by a power of 10.
+ 1. Return ? CreateTemporalDuration(_internalDuration_.[[Date]].[[Years]], _internalDuration_.[[Date]].[[Months]], _internalDuration_.[[Date]].[[Weeks]], _internalDuration_.[[Date]].[[Days]] + _days_ × _sign_, _hours_ × _sign_, _minutes_ × _sign_, _seconds_ × _sign_, _milliseconds_ × _sign_, _microseconds_ × _sign_, _nanoseconds_ × _sign_).
+
+
+
+
+
+ ToTemporalDuration (
+ _item_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.Duration or a throw completion
+
+
+
description
+
Converts _item_ to a new Temporal.Duration instance if possible and returns that, and throws otherwise.
+
+
+ 1. If _item_ is an Object and _item_ has an [[InitializedTemporalDuration]] internal slot, then
+ 1. Return ! CreateTemporalDuration(_item_.[[Years]], _item_.[[Months]], _item_.[[Weeks]], _item_.[[Days]], _item_.[[Hours]], _item_.[[Minutes]], _item_.[[Seconds]], _item_.[[Milliseconds]], _item_.[[Microseconds]], _item_.[[Nanoseconds]]).
+ 1. If _item_ is not an Object, then
+ 1. If _item_ is not a String, throw a *TypeError* exception.
+ 1. Return ? ParseTemporalDurationString(_item_).
+ 1. Let _result_ be a new Partial Duration Record with each field set to 0.
+ 1. Let _partial_ be ? ToPartialDurationRecord(_item_).
+ 1. If _partial_.[[Years]] is not *undefined*, set _result_.[[Years]] to _partial_.[[Years]].
+ 1. If _partial_.[[Months]] is not *undefined*, set _result_.[[Months]] to _partial_.[[Months]].
+ 1. If _partial_.[[Weeks]] is not *undefined*, set _result_.[[Weeks]] to _partial_.[[Weeks]].
+ 1. If _partial_.[[Days]] is not *undefined*, set _result_.[[Days]] to _partial_.[[Days]].
+ 1. If _partial_.[[Hours]] is not *undefined*, set _result_.[[Hours]] to _partial_.[[Hours]].
+ 1. If _partial_.[[Minutes]] is not *undefined*, set _result_.[[Minutes]] to _partial_.[[Minutes]].
+ 1. If _partial_.[[Seconds]] is not *undefined*, set _result_.[[Seconds]] to _partial_.[[Seconds]].
+ 1. If _partial_.[[Milliseconds]] is not *undefined*, set _result_.[[Milliseconds]] to _partial_.[[Milliseconds]].
+ 1. If _partial_.[[Microseconds]] is not *undefined*, set _result_.[[Microseconds]] to _partial_.[[Microseconds]].
+ 1. If _partial_.[[Nanoseconds]] is not *undefined*, set _result_.[[Nanoseconds]] to _partial_.[[Nanoseconds]].
+ 1. Return ? CreateTemporalDuration(_result_.[[Years]], _result_.[[Months]], _result_.[[Weeks]], _result_.[[Days]], _result_.[[Hours]], _result_.[[Minutes]], _result_.[[Seconds]], _result_.[[Milliseconds]], _result_.[[Microseconds]], _result_.[[Nanoseconds]]).
+
+
+
+
+
+ TemporalDurationToString (
+ _duration_: a Temporal.Duration,
+ _precision_: either an integer between 0 and 9 inclusive or ~auto~,
+ ): a String
+
+
+
description
+
It returns a String which is the ISO 8601 representation of _duration_, with the number of decimal places in the seconds value controlled by _precision_.
+
+
+ 1. Let _sign_ be DurationSign(_duration_).
+ 1. Let _datePart_ be the empty String.
+ 1. If _duration_.[[Years]] ≠ 0, then
+ 1. Set _datePart_ to the string concatenation of abs(_duration_.[[Years]]) formatted as a decimal number and the code unit 0x0059 (LATIN CAPITAL LETTER Y).
+ 1. If _duration_.[[Months]] ≠ 0, then
+ 1. Set _datePart_ to the string concatenation of _datePart_, abs(_duration_.[[Months]]) formatted as a decimal number, and the code unit 0x004D (LATIN CAPITAL LETTER M).
+ 1. If _duration_.[[Weeks]] ≠ 0, then
+ 1. Set _datePart_ to the string concatenation of _datePart_, abs(_duration_.[[Weeks]]) formatted as a decimal number, and the code unit 0x0057 (LATIN CAPITAL LETTER W).
+ 1. If _duration_.[[Days]] ≠ 0, then
+ 1. Set _datePart_ to the string concatenation of _datePart_, abs(_duration_.[[Days]]) formatted as a decimal number, and the code unit 0x0044 (LATIN CAPITAL LETTER D).
+ 1. Let _timePart_ be the empty String.
+ 1. If _duration_.[[Hours]] ≠ 0, then
+ 1. Set _timePart_ to the string concatenation of abs(_duration_.[[Hours]]) formatted as a decimal number and the code unit 0x0048 (LATIN CAPITAL LETTER H).
+ 1. If _duration_.[[Minutes]] ≠ 0, then
+ 1. Set _timePart_ to the string concatenation of _timePart_, abs(_duration_.[[Minutes]]) formatted as a decimal number, and the code unit 0x004D (LATIN CAPITAL LETTER M).
+ 1. Let _zeroMinutesAndHigher_ be *false*.
+ 1. If DefaultTemporalLargestUnit(_duration_) is one of ~second~, ~millisecond~, ~microsecond~, or ~nanosecond~, set _zeroMinutesAndHigher_ to *true*.
+ 1. Let _secondsDuration_ be TimeDurationFromComponents(0, 0, _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]]).
+ 1. If _secondsDuration_ ≠ 0, or _zeroMinutesAndHigher_ is *true*, or _precision_ is not ~auto~, then
+ 1. Let _secondsPart_ be abs(truncate(_secondsDuration_ / 109)) formatted as a decimal number.
+ 1. Let _subSecondsPart_ be FormatFractionalSeconds(abs(remainder(_secondsDuration_, 109)), _precision_).
+ 1. Set _timePart_ to the string concatenation of _timePart_, _secondsPart_, _subSecondsPart_, and the code unit 0x0053 (LATIN CAPITAL LETTER S).
+ 1. Let _signPart_ be the code unit 0x002D (HYPHEN-MINUS) if _sign_ < 0, and otherwise the empty String.
+ 1. Let _result_ be the string concatenation of _signPart_, the code unit 0x0050 (LATIN CAPITAL LETTER P) and _datePart_.
+ 1. If _timePart_ is not the empty String, then
+ 1. Set _result_ to the string concatenation of _result_, the code unit 0x0054 (LATIN CAPITAL LETTER T), and _timePart_.
+ 1. Return _result_.
+
+
+
+
+
+ AddDurations (
+ _operation_: either ~add~ or ~subtract~,
+ _duration_: a Temporal.Duration,
+ _other_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.Duration or a throw completion
+
+
+
description
+
+ It adds or subtracts the components of a second duration _other_ to or from those of a first duration _duration_, resulting in a longer or shorter duration, unless calendar calculations would be required, in which case it throws an exception.
+ It balances the result, ensuring that no mixed signs remain.
+
+
+
+ 1. Set _other_ to ? ToTemporalDuration(_other_).
+ 1. If _operation_ is ~subtract~, set _other_ to CreateNegatedTemporalDuration(_other_).
+ 1. Let _largestUnit1_ be DefaultTemporalLargestUnit(_duration_).
+ 1. Let _largestUnit2_ be DefaultTemporalLargestUnit(_other_).
+ 1. Let _largestUnit_ be LargerOfTwoTemporalUnits(_largestUnit1_, _largestUnit2_).
+ 1. If IsCalendarUnit(_largestUnit_) is *true*, throw a *RangeError* exception.
+ 1. Let _d1_ be ToInternalDurationRecordWith24HourDays(_duration_).
+ 1. Let _d2_ be ToInternalDurationRecordWith24HourDays(_other_).
+ 1. Let _timeResult_ be ? AddTimeDuration(_d1_.[[Time]], _d2_.[[Time]]).
+ 1. Let _result_ be CombineDateAndTimeDuration(ZeroDateDuration(), _timeResult_).
+ 1. Return ? TemporalDurationFromInternal(_result_, _largestUnit_).
+
+
+
+
+
+ DurationSign (
+ _duration_: a Temporal.Duration,
+ ): one of -1, 0, or 1
+
+
+
description
+
It returns 1 if the most significant non-zero field in the _duration_ argument is positive, and -1 if the most significant non-zero field is negative. If all of _duration_'s fields are zero, it returns 0.
+
+
+ 1. For each value _v_ of « _duration_.[[Years]], _duration_.[[Months]], _duration_.[[Weeks]], _duration_.[[Days]], _duration_.[[Hours]], _duration_.[[Minutes]], _duration_.[[Seconds]], _duration_.[[Milliseconds]], _duration_.[[Microseconds]], _duration_.[[Nanoseconds]] », do
+ 1. If _v_ < 0, return -1.
+ 1. If _v_ > 0, return 1.
+ 1. Return 0.
+
+
+
+
+
+ IsValidDuration (
+ _years_: an integer,
+ _months_: an integer,
+ _weeks_: an integer,
+ _days_: an integer,
+ _hours_: an integer,
+ _minutes_: an integer,
+ _seconds_: an integer,
+ _milliseconds_: an integer,
+ _microseconds_: an integer,
+ _nanoseconds_: an integer,
+ ): a Boolean
+
+
+
description
+
It returns *true* if its arguments form valid input from which to construct a Temporal.Duration, and *false* otherwise.
+
+
+ 1. Let _sign_ be 0.
+ 1. For each value _v_ of « _years_, _months_, _weeks_, _days_, _hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_ », do
+ 1. Assert: 𝔽(_v_) is finite.
+ 1. If _v_ < 0, then
+ 1. If _sign_ > 0, return *false*.
+ 1. Set _sign_ to -1.
+ 1. Else if _v_ > 0, then
+ 1. If _sign_ < 0, return *false*.
+ 1. Set _sign_ to 1.
+ 1. If abs(_years_) ≥ 232, return *false*.
+ 1. If abs(_months_) ≥ 232, return *false*.
+ 1. If abs(_weeks_) ≥ 232, return *false*.
+ 1. Let _normalizedNanoseconds_ be _days_ × 86,400 × 109 + _hours_ × 3600 × 109 + _minutes_ × 60 × 109 + _seconds_ × 109 + ℝ(𝔽(_milliseconds_)) × 106 + ℝ(𝔽(_microseconds_)) × 103 + ℝ(𝔽(_nanoseconds_)).
+ 1. NOTE: The above step cannot be implemented directly using 64-bit floating-point arithmetic. Multiplying by 10-3, 10-6, and 10-9 respectively may be imprecise when _milliseconds_, _microseconds_, or _nanoseconds_ is an unsafe integer. The step can be implemented by using 128-bit integers and performing all arithmetic on nanosecond values. It could also be implemented in C++ with an implementation of `std::remquo()` with sufficient bits in the quotient. String manipulation will also give an exact result, since the multiplication is by a power of 10.
+ 1. If abs(_normalizedNanoseconds_) ≥ 109 × 253, return *false*.
+ 1. Return *true*.
+
+
+
+
+
Partial Duration Records
+
A partial Duration Record is a Record value used to represent a portion of a Temporal.Duration object, in which it is not required that all the fields be specified.
+
+ Partial Duration Records have the fields listed in .
+ Additionally, Partial Duration Records must have at least one field that is not *undefined*.
+
+
+
+
+
Field Name
+
Value
+
Meaning
+
+
+
[[Years]]
+
a float64-representable integer or *undefined*
+
+ The number of years in the duration.
+
+
+
+
[[Months]]
+
a float64-representable integer or *undefined*
+
+ The number of months in the duration.
+
+
+
+
[[Weeks]]
+
a float64-representable integer or *undefined*
+
+ The number of weeks in the duration.
+
+
+
+
[[Days]]
+
a float64-representable integer or *undefined*
+
+ The number of days in the duration.
+
+
+
+
[[Hours]]
+
a float64-representable integer or *undefined*
+
+ The number of hours in the duration.
+
+
+
+
[[Minutes]]
+
a float64-representable integer or *undefined*
+
+ The number of minutes in the duration.
+
+
+
+
[[Seconds]]
+
a float64-representable integer or *undefined*
+
+ The number of seconds in the duration.
+
+
+
+
[[Milliseconds]]
+
a float64-representable integer or *undefined*
+
+ The number of milliseconds in the duration.
+
+
+
+
[[Microseconds]]
+
a float64-representable integer or *undefined*
+
+ The number of microseconds in the duration.
+
+
+
+
[[Nanoseconds]]
+
a float64-representable integer or *undefined*
+
+ The number of nanoseconds in the duration.
+
+
+
+
+
+
+
+
+ ToPartialDurationRecord (
+ _temporalDurationLike_: an ECMAScript language value,
+ ): either a normal completion containing a Partial Duration Record or a throw completion
+
+
+
description
+
The returned Record has its fields set according to the properties of _temporalDurationLike_.
+
+
+ 1. If _temporalDurationLike_ is not an Object, throw a *TypeError* exception.
+ 1. Let _result_ be a new partial Duration Record with each field set to *undefined*.
+ 1. NOTE: The following steps read properties and perform independent validation in alphabetical order.
+ 1. Let _days_ be ? Get(_temporalDurationLike_, *"days"*).
+ 1. If _days_ is not *undefined*, set _result_.[[Days]] to ? ToIntegerIfIntegral(_days_).
+ 1. Let _hours_ be ? Get(_temporalDurationLike_, *"hours"*).
+ 1. If _hours_ is not *undefined*, set _result_.[[Hours]] to ? ToIntegerIfIntegral(_hours_).
+ 1. Let _microseconds_ be ? Get(_temporalDurationLike_, *"microseconds"*).
+ 1. If _microseconds_ is not *undefined*, set _result_.[[Microseconds]] to ? ToIntegerIfIntegral(_microseconds_).
+ 1. Let _milliseconds_ be ? Get(_temporalDurationLike_, *"milliseconds"*).
+ 1. If _milliseconds_ is not *undefined*, set _result_.[[Milliseconds]] to ? ToIntegerIfIntegral(_milliseconds_).
+ 1. Let _minutes_ be ? Get(_temporalDurationLike_, *"minutes"*).
+ 1. If _minutes_ is not *undefined*, set _result_.[[Minutes]] to ? ToIntegerIfIntegral(_minutes_).
+ 1. Let _months_ be ? Get(_temporalDurationLike_, *"months"*).
+ 1. If _months_ is not *undefined*, set _result_.[[Months]] to ? ToIntegerIfIntegral(_months_).
+ 1. Let _nanoseconds_ be ? Get(_temporalDurationLike_, *"nanoseconds"*).
+ 1. If _nanoseconds_ is not *undefined*, set _result_.[[Nanoseconds]] to ? ToIntegerIfIntegral(_nanoseconds_).
+ 1. Let _seconds_ be ? Get(_temporalDurationLike_, *"seconds"*).
+ 1. If _seconds_ is not *undefined*, set _result_.[[Seconds]] to ? ToIntegerIfIntegral(_seconds_).
+ 1. Let _weeks_ be ? Get(_temporalDurationLike_, *"weeks"*).
+ 1. If _weeks_ is not *undefined*, set _result_.[[Weeks]] to ? ToIntegerIfIntegral(_weeks_).
+ 1. Let _years_ be ? Get(_temporalDurationLike_, *"years"*).
+ 1. If _years_ is not *undefined*, set _result_.[[Years]] to ? ToIntegerIfIntegral(_years_).
+ 1. If _years_ is *undefined*, and _months_ is *undefined*, and _weeks_ is *undefined*, and _days_ is *undefined*, and _hours_ is *undefined*, and _minutes_ is *undefined*, and _seconds_ is *undefined*, and _milliseconds_ is *undefined*, and _microseconds_ is *undefined*, and _nanoseconds_ is *undefined*, throw a *TypeError* exception.
+ 1. Return _result_.
+
+
+
+
+
Duration Nudge Result Records
+
A Duration Nudge Result Record is a Record value used to represent the result of rounding a duration up or down to an increment relative to a date-time, as in NudgeToCalendarUnit, NudgeToZonedTime, or NudgeToDayOrTime.
+
Duration Nudge Result Records have the fields listed in .
+
+
+
+
Field Name
+
Value
+
Meaning
+
+
+
[[Duration]]
+
an Internal Duration Record
+
+ The resulting duration.
+
+
+
+
[[NudgedEpochNs]]
+
an epoch nanoseconds value
+
+ The epoch time corresponding to the rounded duration, relative to the starting point.
+
+
+
+
[[DidExpandCalendarUnit]]
+
a Boolean
+
+ Whether the rounding operation caused the duration to expand to the next day or larger unit.
+
+
+
+
+
+
+
+
+ ComputeNudgeWindow (
+ _sign_: either -1 or 1,
+ _duration_: an Internal Duration Record,
+ _originEpochNs_: an epoch nanoseconds value,
+ _isoDateTime_: an ISO Date-Time Record,
+ _timeZone_: either an available time zone identifier or ~unset~,
+ _calendar_: a calendar type,
+ _increment_: a positive integer,
+ _unit_: a date unit,
+ _additionalShift_: a Boolean,
+ ): either a normal completion containing a Record with fields [[R1]] (a mathematical value), [[R2]] (a mathematical value), [[StartEpochNs]] (an epoch nanoseconds value), [[EndEpochNs]] (an epoch nanoseconds value), [[StartDuration]] (an Internal Duration Record), and [[EndDuration]] (an Internal Duration Record), or a throw completion
+
+
+
description
+
+ It implements calculating the upper and lower bounds of the starting point added to the duration in epoch nanoseconds.
+
+
+
+ 1. If _unit_ is ~year~, then
+ 1. Let _years_ be RoundNumberToIncrement(_duration_.[[Date]].[[Years]], _increment_, ~trunc~).
+ 1. If _additionalShift_ is *false*, then
+ 1. Let _r1_ be _years_.
+ 1. Else,
+ 1. Let _r1_ be _years_ + _increment_ × _sign_.
+ 1. Let _r2_ be _r1_ + _increment_ × _sign_.
+ 1. Let _startDateDuration_ be ? CreateDateDurationRecord(_r1_, 0, 0, 0).
+ 1. Let _endDateDuration_ be ? CreateDateDurationRecord(_r2_, 0, 0, 0).
+ 1. Else if _unit_ is ~month~, then
+ 1. Let _months_ be RoundNumberToIncrement(_duration_.[[Date]].[[Months]], _increment_, ~trunc~).
+ 1. If _additionalShift_ is *false*, then
+ 1. Let _r1_ be _months_.
+ 1. Else,
+ 1. Let _r1_ be _months_ + _increment_ × _sign_.
+ 1. Let _r2_ be _r1_ + _increment_ × _sign_.
+ 1. Let _startDateDuration_ be ? AdjustDateDurationRecord(_duration_.[[Date]], 0, 0, _r1_).
+ 1. Let _endDateDuration_ be ? AdjustDateDurationRecord(_duration_.[[Date]], 0, 0, _r2_).
+ 1. Else if _unit_ is ~week~, then
+ 1. Let _yearsMonths_ be ! AdjustDateDurationRecord(_duration_.[[Date]], 0, 0).
+ 1. Let _weeksStart_ be ? CalendarDateAdd(_calendar_, _isoDateTime_.[[ISODate]], _yearsMonths_, ~constrain~).
+ 1. Let _weeksEnd_ be AddDaysToISODate(_weeksStart_, _duration_.[[Date]].[[Days]]).
+ 1. Let _untilResult_ be CalendarDateUntil(_calendar_, _weeksStart_, _weeksEnd_, ~week~).
+ 1. Let _weeks_ be RoundNumberToIncrement(_duration_.[[Date]].[[Weeks]] + _untilResult_.[[Weeks]], _increment_, ~trunc~).
+ 1. Let _r1_ be _weeks_.
+ 1. Let _r2_ be _weeks_ + _increment_ × _sign_.
+ 1. Let _startDateDuration_ be ? AdjustDateDurationRecord(_duration_.[[Date]], 0, _r1_).
+ 1. Let _endDateDuration_ be ? AdjustDateDurationRecord(_duration_.[[Date]], 0, _r2_).
+ 1. Else,
+ 1. Assert: _unit_ is ~day~.
+ 1. Let _days_ be RoundNumberToIncrement(_duration_.[[Date]].[[Days]], _increment_, ~trunc~).
+ 1. Let _r1_ be _days_.
+ 1. Let _r2_ be _days_ + _increment_ × _sign_.
+ 1. Let _startDateDuration_ be ? AdjustDateDurationRecord(_duration_.[[Date]], _r1_).
+ 1. Let _endDateDuration_ be ? AdjustDateDurationRecord(_duration_.[[Date]], _r2_).
+ 1. Assert: If _sign_ = 1, _r1_ ≥ 0 and _r1_ < _r2_.
+ 1. Assert: If _sign_ = -1, _r1_ ≤ 0 and _r1_ > _r2_.
+ 1. If _r1_ = 0, then
+ 1. Let _startEpochNs_ be _originEpochNs_.
+ 1. Else,
+ 1. Let _start_ be ? CalendarDateAdd(_calendar_, _isoDateTime_.[[ISODate]], _startDateDuration_, ~constrain~).
+ 1. Let _startDateTime_ be CombineISODateAndTimeRecord(_start_, _isoDateTime_.[[Time]]).
+ 1. If _timeZone_ is ~unset~, then
+ 1. Let _startEpochNs_ be GetUTCEpochNanoseconds(_startDateTime_).
+ 1. Else,
+ 1. Let _startEpochNs_ be ? GetEpochNanosecondsFor(_timeZone_, _startDateTime_, ~compatible~).
+ 1. Let _end_ be ? CalendarDateAdd(_calendar_, _isoDateTime_.[[ISODate]], _endDateDuration_, ~constrain~).
+ 1. Let _endDateTime_ be CombineISODateAndTimeRecord(_end_, _isoDateTime_.[[Time]]).
+ 1. If _timeZone_ is ~unset~, then
+ 1. Let _endEpochNs_ be GetUTCEpochNanoseconds(_endDateTime_).
+ 1. Else,
+ 1. Let _endEpochNs_ be ? GetEpochNanosecondsFor(_timeZone_, _endDateTime_, ~compatible~).
+ 1. Let _startDuration_ be CombineDateAndTimeDuration(_startDateDuration_, 0).
+ 1. Let _endDuration_ be CombineDateAndTimeDuration(_endDateDuration_, 0).
+ 1. Return the Record { [[R1]]: _r1_, [[R2]]: _r2_, [[StartEpochNs]]: _startEpochNs_, [[EndEpochNs]]: _endEpochNs_, [[StartDuration]]: _startDuration_, [[EndDuration]]: _endDuration_ }.
+
+
+
+
+
+ NudgeToCalendarUnit (
+ _sign_: either -1 or 1,
+ _duration_: an Internal Duration Record,
+ _originEpochNs_: an epoch nanoseconds value,
+ _destEpochNs_: an epoch nanoseconds value,
+ _isoDateTime_: an ISO Date-Time Record,
+ _timeZone_: either an available time zone identifier or ~unset~,
+ _calendar_: a calendar type,
+ _increment_: a positive integer,
+ _unit_: a date unit,
+ _roundingMode_: a rounding mode,
+ ): either a normal completion containing a Record with fields [[NudgeResult]] (a Duration Nudge Result Record) and [[Total]] (a mathematical value), or a throw completion
+
+
+
description
+
+ It implements rounding a duration to an increment of a calendar unit, relative to a starting point, by calculating the upper and lower bounds of the starting point added to the duration in epoch nanoseconds, and rounding according to which one is closer to _destEpochNs_.
+
+
+
+ 1. Let _didExpandCalendarUnit_ be *false*.
+ 1. Let _nudgeWindow_ be ? ComputeNudgeWindow(_sign_, _duration_, _originEpochNs_, _isoDateTime_, _timeZone_, _calendar_, _increment_, _unit_, *false*).
+ 1. Let _startEpochNs_ be _nudgeWindow_.[[StartEpochNs]].
+ 1. Let _endEpochNs_ be _nudgeWindow_.[[EndEpochNs]].
+ 1. If _sign_ = 1, then
+ 1. If _startEpochNs_ ≤ _destEpochNs_ ≤ _endEpochNs_ is *false*, then
+ 1. Set _nudgeWindow_ to ? ComputeNudgeWindow(_sign_, _duration_, _originEpochNs_, _isoDateTime_, _timeZone_, _calendar_, _increment_, _unit_, *true*).
+ 1. Assert: _nudgeWindow_.[[StartEpochNs]] ≤ _destEpochNs_ ≤ _nudgeWindow_.[[EndEpochNs]].
+ 1. Set _didExpandCalendarUnit_ to *true*.
+ 1. Else,
+ 1. If _endEpochNs_ ≤ _destEpochNs_ ≤ _startEpochNs_ is *false*, then
+ 1. Set _nudgeWindow_ to ? ComputeNudgeWindow(_sign_, _duration_, _originEpochNs_, _isoDateTime_, _timeZone_, _calendar_, _increment_, _unit_, *true*).
+ 1. Assert: _nudgeWindow_.[[EndEpochNs]] ≤ _destEpochNs_ ≤ _nudgeWindow_.[[StartEpochNs]].
+ 1. Set _didExpandCalendarUnit_ to *true*.
+ 1. Let _r1_ be _nudgeWindow_.[[R1]].
+ 1. Let _r2_ be _nudgeWindow_.[[R2]].
+ 1. Set _startEpochNs_ to _nudgeWindow_.[[StartEpochNs]].
+ 1. Set _endEpochNs_ to _nudgeWindow_.[[EndEpochNs]].
+ 1. Let _startDuration_ be _nudgeWindow_.[[StartDuration]].
+ 1. Let _endDuration_ be _nudgeWindow_.[[EndDuration]].
+ 1. Assert: _startEpochNs_ ≠ _endEpochNs_.
+ 1. Let _progress_ be (_destEpochNs_ - _startEpochNs_) / (_endEpochNs_ - _startEpochNs_).
+ 1. Let _total_ be _r1_ + _progress_ × _increment_ × _sign_.
+ 1. NOTE: The above two steps cannot be implemented directly using floating-point arithmetic. This division can be implemented as if expressing _total_ as the quotient of two time durations (which may not be safe integers), performing all other calculations before the division, and finally performing one division operation with a floating-point result for _total_. The division can be implemented in C++ with the `__float128` type if the compiler supports it, or with software emulation such as in the SoftFP library.
+ 1. Assert: 0 ≤ _progress_ ≤ 1.
+ 1. If _sign_ < 0, let _isNegative_ be ~negative~; else let _isNegative_ be ~positive~.
+ 1. Let _unsignedRoundingMode_ be GetUnsignedRoundingMode(_roundingMode_, _isNegative_).
+ 1. If _progress_ = 1, then
+ 1. Let _roundedUnit_ be abs(_r2_).
+ 1. Else,
+ 1. Assert: abs(_r1_) ≤ abs(_total_) < abs(_r2_).
+ 1. Let _roundedUnit_ be ApplyUnsignedRoundingMode(abs(_total_), abs(_r1_), abs(_r2_), _unsignedRoundingMode_).
+ 1. If _roundedUnit_ is abs(_r2_), then
+ 1. Set _didExpandCalendarUnit_ to *true*.
+ 1. Let _resultDuration_ be _endDuration_.
+ 1. Let _nudgedEpochNs_ be _endEpochNs_.
+ 1. Else,
+ 1. Let _resultDuration_ be _startDuration_.
+ 1. Let _nudgedEpochNs_ be _startEpochNs_.
+ 1. Let _nudgeResult_ be Duration Nudge Result Record { [[Duration]]: _resultDuration_, [[NudgedEpochNs]]: _nudgedEpochNs_, [[DidExpandCalendarUnit]]: _didExpandCalendarUnit_ }.
+ 1. Return the Record { [[NudgeResult]]: _nudgeResult_, [[Total]]: _total_ }.
+
+
+
+
+
+ NudgeToZonedTime (
+ _sign_: either -1 or 1,
+ _duration_: an Internal Duration Record,
+ _isoDateTime_: an ISO Date-Time Record,
+ _timeZone_: an available time zone identifier,
+ _calendar_: a calendar type,
+ _increment_: a positive integer,
+ _unit_: a time unit,
+ _roundingMode_: a rounding mode,
+ ): either a normal completion containing a Duration Nudge Result Record or a throw completion
+
+
+
description
+
+ It implements rounding a duration to an increment of a time unit, relative to a `Temporal.ZonedDateTime` starting point, accounting for the case where the rounding causes the time to exceed the total time within a day, which may be influenced by UTC offset changes in the time zone.
+
+
+
+ 1. Let _start_ be ? CalendarDateAdd(_calendar_, _isoDateTime_.[[ISODate]], _duration_.[[Date]], ~constrain~).
+ 1. Let _startDateTime_ be CombineISODateAndTimeRecord(_start_, _isoDateTime_.[[Time]]).
+ 1. Let _endDate_ be AddDaysToISODate(_start_, _sign_).
+ 1. Let _endDateTime_ be CombineISODateAndTimeRecord(_endDate_, _isoDateTime_.[[Time]]).
+ 1. Let _startEpochNs_ be ? GetEpochNanosecondsFor(_timeZone_, _startDateTime_, ~compatible~).
+ 1. Let _endEpochNs_ be ? GetEpochNanosecondsFor(_timeZone_, _endDateTime_, ~compatible~).
+ 1. Let _daySpan_ be TimeDurationFromEpochNanosecondsDifference(_endEpochNs_, _startEpochNs_).
+ 1. Assert: TimeDurationSign(_daySpan_) = _sign_.
+ 1. Let _unitLength_ be the value in the "Length in Nanoseconds" column of the row of whose "Value" column contains _unit_.
+ 1. Let _roundedTimeDuration_ be ? RoundTimeDurationToIncrement(_duration_.[[Time]], _increment_ × _unitLength_, _roundingMode_).
+ 1. Let _beyondDaySpan_ be ! AddTimeDuration(_roundedTimeDuration_, -_daySpan_).
+ 1. If TimeDurationSign(_beyondDaySpan_) ≠ -_sign_, then
+ 1. Let _didRoundBeyondDay_ be *true*.
+ 1. Let _dayDelta_ be _sign_.
+ 1. Set _roundedTimeDuration_ to ? RoundTimeDurationToIncrement(_beyondDaySpan_, _increment_ × _unitLength_, _roundingMode_).
+ 1. Let _nudgedEpochNs_ be AddTimeDurationToEpochNanoseconds(_roundedTimeDuration_, _endEpochNs_).
+ 1. Else,
+ 1. Let _didRoundBeyondDay_ be *false*.
+ 1. Let _dayDelta_ be 0.
+ 1. Let _nudgedEpochNs_ be AddTimeDurationToEpochNanoseconds(_roundedTimeDuration_, _startEpochNs_).
+ 1. Let _dateDuration_ be ! AdjustDateDurationRecord(_duration_.[[Date]], _duration_.[[Date]].[[Days]] + _dayDelta_).
+ 1. Let _resultDuration_ be CombineDateAndTimeDuration(_dateDuration_, _roundedTimeDuration_).
+ 1. Return Duration Nudge Result Record { [[Duration]]: _resultDuration_, [[NudgedEpochNs]]: _nudgedEpochNs_, [[DidExpandCalendarUnit]]: _didRoundBeyondDay_ }.
+
+
+
+
+
+ NudgeToDayOrTime (
+ _duration_: an Internal Duration Record,
+ _destEpochNs_: an epoch nanoseconds value,
+ _largestUnit_: a Temporal unit,
+ _increment_: a positive integer,
+ _smallestUnit_: either a time unit or ~day~,
+ _roundingMode_: a rounding mode,
+ ): either a normal completion containing a Duration Nudge Result Record or a throw completion
+
+
+
description
+
+ It implements rounding a duration to an increment of a time unit, in cases unaffected by the calendar or time zone.
+
+
+
+ 1. Let _timeDuration_ be ! Add24HourDaysToTimeDuration(_duration_.[[Time]], _duration_.[[Date]].[[Days]]).
+ 1. Let _unitLength_ be the value in the "Length in Nanoseconds" column of the row of whose "Value" column contains _smallestUnit_.
+ 1. Let _roundedTime_ be ? RoundTimeDurationToIncrement(_timeDuration_, _unitLength_ × _increment_, _roundingMode_).
+ 1. Let _diffTime_ be ! AddTimeDuration(_roundedTime_, -_timeDuration_).
+ 1. Let _wholeDays_ be truncate(TotalTimeDuration(_timeDuration_, ~day~)).
+ 1. Let _roundedWholeDays_ be truncate(TotalTimeDuration(_roundedTime_, ~day~)).
+ 1. Let _dayDelta_ be _roundedWholeDays_ - _wholeDays_.
+ 1. If _dayDelta_ < 0, let _dayDeltaSign_ be -1; else if _dayDelta_ > 0, let _dayDeltaSign_ be 1; else let _dayDeltaSign_ be 0.
+ 1. If _dayDeltaSign_ = TimeDurationSign(_timeDuration_), let _didExpandDays_ be *true*; else let _didExpandDays_ be *false*.
+ 1. Let _nudgedEpochNs_ be AddTimeDurationToEpochNanoseconds(_diffTime_, _destEpochNs_).
+ 1. Let _days_ be 0.
+ 1. Let _remainder_ be _roundedTime_.
+ 1. If TemporalUnitCategory(_largestUnit_) is ~date~, then
+ 1. Set _days_ to _roundedWholeDays_.
+ 1. Set _remainder_ to ! AddTimeDuration(_roundedTime_, TimeDurationFromComponents(-_roundedWholeDays_ * HoursPerDay, 0, 0, 0, 0, 0)).
+ 1. Let _dateDuration_ be ! AdjustDateDurationRecord(_duration_.[[Date]], _days_).
+ 1. Let _resultDuration_ be CombineDateAndTimeDuration(_dateDuration_, _remainder_).
+ 1. Return Duration Nudge Result Record { [[Duration]]: _resultDuration_, [[NudgedEpochNs]]: _nudgedEpochNs_, [[DidExpandCalendarUnit]]: _didExpandDays_ }.
+
+
+
+
+
+ BubbleRelativeDuration (
+ _sign_: either -1 or 1,
+ _duration_: an Internal Duration Record,
+ _nudgedEpochNs_: an epoch nanoseconds value,
+ _isoDateTime_: an ISO Date-Time Record,
+ _timeZone_: either an available time zone identifier or ~unset~,
+ _calendar_: a calendar type,
+ _largestUnit_: a Temporal unit,
+ _smallestUnit_: a date unit,
+ ): either a normal completion containing an Internal Duration Record or a throw completion
+
+
+
description
+
+ Given a duration that has potentially been made bottom-heavy by rounding in NudgeToCalendarUnit, NudgeToZonedTime, or NudgeToDayOrTime, it bubbles up smaller units to larger units.
+
+
+
+ 1. If _smallestUnit_ is _largestUnit_, return _duration_.
+ 1. Let _largestUnitIndex_ be the ordinal index of the row of whose "Value" column contains _largestUnit_.
+ 1. Let _smallestUnitIndex_ be the ordinal index of the row of whose "Value" column contains _smallestUnit_.
+ 1. Let _unitIndex_ be _smallestUnitIndex_ - 1.
+ 1. Let _done_ be *false*.
+ 1. Repeat, while _unitIndex_ ≥ _largestUnitIndex_ and _done_ is *false*,
+ 1. Let _unit_ be the value in the "Value" column of in the row whose ordinal index is _unitIndex_.
+ 1. If _unit_ is not ~week~, or _largestUnit_ is ~week~, then
+ 1. If _unit_ is ~year~, then
+ 1. Let _years_ be _duration_.[[Date]].[[Years]] + _sign_.
+ 1. Let _endDuration_ be ? CreateDateDurationRecord(_years_, 0, 0, 0).
+ 1. Else if _unit_ is ~month~, then
+ 1. Let _months_ be _duration_.[[Date]].[[Months]] + _sign_.
+ 1. Let _endDuration_ be ? AdjustDateDurationRecord(_duration_.[[Date]], 0, 0, _months_).
+ 1. Else,
+ 1. Assert: _unit_ is ~week~.
+ 1. Let _weeks_ be _duration_.[[Date]].[[Weeks]] + _sign_.
+ 1. Let _endDuration_ be ? AdjustDateDurationRecord(_duration_.[[Date]], 0, _weeks_).
+ 1. Let _end_ be ? CalendarDateAdd(_calendar_, _isoDateTime_.[[ISODate]], _endDuration_, ~constrain~).
+ 1. Let _endDateTime_ be CombineISODateAndTimeRecord(_end_, _isoDateTime_.[[Time]]).
+ 1. If _timeZone_ is ~unset~, then
+ 1. Let _endEpochNs_ be GetUTCEpochNanoseconds(_endDateTime_).
+ 1. Else,
+ 1. Let _endEpochNs_ be ? GetEpochNanosecondsFor(_timeZone_, _endDateTime_, ~compatible~).
+ 1. Let _beyondEnd_ be _nudgedEpochNs_ - _endEpochNs_.
+ 1. If _beyondEnd_ < 0, let _beyondEndSign_ be -1; else if _beyondEnd_ > 0, let _beyondEndSign_ be 1; else let _beyondEndSign_ be 0.
+ 1. If _beyondEndSign_ ≠ -_sign_, then
+ 1. Set _duration_ to CombineDateAndTimeDuration(_endDuration_, 0).
+ 1. Else,
+ 1. Set _done_ to *true*.
+ 1. Set _unitIndex_ to _unitIndex_ - 1.
+ 1. Return _duration_.
+
+
+
+
+
+ RoundRelativeDuration (
+ _duration_: an Internal Duration Record,
+ _originEpochNs_: an epoch nanoseconds value,
+ _destEpochNs_: an epoch nanoseconds value,
+ _isoDateTime_: an ISO Date-Time Record,
+ _timeZone_: either an available time zone identifier or ~unset~,
+ _calendar_: a calendar type,
+ _largestUnit_: a Temporal unit,
+ _increment_: a positive integer,
+ _smallestUnit_: a Temporal unit,
+ _roundingMode_: a rounding mode,
+ ): either a normal completion containing an Internal Duration Record or a throw completion
+
+
+
description
+
+ It rounds a duration _duration_ relative to _isoDateTime_ according to the rounding parameters _smallestUnit_, _increment_, and _roundingMode_, bubbles overflows up to the next highest unit until _largestUnit_, and returns the rounded duration.
+
+
+
+ 1. Let _irregularLengthUnit_ be *false*.
+ 1. If IsCalendarUnit(_smallestUnit_) is *true*, set _irregularLengthUnit_ to *true*.
+ 1. If _timeZone_ is not ~unset~ and _smallestUnit_ is ~day~, set _irregularLengthUnit_ to *true*.
+ 1. If InternalDurationSign(_duration_) < 0, let _sign_ be -1; else let _sign_ be 1.
+ 1. If _irregularLengthUnit_ is *true*, then
+ 1. Let _record_ be ? NudgeToCalendarUnit(_sign_, _duration_, _originEpochNs_, _destEpochNs_, _isoDateTime_, _timeZone_, _calendar_, _increment_, _smallestUnit_, _roundingMode_).
+ 1. Let _nudgeResult_ be _record_.[[NudgeResult]].
+ 1. Else if _timeZone_ is not ~unset~, then
+ 1. Let _nudgeResult_ be ? NudgeToZonedTime(_sign_, _duration_, _isoDateTime_, _timeZone_, _calendar_, _increment_, _smallestUnit_, _roundingMode_).
+ 1. Else,
+ 1. Let _nudgeResult_ be ? NudgeToDayOrTime(_duration_, _destEpochNs_, _largestUnit_, _increment_, _smallestUnit_, _roundingMode_).
+ 1. Set _duration_ to _nudgeResult_.[[Duration]].
+ 1. If _nudgeResult_.[[DidExpandCalendarUnit]] is *true* and _smallestUnit_ is not ~week~, then
+ 1. Let _startUnit_ be LargerOfTwoTemporalUnits(_smallestUnit_, ~day~).
+ 1. Set _duration_ to ? BubbleRelativeDuration(_sign_, _duration_, _nudgeResult_.[[NudgedEpochNs]], _isoDateTime_, _timeZone_, _calendar_, _largestUnit_, _startUnit_).
+ 1. Return _duration_.
+
+
+
+
+
+ TotalRelativeDuration (
+ _duration_: an Internal Duration Record,
+ _originEpochNs_: an epoch nanoseconds value,
+ _destEpochNs_: an epoch nanoseconds value,
+ _isoDateTime_: an ISO Date-Time Record,
+ _timeZone_: either an available time zone identifier or ~unset~,
+ _calendar_: a calendar type,
+ _unit_: a Temporal unit,
+ ): either a normal completion containing a mathematical value, or a throw completion
+
+
+
description
+
It returns the total number of _unit_ in _duration_, relative to _isoDateTime_ if a starting point is necessary for calendar units.
+
+
+ 1. If IsCalendarUnit(_unit_) is *true*, or _timeZone_ is not ~unset~ and _unit_ is ~day~, then
+ 1. If InternalDurationSign(_duration_) < 0, let _sign_ be -1; else let _sign_ be 1.
+ 1. Let _record_ be ? NudgeToCalendarUnit(_sign_, _duration_, _originEpochNs_, _destEpochNs_, _isoDateTime_, _timeZone_, _calendar_, 1, _unit_, ~trunc~).
+ 1. Return _record_.[[Total]].
+ 1. Let _timeDuration_ be ! Add24HourDaysToTimeDuration(_duration_.[[Time]], _duration_.[[Date]].[[Days]]).
+ 1. Return TotalTimeDuration(_timeDuration_, _unit_).
+
+
+
+
diff --git a/temporal/formatting.emu b/temporal/formatting.emu
new file mode 100644
index 0000000000..1b92cddb5c
--- /dev/null
+++ b/temporal/formatting.emu
@@ -0,0 +1,269 @@
+
+
+
+
+
Formatting RFC 9557 Strings
+
+
This section contains abstract operations used for serializing data into various partial RFC 9557 string formats.
+
+
+
+ FormatCalendarAnnotation (
+ _id_: a calendar type,
+ _showCalendar_: one of ~auto~, ~always~, ~never~, or ~critical~,
+ ): a String
+
+
+
description
+
+ It returns a string with a calendar annotation suitable for concatenating to the end of an ISO 8601 / RFC 9557 string.
+ Depending on the given _id_ and value of _showCalendar_, the string may be empty if no calendar annotation need be included.
+
+
+
+ 1. If _showCalendar_ is ~never~, return the empty String.
+ 1. If _showCalendar_ is ~auto~ and _id_ is *"iso8601"*, return the empty String.
+ 1. If _showCalendar_ is ~critical~, let _flag_ be *"!"*; else, let flag be the empty String.
+ 1. Return the string-concatenation of *"["*, _flag_, *"u-ca="*, _id_, and *"]"*.
+
+
+
+
+
+ FormatDateTimeUTCOffsetRounded (
+ _offsetNanoseconds_: an integer in the interval from -86400 × 109 (exclusive) to 86400 × 109 (exclusive),
+ ): a String
+
+
+
description
+
It rounds _offsetNanoseconds_ to the nearest minute boundary and formats the rounded value into a ±HH:MM format, to support available named time zones that may have sub-minute offsets.
+
+
+ 1. Set _offsetNanoseconds_ to RoundNumberToIncrement(_offsetNanoseconds_, 60 × 109, ~half-expand~).
+ 1. Let _offsetMinutes_ be _offsetNanoseconds_ / (60 × 109).
+ 1. Return FormatOffsetTimeZoneIdentifier(_offsetMinutes_).
+
+
+
+
+
+ FormatFractionalSeconds (
+ _subSecondNanoseconds_: an integer in the inclusive interval from 0 to 999999999,
+ _precision_: either an integer in the inclusive interval from 0 to 9 or ~auto~,
+ ): a String
+
+
+
description
+
+ If _precision_ = 0, or _precision_ is ~auto~ and _subSecondNanoseconds_ = 0, then an empty String will be returned.
+ Otherwise, the output will be a decimal point followed by a sequence of fractional seconds digits, truncated to _precision_ digits or (if _precision_ is ~auto~) to the last non-zero digit.
+
+
+
+ 1. If _precision_ is ~auto~, then
+ 1. If _subSecondNanoseconds_ = 0, return the empty String.
+ 1. Let _fractionString_ be ToZeroPaddedDecimalString(_subSecondNanoseconds_, 9).
+ 1. Set _fractionString_ to the longest prefix of _fractionString_ ending with a code unit other than 0x0030 (DIGIT ZERO).
+ 1. Else,
+ 1. If _precision_ = 0, return the empty String.
+ 1. Let _fractionString_ be ToZeroPaddedDecimalString(_subSecondNanoseconds_, 9).
+ 1. Set _fractionString_ to the substring of _fractionString_ from 0 to _precision_.
+ 1. Return the string-concatenation of the code unit 0x002E (FULL STOP) and _fractionString_.
+
+
+
+
+
+ FormatISODateTime (
+ _isoDateTime_: an ISO Date-Time Record,
+ _calendar_: a calendar type,
+ _precision_: either an integer in the inclusive interval from 0 to 9, ~minute~, or ~auto~,
+ _showCalendar_: one of ~auto~, ~always~, ~never~, or ~critical~,
+ ): a String
+
+
+
description
+
It formats an ISO Date-Time Record into an ISO 8601 / RFC 9557 string, to the precision specified by _precision_.
+
+
+ 1. Let _yearString_ be PadISOYear(_isoDateTime_.[[ISODate]].[[Year]]).
+ 1. Let _monthString_ be ToZeroPaddedDecimalString(_isoDateTime_.[[ISODate]].[[Month]], 2).
+ 1. Let _dayString_ be ToZeroPaddedDecimalString(_isoDateTime_.[[ISODate]].[[Day]], 2).
+ 1. Let _subSecondNanoseconds_ be _isoDateTime_.[[Time]].[[Millisecond]] × 106 + _isoDateTime_.[[Time]].[[Microsecond]] × 103 + _isoDateTime_.[[Time]].[[Nanosecond]].
+ 1. Let _timeString_ be FormatTimeString(_isoDateTime_.[[Time]].[[Hour]], _isoDateTime_.[[Time]].[[Minute]], _isoDateTime_.[[Time]].[[Second]], _subSecondNanoseconds_, _precision_).
+ 1. Let _calendarString_ be FormatCalendarAnnotation(_calendar_, _showCalendar_).
+ 1. Return the string-concatenation of _yearString_, the code unit 0x002D (HYPHEN-MINUS), _monthString_, the code unit 0x002D (HYPHEN-MINUS), _dayString_, 0x0054 (LATIN CAPITAL LETTER T), _timeString_, and _calendarString_.
+
+
+
+
+
+ FormatOffsetTimeZoneIdentifier (
+ _offsetMinutes_: an integer in the inclusive interval from -1439 to 1439,
+ optional _style_: either ~separated~ or ~unseparated~,
+ ): an offset time zone identifier
+
+
+
description
+
+ It formats a UTC offset, in minutes, into a UTC offset string.
+ If _style_ is ~separated~ or not present, then the output will be formatted like ±HH:MM.
+ If _style_ is ~unseparated~, then the output will be formatted like ±HHMM.
+
+
+
+ 1. If _offsetMinutes_ ≥ 0, let _sign_ be the code unit 0x002B (PLUS SIGN); else let _sign_ be the code unit 0x002D (HYPHEN-MINUS).
+ 1. Let _absoluteMinutes_ be abs(_offsetMinutes_).
+ 1. Let _hour_ be floor(_absoluteMinutes_ / 60).
+ 1. Let _minute_ be _absoluteMinutes_ modulo 60.
+ 1. Let _timeString_ be FormatTimeString(_hour_, _minute_, 0, 0, ~minute~, _style_).
+ 1. Return the string-concatenation of _sign_ and _timeString_.
+
+
+
+
+
+ FormatTimeString (
+ _hour_: an integer in the inclusive interval from 0 to 23,
+ _minute_: an integer in the inclusive interval from 0 to 59,
+ _second_: an integer in the inclusive interval from 0 to 59,
+ _subSecondNanoseconds_: an integer in the inclusive interval from 0 to 999999999,
+ _precision_: either an integer in the inclusive interval from 0 to 9, ~minute~, or ~auto~,
+ optional _style_: either ~separated~ or ~unseparated~,
+ ): a String
+
+
+
description
+
+ It formats a collection of unsigned time components into a string, truncating units as necessary, and separating hours, minutes, and seconds with colons unless _style_ is ~unseparated~.
+ The output will be formatted like HH:MM or HHMM if _precision_ is ~minute~.
+ Otherwise, the output will be formatted like HH:MM:SS or HHMMSS if _precision_ = 0, or _subSecondNanoseconds_ = 0 and _precision_ is ~auto~.
+ Otherwise, the output will be formatted like HH:MM:SS.fff or HHMMSS.fff where "fff" is a sequence of fractional seconds digits, truncated to _precision_ digits or (if _precision_ is ~auto~) to the last non-zero digit.
+
+
+
+ 1. If _style_ is present and _style_ is ~unseparated~, let _separator_ be the empty String; else let _separator_ be *":"*.
+ 1. Let _hh_ be ToZeroPaddedDecimalString(_hour_, 2).
+ 1. Let _mm_ be ToZeroPaddedDecimalString(_minute_, 2).
+ 1. If _precision_ is ~minute~, return the string-concatenation of _hh_, _separator_, and _mm_.
+ 1. Let _ss_ be ToZeroPaddedDecimalString(_second_, 2).
+ 1. Let _subSecondsPart_ be FormatFractionalSeconds(_subSecondNanoseconds_, _precision_).
+ 1. Return the string-concatenation of _hh_, _separator_, _mm_, _separator_, _ss_, and _subSecondsPart_.
+
+
+
+
+
+ FormatUTCOffsetNanoseconds (
+ _offsetNanoseconds_: an integer in the interval from -86400 × 109 (exclusive) to 86400 × 109 (exclusive),
+ ): a String
+
+
+
description
+
+ If the offset represents an integer number of minutes, then the output will be formatted like ±HH:MM.
+ Otherwise, the output will be formatted like ±HH:MM:SS or (if the offset does not evenly divide into seconds) ±HH:MM:SS.fff… where the "fff" part is a sequence of at least 1 and at most 9 fractional seconds digits with no trailing zeroes.
+
+
+
+ 1. If _offsetNanoseconds_ ≥ 0, let _sign_ be the code unit 0x002B (PLUS SIGN); else let _sign_ be the code unit 0x002D (HYPHEN-MINUS).
+ 1. Let _absoluteNanoseconds_ be abs(_offsetNanoseconds_).
+ 1. Let _hour_ be floor(_absoluteNanoseconds_ / (3600 × 109)).
+ 1. Let _minute_ be floor(_absoluteNanoseconds_ / (60 × 109)) modulo 60.
+ 1. Let _second_ be floor(_absoluteNanoseconds_ / 109) modulo 60.
+ 1. Let _subSecondNanoseconds_ be _absoluteNanoseconds_ modulo 109.
+ 1. If _second_ = 0 and _subSecondNanoseconds_ = 0, let _precision_ be ~minute~; else let _precision_ be ~auto~.
+ 1. Let _timeString_ be FormatTimeString(_hour_, _minute_, _second_, _subSecondNanoseconds_, _precision_).
+ 1. Return the string-concatenation of _sign_ and _timeString_.
+
+
+
+
+
+ PadISOYear (
+ _y_: an integer,
+ ): a String
+
+
+
description
+
It returns a String representation of _y_ suitable for inclusion in an ISO 8601 string, either in 4-digit format or 6-digit format with sign.
+
+
+ 1. If _y_ ≥ 0 and _y_ ≤ 9999, return ToZeroPaddedDecimalString(_y_, 4).
+ 1. If _y_ > 0, let _yearSign_ be *"+"*; else let _yearSign_ be *"-"*.
+ 1. Let _year_ be ToZeroPaddedDecimalString(abs(_y_), 6).
+ 1. Return the string-concatenation of _yearSign_ and _year_.
+
+
+
+
+
+ ToSecondsStringPrecisionRecord (
+ _smallestUnit_: one of ~minute~, ~second~, ~millisecond~, ~microsecond~, ~nanosecond~, or ~unset~,
+ _fractionalDigitCount_: either an integer in the inclusive interval from 0 to 9 or ~auto~,
+ ): a Record with fields [[Precision]] (either an integer in the inclusive interval from 0 to 9, ~minute~, or ~auto~), [[Unit]] (one of ~minute~, ~second~, ~millisecond~, ~microsecond~, or ~nanosecond~), and [[Increment]] (one of 1, 10, or 100)
+
+
+
description
+
+ The returned Record represents details for serializing minutes and seconds to a string subject to the specified _smallestUnit_ or (when _smallestUnit_ is ~unset~) _fractionalDigitCount_ digits after the decimal point in the seconds.
+ Its [[Precision]] field is either that count of digits, the value ~auto~ signifying that there should be no insignificant trailing zeroes, or the value ~minute~ signifying that seconds should not be included at all.
+ Its [[Unit]] field is the most precise unit that can contribute to the string, and its [[Increment]] field indicates the rounding increment that should be applied to that unit.
+
+
+
+ 1. If _smallestUnit_ is ~minute~, return the Record {
+ [[Precision]]: ~minute~,
+ [[Unit]]: ~minute~,
+ [[Increment]]: 1
+ }.
+ 1. If _smallestUnit_ is ~second~, return the Record {
+ [[Precision]]: 0,
+ [[Unit]]: ~second~,
+ [[Increment]]: 1
+ }.
+ 1. If _smallestUnit_ is ~millisecond~, return the Record {
+ [[Precision]]: 3,
+ [[Unit]]: ~millisecond~,
+ [[Increment]]: 1
+ }.
+ 1. If _smallestUnit_ is ~microsecond~, return the Record {
+ [[Precision]]: 6,
+ [[Unit]]: ~microsecond~,
+ [[Increment]]: 1
+ }.
+ 1. If _smallestUnit_ is ~nanosecond~, return the Record {
+ [[Precision]]: 9,
+ [[Unit]]: ~nanosecond~,
+ [[Increment]]: 1
+ }.
+ 1. Assert: _smallestUnit_ is ~unset~.
+ 1. If _fractionalDigitCount_ is ~auto~, return the Record {
+ [[Precision]]: ~auto~,
+ [[Unit]]: ~nanosecond~,
+ [[Increment]]: 1
+ }.
+ 1. If _fractionalDigitCount_ = 0, return the Record {
+ [[Precision]]: 0,
+ [[Unit]]: ~second~,
+ [[Increment]]: 1
+ }.
+ 1. If _fractionalDigitCount_ is in the inclusive interval from 1 to 3, return the Record {
+ [[Precision]]: _fractionalDigitCount_,
+ [[Unit]]: ~millisecond~,
+ [[Increment]]: 103 - _fractionalDigitCount_
+ }.
+ 1. If _fractionalDigitCount_ is in the inclusive interval from 4 to 6, return the Record {
+ [[Precision]]: _fractionalDigitCount_,
+ [[Unit]]: ~microsecond~,
+ [[Increment]]: 106 - _fractionalDigitCount_
+ }.
+ 1. Assert: _fractionalDigitCount_ is in the inclusive interval from 7 to 9.
+ 1. Return the Record {
+ [[Precision]]: _fractionalDigitCount_,
+ [[Unit]]: ~nanosecond~,
+ [[Increment]]: 109 - _fractionalDigitCount_
+ }.
+
+
+
diff --git a/temporal/grammar.emu b/temporal/grammar.emu
new file mode 100644
index 0000000000..2ace2bf154
--- /dev/null
+++ b/temporal/grammar.emu
@@ -0,0 +1,826 @@
+
+
+
+
Parsing ISO 8601 / RFC 9557 Strings
+
+
+ Several operations in this section are intended to parse strings representing a date, a time, a duration, or a combined date and time.
+ For the purposes of these operations, a valid ISO 8601 / RFC 9557 string is defined as a string that can be generated by one of the goal elements of the following grammar.
+
+
+
+
ISO 8601 / RFC 9557 Grammar
+
+
This grammar is adapted from the ABNF grammar of the ISO 8601 date-time format that is given in appendix A of RFC 3339, augmented with the grammar of annotations in section 4.1 of RFC 9557.
+
+ RFC 9557 and ISO 8601 are similar, but ISO 8601 defines a number of optional deviations that are allowed "by agreement between the communicating parties".
+ The following is a list of deviations supported by this grammar:
+
+
+
Only the calendar date format is supported, not the weekdate or ordinal date format.
Fractional parts may have 1 through 9 decimal places.
+
In time representations, only seconds are allowed to have a fractional part.
+
In duration representations, only hours, minutes, and seconds are allowed to have a fractional part.
+
A space may be used to separate the date and time in a combined date / time representation, but not in a duration (e.g., *"1970-01-01 00:00Z"* is valid but *"P1D 1H"* is not).
+
Alphabetic designators may be in lower or upper case (e.g., *"1970-01-01t00:00Z"* and *"1970-01-01T00:00z"* and *"pT1m"* are valid).
+
Period or comma may be used as the decimal separator (e.g., *"PT1,00H"* is a valid representation of a 1-hour duration).
+
UTC offsets of *"-00:00"* and *"-0000"* and *"-00"* are allowed, and all mean the same thing as *"+00:00"*.
+
UTC offsets may have seconds and up to 9 sub-second fractional digits (e.g., *"1970-01-01T00:00:00+00:00:00.123456789"* is valid).
+
The constituent date, time, and UTC offset parts of a combined representation may each independently use basic format (with no separator symbols) or extended format (with mandatory `-` or `:` separators), as long as each such part is itself in either basic format or extended format (e.g., *"1970-01-01T012345"* and *"19700101T01:23:45"* are valid but *"1970-0101T012345"* and *"1970-01-01T0123:45"* are not).
+
+ When parsing a date representation for a Temporal.PlainMonthDay, the year may be omitted.
+ The year may optionally be replaced by `--` as in RFC 3339 Appendix A.
+
+
When parsing a date representation without a day for a Temporal.PlainYearMonth, the expression is allowed to be in basic format (with no separator symbols).
+
A duration specifier of *"W"* (weeks) can be combined with any of the other specifiers (e.g., *"P1M1W1D"* is valid).
+
Anything else described by ISO 8601 as requiring mutual agreement between communicating parties, is disallowed.
+
+
+ In addition to the above deviations, any number of conforming RFC 9557 suffixes in square brackets are allowed.
+ However, the only recognized suffixes are time zone and BCP 47 calendar.
+ Others are ignored, unless they are prefixed with `!`, in which case they are rejected.
+ Note that the suffix keys, although they look similar, are not the same as keys in RFC 6067.
+ In particular, keys are lowercase-only.
+
+
+
+ Alpha ::: one of
+ `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` `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`
+
+ LowercaseAlpha ::: one of
+ `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`
+
+ HoursDesignator ::: one of
+ `H` `h`
+
+ MinutesDesignator ::: one of
+ `M` `m`
+
+ MonthsDesignator ::: one of
+ `M` `m`
+
+ DurationDesignator ::: one of
+ `P` `p`
+
+ SecondsDesignator ::: one of
+ `S` `s`
+
+ DateTimeSeparator :::
+ <SP>
+ `T`
+ `t`
+
+ TimeDesignator ::: one of
+ `T` `t`
+
+ WeeksDesignator ::: one of
+ `W` `w`
+
+ YearsDesignator ::: one of
+ `Y` `y`
+
+ UTCDesignator ::: one of
+ `Z` `z`
+
+ AnnotationCriticalFlag :::
+ `!`
+
+ DateYear :::
+ DecimalDigit DecimalDigit DecimalDigit DecimalDigit
+ ASCIISign DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
+
+
Grammar symbols not explicitly defined above (|NonZeroDigit|, |DecimalDigit|, |DecimalDigits|) have the definitions used in the Lexical Grammar for numeric literals ().
+
+
+
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*.
+
+
+
+
+
+ It is a Syntax Error if |DateYear| is *"-000000"*.
+
+
+
+
+
+
+
RFC 9557 Time Zone Parse Records
+
A RFC 9557 Time Zone Parse Record is a Record value used to represent the result of parsing the representation of the time zone in an ISO 8601 / RFC 9557 string.
+
RFC 9557 Time Zone Parse Records have the fields listed in .
+
+
+
+
Field Name
+
Value
+
Meaning
+
+
+
[[Z]]
+
a Boolean
+
+ Whether the string contained the `Z` UTC designator.
+
+
+
+
[[OffsetString]]
+
a String or ~empty~
+
+ The UTC offset from the string, or ~empty~ if none was present.
+
+
+
+
[[TimeZoneAnnotation]]
+
a String or ~empty~
+
+ The time zone annotation from the string, or ~empty~ if none was present.
+
+
+
+
+
+
+
+
Time Zone Identifier Parse Records
+
A Time Zone Identifier Parse Record is a Record value used to represent the result of parsing a time zone identifier either as an offset time zone or named time zone.
+
Time Zone Identifier Parse Records have the fields listed in .
+
The two fields are mutually exclusive. One of them always has the value ~empty~.
+
+
+
+
Field Name
+
Value
+
Meaning
+
+
+
[[Name]]
+
a String or ~empty~
+
+ The time zone's name (not necessarily an available named time zone identifier), or ~empty~ if the time zone is an offset time zone.
+
+
+
+
[[OffsetMinutes]]
+
an integer in the inclusive interval from -1439 to 1439, or ~empty~
+
+ The time zone's UTC offset expressed as a number of minutes, or ~empty~ if the time zone is a named time zone.
+
+
+
+
+
+
+
+
ISO Date-Time Parse Records
+
An ISO Date-Time Parse Record is a Record value used to represent the result of parsing an ISO 8601 / RFC 9557 string.
+
+ For any ISO Date-Time Parse Record _r_, IsValidISODate(_r_.[[Year]], _r_.[[Month]], _r_.[[Day]]) must return *true*, or, if _r_.[[Year]] is ~empty~, IsValidISODate(1972, _r_.[[Month]], _r_.[[Day]]) must return *true*.
+ It is not necessary for the represented date and time to be within the range given by ISODateTimeWithinLimits.
+
+
ISO Date-Time Parse Records have the fields listed in .
+
+
+
+
Field Name
+
Value
+
Meaning
+
+
+
[[Year]]
+
an integer or ~empty~
+
+ The year in the ISO 8601 calendar, or ~empty~ if the string's format was that of |TemporalMonthDayString| and the year was omitted.
+
+
+
+
[[Month]]
+
an integer between 1 and 12, inclusive
+
+ The number of the month in the ISO 8601 calendar.
+
+
+
+
[[Day]]
+
an integer between 1 and 31, inclusive
+
+ The number of the day of the month in the ISO 8601 calendar.
+
+
+
+
[[Time]]
+
either a Time Record with [[Days]] value 0, or ~start-of-day~
+
+ The time of day, or ~start-of-day~ if the time was omitted from the string.
+
+
+
+
[[TimeZone]]
+
an RFC 9557 Time Zone Parse Record
+
+ A representation of how the time zone was expressed in the string.
+
+
+
+
[[Calendar]]
+
a String or ~empty~
+
+ The calendar type from the string, or ~empty~ if none was present.
+
+
+
+
+
+
+
+
+ ParseISODateTime (
+ _isoString_: a String,
+ _allowedFormats_: a List of nonterminals,
+ ): either a normal completion containing an ISO Date-Time Parse Record or a throw completion
+
+
+
description
+
It parses the argument as an ISO 8601 / RFC 9557 string and returns a Record representing each date and time component as a distinct field.
+
+
+ 1. Let _parseResult_ be ~empty~.
+ 1. Let _calendar_ be ~empty~.
+ 1. Let _yearAbsent_ be *false*.
+ 1. For each nonterminal _goal_ of _allowedFormats_, do
+ 1. If _parseResult_ is not a Parse Node, then
+ 1. Set _parseResult_ to ParseText(StringToCodePoints(_isoString_), _goal_).
+ 1. If _parseResult_ is a Parse Node, then
+ 1. Let _calendarWasCritical_ be *false*.
+ 1. For each |Annotation| Parse Node _annotation_ contained within _parseResult_, do
+ 1. Let _key_ be the source text matched by the |AnnotationKey| Parse Node contained within _annotation_.
+ 1. Let _value_ be the source text matched by the |AnnotationValue| Parse Node contained within _annotation_.
+ 1. If CodePointsToString(_key_) is *"u-ca"*, then
+ 1. If _calendar_ is ~empty~, then
+ 1. Set _calendar_ to CodePointsToString(_value_).
+ 1. If _annotation_ contains an |AnnotationCriticalFlag| Parse Node, set _calendarWasCritical_ to *true*.
+ 1. Else,
+ 1. If _annotation_ contains an |AnnotationCriticalFlag| Parse Node, or _calendarWasCritical_ is *true*, throw a *RangeError* exception.
+ 1. Else,
+ 1. If _annotation_ contains an |AnnotationCriticalFlag| Parse Node, throw a *RangeError* exception.
+ 1. If _parseResult_ does not contain an |AnnotatedDateTime| Parse Node and _goal_ is |TemporalYearMonthString| or |TemporalMonthDayString|, then
+ 1. If _calendar_ is not ~empty~ and the ASCII-lowercase of _calendar_ is not *"iso8601"*, throw a *RangeError* exception.
+ 1. If _goal_ is |TemporalMonthDayString|, set _yearAbsent_ to *true*.
+ 1. If _parseResult_ is not a Parse Node, throw a *RangeError* exception.
+ 1. NOTE: Applications of StringToNumber below do not lose precision, since each of the parsed values is guaranteed to be a sufficiently short string of decimal digits.
+ 1. Let each of _year_, _month_, _day_, _hour_, _minute_, _second_, and _fSeconds_ be the source text matched by the respective |DateYear|, |DateMonth|, |DateDay|, the first |Hour|, the first |MinuteSecond|, |TimeSecond|, and the first |TemporalDecimalFraction| Parse Node contained within _parseResult_, or an empty sequence of code points if not present.
+ 1. Let _yearMV_ be ℝ(StringToNumber(CodePointsToString(_year_))).
+ 1. If _month_ is empty, then
+ 1. Let _monthMV_ be 1.
+ 1. Else,
+ 1. Let _monthMV_ be ℝ(StringToNumber(CodePointsToString(_month_))).
+ 1. If _day_ is empty, then
+ 1. Let _dayMV_ be 1.
+ 1. Else,
+ 1. Let _dayMV_ be ℝ(StringToNumber(CodePointsToString(_day_))).
+ 1. If _hour_ is empty, then
+ 1. Let _hourMV_ be 0.
+ 1. Else,
+ 1. Let _hourMV_ be ℝ(StringToNumber(CodePointsToString(_hour_))).
+ 1. If _minute_ is empty, then
+ 1. Let _minuteMV_ be 0.
+ 1. Else,
+ 1. Let _minuteMV_ be ℝ(StringToNumber(CodePointsToString(_minute_))).
+ 1. If _second_ is empty, then
+ 1. Let _secondMV_ be 0.
+ 1. Else,
+ 1. Let _secondMV_ be ℝ(StringToNumber(CodePointsToString(_second_))).
+ 1. If _secondMV_ = 60, then
+ 1. Set _secondMV_ to 59.
+ 1. If _fSeconds_ is not empty, then
+ 1. Let _fSecondsDigits_ be the substring of CodePointsToString(_fSeconds_) from 1.
+ 1. Let _fSecondsDigitsExtended_ be the string-concatenation of _fSecondsDigits_ and *"000000000"*.
+ 1. Let _millisecond_ be the substring of _fSecondsDigitsExtended_ from 0 to 3.
+ 1. Let _microsecond_ be the substring of _fSecondsDigitsExtended_ from 3 to 6.
+ 1. Let _nanosecond_ be the substring of _fSecondsDigitsExtended_ from 6 to 9.
+ 1. Let _millisecondMV_ be ℝ(StringToNumber(_millisecond_)).
+ 1. Let _microsecondMV_ be ℝ(StringToNumber(_microsecond_)).
+ 1. Let _nanosecondMV_ be ℝ(StringToNumber(_nanosecond_)).
+ 1. Else,
+ 1. Let _millisecondMV_ be 0.
+ 1. Let _microsecondMV_ be 0.
+ 1. Let _nanosecondMV_ be 0.
+ 1. Assert: IsValidISODate(_yearMV_, _monthMV_, _dayMV_) is *true*.
+ 1. If _hour_ is empty, then
+ 1. Let _time_ be ~start-of-day~.
+ 1. Else,
+ 1. Let _time_ be CreateTimeRecord(_hourMV_, _minuteMV_, _secondMV_, _millisecondMV_, _microsecondMV_, _nanosecondMV_).
+ 1. Let _timeZoneResult_ be RFC 9557 Time Zone Parse Record { [[Z]]: *false*, [[OffsetString]]: ~empty~, [[TimeZoneAnnotation]]: ~empty~ }.
+ 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 |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. If _yearAbsent_ is *true*, let _yearReturn_ be ~empty~; else let _yearReturn_ be _yearMV_.
+ 1. Return ISO Date-Time Parse Record {
+ [[Year]]: _yearReturn_,
+ [[Month]]: _monthMV_,
+ [[Day]]: _dayMV_,
+ [[Time]]: _time_,
+ [[TimeZone]]: _timeZoneResult_,
+ [[Calendar]]: _calendar_
+ }.
+
+
+
+
+
+ ParseTemporalCalendarString (
+ _string_: a String,
+ ): either a normal completion containing a String or a throw completion
+
+
+
description
+
+ It parses the argument either as an ISO 8601 / RFC 9557 string or bare calendar type, and returns the calendar type.
+ The returned string is syntactically a valid calendar type, but not necessarily an existing one.
+
+
+
+ 1. Let _parseResult_ be Completion(ParseISODateTime(_string_, « |TemporalDateTimeString[+Zoned]|, |TemporalDateTimeString[~Zoned]|, |TemporalInstantString|, |TemporalTimeString|, |TemporalMonthDayString|, |TemporalYearMonthString| »)).
+ 1. If _parseResult_ is a normal completion, then
+ 1. Let _calendar_ be _parseResult_.[[Value]].[[Calendar]].
+ 1. If _calendar_ is ~empty~, return *"iso8601"*.
+ 1. Return _calendar_.
+ 1. Set _parseResult_ to ParseText(StringToCodePoints(_string_), |AnnotationValue|).
+ 1. If _parseResult_ is a List of errors, throw a *RangeError* exception.
+ 1. Return _string_.
+
+
+
+
+
+ ParseTemporalDurationString (
+ _isoString_: a String,
+ ): either a normal completion containing a Temporal.Duration or a throw completion
+
+
+
description
+
It parses the argument as an ISO 8601 duration string.
+
+ ToIntegerWithTruncation(the empty String) = 0.
+ Use of mathematical values rather than approximations is important to avoid off-by-one errors with input like "PT46H66M71.50040904S".
+
+ 1. Let _duration_ be ParseText(StringToCodePoints(_isoString_), |TemporalDurationString|).
+ 1. If _duration_ is a List of errors, throw a *RangeError* exception.
+ 1. Let _sign_ be the source text matched by the |ASCIISign| Parse Node contained within _duration_, or an empty sequence of code points if not present.
+ 1. If _duration_ contains a |DurationYearsPart| Parse Node, then
+ 1. Let _yearsNode_ be that |DurationYearsPart| Parse Node contained within _duration_.
+ 1. Let _years_ be the source text matched by the |DecimalDigits| Parse Node contained within _yearsNode_.
+ 1. Else,
+ 1. Let _years_ be an empty sequence of code points.
+ 1. If _duration_ contains a |DurationMonthsPart| Parse Node, then
+ 1. Let _monthsNode_ be the |DurationMonthsPart| Parse Node contained within _duration_.
+ 1. Let _months_ be the source text matched by the |DecimalDigits| Parse Node contained within _monthsNode_.
+ 1. Else,
+ 1. Let _months_ be an empty sequence of code points.
+ 1. If _duration_ contains a |DurationWeeksPart| Parse Node, then
+ 1. Let _weeksNode_ be the |DurationWeeksPart| Parse Node contained within _duration_.
+ 1. Let _weeks_ be the source text matched by the |DecimalDigits| Parse Node contained within _weeksNode_.
+ 1. Else,
+ 1. Let _weeks_ be an empty sequence of code points.
+ 1. If _duration_ contains a |DurationDaysPart| Parse Node, then
+ 1. Let _daysNode_ be the |DurationDaysPart| Parse Node contained within _duration_.
+ 1. Let _days_ be the source text matched by the |DecimalDigits| Parse Node contained within _daysNode_.
+ 1. Else,
+ 1. Let _days_ be an empty sequence of code points.
+ 1. If _duration_ contains a |DurationHoursPart| Parse Node, then
+ 1. Let _hoursNode_ be the |DurationHoursPart| Parse Node contained within _duration_.
+ 1. Let _hours_ be the source text matched by the |DecimalDigits| Parse Node contained within _hoursNode_.
+ 1. Let _fHours_ be the source text matched by the |TemporalDecimalFraction| Parse Node contained within _hoursNode_, or an empty sequence of code points if not present.
+ 1. Else,
+ 1. Let _hours_ be an empty sequence of code points.
+ 1. Let _fHours_ be an empty sequence of code points.
+ 1. If _duration_ contains a |DurationMinutesPart| Parse Node, then
+ 1. Let _minutesNode_ be the |DurationMinutesPart| Parse Node contained within _duration_.
+ 1. Let _minutes_ be the source text matched by the |DecimalDigits| Parse Node contained within _minutesNode_.
+ 1. Let _fMinutes_ be the source text matched by the |TemporalDecimalFraction| Parse Node contained within _minutesNode_, or an empty sequence of code points if not present.
+ 1. Else,
+ 1. Let _minutes_ be an empty sequence of code points.
+ 1. Let _fMinutes_ be an empty sequence of code points.
+ 1. If _duration_ contains a |DurationSecondsPart| Parse Node, then
+ 1. Let _secondsNode_ be the |DurationSecondsPart| Parse Node contained within _duration_.
+ 1. Let _seconds_ be the source text matched by the |DecimalDigits| Parse Node contained within _secondsNode_.
+ 1. Let _fSeconds_ be the source text matched by the |TemporalDecimalFraction| Parse Node contained within _secondsNode_, or an empty sequence of code points if not present.
+ 1. Else,
+ 1. Let _seconds_ be an empty sequence of code points.
+ 1. Let _fSeconds_ be an empty sequence of code points.
+ 1. Let _yearsMV_ be ? ToIntegerWithTruncation(CodePointsToString(_years_)).
+ 1. Let _monthsMV_ be ? ToIntegerWithTruncation(CodePointsToString(_months_)).
+ 1. Let _weeksMV_ be ? ToIntegerWithTruncation(CodePointsToString(_weeks_)).
+ 1. Let _daysMV_ be ? ToIntegerWithTruncation(CodePointsToString(_days_)).
+ 1. Let _hoursMV_ be ? ToIntegerWithTruncation(CodePointsToString(_hours_)).
+ 1. If _fHours_ is not empty, then
+ 1. Assert: _minutes_, _fMinutes_, _seconds_, and _fSeconds_ are empty.
+ 1. Let _fHoursDigits_ be the substring of CodePointsToString(_fHours_) from 1.
+ 1. Let _fHoursScale_ be the length of _fHoursDigits_.
+ 1. Let _minutesMV_ be ? ToIntegerWithTruncation(_fHoursDigits_) / 10_fHoursScale_ × 60.
+ 1. Else,
+ 1. Let _minutesMV_ be ? ToIntegerWithTruncation(CodePointsToString(_minutes_)).
+ 1. If _fMinutes_ is not empty, then
+ 1. Assert: _seconds_ and _fSeconds_ are empty.
+ 1. Let _fMinutesDigits_ be the substring of CodePointsToString(_fMinutes_) from 1.
+ 1. Let _fMinutesScale_ be the length of _fMinutesDigits_.
+ 1. Let _secondsMV_ be ? ToIntegerWithTruncation(_fMinutesDigits_) / 10_fMinutesScale_ × 60.
+ 1. Else if _seconds_ is not empty, then
+ 1. Let _secondsMV_ be ? ToIntegerWithTruncation(CodePointsToString(_seconds_)).
+ 1. Else,
+ 1. Let _secondsMV_ be remainder(_minutesMV_, 1) × 60.
+ 1. If _fSeconds_ is not empty, then
+ 1. Let _fSecondsDigits_ be the substring of CodePointsToString(_fSeconds_) from 1.
+ 1. Let _fSecondsScale_ be the length of _fSecondsDigits_.
+ 1. Let _millisecondsMV_ be ? ToIntegerWithTruncation(_fSecondsDigits_) / 10_fSecondsScale_ × 1000.
+ 1. Else,
+ 1. Let _millisecondsMV_ be remainder(_secondsMV_, 1) × 1000.
+ 1. Let _microsecondsMV_ be remainder(_millisecondsMV_, 1) × 1000.
+ 1. Let _nanosecondsMV_ be remainder(_microsecondsMV_, 1) × 1000.
+ 1. If _sign_ contains the code point U+002D (HYPHEN-MINUS), then
+ 1. Let _factor_ be -1.
+ 1. Else,
+ 1. Let _factor_ be 1.
+ 1. Set _yearsMV_ to _yearsMV_ × _factor_.
+ 1. Set _monthsMV_ to _monthsMV_ × _factor_.
+ 1. Set _weeksMV_ to _weeksMV_ × _factor_.
+ 1. Set _daysMV_ to _daysMV_ × _factor_.
+ 1. Set _hoursMV_ to _hoursMV_ × _factor_.
+ 1. Set _minutesMV_ to floor(_minutesMV_) × _factor_.
+ 1. Set _secondsMV_ to floor(_secondsMV_) × _factor_.
+ 1. Set _millisecondsMV_ to floor(_millisecondsMV_) × _factor_.
+ 1. Set _microsecondsMV_ to floor(_microsecondsMV_) × _factor_.
+ 1. Set _nanosecondsMV_ to floor(_nanosecondsMV_) × _factor_.
+ 1. Return ? CreateTemporalDuration(_yearsMV_, _monthsMV_, _weeksMV_, _daysMV_, _hoursMV_, _minutesMV_, _secondsMV_, _millisecondsMV_, _microsecondsMV_, _nanosecondsMV_).
+
+
+
+
+
+ ParseTemporalTimeZoneString (
+ _timeZoneString_: a String,
+ ): either a normal completion containing a Time Zone Identifier Parse Record, or a throw completion
+
+
+
description
+
+ It parses the argument as either a time zone identifier or an ISO 8601 / RFC 9557 string.
+ The returned Record's fields are set as follows:
+
+
If _timeZoneString_ is a named time zone identifier, then [[Name]] is _timeZoneString_.
+
Otherwise, if _timeZoneString_ is an offset time zone identifier, then [[OffsetMinutes]] is the time zone's UTC offset.
+
Otherwise, if _timeZoneString_ is a string with a time zone annotation containing a named time zone identifier, then [[Name]] is the time zone identifier contained in the annotation.
+
Otherwise, if _timeZoneString_ is a string with a time zone annotation containing an offset time zone identifier, then [[OffsetMinutes]] is the time zone's UTC offset.
+
Otherwise, if _timeZoneString_ is a string using a *Z* offset designator, then [[Name]] is *"UTC"*.
+
Otherwise, if _timeZoneString_ is a string using a numeric UTC offset, then [[OffsetMinutes]] is that numeric UTC offset.
+
Otherwise, a *RangeError* is thrown.
+
+
+
+
+ 1. Let _parseResult_ be ParseText(StringToCodePoints(_timeZoneString_), |TimeZoneIdentifier|).
+ 1. If _parseResult_ is a Parse Node, return ! ParseTimeZoneIdentifier(_timeZoneString_).
+ 1. Let _result_ be ? ParseISODateTime(_timeZoneString_, « |TemporalDateTimeString[+Zoned]|, |TemporalDateTimeString[~Zoned]|, |TemporalInstantString|, |TemporalTimeString|, |TemporalMonthDayString|, |TemporalYearMonthString| »).
+ 1. Let _timeZoneResult_ be _result_.[[TimeZone]].
+ 1. If _timeZoneResult_.[[TimeZoneAnnotation]] is not ~empty~, return ! ParseTimeZoneIdentifier(_timeZoneResult_.[[TimeZoneAnnotation]]).
+ 1. If _timeZoneResult_.[[Z]] is *true*, return ! ParseTimeZoneIdentifier(*"UTC"*).
+ 1. If _timeZoneResult_.[[OffsetString]] is not ~empty~, return ? ParseTimeZoneIdentifier(_timeZoneResult_.[[OffsetString]]).
+ 1. Throw a *RangeError* exception.
+
+
+
+
+
+ ParseTimeZoneIdentifier (
+ _identifier_: a String,
+ ): either a normal completion containing a Time Zone Identifier Parse Record, or a throw completion
+
+
+
description
+
+ It parses _identifier_ to determine whether it identifies an offset time zone or named time zone. If _identifier_ is syntactically invalid, a *RangeError* will be thrown.
+
+
+
+ 1. Let _parseResult_ be ParseText(StringToCodePoints(_identifier_), |TimeZoneIdentifier|).
+ 1. If _parseResult_ is a List of errors, throw a *RangeError* exception.
+ 1. If _parseResult_ contains a |TimeZoneIANAName| Parse Node, then
+ 1. Let _name_ be the source text matched by the |TimeZoneIANAName| Parse Node contained within _parseResult_.
+ 1. NOTE: _name_ is syntactically valid, but does not necessarily conform to IANA Time Zone Database naming guidelines or correspond with an available named time zone identifier.
+ 1. Return Time Zone Identifier Parse Record { [[Name]]: CodePointsToString(_name_), [[OffsetMinutes]]: ~empty~ }.
+ 1. Assert: _parseResult_ contains a |UTCOffset[~SubMinutePrecision]| Parse Node.
+ 1. Let _offset_ be the source text matched by the |UTCOffset[~SubMinutePrecision]| Parse Node contained within _parseResult_.
+ 1. Let _offsetNanoseconds_ be ! ParseDateTimeUTCOffset(CodePointsToString(_offset_)).
+ 1. Let _offsetMinutes_ be _offsetNanoseconds_ / (60 × 109).
+ 1. Return Time Zone Identifier Parse Record { [[Name]]: ~empty~, [[OffsetMinutes]]: _offsetMinutes_ }.
+
+
+
diff --git a/temporal/instant.emu b/temporal/instant.emu
new file mode 100644
index 0000000000..8690b7603f
--- /dev/null
+++ b/temporal/instant.emu
@@ -0,0 +1,466 @@
+
+
+
+
+
Temporal.Instant Objects
+
A Temporal.Instant object is an Object referencing a fixed point in time with nanoseconds precision.
+
+
+
The Temporal.Instant Constructor
+
The Temporal.Instant constructor:
+
+
+ creates and initializes a new Temporal.Instant object when called as a constructor.
+
+
+ is not intended to be called as a function and will throw an exception when called in that manner.
+
+
+ may be used as the value of an `extends` clause of a class definition.
+ Subclass constructors that intend to inherit the specified Temporal.Instant behaviour must
+ include a super call to the %Temporal.Instant% constructor to create and initialize subclass
+ instances with the necessary internal slots.
+
+
+
+
+
Temporal.Instant ( _epochNanoseconds_ )
+
This function performs the following steps when called:
+
+ 1. If NewTarget is *undefined*, throw a *TypeError* exception.
+ 1. Let _epochNanoseconds_ be ? ToBigInt(_epochNanoseconds_).
+ 1. If IsValidEpochNanoseconds(_epochNanoseconds_) is *false*, throw a *RangeError* exception.
+ 1. Return ? CreateTemporalInstant(_epochNanoseconds_, NewTarget).
+
+
+
+
+
+
Properties of the Temporal.Instant Constructor
+
The value of the [[Prototype]] internal slot of the Temporal.Instant constructor is the intrinsic object %Function.prototype%.
+
The Temporal.Instant constructor has the following properties:
+
+
+
Temporal.Instant.prototype
+
The initial value of `Temporal.Instant.prototype` is %Temporal.Instant.prototype%.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *false* }.
+
+
+
+
Temporal.Instant.from ( _item_ )
+
This function performs the following steps when called:
This function performs the following steps when called:
+
+ 1. Set _epochMilliseconds_ to ? ToNumber(_epochMilliseconds_).
+ 1. Set _epochMilliseconds_ to ? NumberToBigInt(_epochMilliseconds_).
+ 1. Let _epochNanoseconds_ be _epochMilliseconds_ × 106.
+ 1. If IsValidEpochNanoseconds(_epochNanoseconds_) is *false*, throw a *RangeError* exception.
+ 1. Return ! CreateTemporalInstant(_epochNanoseconds_).
+
+
+
+
+
The initial value of the %Symbol.toStringTag% property is the String *"Temporal.Instant"*.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.
+
+
+
+
get Temporal.Instant.prototype.epochMilliseconds
+
+ `Temporal.Instant.prototype.epochMilliseconds` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _instant_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_instant_, [[InitializedTemporalInstant]]).
+ 1. Let _epochMilliseconds_ be floor(_instant_.[[EpochNanoseconds]] / 106).
+ 1. Return 𝔽(_epochMilliseconds_).
+
+
+
+
+
get Temporal.Instant.prototype.epochNanoseconds
+
+ `Temporal.Instant.prototype.epochNanoseconds` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _instant_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_instant_, [[InitializedTemporalInstant]]).
+ 1. Return ℤ(_instant_.[[EpochNanoseconds]]).
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _instant_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_instant_, [[InitializedTemporalInstant]]).
+ 1. Return ? DifferenceTemporalInstant(~since~, _instant_, _other_, _options_).
+
+
+
+
+
Temporal.Instant.prototype.round ( _roundTo_ )
+
This method performs the following steps when called:
+
+ 1. Let _instant_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_instant_, [[InitializedTemporalInstant]]).
+ 1. If _roundTo_ is *undefined*, throw a *TypeError* exception.
+ 1. If _roundTo_ is a String, then
+ 1. Let _paramString_ be _roundTo_.
+ 1. Set _roundTo_ to OrdinaryObjectCreate(*null*).
+ 1. Perform ! CreateDataPropertyOrThrow(_roundTo_, *"smallestUnit"*, _paramString_).
+ 1. Else,
+ 1. Set _roundTo_ to ? GetOptionsObject(_roundTo_).
+ 1. NOTE: The following steps read options and perform independent validation in alphabetical order (GetRoundingIncrementOption reads *"roundingIncrement"* and GetRoundingModeOption reads *"roundingMode"*).
+ 1. Let _roundingIncrement_ be ? GetRoundingIncrementOption(_roundTo_).
+ 1. Let _roundingMode_ be ? GetRoundingModeOption(_roundTo_, ~half-expand~).
+ 1. Let _smallestUnit_ be ? GetTemporalUnitValuedOption(_roundTo_, *"smallestUnit"*, ~required~).
+ 1. Perform ? ValidateTemporalUnitValue(_smallestUnit_, ~time~).
+ 1. If _smallestUnit_ is ~hour~, then
+ 1. Let _maximum_ be HoursPerDay.
+ 1. Else if _smallestUnit_ is ~minute~, then
+ 1. Let _maximum_ be MinutesPerHour × HoursPerDay.
+ 1. Else if _smallestUnit_ is ~second~, then
+ 1. Let _maximum_ be SecondsPerMinute × MinutesPerHour × HoursPerDay.
+ 1. Else if _smallestUnit_ is ~millisecond~, then
+ 1. Let _maximum_ be ℝ(msPerDay).
+ 1. Else if _smallestUnit_ is ~microsecond~, then
+ 1. Let _maximum_ be 103 × ℝ(msPerDay).
+ 1. Else,
+ 1. Assert: _smallestUnit_ is ~nanosecond~.
+ 1. Let _maximum_ be nsPerDay.
+ 1. Perform ? ValidateTemporalRoundingIncrement(_roundingIncrement_, _maximum_, *true*).
+ 1. Let _roundedNs_ be RoundEpochNanoseconds(_instant_.[[EpochNanoseconds]], _roundingIncrement_, _smallestUnit_, _roundingMode_).
+ 1. Return ! CreateTemporalInstant(_roundedNs_).
+
+
+
+
+
Temporal.Instant.prototype.equals ( _other_ )
+
This method performs the following steps when called:
+
+ 1. Let _instant_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_instant_, [[InitializedTemporalInstant]]).
+ 1. Set _other_ to ? ToTemporalInstant(_other_).
+ 1. If _instant_.[[EpochNanoseconds]] ≠ _other_.[[EpochNanoseconds]], return *false*.
+ 1. Return *true*.
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _instant_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_instant_, [[InitializedTemporalInstant]]).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. NOTE: The following steps read options and perform independent validation in alphabetical order (GetTemporalFractionalSecondDigitsOption reads *"fractionalSecondDigits"* and GetRoundingModeOption reads *"roundingMode"*).
+ 1. Let _digits_ be ? GetTemporalFractionalSecondDigitsOption(_resolvedOptions_).
+ 1. Let _roundingMode_ be ? GetRoundingModeOption(_resolvedOptions_, ~trunc~).
+ 1. Let _smallestUnit_ be ? GetTemporalUnitValuedOption(_resolvedOptions_, *"smallestUnit"*, ~unset~).
+ 1. Let _timeZone_ be ? Get(_resolvedOptions_, *"timeZone"*).
+ 1. Perform ? ValidateTemporalUnitValue(_smallestUnit_, ~time~).
+ 1. If _smallestUnit_ is ~hour~, throw a *RangeError* exception.
+ 1. If _timeZone_ is not *undefined*, then
+ 1. Set _timeZone_ to ? ToTemporalTimeZoneIdentifier(_timeZone_).
+ 1. Let _precision_ be ToSecondsStringPrecisionRecord(_smallestUnit_, _digits_).
+ 1. Let _roundedNs_ be RoundEpochNanoseconds(_instant_.[[EpochNanoseconds]], _precision_.[[Increment]], _precision_.[[Unit]], _roundingMode_).
+ 1. Let _roundedInstant_ be ! CreateTemporalInstant(_roundedNs_).
+ 1. Return TemporalInstantToString(_roundedInstant_, _timeZone_, _precision_.[[Precision]]).
+
+
+
+
+
+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement this method as specified in the ECMA-402 specification.
+ If an ECMAScript implementation does not include the ECMA-402 API the following specification of this method is used.
+
+
The meanings of the optional parameters to this method are defined in the ECMA-402 specification; implementations that do not include ECMA-402 support must not use those parameter positions for anything else.
+
This method performs the following steps when called:
+
+ 1. Let _instant_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_instant_, [[InitializedTemporalInstant]]).
+ 1. Return TemporalInstantToString(_instant_, *undefined*, ~auto~).
+
+
+
+
+
Temporal.Instant.prototype.toJSON ( )
+
This method performs the following steps when called:
+
+ 1. Let _instant_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_instant_, [[InitializedTemporalInstant]]).
+ 1. Return TemporalInstantToString(_instant_, *undefined*, ~auto~).
+
+
+
+
+
Temporal.Instant.prototype.valueOf ( )
+
This method performs the following steps when called:
+
+ 1. Throw a *TypeError* exception.
+
+
+
+ This method always throws, because in the absence of `valueOf()`, expressions with arithmetic operators such as `instant1 > instant2` would fall back to being equivalent to `instant1.toString() > instant2.toString()`.
+ Lexicographical comparison of serialized strings might not seem obviously wrong, because the result would sometimes be correct.
+ Implementations are encouraged to phrase the error message to point users to `Temporal.Instant.compare()`, `Temporal.Instant.prototype.equals()`, and/or `Temporal.Instant.prototype.toString()`.
+
This method performs the following steps when called:
+
+ 1. Let _instant_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_instant_, [[InitializedTemporalInstant]]).
+ 1. Set _timeZone_ to ? ToTemporalTimeZoneIdentifier(_timeZone_).
+ 1. Return ! CreateTemporalZonedDateTime(_instant_.[[EpochNanoseconds]], _timeZone_, *"iso8601"*).
+
+
+
+
+
+
Properties of Temporal.Instant Instances
+
+
+ Temporal.Instant instances are ordinary objects that inherit properties from the %Temporal.Instant.prototype% intrinsic object.
+ Temporal.Instant instances are initially created with the internal slots described in .
+
+
+
+
+
+ Internal Slot
+
+
+ Description
+
+
+
+
+ [[InitializedTemporalInstant]]
+
+
+ The only specified use of this slot is for distinguishing Temporal.Instant instances from other objects.
+
+
+
+
+ [[EpochNanoseconds]]
+
+
+ A BigInt representing the number of nanoseconds since the epoch, as described in
+
+
+
+
+
+
+
+
Abstract Operations for Temporal.Instant Objects
+
+
+
+ CreateTemporalInstant (
+ _epochNanoseconds_: an epoch nanoseconds value,
+ optional _newTarget_: a constructor,
+ ): either a normal completion containing a Temporal.Instant or a throw completion
+
+
+
description
+
It creates a Temporal.Instant instance and fills the internal slots with valid values.
+
+
+ 1. Assert: IsValidEpochNanoseconds(_epochNanoseconds_) is *true*.
+ 1. If _newTarget_ is not present, set _newTarget_ to %Temporal.Instant%.
+ 1. Let _object_ be ? OrdinaryCreateFromConstructor(_newTarget_, *"%Temporal.Instant.prototype%"*, « [[InitializedTemporalInstant]], [[EpochNanoseconds]] »).
+ 1. Set _object_.[[EpochNanoseconds]] to _epochNanoseconds_.
+ 1. Return _object_.
+
+
+
+
+
+ ToTemporalInstant (
+ _item_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.Instant or a throw completion
+
+
+
description
+
Converts _item_ to a new Temporal.Instant instance if possible, and throws otherwise.
+
+
+ 1. If _item_ is an Object, then
+ 1. If _item_ has an [[InitializedTemporalInstant]] or [[InitializedTemporalZonedDateTime]] internal slot, then
+ 1. Return ! CreateTemporalInstant(_item_.[[EpochNanoseconds]]).
+ 1. NOTE: This use of ToPrimitive allows Instant-like objects to be converted.
+ 1. Set _item_ to ? ToPrimitive(_item_, ~string~).
+ 1. If _item_ is not a String, throw a *TypeError* exception.
+ 1. Let _parsed_ be ? ParseISODateTime(_item_, « |TemporalInstantString| »).
+ 1. Assert: Either _parsed_.[[TimeZone]].[[OffsetString]] is not ~empty~ or _parsed_.[[TimeZone]].[[Z]] is *true*, but not both.
+ 1. If _parsed_.[[TimeZone]].[[Z]] is *true*, let _offsetNanoseconds_ be 0; else let _offsetNanoseconds_ be ! ParseDateTimeUTCOffset(_parsed_.[[TimeZone]].[[OffsetString]]).
+ 1. Let _time_ be _parsed_.[[Time]].
+ 1. Assert: _time_ is not ~start-of-day~.
+ 1. Let _balanced_ be BalanceISODateTime(_parsed_.[[Year]], _parsed_.[[Month]], _parsed_.[[Day]], _time_.[[Hour]], _time_.[[Minute]], _time_.[[Second]], _time_.[[Millisecond]], _time_.[[Microsecond]], _time_.[[Nanosecond]] - _offsetNanoseconds_).
+ 1. Perform ? CheckISODaysRange(_balanced_.[[ISODate]]).
+ 1. Let _epochNanoseconds_ be GetUTCEpochNanoseconds(_balanced_).
+ 1. If IsValidEpochNanoseconds(_epochNanoseconds_) is *false*, throw a *RangeError* exception.
+ 1. Return ! CreateTemporalInstant(_epochNanoseconds_).
+
+
+
+
+
+ TemporalInstantToString (
+ _instant_: a Temporal.Instant,
+ _timeZone_: either an available time zone identifier or *undefined*,
+ _precision_: either an integer in the inclusive interval from 0 to 9, ~minute~, or ~auto~,
+ ): a String
+
+
+
description
+
It formats _instant_ as an ISO 8601 / RFC 9557 string, to the precision specified by _precision_, using the UTC offset of _timeZone_, or `Z` if _timeZone_ is *undefined*.
+
+
+ 1. Let _outputTimeZone_ be _timeZone_.
+ 1. If _outputTimeZone_ is *undefined*, set _outputTimeZone_ to *"UTC"*.
+ 1. Let _epochNs_ be _instant_.[[EpochNanoseconds]].
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_outputTimeZone_, _epochNs_).
+ 1. Let _dateTimeString_ be FormatISODateTime(_isoDateTime_, *"iso8601"*, _precision_, ~never~).
+ 1. If _timeZone_ is *undefined*, then
+ 1. Let _timeZoneString_ be *"Z"*.
+ 1. Else,
+ 1. Let _offsetNanoseconds_ be GetOffsetNanosecondsFor(_outputTimeZone_, _epochNs_).
+ 1. Let _timeZoneString_ be FormatDateTimeUTCOffsetRounded(_offsetNanoseconds_).
+ 1. Return the string-concatenation of _dateTimeString_ and _timeZoneString_.
+
+
+
+
+
+ AddDurationToInstant (
+ _operation_: either ~add~ or ~subtract~,
+ _instant_: a Temporal.Instant,
+ _temporalDurationLike_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.Instant or a throw completion
+
+
+
description
+
It adds/subtracts _temporalDurationLike_ to/from _instant_.
+
+
+ 1. Let _duration_ be ? ToTemporalDuration(_temporalDurationLike_).
+ 1. If _operation_ is ~subtract~, set _duration_ to CreateNegatedTemporalDuration(_duration_).
+ 1. Let _largestUnit_ be DefaultTemporalLargestUnit(_duration_).
+ 1. If TemporalUnitCategory(_largestUnit_) is ~date~, throw a *RangeError* exception.
+ 1. Let _internalDuration_ be ToInternalDurationRecordWith24HourDays(_duration_).
+ 1. Let _epochNanoseconds_ be ? AddEpochNanoseconds(_instant_.[[EpochNanoseconds]], _internalDuration_.[[Time]]).
+ 1. Return ! CreateTemporalInstant(_epochNanoseconds_).
+
+
+
+
+
+ DifferenceTemporalInstant (
+ _operation_: either ~since~ or ~until~,
+ _instant_: a Temporal.Instant,
+ _other_: an ECMAScript language value,
+ _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.Duration or a throw completion
+
+
+
description
+
It computes the difference between the two times represented by _instant_ and _other_, optionally rounds it, and returns it as a Temporal.Duration object.
+
+
+ 1. Set _other_ to ? ToTemporalInstant(_other_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _settings_ be ? GetDifferenceSettings(_operation_, _resolvedOptions_, ~time~, « », ~nanosecond~, ~second~).
+ 1. Let _internalDuration_ be DifferenceEpochNanoseconds(_instant_.[[EpochNanoseconds]], _other_.[[EpochNanoseconds]], _settings_.[[RoundingIncrement]], _settings_.[[SmallestUnit]], _settings_.[[RoundingMode]]).
+ 1. Let _result_ be ! TemporalDurationFromInternal(_internalDuration_, _settings_.[[LargestUnit]]).
+ 1. If _operation_ is ~since~, set _result_ to CreateNegatedTemporalDuration(_result_).
+ 1. Return _result_.
+
+
+
+
diff --git a/temporal/now.emu b/temporal/now.emu
new file mode 100644
index 0000000000..1adc202537
--- /dev/null
+++ b/temporal/now.emu
@@ -0,0 +1,121 @@
+
+
+
+
+
The Temporal.Now Object
+
The Temporal.Now object:
+
+
is an ordinary object.
+
has a [[Prototype]] internal slot whose value is %Object.prototype%.
+
is not a function object.
+
does not have a [[Construct]] internal method; it cannot be used as a constructor with the `new` operator.
+
does not have a [[Call]] internal method; it cannot be invoked as a function.
+
+
+
+
Value Properties of the Temporal.Now Object
+
+
+
Temporal.Now [ %Symbol.toStringTag% ]
+
The initial value of the %Symbol.toStringTag% property is the String *"Temporal.Now"*.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.
+
+
+
+
+
Function Properties of the Temporal.Now Object
+
+
+
Temporal.Now.timeZoneId ( )
+
This function performs the following steps when called:
This function performs the following steps when called:
+
+ 1. If _temporalTimeZoneLike_ is *undefined*, then
+ 1. Let _timeZone_ be SystemTimeZoneIdentifier().
+ 1. Else,
+ 1. Let _timeZone_ be ? ToTemporalTimeZoneIdentifier(_temporalTimeZoneLike_).
+ 1. Let _epochNanoseconds_ be SystemUTCEpochNanoseconds().
+ 1. Return ! CreateTemporalZonedDateTime(_epochNanoseconds_, _timeZone_, *"iso8601"*).
+
+
+
+
+
This function performs the following steps when called:
+
+ 1. Let _isoDateTime_ be ? SystemDateTime(_temporalTimeZoneLike_).
+ 1. Return ! CreateTemporalTime(_isoDateTime_.[[Time]]).
+
+
+
+
+
+
Abstract Operations for the Temporal.Now Object
+
+
+
+ SystemDateTime (
+ _temporalTimeZoneLike_: an ECMAScript language value,
+ ): either a normal completion containing an ISO Date-Time Record or a throw completion
+
+
+
description
+
+
+
+ 1. If _temporalTimeZoneLike_ is *undefined*, then
+ 1. Let _timeZone_ be SystemTimeZoneIdentifier().
+ 1. Else,
+ 1. Let _timeZone_ be ? ToTemporalTimeZoneIdentifier(_temporalTimeZoneLike_).
+ 1. Let _epochNs_ be SystemUTCEpochNanoseconds().
+ 1. Return GetISODateTimeFor(_timeZone_, _epochNs_).
+
+
+
+
+
SystemUTCEpochNanoseconds ( ): an epoch nanoseconds value
+
+
description
+
+
+
+ 1. Let _global_ be GetGlobalObject().
+ 1. Return HostSystemUTCEpochNanoseconds(_global_).
+
+
+
+
diff --git a/temporal/plaindate.emu b/temporal/plaindate.emu
new file mode 100644
index 0000000000..2de5a40d8d
--- /dev/null
+++ b/temporal/plaindate.emu
@@ -0,0 +1,717 @@
+
+
+
+
+
Temporal.PlainDate Objects
+
+ A Temporal.PlainDate object is an Object that contains integers corresponding to a
+ particular year, month, and day in the ISO8601 calendar, as well as a calendar type used to
+ interpret those integers in a particular calendar.
+
+
+
+
The Temporal.PlainDate Constructor
+
The Temporal.PlainDate constructor:
+
+
+ creates and initializes a new Temporal.PlainDate object when called as a constructor.
+
+
+ is not intended to be called as a function and will throw an exception when called in that manner.
+
+
+ may be used as the value of an `extends` clause of a class definition.
+ Subclass constructors that intend to inherit the specified Temporal.PlainDate behaviour must
+ include a super call to the %Temporal.PlainDate% constructor to create and initialize subclass
+ instances with the necessary internal slots.
+
This function performs the following steps when called:
+
+ 1. If NewTarget is *undefined*, throw a *TypeError* exception.
+ 1. Let _y_ be ? ToIntegerWithTruncation(_isoYear_).
+ 1. Let _m_ be ? ToIntegerWithTruncation(_isoMonth_).
+ 1. Let _d_ be ? ToIntegerWithTruncation(_isoDay_).
+ 1. If _calendar_ is *undefined*, set _calendar_ to *"iso8601"*.
+ 1. If _calendar_ is not a String, throw a *TypeError* exception.
+ 1. Set _calendar_ to ? CanonicalizeCalendar(_calendar_).
+ 1. If IsValidISODate(_y_, _m_, _d_) is *false*, throw a *RangeError* exception.
+ 1. Let _isoDate_ be CreateISODateRecord(_y_, _m_, _d_).
+ 1. Return ? CreateTemporalDate(_isoDate_, _calendar_, NewTarget).
+
+
+
+
+
+
Properties of the Temporal.PlainDate Constructor
+
The Temporal.PlainDate constructor:
+
+
has a [[Prototype]] internal slot whose value is %Function.prototype%.
+
has the following properties:
+
+
+
+
Temporal.PlainDate.prototype
+
The initial value of `Temporal.PlainDate.prototype` is %Temporal.PlainDate.prototype%.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *false* }.
This function performs the following steps when called:
+
+ 1. Set _one_ to ? ToTemporalDate(_one_).
+ 1. Set _two_ to ? ToTemporalDate(_two_).
+ 1. Return 𝔽(CompareISODate(_one_.[[ISODate]], _two_.[[ISODate]])).
+
+
+
+
+
+
Properties of the Temporal.PlainDate Prototype Object
+
+
The Temporal.PlainDate prototype object
+
+
is itself an ordinary object.
+
is not a Temporal.PlainDate instance and does not have a [[InitializedTemporalDate]] internal slot.
+
has a [[Prototype]] internal slot whose value is %Object.prototype%.
+
+
+
+ An ECMAScript implementation that includes the ECMA-402 Internationalization API extends this prototype with additional properties in order to represent calendar data.
+
+
+
+
Temporal.PlainDate.prototype.constructor
+
The initial value of `Temporal.PlainDate.prototype.constructor` is %Temporal.PlainDate%.
The initial value of the %Symbol.toStringTag% property is the String *"Temporal.PlainDate"*.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.
+
+
+
+
get Temporal.PlainDate.prototype.calendarId
+
+ `Temporal.PlainDate.prototype.calendarId` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return _plainDate_.[[Calendar]].
+
+
+
+
+
get Temporal.PlainDate.prototype.era
+
+ `Temporal.PlainDate.prototype.era` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[Era]].
+
+
+
+
+
get Temporal.PlainDate.prototype.eraYear
+
+ `Temporal.PlainDate.prototype.eraYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Let _result_ be CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[EraYear]].
+ 1. If _result_ is *undefined*, return *undefined*.
+ 1. Return 𝔽(_result_).
+
+
+
+
+
get Temporal.PlainDate.prototype.year
+
+ `Temporal.PlainDate.prototype.year` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[Year]]).
+
+
+
+
+
get Temporal.PlainDate.prototype.month
+
+ `Temporal.PlainDate.prototype.month` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[Month]]).
+
+
+
+
+
get Temporal.PlainDate.prototype.monthCode
+
+ `Temporal.PlainDate.prototype.monthCode` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[MonthCode]].
+
+
+
+
+
get Temporal.PlainDate.prototype.day
+
+ `Temporal.PlainDate.prototype.day` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[Day]]).
+
+
+
+
+
get Temporal.PlainDate.prototype.dayOfWeek
+
+ `Temporal.PlainDate.prototype.dayOfWeek` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[DayOfWeek]]).
+
+
+
+
+
get Temporal.PlainDate.prototype.dayOfYear
+
+ `Temporal.PlainDate.prototype.dayOfYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[DayOfYear]]).
+
+
+
+
+
get Temporal.PlainDate.prototype.weekOfYear
+
+ `Temporal.PlainDate.prototype.weekOfYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Let _result_ be CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[WeekOfYear]].[[Week]].
+ 1. If _result_ is *undefined*, return *undefined*.
+ 1. Return 𝔽(_result_).
+
+
+
+
+
get Temporal.PlainDate.prototype.yearOfWeek
+
+ `Temporal.PlainDate.prototype.yearOfWeek` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Let _result_ be CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[WeekOfYear]].[[Year]].
+ 1. If _result_ is *undefined*, return *undefined*.
+ 1. Return 𝔽(_result_).
+
+
+
+
+
get Temporal.PlainDate.prototype.daysInWeek
+
+ `Temporal.PlainDate.prototype.daysInWeek` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[DaysInWeek]]).
+
+
+
+
+
get Temporal.PlainDate.prototype.daysInMonth
+
+ `Temporal.PlainDate.prototype.daysInMonth` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[DaysInMonth]]).
+
+
+
+
+
get Temporal.PlainDate.prototype.daysInYear
+
+ `Temporal.PlainDate.prototype.daysInYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[DaysInYear]]).
+
+
+
+
+
get Temporal.PlainDate.prototype.monthsInYear
+
+ `Temporal.PlainDate.prototype.monthsInYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[MonthsInYear]]).
+
+
+
+
+
get Temporal.PlainDate.prototype.inLeapYear
+
+ `Temporal.PlainDate.prototype.inLeapYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return CalendarISOToDate(_plainDate_.[[Calendar]], _plainDate_.[[ISODate]]).[[InLeapYear]].
+
+
+
+
+
Temporal.PlainDate.prototype.toPlainYearMonth ( )
+
This method performs the following steps when called:
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Let _calendar_ be _plainDate_.[[Calendar]].
+ 1. Let _fields_ be ISODateToFields(_calendar_, _plainDate_.[[ISODate]], ~date~).
+ 1. Let _isoDate_ be ? CalendarYearMonthFromFields(_calendar_, _fields_, ~constrain~).
+ 1. Return ! CreateTemporalYearMonth(_isoDate_, _calendar_).
+ 1. NOTE: The call to CalendarYearMonthFromFields is necessary in order to create a PlainYearMonth object with the [[Day]] field of the [[ISODate]] internal slot set correctly.
+
+
+
+
+
Temporal.PlainDate.prototype.toPlainMonthDay ( )
+
This method performs the following steps when called:
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Let _calendar_ be _plainDate_.[[Calendar]].
+ 1. Let _fields_ be ISODateToFields(_calendar_, _plainDate_.[[ISODate]], ~date~).
+ 1. Let _isoDate_ be ? CalendarMonthDayFromFields(_calendar_, _fields_, ~constrain~).
+ 1. Return ! CreateTemporalMonthDay(_isoDate_, _calendar_).
+ 1. NOTE: The call to CalendarMonthDayFromFields is necessary in order to create a PlainMonthDay object with the [[Year]] field of the [[ISODate]] internal slot set correctly.
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. If ? IsPartialTemporalObject(_temporalDateLike_) is *false*, throw a *TypeError* exception.
+ 1. Let _calendar_ be _plainDate_.[[Calendar]].
+ 1. Let _fields_ be ISODateToFields(_calendar_, _plainDate_.[[ISODate]], ~date~).
+ 1. Let _partialDate_ be ? PrepareCalendarFields(_calendar_, _temporalDateLike_, « ~year~, ~month~, ~month-code~, ~day~ », « », ~partial~).
+ 1. Set _fields_ to CalendarMergeFields(_calendar_, _fields_, _partialDate_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _isoDate_ be ? CalendarDateFromFields(_calendar_, _fields_, _overflow_).
+ 1. Return ! CreateTemporalDate(_isoDate_, _calendar_).
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. If _item_ is an Object, then
+ 1. Let _timeZoneLike_ be ? Get(_item_, *"timeZone"*).
+ 1. If _timeZoneLike_ is *undefined*, then
+ 1. Let _timeZone_ be ? ToTemporalTimeZoneIdentifier(_item_).
+ 1. Let _temporalTime_ be *undefined*.
+ 1. Else,
+ 1. Let _timeZone_ be ? ToTemporalTimeZoneIdentifier(_timeZoneLike_).
+ 1. Let _temporalTime_ be ? Get(_item_, *"plainTime"*).
+ 1. Else,
+ 1. Let _timeZone_ be ? ToTemporalTimeZoneIdentifier(_item_).
+ 1. Let _temporalTime_ be *undefined*.
+ 1. If _temporalTime_ is *undefined*, then
+ 1. Let _epochNs_ be ? GetStartOfDay(_timeZone_, _plainDate_.[[ISODate]]).
+ 1. Else,
+ 1. Set _temporalTime_ to ? ToTemporalTime(_temporalTime_).
+ 1. Let _isoDateTime_ be CombineISODateAndTimeRecord(_plainDate_.[[ISODate]], _temporalTime_.[[Time]]).
+ 1. If ISODateTimeWithinLimits(_isoDateTime_) is *false*, throw a *RangeError* exception.
+ 1. Let _epochNs_ be ? GetEpochNanosecondsFor(_timeZone_, _isoDateTime_, ~compatible~).
+ 1. Return ! CreateTemporalZonedDateTime(_epochNs_, _timeZone_, _plainDate_.[[Calendar]]).
+
+
+
+
+
+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement this method as specified in the ECMA-402 specification.
+ If an ECMAScript implementation does not include the ECMA-402 API the following specification of this method is used.
+
+
The meanings of the optional parameters to this method are defined in the ECMA-402 specification; implementations that do not include ECMA-402 support must not use those parameter positions for anything else.
+
This method performs the following steps when called:
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return TemporalDateToString(_plainDate_, ~auto~).
+
+
+
+
+
Temporal.PlainDate.prototype.toJSON ( )
+
This method performs the following steps when called:
+
+ 1. Let _plainDate_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDate_, [[InitializedTemporalDate]]).
+ 1. Return TemporalDateToString(_plainDate_, ~auto~).
+
+
+
+
+
Temporal.PlainDate.prototype.valueOf ( )
+
This method performs the following steps when called:
+
+ 1. Throw a *TypeError* exception.
+
+
+
+ This method always throws, because in the absence of `valueOf()`, expressions with arithmetic operators such as `plainDate1 > plainDate2` would fall back to being equivalent to `plainDate1.toString() > plainDate2.toString()`.
+ Lexicographical comparison of serialized strings might not seem obviously wrong, because the result would sometimes be correct.
+ Implementations are encouraged to phrase the error message to point users to `Temporal.PlainDate.compare()`, `Temporal.PlainDate.prototype.equals()`, and/or `Temporal.PlainDate.prototype.toString()`.
+
+
+
+
+
+
+
Properties of Temporal.PlainDate Instances
+
+ Temporal.PlainDate instances are ordinary objects that inherit properties from the %Temporal.PlainDate.prototype% intrinsic object.
+ Temporal.PlainDate instances are initially created with the internal slots described in .
+
+
+
+
+
+ Internal Slot
+
+
+ Description
+
+
+
+
+ [[InitializedTemporalDate]]
+
+
+ The only specified use of this slot is for distinguishing Temporal.PlainDate instances from other objects.
+
+
+
+
+ [[ISODate]]
+
+
+ An ISO Date Record.
+
+
+
+
+ [[Calendar]]
+
+
+ A calendar type.
+
+
+
+
+
+
+
+
Abstract Operations for Temporal.PlainDate Objects
+
+
+
+ CreateTemporalDate (
+ _isoDate_: an ISO Date Record,
+ _calendar_: a calendar type,
+ optional _newTarget_: a constructor,
+ ): either a normal completion containing a Temporal.PlainDate or a throw completion
+
+
+
description
+
It creates a Temporal.PlainDate instance and fills the internal slots with valid values.
+
+
+ 1. If ISODateWithinLimits(_isoDate_) is *false*, throw a *RangeError* exception.
+ 1. If _newTarget_ is not present, set _newTarget_ to %Temporal.PlainDate%.
+ 1. Let _object_ be ? OrdinaryCreateFromConstructor(_newTarget_, *"%Temporal.PlainDate.prototype%"*, « [[InitializedTemporalDate]], [[ISODate]], [[Calendar]] »).
+ 1. Set _object_.[[ISODate]] to _isoDate_.
+ 1. Set _object_.[[Calendar]] to _calendar_.
+ 1. Return _object_.
+
+
+
+
+
+ ToTemporalDate (
+ _item_: an ECMAScript language value,
+ optional _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.PlainDate or a throw completion
+
+
+
description
+
Converts _item_ to a new Temporal.PlainDate instance if possible, and throws otherwise.
+
+
+ 1. If _options_ is not present, set _options_ to *undefined*.
+ 1. If _item_ is an Object, then
+ 1. If _item_ has an [[InitializedTemporalDate]] internal slot, then
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Return ! CreateTemporalDate(_item_.[[ISODate]], _item_.[[Calendar]]).
+ 1. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_item_.[[TimeZone]], _item_.[[EpochNanoseconds]]).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Return ! CreateTemporalDate(_isoDateTime_.[[ISODate]], _item_.[[Calendar]]).
+ 1. If _item_ has an [[InitializedTemporalDateTime]] internal slot, then
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Return ! CreateTemporalDate(_item_.[[ISODateTime]].[[ISODate]], _item_.[[Calendar]]).
+ 1. Let _calendar_ be ? GetTemporalCalendarIdentifierWithISODefault(_item_).
+ 1. Let _fields_ be ? PrepareCalendarFields(_calendar_, _item_, « ~year~, ~month~, ~month-code~, ~day~ », «», «»).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _isoDate_ be ? CalendarDateFromFields(_calendar_, _fields_, _overflow_).
+ 1. Return ! CreateTemporalDate(_isoDate_, _calendar_).
+ 1. If _item_ is not a String, throw a *TypeError* exception.
+ 1. Let _result_ be ? ParseISODateTime(_item_, « |TemporalDateTimeString[~Zoned]| »).
+ 1. Let _calendar_ be _result_.[[Calendar]].
+ 1. If _calendar_ is ~empty~, set _calendar_ to *"iso8601"*.
+ 1. Set _calendar_ to ? CanonicalizeCalendar(_calendar_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _isoDate_ be CreateISODateRecord(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]]).
+ 1. Return ? CreateTemporalDate(_isoDate_, _calendar_).
+
+
+
+
+
+ TemporalDateToString (
+ _temporalDate_: a Temporal.PlainDate,
+ _showCalendar_: one of ~auto~, ~always~, ~never~, or ~critical~,
+ ): a String
+
+
+
description
+
It formats _temporalDate_ to an ISO 8601 / RFC 9557 string.
+
+
+ 1. Let _year_ be PadISOYear(_temporalDate_.[[ISODate]].[[Year]]).
+ 1. Let _month_ be ToZeroPaddedDecimalString(_temporalDate_.[[ISODate]].[[Month]], 2).
+ 1. Let _day_ be ToZeroPaddedDecimalString(_temporalDate_.[[ISODate]].[[Day]], 2).
+ 1. Let _calendar_ be FormatCalendarAnnotation(_temporalDate_.[[Calendar]], _showCalendar_).
+ 1. Return the string-concatenation of _year_, the code unit 0x002D (HYPHEN-MINUS), _month_, the code unit 0x002D (HYPHEN-MINUS), _day_, and _calendar_.
+
+
+
+
+
+ AddDurationToDate (
+ _operation_: either ~add~ or ~subtract~,
+ _temporalDate_: a Temporal.PlainDate,
+ _temporalDurationLike_: an ECMAScript language value,
+ _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.PlainDate or a throw completion
+
+
+
description
+
It adds/subtracts _temporalDurationLike_ to/from _temporalDate_, returning a point in time that is in the future/past relative to _temporalDate_.
+
+
+ 1. Let _calendar_ be _temporalDate_.[[Calendar]].
+ 1. Let _duration_ be ? ToTemporalDuration(_temporalDurationLike_).
+ 1. If _operation_ is ~subtract~, set _duration_ to CreateNegatedTemporalDuration(_duration_).
+ 1. Let _internalDuration_ be ToInternalDurationRecordWith24HourDays(_duration_).
+ 1. Let _days_ be truncate(_internalDuration_.[[Time]] / nsPerDay).
+ 1. Let _dateDuration_ be ! CreateDateDurationRecord(_internalDuration_.[[Date]].[[Years]], _internalDuration_.[[Date]].[[Months]], _internalDuration_.[[Date]].[[Weeks]], _days_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _result_ be ? CalendarDateAdd(_calendar_, _temporalDate_.[[ISODate]], _dateDuration_, _overflow_).
+ 1. Return ! CreateTemporalDate(_result_, _calendar_).
+
+
+
+
+
+ DifferenceTemporalPlainDate (
+ _operation_: either ~since~ or ~until~,
+ _temporalDate_: a Temporal.PlainDate,
+ _other_: an ECMAScript language value,
+ _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.Duration or a throw completion
+
+
+
description
+
It computes the difference between the two times represented by _temporalDate_ and _other_, optionally rounds it, and returns it as a Temporal.Duration object.
+
+
+ 1. Set _other_ to ? ToTemporalDate(_other_).
+ 1. If CalendarEquals(_temporalDate_.[[Calendar]], _other_.[[Calendar]]) is *false*, throw a *RangeError* exception.
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _settings_ be ? GetDifferenceSettings(_operation_, _resolvedOptions_, ~date~, « », ~day~, ~day~).
+ 1. If CompareISODate(_temporalDate_.[[ISODate]], _other_.[[ISODate]]) = 0, then
+ 1. Return ! CreateTemporalDuration(0, 0, 0, 0, 0, 0, 0, 0, 0, 0).
+ 1. Let _dateDifference_ be CalendarDateUntil(_temporalDate_.[[Calendar]], _temporalDate_.[[ISODate]], _other_.[[ISODate]], _settings_.[[LargestUnit]]).
+ 1. Let _duration_ be CombineDateAndTimeDuration(_dateDifference_, 0).
+ 1. If _settings_.[[SmallestUnit]] is not ~day~ or _settings_.[[RoundingIncrement]] ≠ 1, then
+ 1. Let _isoDateTime_ be CombineISODateAndTimeRecord(_temporalDate_.[[ISODate]], MidnightTimeRecord()).
+ 1. Let _originEpochNs_ be GetUTCEpochNanoseconds(_isoDateTime_).
+ 1. Let _isoDateTimeOther_ be CombineISODateAndTimeRecord(_other_.[[ISODate]], MidnightTimeRecord()).
+ 1. Let _destEpochNs_ be GetUTCEpochNanoseconds(_isoDateTimeOther_).
+ 1. Set _duration_ to ? RoundRelativeDuration(_duration_, _originEpochNs_, _destEpochNs_, _isoDateTime_, ~unset~, _temporalDate_.[[Calendar]], _settings_.[[LargestUnit]], _settings_.[[RoundingIncrement]], _settings_.[[SmallestUnit]], _settings_.[[RoundingMode]]).
+ 1. Let _result_ be ! TemporalDurationFromInternal(_duration_, ~day~).
+ 1. If _operation_ is ~since~, set _result_ to CreateNegatedTemporalDuration(_result_).
+ 1. Return _result_.
+
+
+
+
diff --git a/temporal/plaindatetime.emu b/temporal/plaindatetime.emu
new file mode 100644
index 0000000000..891b813672
--- /dev/null
+++ b/temporal/plaindatetime.emu
@@ -0,0 +1,869 @@
+
+
+
+
+
Temporal.PlainDateTime Objects
+
A Temporal.PlainDateTime object is an Object that contains integers corresponding to a particular year, month, day, hour, minute, second, millisecond, microsecond, and nanosecond, as well as a calendar type used to interpret those integers in a particular calendar.
+
+
+
The Temporal.PlainDateTime Constructor
+
The Temporal.PlainDateTime constructor:
+
+
+ creates and initializes a new Temporal.PlainDateTime object when called as a constructor.
+
+
+ is not intended to be called as a function and will throw an exception when called in that manner.
+
+
+ may be used as the value of an `extends` clause of a class definition.
+ Subclass constructors that intend to inherit the specified Temporal.PlainDateTime behaviour must
+ include a super call to the %Temporal.PlainDateTime% constructor to create and initialize subclass
+ instances with the necessary internal slots.
+
This function performs the following steps when called:
+
+ 1. If NewTarget is *undefined*, throw a *TypeError* exception.
+ 1. Set _isoYear_ to ? ToIntegerWithTruncation(_isoYear_).
+ 1. Set _isoMonth_ to ? ToIntegerWithTruncation(_isoMonth_).
+ 1. Set _isoDay_ to ? ToIntegerWithTruncation(_isoDay_).
+ 1. If _hour_ is *undefined*, set _hour_ to 0; else set _hour_ to ? ToIntegerWithTruncation(_hour_).
+ 1. If _minute_ is *undefined*, set _minute_ to 0; else set _minute_ to ? ToIntegerWithTruncation(_minute_).
+ 1. If _second_ is *undefined*, set _second_ to 0; else set _second_ to ? ToIntegerWithTruncation(_second_).
+ 1. If _millisecond_ is *undefined*, set _millisecond_ to 0; else set _millisecond_ to ? ToIntegerWithTruncation(_millisecond_).
+ 1. If _microsecond_ is *undefined*, set _microsecond_ to 0; else set _microsecond_ to ? ToIntegerWithTruncation(_microsecond_).
+ 1. If _nanosecond_ is *undefined*, set _nanosecond_ to 0; else set _nanosecond_ to ? ToIntegerWithTruncation(_nanosecond_).
+ 1. If _calendar_ is *undefined*, set _calendar_ to *"iso8601"*.
+ 1. If _calendar_ is not a String, throw a *TypeError* exception.
+ 1. Set _calendar_ to ? CanonicalizeCalendar(_calendar_).
+ 1. If IsValidISODate(_isoYear_, _isoMonth_, _isoDay_) is *false*, throw a *RangeError* exception.
+ 1. Let _isoDate_ be CreateISODateRecord(_isoYear_, _isoMonth_, _isoDay_).
+ 1. If IsValidTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_) is *false*, throw a *RangeError* exception.
+ 1. Let _time_ be CreateTimeRecord(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_).
+ 1. Let _isoDateTime_ be CombineISODateAndTimeRecord(_isoDate_, _time_).
+ 1. Return ? CreateTemporalDateTime(_isoDateTime_, _calendar_, NewTarget).
+
+
+
+
+
+
Properties of the Temporal.PlainDateTime Constructor
+
The value of the [[Prototype]] internal slot of the Temporal.PlainDateTime constructor is the intrinsic object %Function.prototype%.
+
The Temporal.PlainDateTime constructor has the following properties:
+
+
+
Temporal.PlainDateTime.prototype
+
The initial value of `Temporal.PlainDateTime.prototype` is %Temporal.PlainDateTime.prototype%.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *false* }.
This function performs the following steps when called:
+
+ 1. Set _one_ to ? ToTemporalDateTime(_one_).
+ 1. Set _two_ to ? ToTemporalDateTime(_two_).
+ 1. Return 𝔽(CompareISODateTime(_one_.[[ISODateTime]], _two_.[[ISODateTime]])).
+
+
+
+
+
+
Properties of the Temporal.PlainDateTime Prototype Object
+
+
The Temporal.PlainDateTime prototype object
+
+
is the intrinsic object %Temporal.PlainDateTime.prototype%.
+
is itself an ordinary object.
+
is not a Temporal.PlainDateTime instance and does not have a [[InitializedTemporalDateTime]] internal slot.
+
has a [[Prototype]] internal slot whose value is %Object.prototype%.
+
+
+
+ An ECMAScript implementation that includes the ECMA-402 Internationalization API extends this prototype with additional properties in order to represent calendar data.
+
+
+
+
Temporal.PlainDateTime.prototype.constructor
+
The initial value of `Temporal.PlainDateTime.prototype.constructor` is %Temporal.PlainDateTime%.
The initial value of the %Symbol.toStringTag% property is the String *"Temporal.PlainDateTime"*.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.
+
+
+
+
get Temporal.PlainDateTime.prototype.calendarId
+
+ `Temporal.PlainDateTime.prototype.calendarId` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return _plainDateTime_.[[Calendar]].
+
+
+
+
+
get Temporal.PlainDateTime.prototype.era
+
+ `Temporal.PlainDate.prototype.era` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[Era]].
+
+
+
+
+
get Temporal.PlainDateTime.prototype.eraYear
+
+ `Temporal.PlainDateTime.prototype.eraYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Let _result_ be CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[EraYear]].
+ 1. If _result_ is *undefined*, return *undefined*.
+ 1. Return 𝔽(_result_).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.year
+
+ `Temporal.PlainDateTime.prototype.year` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[Year]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.month
+
+ `Temporal.PlainDateTime.prototype.month` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[Month]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.monthCode
+
+ `Temporal.PlainDateTime.prototype.monthCode` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[MonthCode]].
+
+
+
+
+
get Temporal.PlainDateTime.prototype.day
+
+ `Temporal.PlainDateTime.prototype.day` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[Day]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.hour
+
+ `Temporal.PlainDateTime.prototype.hour` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(_plainDateTime_.[[ISODateTime]].[[Time]].[[Hour]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.minute
+
+ `Temporal.PlainDateTime.prototype.minute` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(_plainDateTime_.[[ISODateTime]].[[Time]].[[Minute]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.second
+
+ `Temporal.PlainDateTime.prototype.second` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(_plainDateTime_.[[ISODateTime]].[[Time]].[[Second]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.millisecond
+
+ `Temporal.PlainDateTime.prototype.millisecond` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(_plainDateTime_.[[ISODateTime]].[[Time]].[[Millisecond]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.microsecond
+
+ `Temporal.PlainDateTime.prototype.microsecond` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(_plainDateTime_.[[ISODateTime]].[[Time]].[[Microsecond]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.nanosecond
+
+ `Temporal.PlainDateTime.prototype.nanosecond` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(_plainDateTime_.[[ISODateTime]].[[Time]].[[Nanosecond]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.dayOfWeek
+
+ `Temporal.PlainDateTime.prototype.dayOfWeek` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[DayOfWeek]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.dayOfYear
+
+ `Temporal.PlainDateTime.prototype.dayOfYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[DayOfYear]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.weekOfYear
+
+ `Temporal.PlainDateTime.prototype.weekOfYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Let _result_ be CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[WeekOfYear]].[[Week]].
+ 1. If _result_ is *undefined*, return *undefined*.
+ 1. Return 𝔽(_result_).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.yearOfWeek
+
+ `Temporal.PlainDateTime.prototype.yearOfWeek` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Let _result_ be CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[WeekOfYear]].[[Year]].
+ 1. If _result_ is *undefined*, return *undefined*.
+ 1. Return 𝔽(_result_).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.daysInWeek
+
+ `Temporal.PlainDateTime.prototype.daysInWeek` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[DaysInWeek]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.daysInMonth
+
+ `Temporal.PlainDateTime.prototype.daysInMonth` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[DaysInMonth]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.daysInYear
+
+ `Temporal.PlainDateTime.prototype.daysInYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[DaysInYear]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.monthsInYear
+
+ `Temporal.PlainDateTime.prototype.monthsInYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[MonthsInYear]]).
+
+
+
+
+
get Temporal.PlainDateTime.prototype.inLeapYear
+
+ `Temporal.PlainDateTime.prototype.inLeapYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return CalendarISOToDate(_plainDateTime_.[[Calendar]], _plainDateTime_.[[ISODateTime]].[[ISODate]]).[[InLeapYear]].
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. If ? IsPartialTemporalObject(_temporalDateTimeLike_) is *false*, throw a *TypeError* exception.
+ 1. Let _calendar_ be _plainDateTime_.[[Calendar]].
+ 1. Let _fields_ be ISODateToFields(_calendar_, _plainDateTime_.[[ISODateTime]].[[ISODate]], ~date~).
+ 1. Set _fields_.[[Hour]] to _plainDateTime_.[[ISODateTime]].[[Time]].[[Hour]].
+ 1. Set _fields_.[[Minute]] to _plainDateTime_.[[ISODateTime]].[[Time]].[[Minute]].
+ 1. Set _fields_.[[Second]] to _plainDateTime_.[[ISODateTime]].[[Time]].[[Second]].
+ 1. Set _fields_.[[Millisecond]] to _plainDateTime_.[[ISODateTime]].[[Time]].[[Millisecond]].
+ 1. Set _fields_.[[Microsecond]] to _plainDateTime_.[[ISODateTime]].[[Time]].[[Microsecond]].
+ 1. Set _fields_.[[Nanosecond]] to _plainDateTime_.[[ISODateTime]].[[Time]].[[Nanosecond]].
+ 1. Let _partialDateTime_ be ? PrepareCalendarFields(_calendar_, _temporalDateTimeLike_, « ~year~, ~month~, ~month-code~, ~day~ », « ~hour~, ~minute~, ~second~, ~millisecond~, ~microsecond~, ~nanosecond~ », ~partial~).
+ 1. Set _fields_ to CalendarMergeFields(_calendar_, _fields_, _partialDateTime_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _overflow_).
+ 1. Return ? CreateTemporalDateTime(_result_, _calendar_).
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. If _roundTo_ is *undefined*, throw a *TypeError* exception.
+ 1. If _roundTo_ is a String, then
+ 1. Let _paramString_ be _roundTo_.
+ 1. Set _roundTo_ to OrdinaryObjectCreate(*null*).
+ 1. Perform ! CreateDataPropertyOrThrow(_roundTo_, *"smallestUnit"*, _paramString_).
+ 1. Else,
+ 1. Set _roundTo_ to ? GetOptionsObject(_roundTo_).
+ 1. NOTE: The following steps read options and perform independent validation in alphabetical order (GetRoundingIncrementOption reads *"roundingIncrement"* and GetRoundingModeOption reads *"roundingMode"*).
+ 1. Let _roundingIncrement_ be ? GetRoundingIncrementOption(_roundTo_).
+ 1. Let _roundingMode_ be ? GetRoundingModeOption(_roundTo_, ~half-expand~).
+ 1. Let _smallestUnit_ be ? GetTemporalUnitValuedOption(_roundTo_, *"smallestUnit"*, ~required~).
+ 1. Perform ? ValidateTemporalUnitValue(_smallestUnit_, ~time~, « ~day~ »).
+ 1. If _smallestUnit_ is ~day~, then
+ 1. Let _maximum_ be 1.
+ 1. Let _inclusive_ be *true*.
+ 1. Else,
+ 1. Let _maximum_ be MaximumTemporalDurationRoundingIncrement(_smallestUnit_).
+ 1. Assert: _maximum_ is not ~unset~.
+ 1. Let _inclusive_ be *false*.
+ 1. Perform ? ValidateTemporalRoundingIncrement(_roundingIncrement_, _maximum_, _inclusive_).
+ 1. If _smallestUnit_ is ~nanosecond~ and _roundingIncrement_ = 1, then
+ 1. Return ! CreateTemporalDateTime(_plainDateTime_.[[ISODateTime]], _plainDateTime_.[[Calendar]]).
+ 1. Let _result_ be RoundISODateTime(_plainDateTime_.[[ISODateTime]], _roundingIncrement_, _smallestUnit_, _roundingMode_).
+ 1. Return ? CreateTemporalDateTime(_result_, _plainDateTime_.[[Calendar]]).
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. NOTE: The following steps read options and perform independent validation in alphabetical order (GetTemporalShowCalendarNameOption reads *"calendarName"*, GetTemporalFractionalSecondDigitsOption reads *"fractionalSecondDigits"*, and GetRoundingModeOption reads *"roundingMode"*).
+ 1. Let _showCalendar_ be ? GetTemporalShowCalendarNameOption(_resolvedOptions_).
+ 1. Let _digits_ be ? GetTemporalFractionalSecondDigitsOption(_resolvedOptions_).
+ 1. Let _roundingMode_ be ? GetRoundingModeOption(_resolvedOptions_, ~trunc~).
+ 1. Let _smallestUnit_ be ? GetTemporalUnitValuedOption(_resolvedOptions_, *"smallestUnit"*, ~unset~).
+ 1. Perform ? ValidateTemporalUnitValue(_smallestUnit_, ~time~).
+ 1. If _smallestUnit_ is ~hour~, throw a *RangeError* exception.
+ 1. Let _precision_ be ToSecondsStringPrecisionRecord(_smallestUnit_, _digits_).
+ 1. Let _result_ be RoundISODateTime(_plainDateTime_.[[ISODateTime]], _precision_.[[Increment]], _precision_.[[Unit]], _roundingMode_).
+ 1. If ISODateTimeWithinLimits(_result_) is *false*, throw a *RangeError* exception.
+ 1. Return FormatISODateTime(_result_, _plainDateTime_.[[Calendar]], _precision_.[[Precision]], _showCalendar_).
+
+
+
+
+
+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement this method as specified in the ECMA-402 specification.
+ If an ECMAScript implementation does not include the ECMA-402 API the following specification of this method is used.
+
+
The meanings of the optional parameters to this method are defined in the ECMA-402 specification; implementations that do not include ECMA-402 support must not use those parameter positions for anything else.
+
This method performs the following steps when called:
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return FormatISODateTime(_plainDateTime_.[[ISODateTime]], _plainDateTime_.[[Calendar]], ~auto~, ~auto~).
+
+
+
+
+
Temporal.PlainDateTime.prototype.toJSON ( )
+
This method performs the following steps when called:
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return FormatISODateTime(_plainDateTime_.[[ISODateTime]], _plainDateTime_.[[Calendar]], ~auto~, ~auto~).
+
+
+
+
+
Temporal.PlainDateTime.prototype.valueOf ( )
+
This method performs the following steps when called:
+
+ 1. Throw a *TypeError* exception.
+
+
+
+ This method always throws, because in the absence of `valueOf()`, expressions with arithmetic operators such as `plainDateTime1 > plainDateTime2` would fall back to being equivalent to `plainDateTime1.toString() > plainDateTime2.toString()`.
+ Lexicographical comparison of serialized strings might not seem obviously wrong, because the result would sometimes be correct.
+ Implementations are encouraged to phrase the error message to point users to `Temporal.PlainDateTime.compare()`, `Temporal.PlainDateTime.prototype.equals()`, and/or `Temporal.PlainDateTime.prototype.toString()`.
+
This method performs the following steps when called:
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Let _timeZone_ be ? ToTemporalTimeZoneIdentifier(_temporalTimeZoneLike_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _disambiguation_ be ? GetTemporalDisambiguationOption(_resolvedOptions_).
+ 1. Let _epochNs_ be ? GetEpochNanosecondsFor(_timeZone_, _plainDateTime_.[[ISODateTime]], _disambiguation_).
+ 1. Return ! CreateTemporalZonedDateTime(_epochNs_, _timeZone_, _plainDateTime_.[[Calendar]]).
+
+
+
+
+
Temporal.PlainDateTime.prototype.toPlainDate ( )
+
This method performs the following steps when called:
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return ! CreateTemporalDate(_plainDateTime_.[[ISODateTime]].[[ISODate]], _plainDateTime_.[[Calendar]]).
+
+
+
+
+
Temporal.PlainDateTime.prototype.toPlainTime ( )
+
This method performs the following steps when called:
+
+ 1. Let _plainDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainDateTime_, [[InitializedTemporalDateTime]]).
+ 1. Return ! CreateTemporalTime(_plainDateTime_.[[ISODateTime]].[[Time]]).
+
+
+
+
+
+
Properties of Temporal.PlainDateTime Instances
+
+ Temporal.PlainDateTime instances are ordinary objects that inherit properties from the %Temporal.PlainDateTime.prototype% intrinsic object.
+ Temporal.PlainDateTime instances are initially created with the internal slots described in .
+
+
+
+
+
+ Internal Slot
+
+
+ Description
+
+
+
+
+ [[InitializedTemporalDateTime]]
+
+
+ The only specified use of this slot is for distinguishing Temporal.PlainDateTime instances from other objects.
+
+
+
+
+ [[ISODateTime]]
+
+
+ An ISO Date-Time Record.
+
+
+
+
+ [[Calendar]]
+
+
+ A calendar type.
+
+
+
+
+
+
+
+
Abstract Operations for Temporal.PlainDateTime Objects
+
+
+
+ CreateTemporalDateTime (
+ _isoDateTime_: an ISO Date-Time Record,
+ _calendar_: a calendar type,
+ optional _newTarget_: a constructor,
+ ): either a normal completion containing a Temporal.PlainDateTime or a throw completion
+
+
+
description
+
It creates a Temporal.PlainDateTime instance and fills the internal slots with valid values.
+
+
+ 1. If ISODateTimeWithinLimits(_isoDateTime_) is *false*, throw a *RangeError* exception.
+ 1. If _newTarget_ is not present, set _newTarget_ to %Temporal.PlainDateTime%.
+ 1. Let _object_ be ? OrdinaryCreateFromConstructor(_newTarget_, *"%Temporal.PlainDateTime.prototype%"*, « [[InitializedTemporalDateTime]], [[ISODateTime]], [[Calendar]] »).
+ 1. Set _object_.[[ISODateTime]] to _isoDateTime_.
+ 1. Set _object_.[[Calendar]] to _calendar_.
+ 1. Return _object_.
+
+
+
+
+
+ ToTemporalDateTime (
+ _item_: an ECMAScript language value,
+ optional _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.PlainDateTime or a throw completion
+
+
+
description
+
Converts _item_ to a new Temporal.PlainDateTime instance if possible, and throws otherwise.
+
+
+ 1. If _options_ is not present, set _options_ to *undefined*.
+ 1. If _item_ is an Object, then
+ 1. If _item_ has an [[InitializedTemporalDateTime]] internal slot, then
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Return ! CreateTemporalDateTime(_item_.[[ISODateTime]], _item_.[[Calendar]]).
+ 1. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_item_.[[TimeZone]], _item_.[[EpochNanoseconds]]).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Return ! CreateTemporalDateTime(_isoDateTime_, _item_.[[Calendar]]).
+ 1. If _item_ has an [[InitializedTemporalDate]] internal slot, then
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _isoDateTime_ be CombineISODateAndTimeRecord(_item_.[[ISODate]], MidnightTimeRecord()).
+ 1. Return ? CreateTemporalDateTime(_isoDateTime_, _item_.[[Calendar]]).
+ 1. Let _calendar_ be ? GetTemporalCalendarIdentifierWithISODefault(_item_).
+ 1. Let _fields_ be ? PrepareCalendarFields(_calendar_, _item_, « ~year~, ~month~, ~month-code~, ~day~ », « ~hour~, ~minute~, ~second~, ~millisecond~, ~microsecond~, ~nanosecond~ », «»).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _overflow_).
+ 1. Return ? CreateTemporalDateTime(_result_, _calendar_).
+ 1. If _item_ is not a String, throw a *TypeError* exception.
+ 1. Let _result_ be ? ParseISODateTime(_item_, « |TemporalDateTimeString[~Zoned]| »).
+ 1. If _result_.[[Time]] is ~start-of-day~, let _time_ be MidnightTimeRecord(); else let _time_ be _result_.[[Time]].
+ 1. Let _calendar_ be _result_.[[Calendar]].
+ 1. If _calendar_ is ~empty~, set _calendar_ to *"iso8601"*.
+ 1. Set _calendar_ to ? CanonicalizeCalendar(_calendar_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _isoDate_ be CreateISODateRecord(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]]).
+ 1. Let _isoDateTime_ be CombineISODateAndTimeRecord(_isoDate_, _time_).
+ 1. Return ? CreateTemporalDateTime(_isoDateTime_, _calendar_).
+
+
+
+
+
+ AddDurationToDateTime (
+ _operation_: either ~add~ or ~subtract~,
+ _dateTime_: a Temporal.PlainDateTime,
+ _temporalDurationLike_: an ECMAScript language value,
+ _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.PlainDateTime or a throw completion
+
+
+
description
+
It adds/subtracts _temporalDurationLike_ to/from _dateTime_, returning a point in time that is in the future/past relative to _datetime_.
+
+
+ 1. Let _duration_ be ? ToTemporalDuration(_temporalDurationLike_).
+ 1. If _operation_ is ~subtract~, set _duration_ to CreateNegatedTemporalDuration(_duration_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _internalDuration_ be ToInternalDurationRecordWith24HourDays(_duration_).
+ 1. Let _timeResult_ be AddTime(_dateTime_.[[ISODateTime]].[[Time]], _internalDuration_.[[Time]]).
+ 1. Let _dateDuration_ be ? AdjustDateDurationRecord(_internalDuration_.[[Date]], _timeResult_.[[Days]]).
+ 1. Let _addedDate_ be ? CalendarDateAdd(_dateTime_.[[Calendar]], _dateTime_.[[ISODateTime]].[[ISODate]], _dateDuration_, _overflow_).
+ 1. Let _result_ be CombineISODateAndTimeRecord(_addedDate_, _timeResult_).
+ 1. Return ? CreateTemporalDateTime(_result_, _dateTime_.[[Calendar]]).
+
+
+
+
+
+ DifferenceTemporalPlainDateTime (
+ _operation_: either ~since~ or ~until~,
+ _dateTime_: a Temporal.PlainDateTime,
+ _other_: an ECMAScript language value,
+ _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.Duration or a throw completion
+
+
+
description
+
It computes the difference between the two times represented by _dateTime_ and _other_, optionally rounds it, and returns it as a Temporal.Duration object.
+
+
+ 1. Set _other_ to ? ToTemporalDateTime(_other_).
+ 1. If CalendarEquals(_dateTime_.[[Calendar]], _other_.[[Calendar]]) is *false*, throw a *RangeError* exception.
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _settings_ be ? GetDifferenceSettings(_operation_, _resolvedOptions_, ~datetime~, « », ~nanosecond~, ~day~).
+ 1. If CompareISODateTime(_dateTime_.[[ISODateTime]], _other_.[[ISODateTime]]) = 0, return ! CreateTemporalDuration(0, 0, 0, 0, 0, 0, 0, 0, 0, 0).
+ 1. Let _internalDuration_ be ? DifferencePlainDateTimeWithRounding(_dateTime_.[[ISODateTime]], _other_.[[ISODateTime]], _dateTime_.[[Calendar]], _settings_.[[LargestUnit]], _settings_.[[RoundingIncrement]], _settings_.[[SmallestUnit]], _settings_.[[RoundingMode]]).
+ 1. Let _result_ be ! TemporalDurationFromInternal(_internalDuration_, _settings_.[[LargestUnit]]).
+ 1. If _operation_ is ~since~, set _result_ to CreateNegatedTemporalDuration(_result_).
+ 1. Return _result_.
+
+
+
+
+
+ DifferencePlainDateTimeWithRounding (
+ _isoDateTime1_: an ISO Date-Time Record,
+ _isoDateTime2_: an ISO Date-Time Record,
+ _calendar_: a calendar type,
+ _largestUnit_: a Temporal unit,
+ _roundingIncrement_: a positive integer,
+ _smallestUnit_: a Temporal unit,
+ _roundingMode_: a rounding mode,
+ ): either a normal completion containing an Internal Duration Record or a throw completion
+
+
+
description
+
+
+
+ 1. If CompareISODateTime(_isoDateTime1_, _isoDateTime2_) = 0, return CombineDateAndTimeDuration(ZeroDateDuration(), 0).
+ 1. If ISODateTimeWithinLimits(_isoDateTime1_) is *false* or ISODateTimeWithinLimits(_isoDateTime2_) is *false*, throw a *RangeError* exception.
+ 1. Let _diff_ be DifferenceISODateTime(_isoDateTime1_, _isoDateTime2_, _calendar_, _largestUnit_).
+ 1. If _smallestUnit_ is ~nanosecond~ and _roundingIncrement_ = 1, return _diff_.
+ 1. Let _originEpochNs_ be GetUTCEpochNanoseconds(_isoDateTime1_).
+ 1. Let _destEpochNs_ be GetUTCEpochNanoseconds(_isoDateTime2_).
+ 1. Return ? RoundRelativeDuration(_diff_, _originEpochNs_, _destEpochNs_, _isoDateTime1_, ~unset~, _calendar_, _largestUnit_, _roundingIncrement_, _smallestUnit_, _roundingMode_).
+
+
+
+
+
+ DifferencePlainDateTimeWithTotal (
+ _isoDateTime1_: an ISO Date-Time Record,
+ _isoDateTime2_: an ISO Date-Time Record,
+ _calendar_: a calendar type,
+ _unit_: a Temporal unit,
+ ): either a normal completion containing a mathematical value or a throw completion
+
+
+
description
+
+
+
+ 1. If CompareISODateTime(_isoDateTime1_, _isoDateTime2_) = 0, return 0.
+ 1. If ISODateTimeWithinLimits(_isoDateTime1_) is *false* or ISODateTimeWithinLimits(_isoDateTime2_) is *false*, throw a *RangeError* exception.
+ 1. Let _diff_ be DifferenceISODateTime(_isoDateTime1_, _isoDateTime2_, _calendar_, _unit_).
+ 1. If _unit_ is ~nanosecond~, return _diff_.[[Time]].
+ 1. Let _originEpochNs_ be GetUTCEpochNanoseconds(_isoDateTime1_).
+ 1. Let _destEpochNs_ be GetUTCEpochNanoseconds(_isoDateTime2_).
+ 1. Return ? TotalRelativeDuration(_diff_, _originEpochNs_, _destEpochNs_, _isoDateTime1_, ~unset~, _calendar_, _unit_).
+
+
+
+
+
+ InterpretTemporalDateTimeFields (
+ _calendar_: a calendar type,
+ _fields_: a Calendar Fields Record,
+ _overflow_: either ~constrain~ or ~reject~,
+ ): either a normal completion containing an ISO Date-Time Record, or a throw completion
+
+
+
description
+
It interprets the date/time fields in the object _fields_ using the given calendar.
+
+
+ 1. Let _isoDate_ be ? CalendarDateFromFields(_calendar_, _fields_, _overflow_).
+ 1. Let _time_ be ? RegulateTime(_fields_.[[Hour]], _fields_.[[Minute]], _fields_.[[Second]], _fields_.[[Millisecond]], _fields_.[[Microsecond]], _fields_.[[Nanosecond]], _overflow_).
+ 1. Return CombineISODateAndTimeRecord(_isoDate_, _time_).
+
+
+
+
diff --git a/temporal/plainmonthday.emu b/temporal/plainmonthday.emu
new file mode 100644
index 0000000000..3921ca3dd1
--- /dev/null
+++ b/temporal/plainmonthday.emu
@@ -0,0 +1,367 @@
+
+
+
+
+
Temporal.PlainMonthDay Objects
+
A Temporal.PlainMonthDay object is an Object that contains integers corresponding to a particular month and day in a particular calendar.
+
+
+
The Temporal.PlainMonthDay Constructor
+
The Temporal.PlainMonthDay constructor:
+
+
+ creates and initializes a new Temporal.PlainMonthDay object when called as a constructor.
+
+
+ is not intended to be called as a function and will throw an exception when called in that manner.
+
+
+ may be used as the value of an `extends` clause of a class definition.
+ Subclass constructors that intend to inherit the specified Temporal.PlainMonthDay behaviour must
+ include a super call to the %Temporal.PlainMonthDay% constructor to create and initialize subclass
+ instances with the necessary internal slots.
+
This function performs the following steps when called:
+
+ 1. If NewTarget is *undefined*, throw a *TypeError* exception.
+ 1. If _referenceISOYear_ is *undefined*, then
+ 1. Set _referenceISOYear_ to *1972*𝔽 (the first ISO 8601 leap year after the epoch).
+ 1. Let _m_ be ? ToIntegerWithTruncation(_isoMonth_).
+ 1. Let _d_ be ? ToIntegerWithTruncation(_isoDay_).
+ 1. If _calendar_ is *undefined*, set _calendar_ to *"iso8601"*.
+ 1. If _calendar_ is not a String, throw a *TypeError* exception.
+ 1. Set _calendar_ to ? CanonicalizeCalendar(_calendar_).
+ 1. Let _y_ be ? ToIntegerWithTruncation(_referenceISOYear_).
+ 1. If IsValidISODate(_y_, _m_, _d_) is *false*, throw a *RangeError* exception.
+ 1. Let _isoDate_ be CreateISODateRecord(_y_, _m_, _d_).
+ 1. Return ? CreateTemporalMonthDay(_isoDate_, _calendar_, NewTarget).
+
+
+
+
+
+
Properties of the Temporal.PlainMonthDay Constructor
+
The value of the [[Prototype]] internal slot of the Temporal.PlainMonthDay constructor is the intrinsic object %Function.prototype%.
+
The Temporal.PlainMonthDay constructor has the following properties:
+
+
+
Temporal.PlainMonthDay.prototype
+
The initial value of `Temporal.PlainMonthDay.prototype` is %Temporal.PlainMonthDay.prototype%.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *false* }.
Properties of the Temporal.PlainMonthDay Prototype Object
+
+
The Temporal.PlainMonthDay prototype object
+
+
is itself an ordinary object.
+
is not a Temporal.PlainMonthDay instance and does not have a [[InitializedTemporalMonthDay]] internal slot.
+
has a [[Prototype]] internal slot whose value is %Object.prototype%.
+
+
+
+ An ECMAScript implementation that includes the ECMA-402 Internationalization API extends this prototype with additional properties in order to represent calendar data.
+
+
+
+
Temporal.PlainMonthDay.prototype.constructor
+
The initial value of `Temporal.PlainMonthDay.prototype.constructor` is %Temporal.PlainMonthDay%.
The initial value of the %Symbol.toStringTag% property is the String *"Temporal.PlainMonthDay"*.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.
+
+
+
+
get Temporal.PlainMonthDay.prototype.calendarId
+
+ `Temporal.PlainMonthDay.prototype.calendarId` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainMonthDay_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainMonthDay_, [[InitializedTemporalMonthDay]]).
+ 1. Return _plainMonthDay_.[[Calendar]].
+
+
+
+
+
get Temporal.PlainMonthDay.prototype.monthCode
+
+ `Temporal.PlainMonthDay.prototype.monthCode` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainMonthDay_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainMonthDay_, [[InitializedTemporalMonthDay]]).
+ 1. Return CalendarISOToDate(_plainMonthDay_.[[Calendar]], _plainMonthDay_.[[ISODate]]).[[MonthCode]].
+
+
+
+
+
get Temporal.PlainMonthDay.prototype.day
+
+ `Temporal.PlainMonthDay.prototype.day` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainMonthDay_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainMonthDay_, [[InitializedTemporalMonthDay]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainMonthDay_.[[Calendar]], _plainMonthDay_.[[ISODate]]).[[Day]]).
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _plainMonthDay_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainMonthDay_, [[InitializedTemporalMonthDay]]).
+ 1. If ? IsPartialTemporalObject(_temporalMonthDayLike_) is *false*, throw a *TypeError* exception.
+ 1. Let _calendar_ be _plainMonthDay_.[[Calendar]].
+ 1. Let _fields_ be ISODateToFields(_calendar_, _plainMonthDay_.[[ISODate]], ~month-day~).
+ 1. Let _partialMonthDay_ be ? PrepareCalendarFields(_calendar_, _temporalMonthDayLike_, « ~year~, ~month~, ~month-code~, ~day~ », « », ~partial~).
+ 1. Set _fields_ to CalendarMergeFields(_calendar_, _fields_, _partialMonthDay_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _isoDate_ be ? CalendarMonthDayFromFields(_calendar_, _fields_, _overflow_).
+ 1. Return ! CreateTemporalMonthDay(_isoDate_, _calendar_).
+
+
+
+
+
+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement this method as specified in the ECMA-402 specification.
+ If an ECMAScript implementation does not include the ECMA-402 API the following specification of this method is used.
+
+
The meanings of the optional parameters to this method are defined in the ECMA-402 specification; implementations that do not include ECMA-402 support must not use those parameter positions for anything else.
+
This method performs the following steps when called:
+
+ 1. Let _plainMonthDay_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainMonthDay_, [[InitializedTemporalMonthDay]]).
+ 1. Return TemporalMonthDayToString(_plainMonthDay_, ~auto~).
+
+
+
+
+
Temporal.PlainMonthDay.prototype.toJSON ( )
+
This method performs the following steps when called:
+
+ 1. Let _plainMonthDay_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainMonthDay_, [[InitializedTemporalMonthDay]]).
+ 1. Return TemporalMonthDayToString(_plainMonthDay_, ~auto~).
+
+
+
+
+
Temporal.PlainMonthDay.prototype.valueOf ( )
+
This method performs the following steps when called:
+
+ 1. Throw a *TypeError* exception.
+
+
+
+ This method always throws, because in the absence of `valueOf()`, expressions with arithmetic operators such as `plainMonthDay1 > plainMonthDay2` would fall back to being equivalent to `plainMonthDay1.toString() > plainMonthDay2.toString()`.
+ Lexicographical comparison of serialized strings might not seem obviously wrong, because the result would sometimes be correct.
+ Implementations are encouraged to phrase the error message to point users to `Temporal.PlainDate.compare()` on the corresponding `PlainDate` objects, `Temporal.PlainMonthDay.prototype.equals()`, and/or `Temporal.PlainMonthDay.prototype.toString()`.
+
This method performs the following steps when called:
+
+ 1. Let _plainMonthDay_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainMonthDay_, [[InitializedTemporalMonthDay]]).
+ 1. If _item_ is not an Object, throw a *TypeError* exception.
+ 1. Let _calendar_ be _plainMonthDay_.[[Calendar]].
+ 1. Let _fields_ be ISODateToFields(_calendar_, _plainMonthDay_.[[ISODate]], ~month-day~).
+ 1. Let _inputFields_ be ? PrepareCalendarFields(_calendar_, _item_, « ~year~ », « », « »).
+ 1. Let _mergedFields_ be CalendarMergeFields(_calendar_, _fields_, _inputFields_).
+ 1. Let _isoDate_ be ? CalendarDateFromFields(_calendar_, _mergedFields_, ~constrain~).
+ 1. Return ! CreateTemporalDate(_isoDate_, _calendar_).
+
+
+
+
+
+
Properties of Temporal.PlainMonthDay Instances
+
+ Temporal.PlainMonthDay instances are ordinary objects that inherit properties from the %Temporal.PlainMonthDay.prototype% intrinsic object.
+ Temporal.PlainMonthDay instances are initially created with the internal slots described in .
+
+
+
+
+
+ Internal Slot
+
+
+ Description
+
+
+
+
+ [[InitializedTemporalMonthDay]]
+
+
+ The only specified use of this slot is for distinguishing Temporal.PlainMonthDay instances from other objects.
+
+
+
+
+ [[ISODate]]
+
+
+ An ISO Date Record.
+ The [[Year]] field is used by the calendar in the [[Calendar]] slot to disambiguate if the [[Month]] and [[Day]] fields are not sufficient to uniquely identify a month and day in that calendar.
+
+
+
+
+ [[Calendar]]
+
+
+ A calendar type.
+
+
+
+
+
+
+
+
Abstract Operations for Temporal.PlainMonthDay Objects
+
+
+
+ CreateTemporalMonthDay (
+ _isoDate_: an ISO Date Record,
+ _calendar_: a calendar type,
+ optional _newTarget_: a constructor,
+ ): either a normal completion containing a Temporal.PlainMonthDay or a throw completion
+
+
+
description
+
It creates a Temporal.PlainMonthDay instance and fills the internal slots with valid values.
+
+
+ 1. If ISODateWithinLimits(_isoDate_) is *false*, throw a *RangeError* exception.
+ 1. If _newTarget_ is not present, set _newTarget_ to %Temporal.PlainMonthDay%.
+ 1. Let _object_ be ? OrdinaryCreateFromConstructor(_newTarget_, *"%Temporal.PlainMonthDay.prototype%"*, « [[InitializedTemporalMonthDay]], [[ISODate]], [[Calendar]] »).
+ 1. Set _object_.[[ISODate]] to _isoDate_.
+ 1. Set _object_.[[Calendar]] to _calendar_.
+ 1. Return _object_.
+
+
+
+
+
+ ToTemporalMonthDay (
+ _item_: an ECMAScript language value,
+ optional _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.PlainMonthDay or a throw completion
+
+
+
description
+
Converts _item_ to a new Temporal.PlainMonthDay instance if possible, and throws otherwise.
+
+
+ 1. If _options_ is not present, set _options_ to *undefined*.
+ 1. If _item_ is an Object, then
+ 1. If _item_ has an [[InitializedTemporalMonthDay]] internal slot, then
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Return ! CreateTemporalMonthDay(_item_.[[ISODate]], _item_.[[Calendar]]).
+ 1. Let _calendar_ be ? GetTemporalCalendarIdentifierWithISODefault(_item_).
+ 1. Let _fields_ be ? PrepareCalendarFields(_calendar_, _item_, « ~year~, ~month~, ~month-code~, ~day~ », «», «»).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _isoDate_ be ? CalendarMonthDayFromFields(_calendar_, _fields_, _overflow_).
+ 1. Return ! CreateTemporalMonthDay(_isoDate_, _calendar_).
+ 1. If _item_ is not a String, throw a *TypeError* exception.
+ 1. Let _result_ be ? ParseISODateTime(_item_, « |TemporalMonthDayString| »).
+ 1. Let _calendar_ be _result_.[[Calendar]].
+ 1. If _calendar_ is ~empty~, set _calendar_ to *"iso8601"*.
+ 1. Set _calendar_ to ? CanonicalizeCalendar(_calendar_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. If _calendar_ is *"iso8601"*, then
+ 1. Let _referenceISOYear_ be 1972 (the first ISO 8601 leap year after the epoch).
+ 1. Let _isoDate_ be CreateISODateRecord(_referenceISOYear_, _result_.[[Month]], _result_.[[Day]]).
+ 1. Return ! CreateTemporalMonthDay(_isoDate_, _calendar_).
+ 1. Let _isoDate_ be CreateISODateRecord(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]]).
+ 1. If ISODateWithinLimits(_isoDate_) is *false*, throw a *RangeError* exception.
+ 1. Set _result_ to ISODateToFields(_calendar_, _isoDate_, ~month-day~).
+ 1. NOTE: The following operation is called with ~constrain~ regardless of _overflow_, in order for the calendar to store a canonical value in the [[Year]] field of the [[ISODate]] internal slot of the result.
+ 1. Set _isoDate_ to ? CalendarMonthDayFromFields(_calendar_, _result_, ~constrain~).
+ 1. Return ! CreateTemporalMonthDay(_isoDate_, _calendar_).
+
+
+
+
+
+ TemporalMonthDayToString (
+ _monthDay_: a Temporal.PlainMonthDay,
+ _showCalendar_: one of ~auto~, ~always~, ~never~, or ~critical~,
+ ): a String
+
+
+
description
+
It formats _monthDay_ into an ISO 8601 / RFC 9557 string.
+
+
+ 1. Let _month_ be ToZeroPaddedDecimalString(_monthDay_.[[ISODate]].[[Month]], 2).
+ 1. Let _day_ be ToZeroPaddedDecimalString(_monthDay_.[[ISODate]].[[Day]], 2).
+ 1. Let _result_ be the string-concatenation of _month_, the code unit 0x002D (HYPHEN-MINUS), and _day_.
+ 1. If _showCalendar_ is one of ~always~ or ~critical~, or _monthDay_.[[Calendar]] is not *"iso8601"*, then
+ 1. Let _year_ be PadISOYear(_monthDay_.[[ISODate]].[[Year]]).
+ 1. Set _result_ to the string-concatenation of _year_, the code unit 0x002D (HYPHEN-MINUS), and _result_.
+ 1. Let _calendarString_ be FormatCalendarAnnotation(_monthDay_.[[Calendar]], _showCalendar_).
+ 1. Set _result_ to the string-concatenation of _result_ and _calendarString_.
+ 1. Return _result_.
+
+
+
+
diff --git a/temporal/plaintime.emu b/temporal/plaintime.emu
new file mode 100644
index 0000000000..f64e218183
--- /dev/null
+++ b/temporal/plaintime.emu
@@ -0,0 +1,504 @@
+
+
+
+
+
Temporal.PlainTime Objects
+
+ A Temporal.PlainTime object is an Object that contains integers corresponding to a particular hour, minute,
+ second, millisecond, microsecond, and nanosecond.
+
+
+
+
The Temporal.PlainTime Constructor
+
The Temporal.PlainTime constructor:
+
+
+ creates and initializes a new Temporal.PlainTime object when called as a constructor.
+
+
+ is not intended to be called as a function and will throw an exception when called in that manner.
+
+
+ may be used as the value of an `extends` clause of a class definition.
+ Subclass constructors that intend to inherit the specified Temporal.PlainTime behaviour must
+ include a super call to the %Temporal.PlainTime% constructor to create and initialize subclass
+ instances with the necessary internal slots.
+
This function performs the following steps when called:
+
+ 1. If NewTarget is *undefined*, throw a *TypeError* exception.
+ 1. If _hour_ is *undefined*, set _hour_ to 0; else set _hour_ to ? ToIntegerWithTruncation(_hour_).
+ 1. If _minute_ is *undefined*, set _minute_ to 0; else set _minute_ to ? ToIntegerWithTruncation(_minute_).
+ 1. If _second_ is *undefined*, set _second_ to 0; else set _second_ to ? ToIntegerWithTruncation(_second_).
+ 1. If _millisecond_ is *undefined*, set _millisecond_ to 0; else set _millisecond_ to ? ToIntegerWithTruncation(_millisecond_).
+ 1. If _microsecond_ is *undefined*, set _microsecond_ to 0; else set _microsecond_ to ? ToIntegerWithTruncation(_microsecond_).
+ 1. If _nanosecond_ is *undefined*, set _nanosecond_ to 0; else set _nanosecond_ to ? ToIntegerWithTruncation(_nanosecond_).
+ 1. If IsValidTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_) is *false*, throw a *RangeError* exception.
+ 1. Let _time_ be CreateTimeRecord(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_).
+ 1. Return ? CreateTemporalTime(_time_, NewTarget).
+
+
+
+
+
+
Properties of the Temporal.PlainTime Constructor
+
+ The value of the [[Prototype]] internal slot of the Temporal.PlainTime constructor is the intrinsic object
+ %Function.prototype%.
+
+
The Temporal.PlainTime constructor has the following properties:
+
+
+
Temporal.PlainTime.prototype
+
The initial value of `Temporal.PlainTime.prototype` is %Temporal.PlainTime.prototype%.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *false* }.
The initial value of the %Symbol.toStringTag% property is the String *"Temporal.PlainTime"*.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.
+
+
+
+
get Temporal.PlainTime.prototype.hour
+
+ `Temporal.PlainTime.prototype.hour` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainTime_, [[InitializedTemporalTime]]).
+ 1. Return 𝔽(_plainTime_.[[Time]].[[Hour]]).
+
+
+
+
+
get Temporal.PlainTime.prototype.minute
+
+ `Temporal.PlainTime.prototype.minute` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainTime_, [[InitializedTemporalTime]]).
+ 1. Return 𝔽(_plainTime_.[[Time]].[[Minute]]).
+
+
+
+
+
get Temporal.PlainTime.prototype.second
+
+ `Temporal.PlainTime.prototype.second` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainTime_, [[InitializedTemporalTime]]).
+ 1. Return 𝔽(_plainTime_.[[Time]].[[Second]]).
+
+
+
+
+
get Temporal.PlainTime.prototype.millisecond
+
+ `Temporal.PlainTime.prototype.millisecond` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainTime_, [[InitializedTemporalTime]]).
+ 1. Return 𝔽(_plainTime_.[[Time]].[[Millisecond]]).
+
+
+
+
+
get Temporal.PlainTime.prototype.microsecond
+
+ `Temporal.PlainTime.prototype.microsecond` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainTime_, [[InitializedTemporalTime]]).
+ 1. Return 𝔽(_plainTime_.[[Time]].[[Microsecond]]).
+
+
+
+
+
get Temporal.PlainTime.prototype.nanosecond
+
+ `Temporal.PlainTime.prototype.nanosecond` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainTime_, [[InitializedTemporalTime]]).
+ 1. Return 𝔽(_plainTime_.[[Time]].[[Nanosecond]]).
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _plainTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainTime_, [[InitializedTemporalTime]]).
+ 1. If ? IsPartialTemporalObject(_temporalTimeLike_) is *false*, throw a *TypeError* exception.
+ 1. Let _partialTime_ be ? ToTemporalTimeRecord(_temporalTimeLike_, ~partial~).
+ 1. If _partialTime_.[[Hour]] is not *undefined*, then
+ 1. Let _hour_ be _partialTime_.[[Hour]].
+ 1. Else,
+ 1. Let _hour_ be _plainTime_.[[Time]].[[Hour]].
+ 1. If _partialTime_.[[Minute]] is not *undefined*, then
+ 1. Let _minute_ be _partialTime_.[[Minute]].
+ 1. Else,
+ 1. Let _minute_ be _plainTime_.[[Time]].[[Minute]].
+ 1. If _partialTime_.[[Second]] is not *undefined*, then
+ 1. Let _second_ be _partialTime_.[[Second]].
+ 1. Else,
+ 1. Let _second_ be _plainTime_.[[Time]].[[Second]].
+ 1. If _partialTime_.[[Millisecond]] is not *undefined*, then
+ 1. Let _millisecond_ be _partialTime_.[[Millisecond]].
+ 1. Else,
+ 1. Let _millisecond_ be _plainTime_.[[Time]].[[Millisecond]].
+ 1. If _partialTime_.[[Microsecond]] is not *undefined*, then
+ 1. Let _microsecond_ be _partialTime_.[[Microsecond]].
+ 1. Else,
+ 1. Let _microsecond_ be _plainTime_.[[Time]].[[Microsecond]].
+ 1. If _partialTime_.[[Nanosecond]] is not *undefined*, then
+ 1. Let _nanosecond_ be _partialTime_.[[Nanosecond]].
+ 1. Else,
+ 1. Let _nanosecond_ be _plainTime_.[[Time]].[[Nanosecond]].
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _result_ be ? RegulateTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_, _overflow_).
+ 1. Return ! CreateTemporalTime(_result_).
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _plainTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainTime_, [[InitializedTemporalTime]]).
+ 1. Return ? DifferenceTemporalPlainTime(~since~, _plainTime_, _other_, _options_).
+
+
+
+
+
Temporal.PlainTime.prototype.round ( _roundTo_ )
+
This method performs the following steps when called:
+
+ 1. Let _plainTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainTime_, [[InitializedTemporalTime]]).
+ 1. If _roundTo_ is *undefined*, throw a *TypeError* exception.
+ 1. If _roundTo_ is a String, then
+ 1. Let _paramString_ be _roundTo_.
+ 1. Set _roundTo_ to OrdinaryObjectCreate(*null*).
+ 1. Perform ! CreateDataPropertyOrThrow(_roundTo_, *"smallestUnit"*, _paramString_).
+ 1. Else,
+ 1. Set _roundTo_ to ? GetOptionsObject(_roundTo_).
+ 1. NOTE: The following steps read options and perform independent validation in alphabetical order (GetRoundingIncrementOption reads *"roundingIncrement"* and GetRoundingModeOption reads *"roundingMode"*).
+ 1. Let _roundingIncrement_ be ? GetRoundingIncrementOption(_roundTo_).
+ 1. Let _roundingMode_ be ? GetRoundingModeOption(_roundTo_, ~half-expand~).
+ 1. Let _smallestUnit_ be ? GetTemporalUnitValuedOption(_roundTo_, *"smallestUnit"*, ~required~).
+ 1. Perform ? ValidateTemporalUnitValue(_smallestUnit_, ~time~).
+ 1. Let _maximum_ be MaximumTemporalDurationRoundingIncrement(_smallestUnit_).
+ 1. Assert: _maximum_ is not ~unset~.
+ 1. Perform ? ValidateTemporalRoundingIncrement(_roundingIncrement_, _maximum_, *false*).
+ 1. Let _result_ be RoundTime(_plainTime_.[[Time]], _roundingIncrement_, _smallestUnit_, _roundingMode_).
+ 1. Return ! CreateTemporalTime(_result_).
+
+
+
+
+
Temporal.PlainTime.prototype.equals ( _other_ )
+
This method performs the following steps when called:
+
+ 1. Let _plainTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainTime_, [[InitializedTemporalTime]]).
+ 1. Set _other_ to ? ToTemporalTime(_other_).
+ 1. If CompareTimeRecord(_plainTime_.[[Time]], _other_.[[Time]]) = 0, return *true*.
+ 1. Return *false*.
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _plainTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainTime_, [[InitializedTemporalTime]]).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. NOTE: The following steps read options and perform independent validation in alphabetical order (GetTemporalFractionalSecondDigitsOption reads *"fractionalSecondDigits"* and GetRoundingModeOption reads *"roundingMode"*).
+ 1. Let _digits_ be ? GetTemporalFractionalSecondDigitsOption(_resolvedOptions_).
+ 1. Let _roundingMode_ be ? GetRoundingModeOption(_resolvedOptions_, ~trunc~).
+ 1. Let _smallestUnit_ be ? GetTemporalUnitValuedOption(_resolvedOptions_, *"smallestUnit"*, ~unset~).
+ 1. Perform ? ValidateTemporalUnitValue(_smallestUnit_, ~time~).
+ 1. If _smallestUnit_ is ~hour~, throw a *RangeError* exception.
+ 1. Let _precision_ be ToSecondsStringPrecisionRecord(_smallestUnit_, _digits_).
+ 1. Let _roundResult_ be RoundTime(_plainTime_.[[Time]], _precision_.[[Increment]], _precision_.[[Unit]], _roundingMode_).
+ 1. Return TimeRecordToString(_roundResult_, _precision_.[[Precision]]).
+
+
+
+
+
+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement this method as specified in the ECMA-402 specification.
+ If an ECMAScript implementation does not include the ECMA-402 API the following specification of this method is used.
+
+
The meanings of the optional parameters to this method are defined in the ECMA-402 specification; implementations that do not include ECMA-402 support must not use those parameter positions for anything else.
+
This method performs the following steps when called:
+
+ 1. Let _plainTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainTime_, [[InitializedTemporalTime]]).
+ 1. Return TimeRecordToString(_plainTime_.[[Time]], ~auto~).
+
+
+
+
+
Temporal.PlainTime.prototype.toJSON ( )
+
This method performs the following steps when called:
+
+ 1. Let _plainTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainTime_, [[InitializedTemporalTime]]).
+ 1. Return TimeRecordToString(_plainTime_.[[Time]], ~auto~).
+
+
+
+
+
Temporal.PlainTime.prototype.valueOf ( )
+
This method performs the following steps when called:
+
+ 1. Throw a *TypeError* exception.
+
+
+
+ This method always throws, because in the absence of `valueOf()`, expressions with arithmetic operators such as `plainTime1 > plainTime2` would fall back to being equivalent to `plainTime1.toString() > plainTime2.toString()`.
+ Lexicographical comparison of serialized strings might not seem obviously wrong, because the result would sometimes be correct.
+ Implementations are encouraged to phrase the error message to point users to `Temporal.PlainTime.compare()`, `Temporal.PlainTime.prototype.equals()`, and/or `Temporal.PlainTime.prototype.toString()`.
+
+
+
+
+
+
+
Properties of Temporal.PlainTime Instances
+
+ Temporal.PlainTime instances are ordinary objects that inherit properties from the %Temporal.PlainTime.prototype% intrinsic object.
+ Temporal.PlainTime instances are initially created with the internal slots described in .
+
+
+
+
+
+ Internal Slot
+
+
+ Description
+
+
+
+
+ [[InitializedTemporalTime]]
+
+
+ The only specified use of this slot is for distinguishing Temporal.PlainTime instances from other objects.
+
+
+
+
+ [[Time]]
+
+
+ A Time Record. The [[Days]] field is ignored.
+
+
+
+
+
+
+
+
Abstract Operations for Temporal.PlainTime Objects
+
+
+
+ CreateTemporalTime (
+ _time_: a Time Record,
+ optional _newTarget_: a constructor,
+ ): either a normal completion containing a Temporal.PlainTime or a throw completion
+
+
+
description
+
It creates a new Temporal.PlainTime instance and fills the internal slots with valid values.
+
+
+ 1. If _newTarget_ is not present, set _newTarget_ to %Temporal.PlainTime%.
+ 1. Let _object_ be ? OrdinaryCreateFromConstructor(_newTarget_, *"%Temporal.PlainTime.prototype%"*, « [[InitializedTemporalTime]], [[Time]] »).
+ 1. Set _object_.[[Time]] to _time_.
+ 1. Return _object_.
+
+
+
+
+
+ ToTemporalTime (
+ _item_: an ECMAScript language value,
+ optional _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.PlainTime or a throw Completion
+
+
+
description
+
Converts _item_ to a new Temporal.PlainTime instance if possible, and throws otherwise.
+
+
+ 1. If _options_ is not present, set _options_ to *undefined*.
+ 1. If _item_ is an Object, then
+ 1. If _item_ has an [[InitializedTemporalTime]] internal slot, then
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Return ! CreateTemporalTime(_item_.[[Time]]).
+ 1. If _item_ has an [[InitializedTemporalDateTime]] internal slot, then
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Return ! CreateTemporalTime(_item_.[[ISODateTime]].[[Time]]).
+ 1. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_item_.[[TimeZone]], _item_.[[EpochNanoseconds]]).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Return ! CreateTemporalTime(_isoDateTime_.[[Time]]).
+ 1. Let _result_ be ? ToTemporalTimeRecord(_item_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Set _result_ to ? RegulateTime(_result_.[[Hour]], _result_.[[Minute]], _result_.[[Second]], _result_.[[Millisecond]], _result_.[[Microsecond]], _result_.[[Nanosecond]], _overflow_).
+ 1. Else,
+ 1. If _item_ is not a String, throw a *TypeError* exception.
+ 1. Let _parseResult_ be ? ParseISODateTime(_item_, « |TemporalTimeString| »).
+ 1. Assert: _parseResult_.[[Time]] is not ~start-of-day~.
+ 1. Set _result_ to _parseResult_.[[Time]].
+ 1. NOTE: A successful parse using |TemporalTimeString| guarantees absence of ambiguity with respect to any ISO 8601 date-only, year-month, or month-day representation.
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Return ! CreateTemporalTime(_result_).
+
+
+
+
+
+ AddDurationToTime (
+ _operation_: either ~add~ or ~subtract~,
+ _temporalTime_: a Temporal.PlainTime,
+ _temporalDurationLike_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.PlainTime or a throw completion
+
+
+
description
+
It adds/subtracts _temporalDurationLike_ to/from _temporalTime_, returning a point in time that is in the future/past relative to _temporalTime_.
+
+
+ 1. Let _duration_ be ? ToTemporalDuration(_temporalDurationLike_).
+ 1. If _operation_ is ~subtract~, set _duration_ to CreateNegatedTemporalDuration(_duration_).
+ 1. Let _internalDuration_ be ToInternalDurationRecord(_duration_).
+ 1. Let _result_ be AddTime(_temporalTime_.[[Time]], _internalDuration_.[[Time]]).
+ 1. Return ! CreateTemporalTime(_result_).
+
+
+
+
+
+ DifferenceTemporalPlainTime (
+ _operation_: either ~since~ or ~until~,
+ _temporalTime_: a Temporal.PlainTime,
+ _other_: an ECMAScript language value,
+ _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.Duration or a throw completion
+
+
+
description
+
It computes the difference between the two times represented by _temporalTime_ and _other_, optionally rounds it, and returns it as a Temporal.Duration object.
+
+
+ 1. Set _other_ to ? ToTemporalTime(_other_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _settings_ be ? GetDifferenceSettings(_operation_, _resolvedOptions_, ~time~, « », ~nanosecond~, ~hour~).
+ 1. Let _timeDuration_ be DifferenceTime(_temporalTime_.[[Time]], _other_.[[Time]]).
+ 1. Set _timeDuration_ to ! RoundTimeDuration(_timeDuration_, _settings_.[[RoundingIncrement]], _settings_.[[SmallestUnit]], _settings_.[[RoundingMode]]).
+ 1. Let _duration_ be CombineDateAndTimeDuration(ZeroDateDuration(), _timeDuration_).
+ 1. Let _result_ be ! TemporalDurationFromInternal(_duration_, _settings_.[[LargestUnit]]).
+ 1. If _operation_ is ~since~, set _result_ to CreateNegatedTemporalDuration(_result_).
+ 1. Return _result_.
+
+
+
+
diff --git a/temporal/plainyearmonth.emu b/temporal/plainyearmonth.emu
new file mode 100644
index 0000000000..913b4ba279
--- /dev/null
+++ b/temporal/plainyearmonth.emu
@@ -0,0 +1,653 @@
+
+
+
+
+
Temporal.PlainYearMonth Objects
+
A Temporal.PlainYearMonth object is an Object that contains integers corresponding to a particular year and month in a particular calendar.
+
+
+
The Temporal.PlainYearMonth Constructor
+
The Temporal.PlainYearMonth constructor:
+
+
+ creates and initializes a new Temporal.PlainYearMonth object when called as a constructor.
+
+
+ is not intended to be called as a function and will throw an exception when called in that manner.
+
+
+ may be used as the value of an `extends` clause of a class definition.
+ Subclass constructors that intend to inherit the specified Temporal.PlainYearMonth behaviour must
+ include a super call to the %Temporal.PlainYearMonth% constructor to create and initialize subclass
+ instances with the necessary internal slots.
+
This function performs the following steps when called:
+
+ 1. If NewTarget is *undefined*, throw a *TypeError* exception.
+ 1. If _referenceISODay_ is *undefined*, then
+ 1. Set _referenceISODay_ to *1*𝔽.
+ 1. Let _y_ be ? ToIntegerWithTruncation(_isoYear_).
+ 1. Let _m_ be ? ToIntegerWithTruncation(_isoMonth_).
+ 1. If _calendar_ is *undefined*, set _calendar_ to *"iso8601"*.
+ 1. If _calendar_ is not a String, throw a *TypeError* exception.
+ 1. Set _calendar_ to ? CanonicalizeCalendar(_calendar_).
+ 1. Let _ref_ be ? ToIntegerWithTruncation(_referenceISODay_).
+ 1. If IsValidISODate(_y_, _m_, _ref_) is *false*, throw a *RangeError* exception.
+ 1. Let _isoDate_ be CreateISODateRecord(_y_, _m_, _ref_).
+ 1. Return ? CreateTemporalYearMonth(_isoDate_, _calendar_, NewTarget).
+
+
+
+
+
+
Properties of the Temporal.PlainYearMonth Constructor
+
The value of the [[Prototype]] internal slot of the Temporal.PlainYearMonth constructor is the intrinsic object %Function.prototype%.
+
The Temporal.PlainYearMonth constructor has the following properties:
+
+
+
Temporal.PlainYearMonth.prototype
+
The initial value of `Temporal.PlainYearMonth.prototype` is %Temporal.PlainYearMonth.prototype%.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *false* }.
This function performs the following steps when called:
+
+ 1. Set _one_ to ? ToTemporalYearMonth(_one_).
+ 1. Set _two_ to ? ToTemporalYearMonth(_two_).
+ 1. Return 𝔽(CompareISODate(_one_.[[ISODate]], _two_.[[ISODate]])).
+
+
+
+
+
+
Properties of the Temporal.PlainYearMonth Prototype Object
+
+
The Temporal.PlainYearMonth prototype object
+
+
is itself an ordinary object.
+
is not a Temporal.PlainYearMonth instance and does not have a [[InitializedTemporalYearMonth]] internal slot.
+
has a [[Prototype]] internal slot whose value is %Object.prototype%.
+
+
+
+ An ECMAScript implementation that includes the ECMA-402 Internationalization API extends this prototype with additional properties in order to represent calendar data.
+
+
+
+
Temporal.PlainYearMonth.prototype.constructor
+
The initial value of `Temporal.PlainYearMonth.prototype.constructor` is %Temporal.PlainYearMonth%.
The initial value of the %Symbol.toStringTag% property is the String *"Temporal.PlainYearMonth"*.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.
+
+
+
+
get Temporal.PlainYearMonth.prototype.calendarId
+
+ `Temporal.PlainYearMonth.prototype.calendarId` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainYearMonth_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainYearMonth_, [[InitializedTemporalYearMonth]]).
+ 1. Return _plainYearMonth_.[[Calendar]].
+
+
+
+
+
get Temporal.PlainYearMonth.prototype.era
+
+ `Temporal.PlainYearMonth.prototype.era` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainYearMonth_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainYearMonth_, [[InitializedTemporalYearMonth]]).
+ 1. Return CalendarISOToDate(_plainYearMonth_.[[Calendar]], _plainYearMonth_.[[ISODate]]).[[Era]].
+
+
+
+
+
get Temporal.PlainYearMonth.prototype.eraYear
+
+ `Temporal.PlainYearMonth.prototype.eraYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainYearMonth_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainYearMonth_, [[InitializedTemporalYearMonth]]).
+ 1. Let _result_ be CalendarISOToDate(_plainYearMonth_.[[Calendar]], _plainYearMonth_.[[ISODate]]).[[EraYear]].
+ 1. If _result_ is *undefined*, return *undefined*.
+ 1. Return 𝔽(_result_).
+
+
+
+
+
get Temporal.PlainYearMonth.prototype.year
+
+ `Temporal.PlainYearMonth.prototype.year` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainYearMonth_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainYearMonth_, [[InitializedTemporalYearMonth]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainYearMonth_.[[Calendar]], _plainYearMonth_.[[ISODate]]).[[Year]]).
+
+
+
+
+
get Temporal.PlainYearMonth.prototype.month
+
+ `Temporal.PlainYearMonth.prototype.month` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainYearMonth_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainYearMonth_, [[InitializedTemporalYearMonth]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainYearMonth_.[[Calendar]], _plainYearMonth_.[[ISODate]]).[[Month]]).
+
+
+
+
+
get Temporal.PlainYearMonth.prototype.monthCode
+
+ `Temporal.PlainYearMonth.prototype.monthCode` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainYearMonth_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainYearMonth_, [[InitializedTemporalYearMonth]]).
+ 1. Return CalendarISOToDate(_plainYearMonth_.[[Calendar]], _plainYearMonth_.[[ISODate]]).[[MonthCode]].
+
+
+
+
+
get Temporal.PlainYearMonth.prototype.daysInYear
+
+ `Temporal.PlainYearMonth.prototype.daysInYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainYearMonth_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainYearMonth_, [[InitializedTemporalYearMonth]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainYearMonth_.[[Calendar]], _plainYearMonth_.[[ISODate]]).[[DaysInYear]]).
+
+
+
+
+
get Temporal.PlainYearMonth.prototype.daysInMonth
+
+ `Temporal.PlainYearMonth.prototype.daysInMonth` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainYearMonth_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainYearMonth_, [[InitializedTemporalYearMonth]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainYearMonth_.[[Calendar]], _plainYearMonth_.[[ISODate]]).[[DaysInMonth]]).
+
+
+
+
+
get Temporal.PlainYearMonth.prototype.monthsInYear
+
+ `Temporal.PlainYearMonth.prototype.monthsInYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainYearMonth_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainYearMonth_, [[InitializedTemporalYearMonth]]).
+ 1. Return 𝔽(CalendarISOToDate(_plainYearMonth_.[[Calendar]], _plainYearMonth_.[[ISODate]]).[[MonthsInYear]]).
+
+
+
+
+
get Temporal.PlainYearMonth.prototype.inLeapYear
+
+ `Temporal.PlainYearMonth.prototype.inLeapYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _plainYearMonth_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainYearMonth_, [[InitializedTemporalYearMonth]]).
+ 1. Return CalendarISOToDate(_plainYearMonth_.[[Calendar]], _plainYearMonth_.[[ISODate]]).[[InLeapYear]].
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _plainYearMonth_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainYearMonth_, [[InitializedTemporalYearMonth]]).
+ 1. If ? IsPartialTemporalObject(_temporalYearMonthLike_) is *false*, throw a *TypeError* exception.
+ 1. Let _calendar_ be _plainYearMonth_.[[Calendar]].
+ 1. Let _fields_ be ISODateToFields(_calendar_, _plainYearMonth_.[[ISODate]], ~year-month~).
+ 1. Let _partialYearMonth_ be ? PrepareCalendarFields(_calendar_, _temporalYearMonthLike_, « ~year~, ~month~, ~month-code~ », « », ~partial~).
+ 1. Set _fields_ to CalendarMergeFields(_calendar_, _fields_, _partialYearMonth_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _isoDate_ be ? CalendarYearMonthFromFields(_calendar_, _fields_, _overflow_).
+ 1. Return ! CreateTemporalYearMonth(_isoDate_, _calendar_).
+
+
+
+
+
+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement this method as specified in the ECMA-402 specification.
+ If an ECMAScript implementation does not include the ECMA-402 API the following specification of this method is used.
+
+
The meanings of the optional parameters to this method are defined in the ECMA-402 specification; implementations that do not include ECMA-402 support must not use those parameter positions for anything else.
+
This method performs the following steps when called:
+
+ 1. Let _plainYearMonth_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainYearMonth_, [[InitializedTemporalYearMonth]]).
+ 1. Return TemporalYearMonthToString(_plainYearMonth_, ~auto~).
+
+
+
+
+
Temporal.PlainYearMonth.prototype.toJSON ( )
+
This method performs the following steps when called:
+
+ 1. Let _plainYearMonth_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainYearMonth_, [[InitializedTemporalYearMonth]]).
+ 1. Return TemporalYearMonthToString(_plainYearMonth_, ~auto~).
+
+
+
+
+
Temporal.PlainYearMonth.prototype.valueOf ( )
+
This method performs the following steps when called:
+
+ 1. Throw a *TypeError* exception.
+
+
+
+ This method always throws, because in the absence of `valueOf()`, expressions with arithmetic operators such as `plainYearMonth1 > plainYearMonth2` would fall back to being equivalent to `plainYearMonth1.toString() > plainYearMonth2.toString()`.
+ Lexicographical comparison of serialized strings might not seem obviously wrong, because the result would sometimes be correct.
+ Implementations are encouraged to phrase the error message to point users to `Temporal.PlainYearMonth.compare()`, `Temporal.PlainYearMonth.prototype.equals()`, and/or `Temporal.PlainYearMonth.prototype.toString()`.
+
This method performs the following steps when called:
+
+ 1. Let _plainYearMonth_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_plainYearMonth_, [[InitializedTemporalYearMonth]]).
+ 1. If _item_ is not an Object, throw a *TypeError* exception.
+ 1. Let _calendar_ be _plainYearMonth_.[[Calendar]].
+ 1. Let _fields_ be ISODateToFields(_calendar_, _plainYearMonth_.[[ISODate]], ~year-month~).
+ 1. Let _inputFields_ be ? PrepareCalendarFields(_calendar_, _item_, « ~day~ », « », « »).
+ 1. Let _mergedFields_ be CalendarMergeFields(_calendar_, _fields_, _inputFields_).
+ 1. Let _isoDate_ be ? CalendarDateFromFields(_calendar_, _mergedFields_, ~constrain~).
+ 1. Return ! CreateTemporalDate(_isoDate_, _calendar_).
+
+
+
+
+
+
Properties of Temporal.PlainYearMonth Instances
+
+ Temporal.PlainYearMonth instances are ordinary objects that inherit properties from the %Temporal.PlainYearMonth.prototype% intrinsic object.
+ Temporal.PlainYearMonth instances are initially created with the internal slots described in .
+
+
+
+
+
+ Internal Slot
+
+
+ Description
+
+
+
+
+ [[InitializedTemporalYearMonth]]
+
+
+ The only specified use of this slot is for distinguishing Temporal.PlainYearMonth instances from other objects.
+
+
+
+
+ [[ISODate]]
+
+
+ An ISO Date Record.
+ The [[Day]] field is used by the calendar in the [[Calendar]] slot to disambiguate if the [[Year]] and [[Month]] fields are not sufficient to uniquely identify a year and month in that calendar.
+
+
+
+
+ [[Calendar]]
+
+
+ A calendar type.
+
+
+
+
+
+
+
+
Abstract Operations for Temporal.PlainYearMonth Objects
+
+
+
+ CreateTemporalYearMonth (
+ _isoDate_: an ISO Date Record,
+ _calendar_: a calendar type,
+ optional _newTarget_: a constructor,
+ ): either a normal completion containing a Temporal.PlainYearMonth or a throw completion
+
+
+
description
+
It creates a Temporal.PlainYearMonth instance and fills the internal slots with valid values.
+
+
+ 1. If ISOYearMonthWithinLimits(_isoDate_) is *false*, throw a *RangeError* exception.
+ 1. If _newTarget_ is not present, set _newTarget_ to %Temporal.PlainYearMonth%.
+ 1. Let _object_ be ? OrdinaryCreateFromConstructor(_newTarget_, *"%Temporal.PlainYearMonth.prototype%"*, « [[InitializedTemporalYearMonth]], [[ISODate]], [[Calendar]] »).
+ 1. Set _object_.[[ISODate]] to _isoDate_.
+ 1. Set _object_.[[Calendar]] to _calendar_.
+ 1. Return _object_.
+
+
+
+
+
+ ToTemporalYearMonth (
+ _item_: an ECMAScript language value,
+ optional _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.PlainYearMonth, or a throw completion
+
+
+
description
+
Converts _item_ to a new Temporal.PlainYearMonth instance if possible, and throws otherwise.
+
+
+ 1. If _options_ is not present, set _options_ to *undefined*.
+ 1. If _item_ is an Object, then
+ 1. If _item_ has an [[InitializedTemporalYearMonth]] internal slot, then
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Return ! CreateTemporalYearMonth(_item_.[[ISODate]], _item_.[[Calendar]]).
+ 1. Let _calendar_ be ? GetTemporalCalendarIdentifierWithISODefault(_item_).
+ 1. Let _fields_ be ? PrepareCalendarFields(_calendar_, _item_, « ~year~, ~month~, ~month-code~ », «», «»).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _isoDate_ be ? CalendarYearMonthFromFields(_calendar_, _fields_, _overflow_).
+ 1. Return ! CreateTemporalYearMonth(_isoDate_, _calendar_).
+ 1. If _item_ is not a String, throw a *TypeError* exception.
+ 1. Let _result_ be ? ParseISODateTime(_item_, « |TemporalYearMonthString| »).
+ 1. Let _calendar_ be _result_.[[Calendar]].
+ 1. If _calendar_ is ~empty~, set _calendar_ to *"iso8601"*.
+ 1. Set _calendar_ to ? CanonicalizeCalendar(_calendar_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _isoDate_ be CreateISODateRecord(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]]).
+ 1. If ISOYearMonthWithinLimits(_isoDate_) is *false*, throw a *RangeError* exception.
+ 1. Set _result_ to ISODateToFields(_calendar_, _isoDate_, ~year-month~).
+ 1. NOTE: The following operation is called with ~constrain~ regardless of _overflow_, in order for the calendar to store a canonical value in the [[Day]] field of the [[ISODate]] internal slot of the result.
+ 1. Set _isoDate_ to ? CalendarYearMonthFromFields(_calendar_, _result_, ~constrain~).
+ 1. Return ! CreateTemporalYearMonth(_isoDate_, _calendar_).
+
+
+
+
+
+ TemporalYearMonthToString (
+ _yearMonth_: a Temporal.PlainYearMonth,
+ _showCalendar_: one of ~auto~, ~always~, ~never~, or ~critical~,
+ ): a String
+
+
+
description
+
It formats _yearMonth_ as an ISO 8601 / RFC 9557 string.
+
+
+ 1. Let _year_ be PadISOYear(_yearMonth_.[[ISODate]].[[Year]]).
+ 1. Let _month_ be ToZeroPaddedDecimalString(_yearMonth_.[[ISODate]].[[Month]], 2).
+ 1. Let _result_ be the string-concatenation of _year_, the code unit 0x002D (HYPHEN-MINUS), and _month_.
+ 1. If _showCalendar_ is one of ~always~ or ~critical~, or _yearMonth_.[[Calendar]] is not *"iso8601"*, then
+ 1. Let _day_ be ToZeroPaddedDecimalString(_yearMonth_.[[ISODate]].[[Day]], 2).
+ 1. Set _result_ to the string-concatenation of _result_, the code unit 0x002D (HYPHEN-MINUS), and _day_.
+ 1. Let _calendarString_ be FormatCalendarAnnotation(_yearMonth_.[[Calendar]], _showCalendar_).
+ 1. Set _result_ to the string-concatenation of _result_ and _calendarString_.
+ 1. Return _result_.
+
+
+
+
+
+ AddDurationToYearMonth (
+ _operation_: either ~add~ or ~subtract~,
+ _yearMonth_: a Temporal.PlainYearMonth,
+ _temporalDurationLike_: an ECMAScript language value,
+ _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.PlainYearMonth or a throw completion
+
+
+
description
+
It adds/subtracts _temporalDurationLike_ to/from _yearMonth_, returning a point in time that is in the future/past relative to _yearMonth_.
+
+
+ 1. Let _duration_ be ? ToTemporalDuration(_temporalDurationLike_).
+ 1. If _operation_ is ~subtract~, set _duration_ to CreateNegatedTemporalDuration(_duration_).
+ 1. Let _internalDuration_ be ToInternalDurationRecord(_duration_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _durationToAdd_ be _internalDuration_.[[Date]].
+ 1. If _durationToAdd_.[[Weeks]] ≠ 0, or _durationToAdd_.[[Days]] ≠ 0, or _internalDuration_.[[Time]] ≠ 0, throw a *RangeError* exception.
+ 1. Let _calendar_ be _yearMonth_.[[Calendar]].
+ 1. Let _fields_ be ISODateToFields(_calendar_, _yearMonth_.[[ISODate]], ~year-month~).
+ 1. Set _fields_.[[Day]] to 1.
+ 1. Let _date_ be ? CalendarDateFromFields(_calendar_, _fields_, ~constrain~).
+ 1. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _date_, _durationToAdd_, _overflow_).
+ 1. Let _addedDateFields_ be ISODateToFields(_calendar_, _addedDate_, ~year-month~).
+ 1. Let _isoDate_ be ? CalendarYearMonthFromFields(_calendar_, _addedDateFields_, _overflow_).
+ 1. Return ! CreateTemporalYearMonth(_isoDate_, _calendar_).
+
+
+
+
+
+ DifferenceTemporalPlainYearMonth (
+ _operation_: either ~since~ or ~until~,
+ _yearMonth_: a Temporal.PlainYearMonth,
+ _other_: an ECMAScript language value,
+ _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.Duration or a throw completion
+
+
+
description
+
It computes the difference between the two times represented by _yearMonth_ and _other_, optionally rounds it, and returns it as a Temporal.Duration object.
+
+
+ 1. Set _other_ to ? ToTemporalYearMonth(_other_).
+ 1. Let _calendar_ be _yearMonth_.[[Calendar]].
+ 1. If CalendarEquals(_calendar_, _other_.[[Calendar]]) is *false*, throw a *RangeError* exception.
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _settings_ be ? GetDifferenceSettings(_operation_, _resolvedOptions_, ~date~, « ~week~, ~day~ », ~month~, ~year~).
+ 1. If CompareISODate(_yearMonth_.[[ISODate]], _other_.[[ISODate]]) = 0, return ! CreateTemporalDuration(0, 0, 0, 0, 0, 0, 0, 0, 0, 0).
+ 1. Let _thisFields_ be ISODateToFields(_calendar_, _yearMonth_.[[ISODate]], ~year-month~).
+ 1. Set _thisFields_.[[Day]] to 1.
+ 1. Let _thisDate_ be ? CalendarDateFromFields(_calendar_, _thisFields_, ~constrain~).
+ 1. Let _otherFields_ be ISODateToFields(_calendar_, _other_.[[ISODate]], ~year-month~).
+ 1. Set _otherFields_.[[Day]] to 1.
+ 1. Let _otherDate_ be ? CalendarDateFromFields(_calendar_, _otherFields_, ~constrain~).
+ 1. Let _dateDifference_ be CalendarDateUntil(_calendar_, _thisDate_, _otherDate_, _settings_.[[LargestUnit]]).
+ 1. Let _yearsMonthsDifference_ be ! AdjustDateDurationRecord(_dateDifference_, 0, 0).
+ 1. Let _duration_ be CombineDateAndTimeDuration(_yearsMonthsDifference_, 0).
+ 1. If _settings_.[[SmallestUnit]] is not ~month~ or _settings_.[[RoundingIncrement]] ≠ 1, then
+ 1. Let _isoDateTime_ be CombineISODateAndTimeRecord(_thisDate_, MidnightTimeRecord()).
+ 1. Let _originEpochNs_ be GetUTCEpochNanoseconds(_isoDateTime_).
+ 1. Let _isoDateTimeOther_ be CombineISODateAndTimeRecord(_otherDate_, MidnightTimeRecord()).
+ 1. Let _destEpochNs_ be GetUTCEpochNanoseconds(_isoDateTimeOther_).
+ 1. Set _duration_ to ? RoundRelativeDuration(_duration_, _originEpochNs_, _destEpochNs_, _isoDateTime_, ~unset~, _calendar_, _settings_.[[LargestUnit]], _settings_.[[RoundingIncrement]], _settings_.[[SmallestUnit]], _settings_.[[RoundingMode]]).
+ 1. Let _result_ be ! TemporalDurationFromInternal(_duration_, ~day~).
+ 1. If _operation_ is ~since~, set _result_ to CreateNegatedTemporalDuration(_result_).
+ 1. Return _result_.
+
+
+
+
+
ISO Year-Month Records
+
An ISO Year-Month Record is a Record value used to represent a valid month in the ISO 8601 calendar, although the year may be outside of the allowed range for Temporal.
+
ISO Year-Month Records have the fields listed in .
+
+
+
+
Field Name
+
Value
+
Meaning
+
+
+
[[Year]]
+
an integer
+
+ The year in the ISO 8601 calendar.
+
+
+
+
[[Month]]
+
an integer between 1 and 12, inclusive
+
+ The number of the month in the ISO 8601 calendar.
+
+
+
+
+
+
+
+
+ BalanceISOYearMonth (
+ _year_: an integer,
+ _month_: an integer,
+ ): an ISO Year-Month Record
+
+
+
description
+
+
+
+ 1. Set _year_ to _year_ + floor((_month_ - 1) / 12).
+ 1. Set _month_ to ((_month_ - 1) modulo 12) + 1.
+ 1. Return ISO Year-Month Record {
+ [[Year]]: _year_,
+ [[Month]]: _month_
+ }.
+
+
+
+
+
+ ISOYearMonthWithinLimits (
+ _isoDate_: an ISO Date Record,
+ ): a Boolean
+
+
+
description
+
It returns *true* if its argument represents a month within the range that a Temporal.PlainYearMonth object can represent, and *false* otherwise.
+
+
+ 1. If _isoDate_.[[Year]] < -271821 or _isoDate_.[[Year]] > 275760, return *false*.
+ 1. If _isoDate_.[[Year]] = -271821 and _isoDate_.[[Month]] < 4, return *false*.
+ 1. If _isoDate_.[[Year]] = 275760 and _isoDate_.[[Month]] > 9, return *false*.
+ 1. Return *true*.
+
+
+
+ Temporal.PlainYearMonth objects can represent any month that contains a day that a Temporal.PlainDate can represent.
+ This ensures that a Temporal.PlainDate object can always be converted into a Temporal.PlainYearMonth object.
+
+ Time zones in ECMAScript are represented by time zone identifiers, which are Strings composed entirely of code units in the inclusive interval from 0x0021 to 0x007E, described by |TimeZoneIdentifier| in the grammar below.
+ Time zones supported by an ECMAScript implementation may be available named time zones, represented by the [[Identifier]] field of the Time Zone Identifier Records returned by AvailableNamedTimeZoneIdentifiers, or offset time zones, represented by Strings for which IsOffsetTimeZoneIdentifer returns *true*.
+
+
+ A primary time zone identifier is the preferred identifier for an available named time zone.
+ A non-primary time zone identifier is an identifier for an available named time zone that is not a primary time zone identifier.
+ An available named time zone identifier is either a primary time zone identifier or a non-primary time zone identifier.
+ Each available named time zone identifier is associated with exactly one available named time zone.
+ Each available named time zone is associated with exactly one primary time zone identifier and zero or more non-primary time zone identifiers.
+
+
An available time zone identifier is either an available named time zone identifier or an offset time zone identifier.
+
+ Time zone identifiers are compared using ASCII-case-insensitive comparisons, and are accepted as input in any variation of letter case.
+ Offset time zone identifiers are compared using the number of minutes represented (not as a String), and are accepted as input in any the formats specified by |UTCOffset[~SubMinutePrecision]|.
+ However, ECMAScript built-in objects will only output the normalized format of a time zone identifier.
+ The normalized format of an available named time zone identifier is the preferred letter case for that identifier.
+ The normalized format of an offset time zone identifier is specified by |NormalizedUTCOffset| in the grammar below, and produced by FormatOffsetTimeZoneIdentifier with _style_ either not present or set to ~separated~.
+
+
+ ECMAScript implementations must support an available named time zone with the identifier *"UTC"*, which must be the primary time zone identifier for the UTC time zone.
+ In addition, implementations may support any number of other available named time zones.
+
+
+ Implementations that follow the requirements for time zones as described in the ECMA-402 Internationalization API specification are called time zone aware.
+ Time zone aware implementations must support available named time zones corresponding to the Zone and Link names of the IANA Time Zone Database, and only such names.
+ In time zone aware implementations, a primary time zone identifier is a Zone name, and a non-primary time zone identifier is a Link name, respectively, in the IANA Time Zone Database except as specifically overridden by AvailableNamedTimeZoneIdentifiers as specified in the ECMA-402 specification.
+ Implementations that do not support the entire IANA Time Zone Database are still recommended to use IANA Time Zone Database names as identifiers to represent time zones.
+
+
These identifiers are described by the grammar in .
+
+
+
+ GetNamedTimeZoneEpochNanoseconds (
+ _timeZoneIdentifier_: an available named time zone identifier,
+ _isoDateTime_: an ISO Date-Time Record,
+ ): a List of BigInts
+
+
+
description
+
+ Each value in the returned List represents a number of nanoseconds since the epoch that corresponds to the given ISO 8601 calendar date and wall-clock time in the named time zone identified by _timeZoneIdentifier_.
+
+
+
+ When the input represents a local time occurring more than once because of a negative time zone transition (e.g. when daylight saving time ends or the time zone offset is decreased due to a time zone rule change), the returned List will have more than one element and will be sorted by ascending numerical value.
+ When the input represents a local time skipped because of a positive time zone transition (e.g. when daylight saving time begins or the time zone offset is increased due to a time zone rule change), the returned List will be empty.
+ Otherwise, the returned List will have one element.
+
+
The default implementation of GetNamedTimeZoneEpochNanoseconds, to be used for ECMAScript implementations that do not include local political rules for any time zones, performs the following steps when called:
+
+ 1. Assert: _timeZoneIdentifier_ is *"UTC"*.
+ 1. Let _epochNanoseconds_ be GetUTCEpochNanoseconds(_isoDateTime_).
+ 1. Return « _epochNanoseconds_ ».
+
+
+
It is required for time zone aware implementations (and recommended for all others) to use the time zone information of the IANA Time Zone Database https://www.iana.org/time-zones/.
+
1:30 AM on 5 November 2017 in America/New_York is repeated twice, so GetNamedTimeZoneEpochNanoseconds for that time zone and ISO date-time would return a List of length 2 in which the first element represents 05:30 UTC (corresponding with 01:30 US Eastern Daylight Time at UTC offset -04:00) and the second element represents 06:30 UTC (corresponding with 01:30 US Eastern Standard Time at UTC offset -05:00).
+
2:30 AM on 12 March 2017 in America/New_York does not exist, so GetNamedTimeZoneEpochNanoseconds for that time zone and ISO date-time would return an empty List.
+
+
+
+
+
+ GetNamedTimeZoneOffsetNanoseconds (
+ _timeZoneIdentifier_: an available named time zone identifier,
+ _epochNanoseconds_: an epoch nanoseconds value,
+ ): an integer
+
+
+
+
The returned integer represents the offset from UTC of the named time zone identified by _timeZoneIdentifier_, at the instant corresponding with _epochNanoseconds_ relative to the epoch, both in nanoseconds.
+
The default implementation of GetNamedTimeZoneOffsetNanoseconds, to be used for ECMAScript implementations that do not include local political rules for any time zones, performs the following steps when called:
Time zone offset values may be positive or negative.
+
+
+
+
+
+ GetNamedTimeZoneNextTransition (
+ _timeZoneIdentifier_: an available named time zone identifier,
+ _epochNanoseconds_: an epoch nanoseconds value,
+ ): either an epoch nanoseconds value or *null*
+
+
+
+
+ The returned value _t_ represents the number of nanoseconds since the epoch that corresponds to the first time zone UTC offset transition strictly after _epochNanoseconds_ in the IANA time zone identified by _timeZoneIdentifier_.
+ The operation returns *null* if no such transition exists for which _t_ ≤ maxEpochNanoseconds.
+
+
+ A transition is a point in time where the UTC offset of a time zone changes, for example when Daylight Saving Time starts or stops.
+ The returned value _t_ represents the first nanosecond where the new UTC offset is used in this time zone, not the last nanosecond where the previous UTC offset is used.
+ In other words, GetOffsetNanosecondsFor(_timeZone_, _t_) ≠ GetOffsetNanosecondsFor(_timeZone_, _t_ - 1).
+
+
Given the same values of _timeZoneIdentifier_ and _epochNanoseconds_, the result must be the same for the lifetime of the surrounding agent.
+
The minimum implementation of GetNamedTimeZoneNextTransition for ECMAScript implementations that do not include local political rules for any time zones performs the following steps when called:
+ GetNamedTimeZonePreviousTransition (
+ _timeZoneIdentifier_: an available named time zone identifier,
+ _epochNanoseconds_: an epoch nanoseconds value,
+ ): either an epoch nanoseconds value or *null*
+
+
+
+
+ The returned value _t_ represents the number of nanoseconds since the epoch that corresponds to the last time zone UTC offset transition strictly before _epochNanoseconds_ in the IANA time zone identified by _timeZoneIdentifier_.
+ The operation returns *null* if no such transition exists for which _t_ ≥ minEpochNanoseconds.
+
+
+ A transition is a point in time where the UTC offset of a time zone changes, for example when Daylight Saving Time starts or stops.
+ The returned value _t_ represents the first nanosecond where the new UTC offset is used in this time zone, not the last nanosecond where the previous UTC offset is used.
+ In other words, GetOffsetNanosecondsFor(_timeZone_, _t_) ≠ GetOffsetNanosecondsFor(_timeZone_, _t_ - 1).
+
+
Given the same values of _timeZoneIdentifier_ and _epochNanoseconds_, the result must be the same for the lifetime of the surrounding agent.
+
The minimum implementation of GetNamedTimeZonePreviousTransition for ECMAScript implementations that do not include local political rules for any time zones performs the following steps when called:
A Time Zone Identifier Record is a Record used to describe an available named time zone identifier and its corresponding primary time zone identifier.
+
Time Zone Identifier Records have the fields listed in .
+
+
+
+
+
Field Name
+
Value
+
Meaning
+
+
+
+
[[Identifier]]
+
a String
+
An available named time zone identifier that is supported by the implementation.
+
+
+
[[PrimaryIdentifier]]
+
a String
+
The primary time zone identifier that [[Identifier]] resolves to.
+
+
+
+
+
If [[Identifier]] is a primary time zone identifier, then [[Identifier]] is [[PrimaryIdentifier]].
+
+
+
+
+
AvailableNamedTimeZoneIdentifiers ( ): a List of Time Zone Identifier Records
+
+
description
+
+ Its result describes all available named time zone identifiers in this implementation, as well as the primary time zone identifier corresponding to each available named time zone identifier.
+ The List is ordered according to the [[Identifier]] field of each Time Zone Identifier Record.
+
+
+
+ Time zone aware implementations, including all implementations that implement the ECMA-402 Internationalization API, must implement the AvailableNamedTimeZoneIdentifiers abstract operation as specified in the ECMA-402 specification.
+ For implementations that are not time zone aware, AvailableNamedTimeZoneIdentifiers performs the following steps when called:
+
+
+ 1. If the implementation does not include local political rules for any time zones, then
+ 1. Return « the Time Zone Identifier Record { [[Identifier]]: *"UTC"*, [[PrimaryIdentifier]]: *"UTC"* } ».
+ 1. Let _identifiers_ be the List of unique available named time zone identifiers, sorted according to lexicographic code unit order.
+ 1. Let _result_ be a new empty List.
+ 1. For each element _identifier_ of _identifiers_, do
+ 1. Let _primary_ be _identifier_.
+ 1. If _identifier_ is a non-primary time zone identifier in this implementation and _identifier_ is not *"UTC"*, then
+ 1. Set _primary_ to the primary time zone identifier associated with _identifier_.
+ 1. NOTE: An implementation may need to resolve _identifier_ iteratively to obtain the primary time zone identifier.
+ 1. Let _record_ be the Time Zone Identifier Record { [[Identifier]]: _identifier_, [[PrimaryIdentifier]]: _primary_ }.
+ 1. Append _record_ to _result_.
+ 1. Assert: _result_ contains a Time Zone Identifier Record _r_ such that _r_.[[Identifier]] is *"UTC"* and _r_.[[PrimaryIdentifier]] is *"UTC"*.
+ 1. Return _result_.
+
+
+
+
+
SystemTimeZoneIdentifier ( ): an available time zone identifier
+
+
description
+
+ It returns a String representing the host environment's current time zone, which is either a primary time zone identifier or an offset time zone identifier.
+
+
+
+
+ 1. If the implementation only supports the UTC time zone, return *"UTC"*.
+ 1. Let _systemTimeZoneString_ be the String representing the host environment's current time zone as a time zone identifier in normalized format, either a primary time zone identifier or an offset time zone identifier.
+ 1. Return _systemTimeZoneString_.
+
+
+
+
+ To ensure the level of functionality that implementations commonly provide in the methods of the Date object, it is recommended that SystemTimeZoneIdentifier return an IANA time zone name corresponding to the host environment's time zone setting, if such a thing exists.
+ GetNamedTimeZoneEpochNanoseconds and GetNamedTimeZoneOffsetNanoseconds must reflect the local political rules for standard time and daylight saving time in that time zone, if such rules exist.
+
+
For example, if the host environment is a browser on a system where the user has chosen US Eastern Time as their time zone, SystemTimeZoneIdentifier returns *"America/New_York"*.
+
+
+
+
+
+ GetAvailableNamedTimeZoneIdentifier (
+ _timeZoneIdentifier_: a named time zone identifier,
+ ): either a Time Zone Identifier Record or ~empty~
+
+
+
description
+
+ If _timeZoneIdentifier_ is an available named time zone identifier, then it returns one of the records in the List returned by AvailableNamedTimeZoneIdentifiers.
+ Otherwise, ~empty~ will be returned.
+
+
+
+ 1. For each element _record_ of AvailableNamedTimeZoneIdentifiers(), do
+ 1. If _record_.[[Identifier]] is an ASCII-case-insensitive match for _timeZoneIdentifier_, return _record_.
+ 1. Return ~empty~.
+
+
+
+ For any _timeZoneIdentifier_, or any value that is an ASCII-case-insensitive match for it, the result of this operation must remain the same for the lifetime of the surrounding agent.
+ Specifically, if that result is a Time Zone Identifier Record, its fields must contain the same values.
+
+
Furthermore, time zone identifiers must not dynamically change from primary to non-primary or vice versa during the lifetime of the surrounding agent, meaning that if _timeZoneIdentifier_ is an ASCII-case-insensitive match for the [[PrimaryIdentifier]] field of the result of a previous call to GetAvailableNamedTimeZoneIdentifier, then GetAvailableNamedTimeZoneIdentifier(_timeZoneIdentifier_) must return a record where [[Identifier]] is [[PrimaryIdentifier]].
+
Due to the complexity of supporting these requirements, it is recommended that the result of AvailableNamedTimeZoneIdentifiers (and therefore GetAvailableNamedTimeZoneIdentifier) remains the same for the lifetime of the surrounding agent.
+
+
+
+
+
+ ToTemporalTimeZoneIdentifier (
+ _temporalTimeZoneLike_: an ECMAScript value,
+ ): either a normal completion containing an available time zone identifier or a throw completion
+
+
+
description
+
It attempts to derive a value from _temporalTimeZoneLike_ that is an available time zone identifier, and returns that value if found or throws an exception if not.
+
+
+ 1. If _temporalTimeZoneLike_ is an Object and _temporalTimeZoneLike_ has an [[InitializedTemporalZonedDateTime]] internal slot, return _temporalTimeZoneLike_.[[TimeZone]].
+ 1. If _temporalTimeZoneLike_ is not a String, throw a *TypeError* exception.
+ 1. Let _parseResult_ be ? ParseTemporalTimeZoneString(_temporalTimeZoneLike_).
+ 1. Let _offsetMinutes_ be _parseResult_.[[OffsetMinutes]].
+ 1. If _offsetMinutes_ is not ~empty~, return FormatOffsetTimeZoneIdentifier(_offsetMinutes_).
+ 1. Let _name_ be _parseResult_.[[Name]].
+ 1. Let _timeZoneIdentifierRecord_ be GetAvailableNamedTimeZoneIdentifier(_name_).
+ 1. If _timeZoneIdentifierRecord_ is ~empty~, throw a *RangeError* exception.
+ 1. Return _timeZoneIdentifierRecord_.[[Identifier]].
+
+
+
+
+
+ GetOffsetNanosecondsFor (
+ _timeZone_: an available time zone identifier,
+ _epochNs_: an epoch nanoseconds value,
+ ): an integer in the interval from -86400 × 109 (exclusive) to 86400 × 109 (exclusive)
+
+
+
description
+
+ It determines the UTC offset of an exact time _epochNs_, in nanoseconds.
+
+
+
+ 1. Let _parseResult_ be ! ParseTimeZoneIdentifier(_timeZone_).
+ 1. If _parseResult_.[[OffsetMinutes]] is not ~empty~, return _parseResult_.[[OffsetMinutes]] × (60 × 109).
+ 1. Return GetNamedTimeZoneOffsetNanoseconds(_parseResult_.[[Name]], _epochNs_).
+
+
+
+
+
+ GetISODateTimeFor (
+ _timeZone_: an available time zone identifier,
+ _epochNs_: an epoch nanoseconds value,
+ ): an ISO Date-Time Record
+
+
+
description
+
+ It returns the components of a wall-clock time in the given _timeZone_, corresponding to the given number of nanoseconds since the epoch.
+
+
+
+ 1. Assert: IsValidEpochNanoseconds(_epochNs_) is *true*.
+ 1. Let _offsetNanoseconds_ be GetOffsetNanosecondsFor(_timeZone_, _epochNs_).
+ 1. Let _remainderNs_ be _epochNs_ modulo 106.
+ 1. Let _epochMilliseconds_ be (_epochNs_ - _remainderNs_) / 106.
+ 1. Let _year_ be EpochTimeToEpochYear(_epochMilliseconds_).
+ 1. Let _month_ be EpochTimeToMonthInYear(_epochMilliseconds_) + 1.
+ 1. Let _day_ be EpochTimeToDate(_epochMilliseconds_).
+ 1. Let _hour_ be ℝ(HourFromTime(𝔽(_epochMilliseconds_))).
+ 1. Let _minute_ be ℝ(MinFromTime(𝔽(_epochMilliseconds_))).
+ 1. Let _second_ be ℝ(SecFromTime(𝔽(_epochMilliseconds_))).
+ 1. Let _millisecond_ be ℝ(msFromTime(𝔽(_epochMilliseconds_))).
+ 1. Let _microsecond_ be floor(_remainderNs_ / 1000).
+ 1. Assert: _microsecond_ < 1000.
+ 1. Let _nanosecond_ be _remainderNs_ modulo 1000.
+ 1. Return BalanceISODateTime(_year_, _month_, _day_, _hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_ + _offsetNanoseconds_).
+
+
+
+
+
+ GetEpochNanosecondsFor (
+ _timeZone_: an available time zone identifier,
+ _isoDateTime_: an ISO Date-Time Record,
+ _disambiguation_: one of ~compatible~, ~earlier~, ~later~, or ~reject~,
+ ): either a normal completion containing an epoch nanoseconds value or a throw completion
+
+ DisambiguatePossibleEpochNanoseconds (
+ _possibleEpochNs_: a List of BigInts,
+ _timeZone_: an available time zone identifier,
+ _isoDateTime_: an ISO Date-Time Record,
+ _disambiguation_: one of ~compatible~, ~earlier~, ~later~, or ~reject~,
+ ): either a normal completion containing an epoch nanoseconds value or a throw completion
+
+
+
description
+
It chooses from a List of possible exact times the one indicated by the _disambiguation_ parameter.
+
+
+ 1. Let _n_ be the number of elements in _possibleEpochNs_.
+ 1. If _n_ = 1, return the sole element of _possibleEpochNs_.
+ 1. If _n_ ≠ 0, then
+ 1. If _disambiguation_ is either ~earlier~ or ~compatible~, return _possibleEpochNs_[0].
+ 1. If _disambiguation_ is ~later~, return _possibleEpochNs_[_n_ - 1].
+ 1. Assert: _disambiguation_ is ~reject~.
+ 1. Throw a *RangeError* exception.
+ 1. Assert: _n_ = 0.
+ 1. If _disambiguation_ is ~reject~, throw a *RangeError* exception.
+ 1. Let _before_ be the latest possible ISO Date-Time Record for which CompareISODateTime(_before_, _isoDateTime_) = -1 and ! GetPossibleEpochNanoseconds(_timeZone_, _before_) is not empty.
+ 1. Let _after_ be the earliest possible ISO Date-Time Record for which CompareISODateTime(_after_, _isoDateTime_) = 1 and ! GetPossibleEpochNanoseconds(_timeZone_, _after_) is not empty.
+ 1. Let _beforePossible_ be ! GetPossibleEpochNanoseconds(_timeZone_, _before_).
+ 1. Assert: The number of elements in _beforePossible_ = 1.
+ 1. Let _afterPossible_ be ! GetPossibleEpochNanoseconds(_timeZone_, _after_).
+ 1. Assert: The number of elements in _afterPossible_ = 1.
+ 1. Let _offsetBefore_ be GetOffsetNanosecondsFor(_timeZone_, the sole element of _beforePossible_).
+ 1. Let _offsetAfter_ be GetOffsetNanosecondsFor(_timeZone_, the sole element of _afterPossible_).
+ 1. Let _nanoseconds_ be _offsetAfter_ - _offsetBefore_.
+ 1. Assert: abs(_nanoseconds_) ≤ nsPerDay.
+ 1. If _disambiguation_ is ~earlier~, then
+ 1. Let _timeDuration_ be TimeDurationFromComponents(0, 0, 0, 0, 0, -_nanoseconds_).
+ 1. Let _earlierTime_ be AddTime(_isoDateTime_.[[Time]], _timeDuration_).
+ 1. Let _earlierDate_ be AddDaysToISODate(_isoDateTime_.[[ISODate]], _earlierTime_.[[Days]]).
+ 1. Let _earlierDateTime_ be CombineISODateAndTimeRecord(_earlierDate_, _earlierTime_).
+ 1. Set _possibleEpochNs_ to ? GetPossibleEpochNanoseconds(_timeZone_, _earlierDateTime_).
+ 1. Assert: _possibleEpochNs_ is not empty.
+ 1. Return _possibleEpochNs_[0].
+ 1. Assert: _disambiguation_ is ~compatible~ or ~later~.
+ 1. Let _timeDuration_ be TimeDurationFromComponents(0, 0, 0, 0, 0, _nanoseconds_).
+ 1. Let _laterTime_ be AddTime(_isoDateTime_.[[Time]], _timeDuration_).
+ 1. Let _laterDate_ be AddDaysToISODate(_isoDateTime_.[[ISODate]], _laterTime_.[[Days]]).
+ 1. Let _laterDateTime_ be CombineISODateAndTimeRecord(_laterDate_, _laterTime_).
+ 1. Set _possibleEpochNs_ to ? GetPossibleEpochNanoseconds(_timeZone_, _laterDateTime_).
+ 1. Set _n_ to the number of elements in _possibleEpochNs_.
+ 1. Assert: _n_ ≠ 0.
+ 1. Return _possibleEpochNs_[_n_ - 1].
+
+
+
+
+
+ GetPossibleEpochNanoseconds (
+ _timeZone_: an available time zone identifier,
+ _isoDateTime_: an ISO Date-Time Record,
+ ): either a normal completion containing a List of epoch nanoseconds values or a throw completion
+
+
+
description
+
+ It determines the possible exact times that may correspond to _isoDateTime_.
+
+
+
+ 1. Let _parseResult_ be ! ParseTimeZoneIdentifier(_timeZone_).
+ 1. If _parseResult_.[[OffsetMinutes]] is not ~empty~, then
+ 1. Let _balanced_ be BalanceISODateTime(_isoDateTime_.[[ISODate]].[[Year]], _isoDateTime_.[[ISODate]].[[Month]], _isoDateTime_.[[ISODate]].[[Day]], _isoDateTime_.[[Time]].[[Hour]], _isoDateTime_.[[Time]].[[Minute]] - _parseResult_.[[OffsetMinutes]], _isoDateTime_.[[Time]].[[Second]], _isoDateTime_.[[Time]].[[Millisecond]], _isoDateTime_.[[Time]].[[Microsecond]], _isoDateTime_.[[Time]].[[Nanosecond]]).
+ 1. Perform ? CheckISODaysRange(_balanced_.[[ISODate]]).
+ 1. Let _epochNanoseconds_ be GetUTCEpochNanoseconds(_balanced_).
+ 1. Let _possibleEpochNanoseconds_ be « _epochNanoseconds_ ».
+ 1. Else,
+ 1. Let _possibleEpochNanoseconds_ be GetNamedTimeZoneEpochNanoseconds(_parseResult_.[[Name]], _isoDateTime_).
+ 1. For each value _epochNanoseconds_ in _possibleEpochNanoseconds_, do
+ 1. If IsValidEpochNanoseconds(_epochNanoseconds_) is *false*, throw a *RangeError* exception.
+ 1. Return _possibleEpochNanoseconds_.
+
+
+
+
+
+ GetStartOfDay (
+ _timeZone_: an available time zone identifier,
+ _isoDate_: an ISO Date Record,
+ ): either a normal completion containing an epoch nanoseconds value or a throw completion
+
+
+
description
+
It determines the exact time that corresponds to the first valid wall-clock time in the calendar date _isoDate_ in _timeZone_.
+
+
+ 1. Let _isoDateTime_ be CombineISODateAndTimeRecord(_isoDate_, MidnightTimeRecord()).
+ 1. Let _possibleEpochNs_ be ? GetPossibleEpochNanoseconds(_timeZone_, _isoDateTime_).
+ 1. If _possibleEpochNs_ is not empty, return _possibleEpochNs_[0].
+ 1. Assert: IsOffsetTimeZoneIdentifier(_timeZone_) is *false*.
+ 1. [declared="isoDateTimeAfter"] Let _possibleEpochNsAfter_ be GetNamedTimeZoneEpochNanoseconds(_timeZone_, _isoDateTimeAfter_), where _isoDateTimeAfter_ is the ISO Date-Time Record for which DifferenceISODateTime(_isoDateTime_, _isoDateTimeAfter_, *"iso8601"*, ~hour~).[[Time]] is the smallest possible value > 0 for which _possibleEpochNsAfter_ is not empty (i.e., _isoDateTimeAfter_ represents the first local time after the transition).
+ 1. Assert: The number of elements in _possibleEpochNsAfter_ = 1.
+ 1. Return the sole element of _possibleEpochNsAfter_.
+
+
+
+
+
+ TimeZoneEquals (
+ _one_: an available time zone identifier,
+ _two_: an available time zone identifier,
+ ): a Boolean
+
+
+
description
+
It returns *true* if its arguments represent time zones using the same identifier.
+
+
+ 1. If _one_ is _two_, return *true*.
+ 1. If IsOffsetTimeZoneIdentifier(_one_) is *false* and IsOffsetTimeZoneIdentifier(_two_) is *false*, then
+ 1. Let _recordOne_ be GetAvailableNamedTimeZoneIdentifier(_one_).
+ 1. Let _recordTwo_ be GetAvailableNamedTimeZoneIdentifier(_two_).
+ 1. Assert: _recordOne_ is not ~empty~.
+ 1. Assert: _recordTwo_ is not ~empty~.
+ 1. If _recordOne_.[[PrimaryIdentifier]] is _recordTwo_.[[PrimaryIdentifier]], return *true*.
+ 1. Assert: If _one_ and _two_ are both offset time zone identifiers, they do not represent the same number of offset minutes.
+ 1. Return *false*.
+
+
+
diff --git a/temporal/zoneddatetime.emu b/temporal/zoneddatetime.emu
new file mode 100644
index 0000000000..a1757d8a9b
--- /dev/null
+++ b/temporal/zoneddatetime.emu
@@ -0,0 +1,1260 @@
+
+
+
+
+
Temporal.ZonedDateTime Objects
+
A Temporal.ZonedDateTime object is an Object referencing a fixed point in time with nanoseconds precision, and containing String identifiers corresponding to a particular time zone and calendar system.
+
+
+
The Temporal.ZonedDateTime Constructor
+
The Temporal.ZonedDateTime constructor:
+
+
+ creates and initializes a new Temporal.ZonedDateTime object when called as a constructor.
+
+
+ is not intended to be called as a function and will throw an exception when called in that manner.
+
+
+ may be used as the value of an `extends` clause of a class definition.
+ Subclass constructors that intend to inherit the specified Temporal.ZonedDateTime behaviour must
+ include a super call to the %Temporal.ZonedDateTime% constructor to create and initialize subclass
+ instances with the necessary internal slots.
+
This function performs the following steps when called:
+
+ 1. If NewTarget is *undefined*, throw a *TypeError* exception.
+ 1. Set _epochNanoseconds_ to ? ToBigInt(_epochNanoseconds_).
+ 1. If IsValidEpochNanoseconds(_epochNanoseconds_) is *false*, throw a *RangeError* exception.
+ 1. If _timeZone_ is not a String, throw a *TypeError* exception.
+ 1. Let _timeZoneParse_ be ? ParseTimeZoneIdentifier(_timeZone_).
+ 1. If _timeZoneParse_.[[OffsetMinutes]] is ~empty~, then
+ 1. Let _identifierRecord_ be GetAvailableNamedTimeZoneIdentifier(_timeZoneParse_.[[Name]]).
+ 1. If _identifierRecord_ is ~empty~, throw a *RangeError* exception.
+ 1. Set _timeZone_ to _identifierRecord_.[[Identifier]].
+ 1. Else,
+ 1. Set _timeZone_ to FormatOffsetTimeZoneIdentifier(_timeZoneParse_.[[OffsetMinutes]]).
+ 1. If _calendar_ is *undefined*, set _calendar_ to *"iso8601"*.
+ 1. If _calendar_ is not a String, throw a *TypeError* exception.
+ 1. Set _calendar_ to ? CanonicalizeCalendar(_calendar_).
+ 1. Return ? CreateTemporalZonedDateTime(_epochNanoseconds_, _timeZone_, _calendar_, NewTarget).
+
+
+
+
+
+
Properties of the Temporal.ZonedDateTime Constructor
+
The value of the [[Prototype]] internal slot of the Temporal.ZonedDateTime constructor is the intrinsic object %Function.prototype%.
+
The Temporal.ZonedDateTime constructor has the following properties:
+
+
+
Temporal.ZonedDateTime.prototype
+
The initial value of `Temporal.ZonedDateTime.prototype` is %Temporal.ZonedDateTime.prototype%.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *false* }.
This function performs the following steps when called:
+
+ 1. Set _one_ to ? ToTemporalZonedDateTime(_one_).
+ 1. Set _two_ to ? ToTemporalZonedDateTime(_two_).
+ 1. Return 𝔽(CompareEpochNanoseconds(_one_.[[EpochNanoseconds]], _two_.[[EpochNanoseconds]])).
+
+
+
+
+
+
Properties of the Temporal.ZonedDateTime Prototype Object
+
+
The Temporal.ZonedDateTime prototype object
+
+
is itself an ordinary object.
+
is not a Temporal.ZonedDateTime instance and does not have a [[InitializedTemporalZonedDateTime]] internal slot.
+
has a [[Prototype]] internal slot whose value is %Object.prototype%.
+
+
+
+ An ECMAScript implementation that includes the ECMA-402 Internationalization API extends this prototype with additional properties in order to represent calendar data.
+
+
+
+
Temporal.ZonedDateTime.prototype.constructor
+
The initial value of `Temporal.ZonedDateTime.prototype.constructor` is %Temporal.ZonedDateTime%.
The initial value of the %Symbol.toStringTag% property is the String *"Temporal.ZonedDateTime"*.
+
This property has the attributes { [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }.
+
+
+
+
get Temporal.ZonedDateTime.prototype.calendarId
+
+ `Temporal.ZonedDateTime.prototype.calendarId` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Return _zonedDateTime_.[[Calendar]].
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.timeZoneId
+
+ `Temporal.ZonedDateTime.prototype.timeZoneId` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Return _zonedDateTime_.[[TimeZone]].
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.era
+
+ `Temporal.ZonedDateTime.prototype.era` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[Era]].
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.eraYear
+
+ `Temporal.ZonedDateTime.prototype.eraYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Let _result_ be CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[EraYear]].
+ 1. If _result_ is *undefined*, return *undefined*.
+ 1. Return 𝔽(_result_).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.year
+
+ `Temporal.ZonedDateTime.prototype.year` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[Year]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.month
+
+ `Temporal.ZonedDateTime.prototype.month` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[Month]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.monthCode
+
+ `Temporal.ZonedDateTime.prototype.monthCode` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[MonthCode]].
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.day
+
+ `Temporal.ZonedDateTime.prototype.day` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[Day]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.hour
+
+ `Temporal.ZonedDateTime.prototype.hour` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(_isoDateTime_.[[Time]].[[Hour]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.minute
+
+ `Temporal.ZonedDateTime.prototype.minute` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(_isoDateTime_.[[Time]].[[Minute]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.second
+
+ `Temporal.ZonedDateTime.prototype.second` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(_isoDateTime_.[[Time]].[[Second]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.millisecond
+
+ `Temporal.ZonedDateTime.prototype.millisecond` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(_isoDateTime_.[[Time]].[[Millisecond]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.microsecond
+
+ `Temporal.ZonedDateTime.prototype.microsecond` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(_isoDateTime_.[[Time]].[[Microsecond]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.nanosecond
+
+ `Temporal.ZonedDateTime.prototype.nanosecond` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(_isoDateTime_.[[Time]].[[Nanosecond]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.epochMilliseconds
+
+ `Temporal.ZonedDateTime.prototype.epochMilliseconds` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _epochMilliseconds_ be floor(_zonedDateTime_.[[EpochNanoseconds]] / 106).
+ 1. Return 𝔽(_epochMilliseconds_).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.epochNanoseconds
+
+ `Temporal.ZonedDateTime.prototype.epochNanoseconds` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Return ℤ(_zonedDateTime_.[[EpochNanoseconds]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.dayOfWeek
+
+ `Temporal.ZonedDateTime.prototype.dayOfWeek` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[DayOfWeek]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.dayOfYear
+
+ `Temporal.ZonedDateTime.prototype.dayOfYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[DayOfYear]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.weekOfYear
+
+ `Temporal.ZonedDateTime.prototype.weekOfYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Let _result_ be CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[WeekOfYear]].[[Week]].
+ 1. If _result_ is *undefined*, return *undefined*.
+ 1. Return 𝔽(_result_).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.yearOfWeek
+
+ `Temporal.ZonedDateTime.prototype.yearOfWeek` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Let _result_ be CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[WeekOfYear]].[[Year]].
+ 1. If _result_ is *undefined*, return *undefined*.
+ 1. Return 𝔽(_result_).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.hoursInDay
+
+ `Temporal.ZonedDateTime.prototype.hoursInDay` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _timeZone_ be _zonedDateTime_.[[TimeZone]].
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_timeZone_, _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Let _today_ be _isoDateTime_.[[ISODate]].
+ 1. Let _tomorrow_ be AddDaysToISODate(_today_, 1).
+ 1. Let _todayNs_ be ? GetStartOfDay(_timeZone_, _today_).
+ 1. Let _tomorrowNs_ be ? GetStartOfDay(_timeZone_, _tomorrow_).
+ 1. Let _diff_ be TimeDurationFromEpochNanosecondsDifference(_tomorrowNs_, _todayNs_).
+ 1. Return 𝔽(TotalTimeDuration(_diff_, ~hour~)).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.daysInWeek
+
+ `Temporal.ZonedDateTime.prototype.daysInWeek` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[DaysInWeek]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.daysInMonth
+
+ `Temporal.ZonedDateTime.prototype.daysInMonth` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[DaysInMonth]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.daysInYear
+
+ `Temporal.ZonedDateTime.prototype.daysInYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[DaysInYear]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.monthsInYear
+
+ `Temporal.ZonedDateTime.prototype.monthsInYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return 𝔽(CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[MonthsInYear]]).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.inLeapYear
+
+ `Temporal.ZonedDateTime.prototype.inLeapYear` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return CalendarISOToDate(_zonedDateTime_.[[Calendar]], _isoDateTime_.[[ISODate]]).[[InLeapYear]].
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.offsetNanoseconds
+
+ `Temporal.ZonedDateTime.prototype.offsetNanoseconds` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Return 𝔽(GetOffsetNanosecondsFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]])).
+
+
+
+
+
get Temporal.ZonedDateTime.prototype.offset
+
+ `Temporal.ZonedDateTime.prototype.offset` is an accessor property whose set accessor function is *undefined*.
+ Its get accessor function performs the following steps:
+
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _offsetNanoseconds_ be GetOffsetNanosecondsFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return FormatUTCOffsetNanoseconds(_offsetNanoseconds_).
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. If ? IsPartialTemporalObject(_temporalZonedDateTimeLike_) is *false*, throw a *TypeError* exception.
+ 1. Let _epochNs_ be _zonedDateTime_.[[EpochNanoseconds]].
+ 1. Let _timeZone_ be _zonedDateTime_.[[TimeZone]].
+ 1. Let _calendar_ be _zonedDateTime_.[[Calendar]].
+ 1. Let _offsetNanoseconds_ be GetOffsetNanosecondsFor(_timeZone_, _epochNs_).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_timeZone_, _epochNs_).
+ 1. Let _fields_ be ISODateToFields(_calendar_, _isoDateTime_.[[ISODate]], ~date~).
+ 1. Set _fields_.[[Hour]] to _isoDateTime_.[[Time]].[[Hour]].
+ 1. Set _fields_.[[Minute]] to _isoDateTime_.[[Time]].[[Minute]].
+ 1. Set _fields_.[[Second]] to _isoDateTime_.[[Time]].[[Second]].
+ 1. Set _fields_.[[Millisecond]] to _isoDateTime_.[[Time]].[[Millisecond]].
+ 1. Set _fields_.[[Microsecond]] to _isoDateTime_.[[Time]].[[Microsecond]].
+ 1. Set _fields_.[[Nanosecond]] to _isoDateTime_.[[Time]].[[Nanosecond]].
+ 1. Set _fields_.[[OffsetString]] to FormatUTCOffsetNanoseconds(_offsetNanoseconds_).
+ 1. Let _partialZonedDateTime_ be ? PrepareCalendarFields(_calendar_, _temporalZonedDateTimeLike_, « ~year~, ~month~, ~month-code~, ~day~ », « ~hour~, ~minute~, ~second~, ~millisecond~, ~microsecond~, ~nanosecond~, ~offset~ », ~partial~).
+ 1. Set _fields_ to CalendarMergeFields(_calendar_, _fields_, _partialZonedDateTime_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _disambiguation_ be ? GetTemporalDisambiguationOption(_resolvedOptions_).
+ 1. Let _offset_ be ? GetTemporalOffsetOption(_resolvedOptions_, ~prefer~).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _dateTimeResult_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _overflow_).
+ 1. Let _newOffsetNanoseconds_ be ! ParseDateTimeUTCOffset(_fields_.[[OffsetString]]).
+ 1. Let _epochNanoseconds_ be ? InterpretISODateTimeOffset(_dateTimeResult_.[[ISODate]], _dateTimeResult_.[[Time]], ~option~, _newOffsetNanoseconds_, _timeZone_, _disambiguation_, _offset_, ~match-exactly~).
+ 1. Return ! CreateTemporalZonedDateTime(_epochNanoseconds_, _timeZone_, _calendar_).
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _timeZone_ be _zonedDateTime_.[[TimeZone]].
+ 1. Let _calendar_ be _zonedDateTime_.[[Calendar]].
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_timeZone_, _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. If _plainTimeLike_ is *undefined*, then
+ 1. Let _epochNs_ be ? GetStartOfDay(_timeZone_, _isoDateTime_.[[ISODate]]).
+ 1. Else,
+ 1. Let _plainTime_ be ? ToTemporalTime(_plainTimeLike_).
+ 1. Let _resultISODateTime_ be CombineISODateAndTimeRecord(_isoDateTime_.[[ISODate]], _plainTime_.[[Time]]).
+ 1. Let _epochNs_ be ? GetEpochNanosecondsFor(_timeZone_, _resultISODateTime_, ~compatible~).
+ 1. Return ! CreateTemporalZonedDateTime(_epochNs_, _timeZone_, _calendar_).
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. If _roundTo_ is *undefined*, throw a *TypeError* exception.
+ 1. If _roundTo_ is a String, then
+ 1. Let _paramString_ be _roundTo_.
+ 1. Set _roundTo_ to OrdinaryObjectCreate(*null*).
+ 1. Perform ! CreateDataPropertyOrThrow(_roundTo_, *"smallestUnit"*, _paramString_).
+ 1. Else,
+ 1. Set _roundTo_ to ? GetOptionsObject(_roundTo_).
+ 1. NOTE: The following steps read options and perform independent validation in alphabetical order (GetRoundingIncrementOption reads *"roundingIncrement"* and GetRoundingModeOption reads *"roundingMode"*).
+ 1. Let _roundingIncrement_ be ? GetRoundingIncrementOption(_roundTo_).
+ 1. Let _roundingMode_ be ? GetRoundingModeOption(_roundTo_, ~half-expand~).
+ 1. Let _smallestUnit_ be ? GetTemporalUnitValuedOption(_roundTo_, *"smallestUnit"*, ~required~).
+ 1. Perform ? ValidateTemporalUnitValue(_smallestUnit_, ~time~, « ~day~ »).
+ 1. If _smallestUnit_ is ~day~, then
+ 1. Let _maximum_ be 1.
+ 1. Let _inclusive_ be *true*.
+ 1. Else,
+ 1. Let _maximum_ be MaximumTemporalDurationRoundingIncrement(_smallestUnit_).
+ 1. Assert: _maximum_ is not ~unset~.
+ 1. Let _inclusive_ be *false*.
+ 1. Perform ? ValidateTemporalRoundingIncrement(_roundingIncrement_, _maximum_, _inclusive_).
+ 1. If _smallestUnit_ is ~nanosecond~ and _roundingIncrement_ = 1, then
+ 1. Return ! CreateTemporalZonedDateTime(_zonedDateTime_.[[EpochNanoseconds]], _zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[Calendar]]).
+ 1. Let _thisNs_ be _zonedDateTime_.[[EpochNanoseconds]].
+ 1. Let _timeZone_ be _zonedDateTime_.[[TimeZone]].
+ 1. Let _calendar_ be _zonedDateTime_.[[Calendar]].
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_timeZone_, _thisNs_).
+ 1. If _smallestUnit_ is ~day~, then
+ 1. Let _dateStart_ be _isoDateTime_.[[ISODate]].
+ 1. Let _dateEnd_ be AddDaysToISODate(_dateStart_, 1).
+ 1. Let _startNs_ be ? GetStartOfDay(_timeZone_, _dateStart_).
+ 1. Assert: _thisNs_ ≥ _startNs_.
+ 1. Let _endNs_ be ? GetStartOfDay(_timeZone_, _dateEnd_).
+ 1. Assert: _thisNs_ < _endNs_.
+ 1. Let _dayLengthNs_ be _endNs_ - _startNs_.
+ 1. Let _dayProgressNs_ be TimeDurationFromEpochNanosecondsDifference(_thisNs_, _startNs_).
+ 1. Let _roundedDayNs_ be ! RoundTimeDurationToIncrement(_dayProgressNs_, _dayLengthNs_, _roundingMode_).
+ 1. Let _epochNanoseconds_ be AddTimeDurationToEpochNanoseconds(_roundedDayNs_, _startNs_).
+ 1. Else,
+ 1. Let _roundResult_ be RoundISODateTime(_isoDateTime_, _roundingIncrement_, _smallestUnit_, _roundingMode_).
+ 1. Let _offsetNanoseconds_ be GetOffsetNanosecondsFor(_timeZone_, _thisNs_).
+ 1. Let _epochNanoseconds_ be ? InterpretISODateTimeOffset(_roundResult_.[[ISODate]], _roundResult_.[[Time]], ~option~, _offsetNanoseconds_, _timeZone_, ~compatible~, ~prefer~, ~match-exactly~).
+ 1. Return ! CreateTemporalZonedDateTime(_epochNanoseconds_, _timeZone_, _calendar_).
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. NOTE: The following steps read options and perform independent validation in alphabetical order (GetTemporalShowCalendarNameOption reads *"calendarName"*, GetTemporalFractionalSecondDigitsOption reads *"fractionalSecondDigits"*, GetTemporalShowOffsetOption reads *"offset"*, and GetRoundingModeOption reads *"roundingMode"*).
+ 1. Let _showCalendar_ be ? GetTemporalShowCalendarNameOption(_resolvedOptions_).
+ 1. Let _digits_ be ? GetTemporalFractionalSecondDigitsOption(_resolvedOptions_).
+ 1. Let _showOffset_ be ? GetTemporalShowOffsetOption(_resolvedOptions_).
+ 1. Let _roundingMode_ be ? GetRoundingModeOption(_resolvedOptions_, ~trunc~).
+ 1. Let _smallestUnit_ be ? GetTemporalUnitValuedOption(_resolvedOptions_, *"smallestUnit"*, ~unset~).
+ 1. Let _showTimeZone_ be ? GetTemporalShowTimeZoneNameOption(_resolvedOptions_).
+ 1. Perform ? ValidateTemporalUnitValue(_smallestUnit_, ~time~).
+ 1. If _smallestUnit_ is ~hour~, throw a *RangeError* exception.
+ 1. Let _precision_ be ToSecondsStringPrecisionRecord(_smallestUnit_, _digits_).
+ 1. Return TemporalZonedDateTimeToString(_zonedDateTime_, _precision_.[[Precision]], _showCalendar_, _showTimeZone_, _showOffset_, _precision_.[[Increment]], _precision_.[[Unit]], _roundingMode_).
+
+
+
+
+
+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement this method as specified in the ECMA-402 specification.
+ If an ECMAScript implementation does not include the ECMA-402 API the following specification of this method is used.
+
+
The meanings of the optional parameters to this method are defined in the ECMA-402 specification; implementations that do not include ECMA-402 support must not use those parameter positions for anything else.
+
This method performs the following steps when called:
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Return TemporalZonedDateTimeToString(_zonedDateTime_, ~auto~, ~auto~, ~auto~, ~auto~).
+
+
+
+
+
Temporal.ZonedDateTime.prototype.toJSON ( )
+
This method performs the following steps when called:
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Return TemporalZonedDateTimeToString(_zonedDateTime_, ~auto~, ~auto~, ~auto~, ~auto~).
+
+
+
+
+
Temporal.ZonedDateTime.prototype.valueOf ( )
+
This method performs the following steps when called:
+
+ 1. Throw a *TypeError* exception.
+
+
+
+ This method always throws, because in the absence of `valueOf()`, expressions with arithmetic operators such as `zonedDateTime1 > zonedDateTime2` would fall back to being equivalent to `zonedDateTime1.toString() > zonedDateTime2.toString()`.
+ Lexicographical comparison of serialized strings might not seem obviously wrong, because the result would sometimes be correct.
+ Implementations are encouraged to phrase the error message to point users to `Temporal.ZonedDateTime.compare()`, `Temporal.ZonedDateTime.prototype.equals()`, and/or `Temporal.ZonedDateTime.prototype.toString()`.
+
+
+
+
+
+
Temporal.ZonedDateTime.prototype.startOfDay ( )
+
This method performs the following steps when called:
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _timeZone_ be _zonedDateTime_.[[TimeZone]].
+ 1. Let _calendar_ be _zonedDateTime_.[[Calendar]].
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_timeZone_, _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Let _epochNanoseconds_ be ? GetStartOfDay(_timeZone_, _isoDateTime_.[[ISODate]]).
+ 1. Return ! CreateTemporalZonedDateTime(_epochNanoseconds_, _timeZone_, _calendar_).
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _timeZone_ be _zonedDateTime_.[[TimeZone]].
+ 1. If _directionParam_ is *undefined*, throw a *TypeError* exception.
+ 1. If _directionParam_ is a String, then
+ 1. Let _paramString_ be _directionParam_.
+ 1. Set _directionParam_ to OrdinaryObjectCreate(*null*).
+ 1. Perform ! CreateDataPropertyOrThrow(_directionParam_, *"direction"*, _paramString_).
+ 1. Else,
+ 1. Set _directionParam_ to ? GetOptionsObject(_directionParam_).
+ 1. Let _direction_ be ? GetDirectionOption(_directionParam_).
+ 1. If IsOffsetTimeZoneIdentifier(_timeZone_) is *true*, return *null*.
+ 1. If _direction_ is ~next~, then
+ 1. Let _transition_ be GetNamedTimeZoneNextTransition(_timeZone_, _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Else,
+ 1. Assert: _direction_ is ~previous~.
+ 1. Let _transition_ be GetNamedTimeZonePreviousTransition(_timeZone_, _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. If _transition_ is *null*, return *null*.
+ 1. Return ! CreateTemporalZonedDateTime(_transition_, _timeZone_, _zonedDateTime_.[[Calendar]]).
+
+
+
+
+
Temporal.ZonedDateTime.prototype.toInstant ( )
+
This method performs the following steps when called:
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Return ! CreateTemporalInstant(_zonedDateTime_.[[EpochNanoseconds]]).
+
+
+
+
+
Temporal.ZonedDateTime.prototype.toPlainDate ( )
+
This method performs the following steps when called:
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return ! CreateTemporalDate(_isoDateTime_.[[ISODate]], _zonedDateTime_.[[Calendar]]).
+
+
+
+
+
Temporal.ZonedDateTime.prototype.toPlainTime ( )
+
This method performs the following steps when called:
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return ! CreateTemporalTime(_isoDateTime_.[[Time]]).
+
+
+
+
+
This method performs the following steps when called:
+
+ 1. Let _zonedDateTime_ be the *this* value.
+ 1. Perform ? RequireInternalSlot(_zonedDateTime_, [[InitializedTemporalZonedDateTime]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[EpochNanoseconds]]).
+ 1. Return ! CreateTemporalDateTime(_isoDateTime_, _zonedDateTime_.[[Calendar]]).
+
+
+
+
+
+
Properties of Temporal.ZonedDateTime Instances
+
+ Temporal.ZonedDateTime instances are ordinary objects that inherit properties from the %Temporal.ZonedDateTime.prototype% intrinsic object.
+ Temporal.ZonedDateTime instances are initially created with the internal slots described in .
+
+
+
+
+
+ Internal Slot
+
+
+ Description
+
+
+
+
+ [[InitializedTemporalZonedDateTime]]
+
+
+ The only specified use of this slot is for distinguishing Temporal.ZonedDateTime instances from other objects.
+
+
+
+
+ [[EpochNanoseconds]]
+
+
+ A BigInt representing the number of nanoseconds since the epoch, as described in
+
+
+
+
+ [[TimeZone]]
+
+
+ An available time zone identifier.
+
+
+
+
+ [[Calendar]]
+
+
+ A calendar type.
+
+
+
+
+
+
+
+
Abstract Operations for Temporal.ZonedDateTime Objects
+
+
+
+ CreateTemporalZonedDateTime (
+ _epochNanoseconds_: an epoch nanoseconds value,
+ _timeZone_: an available time zone identifier,
+ _calendar_: a calendar type,
+ optional _newTarget_: a constructor,
+ ): either a normal completion containing a Temporal.ZonedDateTime or a throw completion
+
+
+
description
+
It creates a Temporal.ZonedDateTime instance and fills the internal slots with valid values.
+
+
+ 1. Assert: IsValidEpochNanoseconds(_epochNanoseconds_) is *true*.
+ 1. If _newTarget_ is not present, set _newTarget_ to %Temporal.ZonedDateTime%.
+ 1. Let _object_ be ? OrdinaryCreateFromConstructor(_newTarget_, *"%Temporal.ZonedDateTime.prototype%"*, « [[InitializedTemporalZonedDateTime]], [[EpochNanoseconds]], [[TimeZone]], [[Calendar]] »).
+ 1. Set _object_.[[EpochNanoseconds]] to _epochNanoseconds_.
+ 1. Set _object_.[[TimeZone]] to _timeZone_.
+ 1. Set _object_.[[Calendar]] to _calendar_.
+ 1. Return _object_.
+
+
+
+
+
+ ToTemporalZonedDateTime (
+ _item_: an ECMAScript language value,
+ optional _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.ZonedDateTime, or a throw completion
+
+
+
description
+
+ Converts _item_ to a new Temporal.ZonedDateTime instance if possible, and throws otherwise.
+
+
+
+ 1. If _options_ is not present, set _options_ to *undefined*.
+ 1. Let _hasUTCDesignator_ be *false*.
+ 1. Let _matchBehaviour_ be ~match-exactly~.
+ 1. If _item_ is an Object, then
+ 1. If _item_ has an [[InitializedTemporalZonedDateTime]] internal slot, then
+ 1. NOTE: The following steps, and similar ones below, read options and perform independent validation in alphabetical order (GetTemporalDisambiguationOption reads *"disambiguation"*, GetTemporalOffsetOption reads *"offset"*, and GetTemporalOverflowOption reads *"overflow"*).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Perform ? GetTemporalDisambiguationOption(_resolvedOptions_).
+ 1. Perform ? GetTemporalOffsetOption(_resolvedOptions_, ~reject~).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Return ! CreateTemporalZonedDateTime(_item_.[[EpochNanoseconds]], _item_.[[TimeZone]], _item_.[[Calendar]]).
+ 1. Let _calendar_ be ? GetTemporalCalendarIdentifierWithISODefault(_item_).
+ 1. Let _fields_ be ? PrepareCalendarFields(_calendar_, _item_, « ~year~, ~month~, ~month-code~, ~day~ », « ~hour~, ~minute~, ~second~, ~millisecond~, ~microsecond~, ~nanosecond~, ~offset~, ~time-zone~ », « ~time-zone~ »).
+ 1. Let _timeZone_ be _fields_.[[TimeZone]].
+ 1. Let _offsetString_ be _fields_.[[OffsetString]].
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _disambiguation_ be ? GetTemporalDisambiguationOption(_resolvedOptions_).
+ 1. Let _offsetOption_ be ? GetTemporalOffsetOption(_resolvedOptions_, ~reject~).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _result_ be ? InterpretTemporalDateTimeFields(_calendar_, _fields_, _overflow_).
+ 1. Let _isoDate_ be _result_.[[ISODate]].
+ 1. Let _time_ be _result_.[[Time]].
+ 1. Else,
+ 1. If _item_ is not a String, throw a *TypeError* exception.
+ 1. Let _result_ be ? ParseISODateTime(_item_, « |TemporalDateTimeString[+Zoned]| »).
+ 1. Let _annotation_ be _result_.[[TimeZone]].[[TimeZoneAnnotation]].
+ 1. Assert: _annotation_ is not ~empty~.
+ 1. Let _timeZone_ be ? ToTemporalTimeZoneIdentifier(_annotation_).
+ 1. Let _offsetString_ be _result_.[[TimeZone]].[[OffsetString]].
+ 1. If _result_.[[TimeZone]].[[Z]] is *true*, then
+ 1. Set _hasUTCDesignator_ to *true*.
+ 1. Let _calendar_ be _result_.[[Calendar]].
+ 1. If _calendar_ is ~empty~, set _calendar_ to *"iso8601"*.
+ 1. Set _calendar_ to ? CanonicalizeCalendar(_calendar_).
+ 1. Set _matchBehaviour_ to ~match-minutes~.
+ 1. If _offsetString_ is not ~empty~, then
+ 1. Let _offsetParseResult_ be ParseText(StringToCodePoints(_offsetString_), |UTCOffset[+SubMinutePrecision]|).
+ 1. Assert: _offsetParseResult_ is a Parse Node.
+ 1. If _offsetParseResult_ contains more than one |MinuteSecond| Parse Node, set _matchBehaviour_ to ~match-exactly~.
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _disambiguation_ be ? GetTemporalDisambiguationOption(_resolvedOptions_).
+ 1. Let _offsetOption_ be ? GetTemporalOffsetOption(_resolvedOptions_, ~reject~).
+ 1. Perform ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _isoDate_ be CreateISODateRecord(_result_.[[Year]], _result_.[[Month]], _result_.[[Day]]).
+ 1. Let _time_ be _result_.[[Time]].
+ 1. If _hasUTCDesignator_ is *true*, then
+ 1. Let _offsetBehaviour_ be ~exact~.
+ 1. Else if _offsetString_ is ~empty~ or _offsetString_ is ~unset~, then
+ 1. Let _offsetBehaviour_ be ~wall~.
+ 1. Else,
+ 1. Let _offsetBehaviour_ be ~option~.
+ 1. Let _offsetNanoseconds_ be 0.
+ 1. If _offsetBehaviour_ is ~option~, then
+ 1. Set _offsetNanoseconds_ to ! ParseDateTimeUTCOffset(_offsetString_).
+ 1. Let _epochNanoseconds_ be ? InterpretISODateTimeOffset(_isoDate_, _time_, _offsetBehaviour_, _offsetNanoseconds_, _timeZone_, _disambiguation_, _offsetOption_, _matchBehaviour_).
+ 1. Return ! CreateTemporalZonedDateTime(_epochNanoseconds_, _timeZone_, _calendar_).
+
+
+
+
+
+ TemporalZonedDateTimeToString (
+ _zonedDateTime_: a Temporal.ZonedDateTime,
+ _precision_: either an integer between 0 and 9 inclusive, ~minute~, or ~auto~,
+ _showCalendar_: one of ~auto~, ~always~, ~never~, or ~critical~,
+ _showTimeZone_: one of ~auto~, ~never~, or ~critical~,
+ _showOffset_: either ~auto~ or ~never~,
+ optional _increment_: a positive integer,
+ optional _unit_: one of ~minute~, ~second~, ~millisecond~, ~microsecond~, or ~nanosecond~,
+ optional _roundingMode_: a rounding mode,
+ ): a String
+
+
+
description
+
+ It returns an ISO 8601 / RFC 9557 string representation of its argument, including a time zone name annotation and calendar annotation, which are extensions to the ISO 8601 format.
+
+
+
+ 1. If _increment_ is not present, set _increment_ to 1.
+ 1. If _unit_ is not present, set _unit_ to ~nanosecond~.
+ 1. If _roundingMode_ is not present, set _roundingMode_ to ~trunc~.
+ 1. Let _epochNs_ be _zonedDateTime_.[[EpochNanoseconds]].
+ 1. Set _epochNs_ to RoundEpochNanoseconds(_epochNs_, _increment_, _unit_, _roundingMode_).
+ 1. Let _timeZone_ be _zonedDateTime_.[[TimeZone]].
+ 1. Let _offsetNanoseconds_ be GetOffsetNanosecondsFor(_timeZone_, _epochNs_).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_timeZone_, _epochNs_).
+ 1. Let _dateTimeString_ be FormatISODateTime(_isoDateTime_, *"iso8601"*, _precision_, ~never~).
+ 1. If _showOffset_ is ~never~, then
+ 1. Let _offsetString_ be the empty String.
+ 1. Else,
+ 1. Let _offsetString_ be FormatDateTimeUTCOffsetRounded(_offsetNanoseconds_).
+ 1. If _showTimeZone_ is ~never~, then
+ 1. Let _timeZoneString_ be the empty String.
+ 1. Else,
+ 1. If _showTimeZone_ is ~critical~, let _flag_ be *"!"*; else let _flag_ be the empty String.
+ 1. Let _timeZoneString_ be the string-concatenation of the code unit 0x005B (LEFT SQUARE BRACKET), _flag_, _timeZone_, and the code unit 0x005D (RIGHT SQUARE BRACKET).
+ 1. Let _calendarString_ be FormatCalendarAnnotation(_zonedDateTime_.[[Calendar]], _showCalendar_).
+ 1. Return the string-concatenation of _dateTimeString_, _offsetString_, _timeZoneString_, and _calendarString_.
+
+
+
+
+
+ AddZonedDateTime (
+ _epochNanoseconds_: an epoch nanoseconds value,
+ _timeZone_: an available time zone identifier,
+ _calendar_: a calendar type,
+ _duration_: an Internal Duration Record,
+ _overflow_: either ~constrain~ or ~reject~,
+ ): either a normal completion containing an epoch nanoseconds value or a throw completion
+
+
+
description
+
+ It adds a duration in various units to a number of nanoseconds _epochNanoseconds_ since the epoch, subject to the rules of the time zone and calendar.
+ As specified in RFC 5545, the date portion of the duration is added in calendar days, and the time portion is added in exact time.
+
+
+
+ 1. If DateDurationSign(_duration_.[[Date]]) = 0, return ? AddEpochNanoseconds(_epochNanoseconds_, _duration_.[[Time]]).
+ 1. Let _isoDateTime_ be GetISODateTimeFor(_timeZone_, _epochNanoseconds_).
+ 1. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _isoDateTime_.[[ISODate]], _duration_.[[Date]], _overflow_).
+ 1. Let _intermediateDateTime_ be CombineISODateAndTimeRecord(_addedDate_, _isoDateTime_.[[Time]]).
+ 1. If ISODateTimeWithinLimits(_intermediateDateTime_) is *false*, throw a *RangeError* exception.
+ 1. Let _intermediateNs_ be ! GetEpochNanosecondsFor(_timeZone_, _intermediateDateTime_, ~compatible~).
+ 1. Return ? AddEpochNanoseconds(_intermediateNs_, _duration_.[[Time]]).
+
+
+
+
+
+ AddDurationToZonedDateTime (
+ _operation_: either ~add~ or ~subtract~,
+ _zonedDateTime_: a Temporal.ZonedDateTime,
+ _temporalDurationLike_: an ECMAScript language value,
+ _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.ZonedDateTime or a throw completion
+
+
+
description
+
It adds/subtracts _temporalDurationLike_ to/from _zonedDateTime_.
+
+
+ 1. Let _duration_ be ? ToTemporalDuration(_temporalDurationLike_).
+ 1. If _operation_ is ~subtract~, set _duration_ to CreateNegatedTemporalDuration(_duration_).
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _overflow_ be ? GetTemporalOverflowOption(_resolvedOptions_).
+ 1. Let _calendar_ be _zonedDateTime_.[[Calendar]].
+ 1. Let _timeZone_ be _zonedDateTime_.[[TimeZone]].
+ 1. Let _internalDuration_ be ToInternalDurationRecord(_duration_).
+ 1. Let _epochNanoseconds_ be ? AddZonedDateTime(_zonedDateTime_.[[EpochNanoseconds]], _timeZone_, _calendar_, _internalDuration_, _overflow_).
+ 1. Return ! CreateTemporalZonedDateTime(_epochNanoseconds_, _timeZone_, _calendar_).
+
+
+
+
+
+ DifferenceZonedDateTime (
+ _ns1_: an epoch nanoseconds value,
+ _ns2_: an epoch nanoseconds value,
+ _timeZone_: an available time zone identifier,
+ _calendar_: a calendar type,
+ _largestUnit_: a Temporal unit,
+ ): either a normal completion containing an Internal Duration Record, or a throw completion
+
+
+
description
+
+ It computes the difference between two exact times expressed in nanoseconds since the epoch, and balances the result so that there is no non-zero unit larger than _largestUnit_ in the result, taking calendar reckoning and time zone offset changes into account.
+
+
+
+ 1. If _ns1_ = _ns2_, return CombineDateAndTimeDuration(ZeroDateDuration(), 0).
+ 1. Let _startDateTime_ be GetISODateTimeFor(_timeZone_, _ns1_).
+ 1. Let _endDateTime_ be GetISODateTimeFor(_timeZone_, _ns2_).
+ 1. If CompareISODate(_startDateTime_.[[ISODate]], _endDateTime_.[[ISODate]]) = 0, then
+ 1. Let _timeDuration_ be TimeDurationFromEpochNanosecondsDifference(_ns2_, _ns1_).
+ 1. Return CombineDateAndTimeDuration(ZeroDateDuration(), _timeDuration_).
+ 1. If _ns2_ - _ns1_ < 0, let _sign_ be 1; else let _sign_ be -1.
+ 1. If _sign_ = -1, let _maxDayCorrection_ be 2; else let _maxDayCorrection_ be 1.
+ 1. Let _dayCorrection_ be 0.
+ 1. Let _timeDuration_ be DifferenceTime(_startDateTime_.[[Time]], _endDateTime_.[[Time]]).
+ 1. If TimeDurationSign(_timeDuration_) = _sign_, set _dayCorrection_ to _dayCorrection_ + 1.
+ 1. Let _success_ be *false*.
+ 1. Repeat, while _dayCorrection_ ≤ _maxDayCorrection_ and _success_ is *false*,
+ 1. Let _intermediateDate_ be AddDaysToISODate(_endDateTime_.[[ISODate]], _dayCorrection_ × _sign_).
+ 1. Let _intermediateDateTime_ be CombineISODateAndTimeRecord(_intermediateDate_, _startDateTime_.[[Time]]).
+ 1. Let _intermediateNs_ be ? GetEpochNanosecondsFor(_timeZone_, _intermediateDateTime_, ~compatible~).
+ 1. Set _timeDuration_ to TimeDurationFromEpochNanosecondsDifference(_ns2_, _intermediateNs_).
+ 1. Let _timeSign_ be TimeDurationSign(_timeDuration_).
+ 1. If _sign_ ≠ _timeSign_, then
+ 1. Set _success_ to *true*.
+ 1. Set _dayCorrection_ to _dayCorrection_ + 1.
+ 1. Assert: _success_ is *true*.
+ 1. Let _dateLargestUnit_ be LargerOfTwoTemporalUnits(_largestUnit_, ~day~).
+ 1. Let _dateDifference_ be CalendarDateUntil(_calendar_, _startDateTime_.[[ISODate]], _intermediateDateTime_.[[ISODate]], _dateLargestUnit_).
+ 1. Return CombineDateAndTimeDuration(_dateDifference_, _timeDuration_).
+
+
+
+
+
+ DifferenceZonedDateTimeWithRounding (
+ _ns1_: an epoch nanoseconds value,
+ _ns2_: an epoch nanoseconds value,
+ _timeZone_: an available time zone identifier,
+ _calendar_: a calendar type,
+ _largestUnit_: a Temporal unit,
+ _roundingIncrement_: a positive integer,
+ _smallestUnit_: a Temporal unit,
+ _roundingMode_: a rounding mode,
+ ): either a normal completion containing an Internal Duration Record, or a throw completion
+
+
+
description
+
+
+
+ 1. If TemporalUnitCategory(_largestUnit_) is ~time~, return DifferenceEpochNanoseconds(_ns1_, _ns2_, _roundingIncrement_, _smallestUnit_, _roundingMode_).
+ 1. Let _difference_ be ? DifferenceZonedDateTime(_ns1_, _ns2_, _timeZone_, _calendar_, _largestUnit_).
+ 1. If _smallestUnit_ is ~nanosecond~ and _roundingIncrement_ = 1, return _difference_.
+ 1. Let _dateTime_ be GetISODateTimeFor(_timeZone_, _ns1_).
+ 1. Return ? RoundRelativeDuration(_difference_, _ns1_, _ns2_, _dateTime_, _timeZone_, _calendar_, _largestUnit_, _roundingIncrement_, _smallestUnit_, _roundingMode_).
+
+
+
+
+
+ DifferenceZonedDateTimeWithTotal (
+ _ns1_: an epoch nanoseconds value,
+ _ns2_: an epoch nanoseconds value,
+ _timeZone_: an available time zone identifier,
+ _calendar_: a calendar type,
+ _unit_: a Temporal unit,
+ ): either a normal completion containing a mathematical value, or a throw completion
+
+
+
description
+
+
+
+ 1. If TemporalUnitCategory(_unit_) is ~time~, then
+ 1. Let _difference_ be TimeDurationFromEpochNanosecondsDifference(_ns2_, _ns1_).
+ 1. Return TotalTimeDuration(_difference_, _unit_).
+ 1. Let _difference_ be ? DifferenceZonedDateTime(_ns1_, _ns2_, _timeZone_, _calendar_, _unit_).
+ 1. Let _dateTime_ be GetISODateTimeFor(_timeZone_, _ns1_).
+ 1. Return ? TotalRelativeDuration(_difference_, _ns1_, _ns2_, _dateTime_, _timeZone_, _calendar_, _unit_).
+
+
+
+
+
+ DifferenceTemporalZonedDateTime (
+ _operation_: either ~until~ or ~since~,
+ _zonedDateTime_: a Temporal.ZonedDateTime,
+ _other_: an ECMAScript language value,
+ _options_: an ECMAScript language value,
+ ): either a normal completion containing a Temporal.Duration or a throw completion
+
+
+
description
+
It computes the difference between the two times represented by _zonedDateTime_ and _other_, optionally rounds it, and returns it as a Temporal.Duration object.
+
+
+ 1. Set _other_ to ? ToTemporalZonedDateTime(_other_).
+ 1. If CalendarEquals(_zonedDateTime_.[[Calendar]], _other_.[[Calendar]]) is *false*, throw a *RangeError* exception.
+ 1. Let _resolvedOptions_ be ? GetOptionsObject(_options_).
+ 1. Let _settings_ be ? GetDifferenceSettings(_operation_, _resolvedOptions_, ~datetime~, « », ~nanosecond~, ~hour~).
+ 1. If TemporalUnitCategory(_settings_.[[LargestUnit]]) is ~time~, then
+ 1. Let _internalDuration_ be DifferenceEpochNanoseconds(_zonedDateTime_.[[EpochNanoseconds]], _other_.[[EpochNanoseconds]], _settings_.[[RoundingIncrement]], _settings_.[[SmallestUnit]], _settings_.[[RoundingMode]]).
+ 1. Let _result_ be ! TemporalDurationFromInternal(_internalDuration_, _settings_.[[LargestUnit]]).
+ 1. If _operation_ is ~since~, set _result_ to CreateNegatedTemporalDuration(_result_).
+ 1. Return _result_.
+ 1. NOTE: To calculate differences in two different time zones, _settings_.[[LargestUnit]] must be a time unit, because day lengths can vary between time zones due to DST and other UTC offset shifts.
+ 1. If TimeZoneEquals(_zonedDateTime_.[[TimeZone]], _other_.[[TimeZone]]) is *false*, throw a *RangeError* exception.
+ 1. If _zonedDateTime_.[[EpochNanoseconds]] = _other_.[[EpochNanoseconds]], return ! CreateTemporalDuration(0, 0, 0, 0, 0, 0, 0, 0, 0, 0).
+ 1. Let _internalDuration_ be ? DifferenceZonedDateTimeWithRounding(_zonedDateTime_.[[EpochNanoseconds]], _other_.[[EpochNanoseconds]], _zonedDateTime_.[[TimeZone]], _zonedDateTime_.[[Calendar]], _settings_.[[LargestUnit]], _settings_.[[RoundingIncrement]], _settings_.[[SmallestUnit]], _settings_.[[RoundingMode]]).
+ 1. Let _result_ be ! TemporalDurationFromInternal(_internalDuration_, ~hour~).
+ 1. If _operation_ is ~since~, set _result_ to CreateNegatedTemporalDuration(_result_).
+ 1. Return _result_.
+
+
+
+
+
+ InterpretISODateTimeOffset (
+ _isoDate_: an ISO Date Record,
+ _time_: either a Time Record or ~start-of-day~,
+ _offsetBehaviour_: one of ~option~, ~exact~, or ~wall~,
+ _offsetNanoseconds_: an integer in the interval from -86400 × 109 (exclusive) to 86400 × 109 (exclusive),
+ _timeZone_: an available time zone identifier,
+ _disambiguation_: one of ~earlier~, ~later~, ~compatible~, or ~reject~,
+ _offsetOption_: one of ~ignore~, ~use~, ~prefer~, or ~reject~,
+ _matchBehaviour_: either ~match-exactly~ or ~match-minutes~,
+ ): either a normal completion containing an epoch nanoseconds value or a throw completion
+
+
+
description
+
+
+ It determines the exact time in _timeZone_ corresponding to the given calendar date and time, and the given UTC offset in nanoseconds.
+ In the case of more than one possible exact time, or no possible exact time, an answer is determined using _offsetBehaviour_, _disambiguation_ and _offsetOption_.
+
+
+ As a special case when parsing ISO 8601 / RFC 9557 strings which are only required to specify time zone offsets to minutes precision, if _matchBehaviour_ is ~match minutes~, then a value for _offsetNanoseconds_ that is rounded to the nearest minute will be accepted in those cases where _offsetNanoseconds_ is compared against _timeZone_'s offset.
+ If _matchBehaviour_ is ~match exactly~, then this does not happen.
+
+
+
+
+ 1. If _time_ is ~start-of-day~, then
+ 1. Assert: _offsetBehaviour_ is ~wall~.
+ 1. Assert: _offsetNanoseconds_ = 0.
+ 1. Return ? GetStartOfDay(_timeZone_, _isoDate_).
+ 1. Let _isoDateTime_ be CombineISODateAndTimeRecord(_isoDate_, _time_).
+ 1. If _offsetBehaviour_ is ~wall~, or _offsetBehaviour_ is ~option~ and _offsetOption_ is ~ignore~, then
+ 1. Return ? GetEpochNanosecondsFor(_timeZone_, _isoDateTime_, _disambiguation_).
+ 1. If _offsetBehaviour_ is ~exact~, or _offsetBehaviour_ is ~option~ and _offsetOption_ is ~use~, then
+ 1. Let _balanced_ be BalanceISODateTime(_isoDate_.[[Year]], _isoDate_.[[Month]], _isoDate_.[[Day]], _time_.[[Hour]], _time_.[[Minute]], _time_.[[Second]], _time_.[[Millisecond]], _time_.[[Microsecond]], _time_.[[Nanosecond]] - _offsetNanoseconds_).
+ 1. Perform ? CheckISODaysRange(_balanced_.[[ISODate]]).
+ 1. Let _epochNanoseconds_ be GetUTCEpochNanoseconds(_balanced_).
+ 1. If IsValidEpochNanoseconds(_epochNanoseconds_) is *false*, throw a *RangeError* exception.
+ 1. Return _epochNanoseconds_.
+ 1. Assert: _offsetBehaviour_ is ~option~.
+ 1. Assert: _offsetOption_ is ~prefer~ or ~reject~.
+ 1. Perform ? CheckISODaysRange(_isoDate_).
+ 1. Let _utcEpochNanoseconds_ be GetUTCEpochNanoseconds(_isoDateTime_).
+ 1. Let _possibleEpochNs_ be ? GetPossibleEpochNanoseconds(_timeZone_, _isoDateTime_).
+ 1. For each element _candidate_ of _possibleEpochNs_, do
+ 1. Let _candidateOffset_ be _utcEpochNanoseconds_ - _candidate_.
+ 1. If _candidateOffset_ = _offsetNanoseconds_, return _candidate_.
+ 1. If _matchBehaviour_ is ~match-minutes~, then
+ 1. Let _roundedCandidateNanoseconds_ be RoundNumberToIncrement(_candidateOffset_, 60 × 109, ~half-expand~).
+ 1. If _roundedCandidateNanoseconds_ = _offsetNanoseconds_, return _candidate_.
+ 1. If _offsetOption_ is ~reject~, throw a *RangeError* exception.
+ 1. Return ? DisambiguatePossibleEpochNanoseconds(_possibleEpochNs_, _timeZone_, _isoDateTime_, _disambiguation_).
+
+
+
+