Stage 3 Draft / September 5, 2024

Temporal proposal

Introduction

The venerable ECMAScript Date object has a number of challenges, including lack of immutability, lack of support for time zones, lack of support for use cases that require dates only or times only, a confusing and non-ergonomic API, and many other challenges.

The Temporal set of types addresses these challenges with a built-in date and time API for ECMAScript that includes:

Figure 1: Temporal Object Relationships
Figure 2: Temporal String Persistence

This specification consists of three parts:

1 The Temporal Object

The Temporal object:

  • is the intrinsic object %Temporal%.
  • is the initial value of the "Temporal" property of the global 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.

1.1 Value Properties of the Temporal Object

1.1.1 Temporal [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Temporal".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

1.2 Constructor Properties of the Temporal Object

1.2.1 Temporal.Instant ( . . . )

See 8.

1.2.2 Temporal.PlainDateTime ( . . . )

See 5.

1.2.3 Temporal.PlainDate ( . . . )

See 3.

1.2.4 Temporal.PlainTime ( . . . )

See 4.

1.2.5 Temporal.PlainYearMonth ( . . . )

See 9.

1.2.6 Temporal.PlainMonthDay ( . . . )

See 10.

1.2.7 Temporal.Duration ( . . . )

See 7.

1.2.8 Temporal.ZonedDateTime ( . . . )

See 6.

1.3 Other Properties of the Temporal Object

1.3.1 Temporal.Now

See 2.

2 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.

2.1 Value Properties of the Temporal.Now Object

2.1.1 Temporal.Now [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Temporal.Now".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

2.2 Function Properties of the Temporal.Now Object

2.2.1 Temporal.Now.timeZoneId ( )

This function performs the following steps when called:

  1. Return SystemTimeZoneIdentifier().

2.2.2 Temporal.Now.instant ( )

This function performs the following steps when called:

  1. Return SystemInstant().

2.2.3 Temporal.Now.plainDateTimeISO ( [ temporalTimeZoneLike ] )

This function performs the following steps when called:

  1. Return ? SystemDateTime(temporalTimeZoneLike).

2.2.4 Temporal.Now.zonedDateTimeISO ( [ temporalTimeZoneLike ] )

This function performs the following steps when called:

  1. Return ? SystemZonedDateTime(temporalTimeZoneLike).

2.2.5 Temporal.Now.plainDateISO ( [ temporalTimeZoneLike ] )

This function performs the following steps when called:

  1. Let dateTime be ? SystemDateTime(temporalTimeZoneLike).
  2. Return ! CreateTemporalDate(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], "iso8601").

2.2.6 Temporal.Now.plainTimeISO ( [ temporalTimeZoneLike ] )

This function performs the following steps when called:

  1. Let dateTime be ? SystemDateTime(temporalTimeZoneLike).
  2. Return ! CreateTemporalTime(dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]]).

2.3 Abstract Operations

2.3.1 HostSystemUTCEpochNanoseconds ( global )

The host-defined abstract operation HostSystemUTCEpochNanoseconds takes argument global (a global object) and returns an integer. 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:

Note

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 ns be the approximate current UTC date and time, in nanoseconds since the epoch.
  2. Return the result of clamping ns between nsMinInstant and nsMaxInstant.

ECMAScript hosts that are not web browsers must use the default implementation of HostSystemUTCEpochNanoseconds.

2.3.2 SystemUTCEpochMilliseconds ( )

The abstract operation SystemUTCEpochMilliseconds takes no arguments and returns a Number. It performs the following steps when called:

  1. Let global be GetGlobalObject().
  2. Let nowNs be HostSystemUTCEpochNanoseconds(global).
  3. Return 𝔽(floor(nowNs / 106)).

2.3.3 SystemUTCEpochNanoseconds ( )

The abstract operation SystemUTCEpochNanoseconds takes no arguments and returns a BigInt. It performs the following steps when called:

  1. Let global be GetGlobalObject().
  2. Let nowNs be HostSystemUTCEpochNanoseconds(global).
  3. Return (nowNs).

2.3.4 SystemInstant ( )

The abstract operation SystemInstant takes no arguments and returns a Temporal.Instant. It performs the following steps when called:

  1. Let ns be SystemUTCEpochNanoseconds().
  2. Return ! CreateTemporalInstant(ns).

2.3.5 SystemDateTime ( temporalTimeZoneLike )

The abstract operation SystemDateTime takes argument temporalTimeZoneLike (an ECMAScript language value) and returns either a normal completion containing a Temporal.PlainDateTime or a throw completion. It performs the following steps when called:

  1. If temporalTimeZoneLike is undefined, then
    1. Let timeZone be SystemTimeZoneIdentifier().
  2. Else,
    1. Let timeZone be ? ToTemporalTimeZoneIdentifier(temporalTimeZoneLike).
  3. Let epochNs be SystemUTCEpochNanoseconds().
  4. Let isoDateTime be GetISODateTimeFor(timeZone, epochNs).
  5. Return ! CreateTemporalDateTime(isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]], isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]], "iso8601").

2.3.6 SystemZonedDateTime ( temporalTimeZoneLike )

The abstract operation SystemZonedDateTime takes argument temporalTimeZoneLike (an ECMAScript language value) and returns either a normal completion containing a Temporal.ZonedDateTime or a throw completion. It performs the following steps when called:

  1. If temporalTimeZoneLike is undefined, then
    1. Let timeZone be SystemTimeZoneIdentifier().
  2. Else,
    1. Let timeZone be ? ToTemporalTimeZoneIdentifier(temporalTimeZoneLike).
  3. Let ns be SystemUTCEpochNanoseconds().
  4. Return ! CreateTemporalZonedDateTime(ns, timeZone, "iso8601").

3 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 an Object value used to interpret those integers in a particular calendar.

3.1 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.

3.1.1 Temporal.PlainDate ( isoYear, isoMonth, isoDay [ , calendar ] )

This function performs the following steps when called:

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let y be ? ToIntegerWithTruncation(isoYear).
  3. Let m be ? ToIntegerWithTruncation(isoMonth).
  4. Let d be ? ToIntegerWithTruncation(isoDay).
  5. If calendar is undefined, set calendar to "iso8601".
  6. If calendar is not a String, throw a TypeError exception.
  7. If IsBuiltinCalendar(calendar) is false, throw a RangeError exception.
  8. Set calendar to CanonicalizeUValue("ca", calendar).
  9. Return ? CreateTemporalDate(y, m, d, calendar, NewTarget).

3.2 Properties of the Temporal.PlainDate Constructor

The Temporal.PlainDate constructor:

  • has a [[Prototype]] internal slot whose value is %Function.prototype%.
  • has the following properties:

3.2.1 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 }.

3.2.2 Temporal.PlainDate.from ( item [ , options ] )

This function performs the following steps when called:

  1. If item is an Object and item has an [[InitializedTemporalDate]] internal slot, then
    1. Set options to ? GetOptionsObject(options).
    2. Perform ? GetTemporalOverflowOption(options).
    3. Return ! CreateTemporalDate(item.[[ISOYear]], item.[[ISOMonth]], item.[[ISODay]], item.[[Calendar]]).
  2. Return ? ToTemporalDate(item, options).

3.2.3 Temporal.PlainDate.compare ( one, two )

This function performs the following steps when called:

  1. Set one to ? ToTemporalDate(one).
  2. Set two to ? ToTemporalDate(two).
  3. Return 𝔽(CompareISODate(one.[[ISOYear]], one.[[ISOMonth]], one.[[ISODay]], two.[[ISOYear]], two.[[ISOMonth]], two.[[ISODay]])).

3.3 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%.
Note
An ECMAScript implementation that includes the ECMA-402 Internationalization API extends this prototype with additional properties in order to represent calendar data.

3.3.1 Temporal.PlainDate.prototype.constructor

The initial value of Temporal.PlainDate.prototype.constructor is %Temporal.PlainDate%.

3.3.2 Temporal.PlainDate.prototype[ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Temporal.PlainDate".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

3.3.3 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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Return temporalDate.[[Calendar]].

3.3.4 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.
  2. Perform ? RequireInternalSlot(plainDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(plainDate).
  4. Return CalendarEra(plainDate.[[Calendar]], isoDate).

3.3.5 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.
  2. Perform ? RequireInternalSlot(plainDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(plainDate).
  4. Let result be CalendarEraYear(plainDate.[[Calendar]], isoDate).
  5. If result is undefined, return undefined.
  6. Return 𝔽(result).

3.3.6 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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  4. Return 𝔽(CalendarYear(temporalDate.[[Calendar]], isoDate)).

3.3.7 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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  4. Return 𝔽(CalendarMonth(temporalDate.[[Calendar]], isoDate)).

3.3.8 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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  4. Return CalendarMonthCode(temporalDate.[[Calendar]], isoDate).

3.3.9 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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  4. Return 𝔽(CalendarDay(temporalDate.[[Calendar]], isoDate)).

3.3.10 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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  4. Return 𝔽(CalendarDayOfWeek(temporalDate.[[Calendar]], isoDate)).

3.3.11 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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  4. Return 𝔽(CalendarDayOfYear(temporalDate.[[Calendar]], isoDate)).

3.3.12 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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  4. Let result be CalendarWeekOfYear(temporalDate.[[Calendar]], isoDate).
  5. If result is undefined, return undefined.
  6. Return 𝔽(result).

3.3.13 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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  4. Let result be CalendarYearOfWeek(temporalDate.[[Calendar]], isoDate).
  5. If result is undefined, return undefined.
  6. Return 𝔽(result).

3.3.14 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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  4. Return 𝔽(CalendarDaysInWeek(temporalDate.[[Calendar]], isoDate)).

3.3.15 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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  4. Return 𝔽(CalendarDaysInMonth(temporalDate.[[Calendar]], isoDate)).

3.3.16 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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  4. Return 𝔽(CalendarDaysInYear(temporalDate.[[Calendar]], isoDate)).

3.3.17 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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  4. Return 𝔽(CalendarMonthsInYear(temporalDate.[[Calendar]], isoDate)).

3.3.18 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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  4. Return CalendarInLeapYear(temporalDate.[[Calendar]], isoDate).

3.3.19 Temporal.PlainDate.prototype.toPlainYearMonth ( )

This method performs the following steps when called:

  1. Let temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let calendar be temporalDate.[[Calendar]].
  4. Let fields be TemporalObjectToFields(temporalDate).
  5. Let isoDate be ? CalendarYearMonthFromFields(calendar, fields, "constrain").
  6. Return ! CreateTemporalYearMonth(isoDate.[[Year]], isoDate.[[Month]], calendar, isoDate.[[Day]]).
  7. NOTE: The call to CalendarYearMonthFromFields is necessary in order to create a PlainYearMonth object with the [[ISOYear]], [[ISOMonth]], and [[ISODay]] internal slots set correctly.

3.3.20 Temporal.PlainDate.prototype.toPlainMonthDay ( )

This method performs the following steps when called:

  1. Let temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let calendar be temporalDate.[[Calendar]].
  4. Let fields be TemporalObjectToFields(temporalDate).
  5. Let isoDate be ? CalendarMonthDayFromFields(calendar, fields, "constrain").
  6. Return ! CreateTemporalMonthDay(isoDate.[[Month]], isoDate.[[Day]], calendar, isoDate.[[Year]]).
  7. NOTE: The call to CalendarMonthDayFromFields is necessary in order to create a PlainMonthDay object with the [[ISOYear]], [[ISOMonth]], and [[ISODay]] internal slots set correctly.

3.3.21 Temporal.PlainDate.prototype.add ( temporalDurationLike [ , options ] )

This method performs the following steps when called:

  1. Let temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Return ? AddDurationToDate(add, temporalDate, temporalDurationLike, options).

3.3.22 Temporal.PlainDate.prototype.subtract ( temporalDurationLike [ , options ] )

This method performs the following steps when called:

  1. Let temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Return ? AddDurationToDate(subtract, temporalDate, temporalDurationLike, options).

3.3.23 Temporal.PlainDate.prototype.with ( temporalDateLike [ , options ] )

This method performs the following steps when called:

  1. Let temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. If ? IsPartialTemporalObject(temporalDateLike) is false, throw a TypeError exception.
  4. Let calendar be temporalDate.[[Calendar]].
  5. Let fields be TemporalObjectToFields(temporalDate).
  6. Let partialDate be ? PrepareCalendarFields(calendar, temporalDateLike, « day, month, month-code, year », « », partial).
  7. Set fields to CalendarMergeFields(calendar, fields, partialDate).
  8. Let resolvedOptions be ? GetOptionsObject(options).
  9. Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
  10. Let isoDate be ? CalendarDateFromFields(calendar, fields, overflow).
  11. Return ! CreateTemporalDate(isoDate.[[Year]], isoDate.[[Month]], isoDate.[[Day]], calendar).

3.3.24 Temporal.PlainDate.prototype.withCalendar ( calendarLike )

This method performs the following steps when called:

  1. Let temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let calendar be ? ToTemporalCalendarIdentifier(calendarLike).
  4. Return ! CreateTemporalDate(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]], calendar).

3.3.25 Temporal.PlainDate.prototype.until ( other [ , options ] )

This method performs the following steps when called:

  1. Let temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Return ? DifferenceTemporalPlainDate(until, temporalDate, other, options).

3.3.26 Temporal.PlainDate.prototype.since ( other [ , options ] )

This method performs the following steps when called:

  1. Let temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Return ? DifferenceTemporalPlainDate(since, temporalDate, other, options).

3.3.27 Temporal.PlainDate.prototype.equals ( other )

This method performs the following steps when called:

  1. Let temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Set other to ? ToTemporalDate(other).
  4. If temporalDate.[[ISOYear]]other.[[ISOYear]], return false.
  5. If temporalDate.[[ISOMonth]]other.[[ISOMonth]], return false.
  6. If temporalDate.[[ISODay]]other.[[ISODay]], return false.
  7. Return CalendarEquals(temporalDate.[[Calendar]], other.[[Calendar]]).

3.3.28 Temporal.PlainDate.prototype.toPlainDateTime ( [ temporalTime ] )

This method performs the following steps when called:

  1. Let temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Set temporalTime to ? ToTemporalTimeOrMidnight(temporalTime).
  4. Return ? CreateTemporalDateTime(temporalDate.[[ISOYear]], temporalDate.[[ISOMonth]], temporalDate.[[ISODay]], temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]], temporalDate.[[Calendar]]).

3.3.29 Temporal.PlainDate.prototype.toZonedDateTime ( item )

This method performs the following steps when called:

  1. Let temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. If item is an Object, then
    1. Let timeZoneLike be ? Get(item, "timeZone").
    2. If timeZoneLike is undefined, then
      1. Let timeZone be ? ToTemporalTimeZoneIdentifier(item).
      2. Let temporalTime be undefined.
    3. Else,
      1. Let timeZone be ? ToTemporalTimeZoneIdentifier(timeZoneLike).
      2. Let temporalTime be ? Get(item, "plainTime").
  4. Else,
    1. Let timeZone be ? ToTemporalTimeZoneIdentifier(item).
    2. Let temporalTime be undefined.
  5. Set temporalTime to ? ToTemporalTimeOrMidnight(temporalTime).
  6. Let isoDateTime be ISO Date-Time Record { [[Year]]: temporalDate.[[ISOYear]], [[Month]]: temporalDate.[[ISOMonth]], [[Day]]: temporalDate.[[ISODay]], [[Hour]]: temporalTime.[[ISOHour]], [[Minute]]: temporalTime.[[ISOMinute]], [[Second]]: temporalTime.[[ISOSecond]], [[Millisecond]]: temporalTime.[[ISOMillisecond]], [[Microsecond]]: temporalTime.[[ISOMicrosecond]], [[Nanosecond]]: temporalTime.[[ISONanosecond]] }.
  7. If ISODateTimeWithinLimits(isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]], isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]]) is false, throw a RangeError exception.
  8. Let epochNs be ? GetEpochNanosecondsFor(timeZone, isoDateTime, "compatible").
  9. Return ! CreateTemporalZonedDateTime(epochNs, timeZone, temporalDate.[[Calendar]]).

3.3.30 Temporal.PlainDate.prototype.toString ( [ options ] )

This method performs the following steps when called:

  1. Let temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Set options to ? GetOptionsObject(options).
  4. Let showCalendar be ? GetTemporalShowCalendarNameOption(options).
  5. Return TemporalDateToString(temporalDate, showCalendar).

3.3.31 Temporal.PlainDate.prototype.toLocaleString ( [ locales [ , options ] ] )

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 temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Return TemporalDateToString(temporalDate, "auto").

3.3.32 Temporal.PlainDate.prototype.toJSON ( )

This method performs the following steps when called:

  1. Let temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Return TemporalDateToString(temporalDate, "auto").

3.3.33 Temporal.PlainDate.prototype.valueOf ( )

This method performs the following steps when called:

  1. Throw a TypeError exception.
Note

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().

3.4 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 Table 1.

Table 1: Internal Slots of Temporal.PlainDate Instances
Internal Slot Description
[[InitializedTemporalDate]] The only specified use of this slot is for distinguishing Temporal.PlainDate instances from other objects.
[[ISOYear]] An integer representing the year in the ISO 8601 calendar.
[[ISOMonth]] An integer between 1 and 12, inclusive, representing the month of the year in the ISO 8601 calendar.
[[ISODay]] An integer between 1 and ISODaysInMonth([[ISOYear]], [[ISOMonth]]), inclusive, representing the day of the month in the ISO 8601 calendar.
[[Calendar]] A String representing the calendar.

3.5 Abstract Operations for Temporal.PlainDate Objects

3.5.1 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.

ISO Date Records have the fields listed in Table 2.

Table 2: ISO Date Record Fields
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.

3.5.2 CreateISODateRecord ( year, month, day )

The abstract operation CreateISODateRecord takes arguments year (an integer), month (an integer between 1 and 12 inclusive), and day (an integer between 1 and 31 inclusive) and returns an ISO Date Record. It performs the following steps when called:

  1. Assert: IsValidISODate(year, month, day) is true.
  2. Return ISO Date Record { [[Year]]: year, [[Month]]: month, [[Day]]: day }.

3.5.3 TemporalObjectToISODateRecord ( temporalObject )

The abstract operation TemporalObjectToISODateRecord takes argument temporalObject (a Temporal.PlainDate, Temporal.PlainDateTime, Temporal.PlainMonthDay, or Temporal.PlainYearMonth) and returns an ISO Date Record. It performs the following steps when called:

  1. Return CreateISODateRecord(temporalObject.[[ISOYear]], temporalObject.[[ISOMonth]], temporalObject.[[ISODay]]).

3.5.4 ISODateTimeToDateRecord ( isoDateTime )

The abstract operation ISODateTimeToDateRecord takes argument isoDateTime (an ISO Date-Time Record) and returns an ISO Date Record. It takes the date part of an ISO Date-Time Record and returns it as an ISO Date Record. It performs the following steps when called:

  1. Return CreateISODateRecord(isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]]).

3.5.5 CreateTemporalDate ( isoYear, isoMonth, isoDay, calendar [ , newTarget ] )

The abstract operation CreateTemporalDate takes arguments isoYear (an integer), isoMonth (an integer), isoDay (an integer), and calendar (a String or Object) and optional argument newTarget (a constructor) and returns either a normal completion containing a Temporal.PlainDate or a throw completion. It creates a Temporal.PlainDate instance and fills the internal slots with valid values. It performs the following steps when called:

  1. If IsValidISODate(isoYear, isoMonth, isoDay) is false, throw a RangeError exception.
  2. If ISODateWithinLimits(isoYear, isoMonth, isoDay) is false, throw a RangeError exception.
  3. If newTarget is not present, set newTarget to %Temporal.PlainDate%.
  4. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.PlainDate.prototype%", « [[InitializedTemporalDate]], [[ISOYear]], [[ISOMonth]], [[ISODay]], [[Calendar]] »).
  5. Set object.[[ISOYear]] to isoYear.
  6. Set object.[[ISOMonth]] to isoMonth.
  7. Set object.[[ISODay]] to isoDay.
  8. Set object.[[Calendar]] to calendar.
  9. Return object.

3.5.6 ToTemporalDate ( item [ , options ] )

The abstract operation ToTemporalDate takes argument item (an ECMAScript language value) and optional argument options (an ECMAScript language value) and returns either a normal completion containing a Temporal.PlainDate or a throw completion. It returns its argument item if it is already a Temporal.PlainDate instance, converts item to a new Temporal.PlainDate instance if possible, and throws otherwise. It performs the following steps when called:

  1. If options is not present, set options to undefined.
  2. If item is an Object, then
    1. If item has an [[InitializedTemporalDate]] internal slot, then
      1. Set options to ? GetOptionsObject(options).
      2. Perform ? GetTemporalOverflowOption(options).
      3. Return item.
    2. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
      1. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[Nanoseconds]]).
      2. Set options to ? GetOptionsObject(options).
      3. Perform ? GetTemporalOverflowOption(options).
      4. Return ! CreateTemporalDate(isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]], item.[[Calendar]]).
    3. If item has an [[InitializedTemporalDateTime]] internal slot, then
      1. Set options to ? GetOptionsObject(options).
      2. Perform ? GetTemporalOverflowOption(options).
      3. Return ! CreateTemporalDate(item.[[ISOYear]], item.[[ISOMonth]], item.[[ISODay]], item.[[Calendar]]).
    4. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(item).
    5. Let fields be ? PrepareCalendarFields(calendar, item, « day, month, month-code, year », «», «»).
    6. Set options to ? GetOptionsObject(options).
    7. Let overflow be ? GetTemporalOverflowOption(options).
    8. Let isoDate be ? CalendarDateFromFields(calendar, fields, overflow).
    9. Return ! CreateTemporalDate(isoDate.[[Year]], isoDate.[[Month]], isoDate.[[Day]], calendar).
  3. If item is not a String, throw a TypeError exception.
  4. Let result be ? ParseTemporalDateTimeString(item).
  5. Assert: IsValidISODate(result.[[Year]], result.[[Month]], result.[[Day]]) is true.
  6. Let calendar be result.[[Calendar]].
  7. If calendar is empty, set calendar to "iso8601".
  8. If IsBuiltinCalendar(calendar) is false, throw a RangeError exception.
  9. Set calendar to CanonicalizeUValue("ca", calendar).
  10. Set options to ? GetOptionsObject(options).
  11. Perform ? GetTemporalOverflowOption(options).
  12. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar).

3.5.7 ISODateSurpasses ( sign, y1, m1, d1, y2, m2, d2 )

The abstract operation ISODateSurpasses takes arguments sign (-1 or 1), y1 (an integer), m1 (an integer), d1 (an integer), y2 (an integer), m2 (an integer), and d2 (an integer) and returns a Boolean. The return value indicates whether the date denoted by y1, m1, d1 surpasses that denoted by y2, m2, d2 in the direction denoted by sign. The former date does not have to exist. Note that this operation is specific to date difference calculations and is not the same as CompareISODate. It performs the following steps when called:

  1. Assert: IsValidISODate(y2, m2, d2).
  2. Let comparison be CompareISODate(y1, m1, d1, y2, m2, d2).
  3. If sign × comparison = 1, return true.
  4. Return false.

3.5.8 DifferenceISODate ( y1, m1, d1, y2, m2, d2, largestUnit )

The abstract operation DifferenceISODate takes arguments y1 (an integer), m1 (an integer), d1 (an integer), y2 (an integer), m2 (an integer), d2 (an integer), and largestUnit ("year", "month", "week", or "day") and returns a Date Duration Record. The return value is the elapsed duration from a first date until a second date, according to the reckoning of the ISO 8601 calendar. No fields larger than largestUnit will be non-zero in the resulting Date Duration Record. It performs the following steps when called:

  1. Assert: IsValidISODate(y1, m1, d1) is true.
  2. Assert: IsValidISODate(y2, m2, d2) is true.
  3. Let sign be -CompareISODate(y1, m1, d1, y2, m2, d2).
  4. If sign = 0, return ! CreateDateDurationRecord(0, 0, 0, 0).
  5. Let years be 0.
  6. If largestUnit is "year", then
    1. Let candidateYears be sign.
    2. Repeat, while ISODateSurpasses(sign, y1 + candidateYears, m1, d1, y2, m2, d2) is false,
      1. Set years to candidateYears.
      2. Set candidateYears to candidateYears + sign.
  7. Let months be 0.
  8. If largestUnit is "year" or largestUnit is "month", then
    1. Let candidateMonths be sign.
    2. Let intermediate be BalanceISOYearMonth(y1 + years, m1 + candidateMonths).
    3. Repeat, while ISODateSurpasses(sign, intermediate.[[Year]], intermediate.[[Month]], d1, y2, m2, d2) is false,
      1. Set months to candidateMonths.
      2. Set candidateMonths to candidateMonths + sign.
      3. Set intermediate to BalanceISOYearMonth(intermediate.[[Year]], intermediate.[[Month]] + sign).
  9. Set intermediate to BalanceISOYearMonth(y1 + years, m1 + months).
  10. Let constrained be ! RegulateISODate(intermediate.[[Year]], intermediate.[[Month]], d1, "constrain").
  11. Let weeks be 0.
  12. If largestUnit is "week", then
    1. Let candidateWeeks be sign.
    2. Set intermediate to BalanceISODate(constrained.[[Year]], constrained.[[Month]], constrained.[[Day]] + 7 × candidateWeeks).
    3. Repeat, while ISODateSurpasses(sign, intermediate.[[Year]], intermediate.[[Month]], intermediate.[[Day]], y2, m2, d2) is false,
      1. Set weeks to candidateWeeks.
      2. Set candidateWeeks to candidateWeeks + sign.
      3. Set intermediate to BalanceISODate(intermediate.[[Year]], intermediate.[[Month]], intermediate.[[Day]] + 7 × sign).
  13. Let days be 0.
  14. Let candidateDays be sign.
  15. Set intermediate to BalanceISODate(constrained.[[Year]], constrained.[[Month]], constrained.[[Day]] + 7 × weeks + candidateDays).
  16. Repeat, while ISODateSurpasses(sign, intermediate.[[Year]], intermediate.[[Month]], intermediate.[[Day]], y2, m2, d2) is false,
    1. Set days to candidateDays.
    2. Set candidateDays to candidateDays + sign.
    3. Set intermediate to BalanceISODate(intermediate.[[Year]], intermediate.[[Month]], intermediate.[[Day]] + sign).
  17. Return ! CreateDateDurationRecord(years, months, weeks, days).

3.5.9 RegulateISODate ( year, month, day, overflow )

The abstract operation RegulateISODate takes arguments year (an integer), month (an integer), day (an integer), and overflow ("constrain" or "reject") and returns either a normal completion containing an ISO Date Record or a throw completion. It performs the overflow correction given 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 clamped to the correct range. It performs the following steps when called:

  1. If overflow is "constrain", then
    1. Set month to the result of clamping month between 1 and 12.
    2. Let daysInMonth be ISODaysInMonth(year, month).
    3. Set day to the result of clamping day between 1 and daysInMonth.
    4. Return CreateISODateRecord(year, month, day).
  2. Else,
    1. Assert: overflow is "reject".
    2. If IsValidISODate(year, month, day) is false, throw a RangeError exception.
    3. Return CreateISODateRecord(year, month, day).

3.5.10 IsValidISODate ( year, month, day )

The abstract operation IsValidISODate takes arguments year (an integer), month (an integer), and day (an integer) and returns a Boolean. 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. It performs the following steps when called:

  1. If month < 1 or month > 12, then
    1. Return false.
  2. Let daysInMonth be ISODaysInMonth(year, month).
  3. If day < 1 or day > daysInMonth, then
    1. Return false.
  4. Return true.

3.5.11 BalanceISODate ( year, month, day )

The abstract operation BalanceISODate takes arguments year (an integer), month (an integer), and day (an integer) and returns an ISO Date Record. It converts the given year, month, and day 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. It performs the following steps when called:

  1. Let epochDays be ISODateToEpochDays(year, month - 1, day).
  2. Let ms be EpochDaysToEpochMs(epochDays, 0).
  3. Return CreateISODateRecord(EpochTimeToEpochYear(ms), EpochTimeToMonthInYear(ms) + 1, EpochTimeToDate(ms)).

3.5.12 PadISOYear ( y )

The abstract operation PadISOYear takes argument y (an integer) and returns a String. 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. It performs the following steps when called:

  1. If y ≥ 0 and y ≤ 9999, then
    1. Return ToZeroPaddedDecimalString(y, 4).
  2. If y > 0, let yearSign be "+"; otherwise, let yearSign be "-".
  3. Let year be ToZeroPaddedDecimalString(abs(y), 6).
  4. Return the string-concatenation of yearSign and year.

3.5.13 TemporalDateToString ( temporalDate, showCalendar )

The abstract operation TemporalDateToString takes arguments temporalDate (a Temporal.PlainDate) and showCalendar ("auto", "always", "never", or "critical") and returns a String. It formats temporalDate to an ISO 8601 string. It performs the following steps when called:

  1. Let year be PadISOYear(temporalDate.[[ISOYear]]).
  2. Let month be ToZeroPaddedDecimalString(temporalDate.[[ISOMonth]], 2).
  3. Let day be ToZeroPaddedDecimalString(temporalDate.[[ISODay]], 2).
  4. Let calendar be MaybeFormatCalendarAnnotation(temporalDate.[[Calendar]], showCalendar).
  5. Return the string-concatenation of year, the code unit 0x002D (HYPHEN-MINUS), month, the code unit 0x002D (HYPHEN-MINUS), day, and calendar.

3.5.14 ISODateWithinLimits ( year, month, day )

The abstract operation ISODateWithinLimits takes arguments year (an integer), month (an integer between 1 and 12 inclusive), and day (an integer between 1 and 31 inclusive) and returns a Boolean. The return value is true if the date in the ISO 8601 calendar given by the arguments is within the representable range of Temporal.PlainDate, and false otherwise.

Note

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.

It performs the following steps when called:

  1. Return ISODateTimeWithinLimits(year, month, day, 12, 0, 0, 0, 0, 0).

3.5.15 AddISODate ( year, month, day, years, months, weeks, days, overflow )

The abstract operation AddISODate takes arguments year (an integer), month (an integer), day (an integer), years (an integer), months (an integer), weeks (an integer), days (an integer), and overflow ("constrain" or "reject") and returns either a normal completion containing an ISO Date Record or a throw completion. It adds the duration denoted by years, months, weeks, days to the date denoted by year, month, day, according to ISO 8601 calendar arithmetic. 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. It performs the following steps when called:

  1. Assert: IsValidISODate(year, month, day) is true.
  2. Let intermediate be BalanceISOYearMonth(year + years, month + months).
  3. Set intermediate to ? RegulateISODate(intermediate.[[Year]], intermediate.[[Month]], day, overflow).
  4. Set days to days + 7 × weeks.
  5. Let d be intermediate.[[Day]] + days.
  6. Let result be BalanceISODate(intermediate.[[Year]], intermediate.[[Month]], d).
  7. If ISODateWithinLimits(result.[[Year]], result.[[Month]], result.[[Day]]) is false, throw a RangeError exception.
  8. Return result.

3.5.16 CompareISODate ( y1, m1, d1, y2, m2, d2 )

The abstract operation CompareISODate takes arguments y1 (an integer), m1 (an integer), d1 (an integer), y2 (an integer), m2 (an integer), and d2 (an integer) and returns -1, 0, or 1. It performs a comparison of the two dates denoted by y1, m1, d1 and _y2, m2, d2 according to ISO 8601 calendar arithmetic. It performs the following steps when called:

  1. Assert: IsValidISODate(y2, m2, d2) is true.
  2. If y1 > y2, return 1.
  3. If y1 < y2, return -1.
  4. If m1 > m2, return 1.
  5. If m1 < m2, return -1.
  6. If d1 > d2, return 1.
  7. If d1 < d2, return -1.
  8. Return 0.

3.5.17 DifferenceTemporalPlainDate ( operation, temporalDate, other, options )

The abstract operation DifferenceTemporalPlainDate takes arguments operation (since or until), temporalDate (a Temporal.PlainDate), other (an ECMAScript language value), and options (an ECMAScript language value) and returns either a normal completion containing a Temporal.Duration or a throw completion. It computes the difference between the two times represented by temporalDate and other, optionally rounds it, and returns it as a Temporal.Duration object. It performs the following steps when called:

  1. If operation is since, let sign be -1. Otherwise, let sign be 1.
  2. Set other to ? ToTemporalDate(other).
  3. If CalendarEquals(temporalDate.[[Calendar]], other.[[Calendar]]) is false, throw a RangeError exception.
  4. Let resolvedOptions be ? GetOptionsObject(options).
  5. Let settings be ? GetDifferenceSettings(operation, resolvedOptions, date, « », "day", "day").
  6. If temporalDate.[[ISOYear]] = other.[[ISOYear]], and temporalDate.[[ISOMonth]] = other.[[ISOMonth]], and temporalDate.[[ISODay]] = other.[[ISODay]], then
    1. Return ! CreateTemporalDuration(0, 0, 0, 0, 0, 0, 0, 0, 0, 0).
  7. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  8. Let isoOther be TemporalObjectToISODateRecord(other).
  9. Let result be CalendarDateUntil(temporalDate.[[Calendar]], isoDate, isoOther, settings.[[LargestUnit]]).
  10. Let duration be ! CreateNormalizedDurationRecord(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], ZeroTimeDuration()).
  11. If settings.[[SmallestUnit]] is "day" and settings.[[RoundingIncrement]] = 1, let roundingGranularityIsNoop be true; else let roundingGranularityIsNoop be false.
  12. If roundingGranularityIsNoop is false, then
    1. Let destEpochNs be GetUTCEpochNanoseconds(isoOther.[[Year]], isoOther.[[Month]], isoOther.[[Day]], 0, 0, 0, 0, 0, 0).
    2. Let dateTime be ISO Date-Time Record { [[Year]]: isoDate.[[Year]], [[Month]]: isoDate.[[Month]], [[Day]]: isoDate.[[Day]], [[Hour]]: 0, [[Minute]]: 0, [[Second]]: 0, [[Millisecond]]: 0, [[Microsecond]]: 0, [[Nanosecond]]: 0 }.
    3. Set duration to ? RoundRelativeDuration(duration, destEpochNs, dateTime, temporalDate.[[Calendar]], unset, settings.[[LargestUnit]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
  13. Return ! CreateTemporalDuration(sign × duration.[[Years]], sign × duration.[[Months]], sign × duration.[[Weeks]], sign × duration.[[Days]], 0, 0, 0, 0, 0, 0).

3.5.18 AddDurationToDate ( operation, temporalDate, temporalDurationLike, options )

The abstract operation AddDurationToDate takes arguments operation (add or subtract), temporalDate (a Temporal.PlainDate), temporalDurationLike (an ECMAScript language value), and options (an ECMAScript language value) and returns either a normal completion containing a Temporal.PlainDate or a throw completion. It adds/subtracts temporalDurationLike to/from temporalDate, returning a point in time that is in the future/past relative to temporalDate. It performs the following steps when called:

  1. If operation is subtract, let sign be -1. Otherwise, let sign be 1.
  2. Let isoDate be TemporalObjectToISODateRecord(temporalDate).
  3. Let calendar be temporalDate.[[Calendar]].
  4. Let duration be ? ToTemporalDurationRecord(temporalDurationLike).
  5. Let norm be NormalizeTimeDuration(sign × duration.[[Hours]], sign × duration.[[Minutes]], sign × duration.[[Seconds]], sign × duration.[[Milliseconds]], sign × duration.[[Microseconds]], sign × duration.[[Nanoseconds]]).
  6. Let balanceResult be ! BalanceTimeDuration(norm, "day").
  7. Let days be sign × duration.[[Days]] + balanceResult.[[Days]].
  8. Let dateDuration be ? CreateDateDurationRecord(sign × duration.[[Years]], sign × duration.[[Months]], sign × duration.[[Weeks]], days).
  9. Set options to ? GetOptionsObject(options).
  10. Let overflow be ? GetTemporalOverflowOption(options).
  11. Let result be ? CalendarDateAdd(calendar, isoDate, dateDuration, overflow).
  12. Return ! CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar).

4 Temporal.PlainTime Objects

A Temporal.PlainTime object is an Object that contains integers corresponding to a particular hour, minute, second, millisecond, microsecond, and nanosecond.

4.1 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.

4.1.1 Temporal.PlainTime ( [ hour [ , minute [ , second [ , millisecond [ , microsecond [ , nanosecond ] ] ] ] ] ] )

This function performs the following steps when called:

  1. If NewTarget is undefined, then
    1. Throw a TypeError exception.
  2. If hour is undefined, set hour to 0; else set hour to ? ToIntegerWithTruncation(hour).
  3. If minute is undefined, set minute to 0; else set minute to ? ToIntegerWithTruncation(minute).
  4. If second is undefined, set second to 0; else set second to ? ToIntegerWithTruncation(second).
  5. If millisecond is undefined, set millisecond to 0; else set millisecond to ? ToIntegerWithTruncation(millisecond).
  6. If microsecond is undefined, set microsecond to 0; else set microsecond to ? ToIntegerWithTruncation(microsecond).
  7. If nanosecond is undefined, set nanosecond to 0; else set nanosecond to ? ToIntegerWithTruncation(nanosecond).
  8. Return ? CreateTemporalTime(hour, minute, second, millisecond, microsecond, nanosecond, NewTarget).

4.2 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:

4.2.1 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 }.

4.2.2 Temporal.PlainTime.from ( item [ , options ] )

This function performs the following steps when called:

  1. If item is an Object and item has an [[InitializedTemporalTime]] internal slot, then
    1. Set options to ? GetOptionsObject(options).
    2. Perform ? GetTemporalOverflowOption(options).
    3. Return ! CreateTemporalTime(item.[[ISOHour]], item.[[ISOMinute]], item.[[ISOSecond]], item.[[ISOMillisecond]], item.[[ISOMicrosecond]], item.[[ISONanosecond]]).
  2. Return ? ToTemporalTime(item, options).

4.2.3 Temporal.PlainTime.compare ( one, two )

This function performs the following steps when called:

  1. Set one to ? ToTemporalTime(one).
  2. Set two to ? ToTemporalTime(two).
  3. Return 𝔽(CompareTemporalTime(one.[[ISOHour]], one.[[ISOMinute]], one.[[ISOSecond]], one.[[ISOMillisecond]], one.[[ISOMicrosecond]], one.[[ISONanosecond]], two.[[ISOHour]], two.[[ISOMinute]], two.[[ISOSecond]], two.[[ISOMillisecond]], two.[[ISOMicrosecond]], two.[[ISONanosecond]])).

4.3 Properties of the Temporal.PlainTime Prototype Object

The Temporal.PlainTime prototype object

  • is itself an ordinary object.
  • is not a Temporal.PlainTime instance and does not have a [[InitializedTemporalTime]] internal slot.
  • has a [[Prototype]] internal slot whose value is %Object.prototype%.

4.3.1 Temporal.PlainTime.prototype.constructor

The initial value of Temporal.PlainTime.prototype.constructor is %Temporal.PlainTime%.

4.3.2 Temporal.PlainTime.prototype[ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Temporal.PlainTime".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

4.3.3 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 temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Return 𝔽(temporalTime.[[ISOHour]]).

4.3.4 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 temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Return 𝔽(temporalTime.[[ISOMinute]]).

4.3.5 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 temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Return 𝔽(temporalTime.[[ISOSecond]]).

4.3.6 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 temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Return 𝔽(temporalTime.[[ISOMillisecond]]).

4.3.7 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 temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Return 𝔽(temporalTime.[[ISOMicrosecond]]).

4.3.8 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 temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Return 𝔽(temporalTime.[[ISONanosecond]]).

4.3.9 Temporal.PlainTime.prototype.add ( temporalDurationLike )

This method performs the following steps when called:

  1. Let temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Return ? AddDurationToOrSubtractDurationFromPlainTime(add, temporalTime, temporalDurationLike).

4.3.10 Temporal.PlainTime.prototype.subtract ( temporalDurationLike )

This method performs the following steps when called:

  1. Let temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Return ? AddDurationToOrSubtractDurationFromPlainTime(subtract, temporalTime, temporalDurationLike).

4.3.11 Temporal.PlainTime.prototype.with ( temporalTimeLike [ , options ] )

This method performs the following steps when called:

  1. Let temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. If ? IsPartialTemporalObject(temporalTimeLike) is false, throw a TypeError exception.
  4. Let partialTime be ? ToTemporalTimeRecord(temporalTimeLike, partial).
  5. If partialTime.[[Hour]] is not undefined, then
    1. Let hour be partialTime.[[Hour]].
  6. Else,
    1. Let hour be temporalTime.[[ISOHour]].
  7. If partialTime.[[Minute]] is not undefined, then
    1. Let minute be partialTime.[[Minute]].
  8. Else,
    1. Let minute be temporalTime.[[ISOMinute]].
  9. If partialTime.[[Second]] is not undefined, then
    1. Let second be partialTime.[[Second]].
  10. Else,
    1. Let second be temporalTime.[[ISOSecond]].
  11. If partialTime.[[Millisecond]] is not undefined, then
    1. Let millisecond be partialTime.[[Millisecond]].
  12. Else,
    1. Let millisecond be temporalTime.[[ISOMillisecond]].
  13. If partialTime.[[Microsecond]] is not undefined, then
    1. Let microsecond be partialTime.[[Microsecond]].
  14. Else,
    1. Let microsecond be temporalTime.[[ISOMicrosecond]].
  15. If partialTime.[[Nanosecond]] is not undefined, then
    1. Let nanosecond be partialTime.[[Nanosecond]].
  16. Else,
    1. Let nanosecond be temporalTime.[[ISONanosecond]].
  17. Set options to ? GetOptionsObject(options).
  18. Let overflow be ? GetTemporalOverflowOption(options).
  19. Let result be ? RegulateTime(hour, minute, second, millisecond, microsecond, nanosecond, overflow).
  20. Return ! CreateTemporalTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]).

4.3.12 Temporal.PlainTime.prototype.until ( other [ , options ] )

This method performs the following steps when called:

  1. Let temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Return ? DifferenceTemporalPlainTime(until, temporalTime, other, options).

4.3.13 Temporal.PlainTime.prototype.since ( other [ , options ] )

This method performs the following steps when called:

  1. Let temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Return ? DifferenceTemporalPlainTime(since, temporalTime, other, options).

4.3.14 Temporal.PlainTime.prototype.round ( roundTo )

This method performs the following steps when called:

  1. Let temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. If roundTo is undefined, then
    1. Throw a TypeError exception.
  4. If roundTo is a String, then
    1. Let paramString be roundTo.
    2. Set roundTo to OrdinaryObjectCreate(null).
    3. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString).
  5. Else,
    1. Set roundTo to ? GetOptionsObject(roundTo).
  6. NOTE: The following steps read options and perform independent validation in alphabetical order (ToTemporalRoundingIncrement reads "roundingIncrement" and ToTemporalRoundingMode reads "roundingMode").
  7. Let roundingIncrement be ? GetRoundingIncrementOption(roundTo).
  8. Let roundingMode be ? GetRoundingModeOption(roundTo, "halfExpand").
  9. Let smallestUnit be ? GetTemporalUnitValuedOption(roundTo, "smallestUnit", time, required).
  10. Let maximum be MaximumTemporalDurationRoundingIncrement(smallestUnit).
  11. Assert: maximum is not undefined.
  12. Perform ? ValidateTemporalRoundingIncrement(roundingIncrement, maximum, false).
  13. Let result be RoundTime(temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]], roundingIncrement, smallestUnit, roundingMode).
  14. Return ! CreateTemporalTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]).

4.3.15 Temporal.PlainTime.prototype.equals ( other )

This method performs the following steps when called:

  1. Let temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Set other to ? ToTemporalTime(other).
  4. If temporalTime.[[ISOHour]]other.[[ISOHour]], return false.
  5. If temporalTime.[[ISOMinute]]other.[[ISOMinute]], return false.
  6. If temporalTime.[[ISOSecond]]other.[[ISOSecond]], return false.
  7. If temporalTime.[[ISOMillisecond]]other.[[ISOMillisecond]], return false.
  8. If temporalTime.[[ISOMicrosecond]]other.[[ISOMicrosecond]], return false.
  9. If temporalTime.[[ISONanosecond]]other.[[ISONanosecond]], return false.
  10. Return true.

4.3.16 Temporal.PlainTime.prototype.toString ( [ options ] )

This method performs the following steps when called:

  1. Let temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Set options to ? GetOptionsObject(options).
  4. NOTE: The following steps read options and perform independent validation in alphabetical order (ToFractionalSecondDigits reads "fractionalSecondDigits" and ToTemporalRoundingMode reads "roundingMode").
  5. Let digits be ? GetTemporalFractionalSecondDigitsOption(options).
  6. Let roundingMode be ? GetRoundingModeOption(options, "trunc").
  7. Let smallestUnit be ? GetTemporalUnitValuedOption(options, "smallestUnit", time, undefined).
  8. If smallestUnit is "hour", throw a RangeError exception.
  9. Let precision be ToSecondsStringPrecisionRecord(smallestUnit, digits).
  10. Let roundResult be RoundTime(temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]], precision.[[Increment]], precision.[[Unit]], roundingMode).
  11. Return TemporalTimeToString(roundResult.[[Hour]], roundResult.[[Minute]], roundResult.[[Second]], roundResult.[[Millisecond]], roundResult.[[Microsecond]], roundResult.[[Nanosecond]], precision.[[Precision]]).

4.3.17 Temporal.PlainTime.prototype.toLocaleString ( [ locales [ , options ] ] )

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 temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Return TemporalTimeToString(temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]], "auto").

4.3.18 Temporal.PlainTime.prototype.toJSON ( )

This method performs the following steps when called:

  1. Let temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Return TemporalTimeToString(temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]], "auto").

4.3.19 Temporal.PlainTime.prototype.valueOf ( )

This method performs the following steps when called:

  1. Throw a TypeError exception.
Note

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().

4.4 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 Table 3.

Table 3: Internal Slots of Temporal.PlainTime Instances
Internal Slot Description
[[InitializedTemporalTime]] The only specified use of this slot is for distinguishing Temporal.PlainTime instances from other objects.
[[ISOHour]] An integer between 0 and 23, inclusive, representing the hour of the day.
[[ISOMinute]] An integer between 0 and 59, inclusive, representing the minute of the hour.
[[ISOSecond]] An integer between 0 and 59, inclusive, representing the second within the minute.
[[ISOMillisecond]] An integer between 0 and 999, inclusive, representing the millisecond within the second.
[[ISOMicrosecond]] An integer between 0 and 999, inclusive, representing the microsecond within the millisecond.
[[ISONanosecond]] An integer between 0 and 999, inclusive, representing the nanosecond within the microsecond.

4.5 Abstract Operations

4.5.1 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 Table 4.

Table 4: Time Record Fields
Field Name Value Meaning
[[Days]] an integer ≥ 0 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.

4.5.2 DifferenceTime ( h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, ns2 )

The abstract operation DifferenceTime takes arguments h1 (an integer between 0 and 23 inclusive), min1 (an integer between 0 and 59 inclusive), s1 (an integer between 0 and 59 inclusive), ms1 (an integer between 0 and 999 inclusive), mus1 (an integer between 0 and 999 inclusive), ns1 (an integer between 0 and 999 inclusive), h2 (an integer between 0 and 23 inclusive), min2 (an integer between 0 and 59 inclusive), s2 (an integer between 0 and 59 inclusive), ms2 (an integer between 0 and 999 inclusive), mus2 (an integer between 0 and 999 inclusive), and ns2 (an integer between 0 and 999 inclusive) and returns a Normalized Time Duration Record. It returns the elapsed duration from a first wall-clock time, until a second wall-clock time. It performs the following steps when called:

  1. Let hours be h2 - h1.
  2. Let minutes be min2 - min1.
  3. Let seconds be s2 - s1.
  4. Let milliseconds be ms2 - ms1.
  5. Let microseconds be mus2 - mus1.
  6. Let nanoseconds be ns2 - ns1.
  7. Let norm be NormalizeTimeDuration(hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
  8. Assert: NormalizedTimeDurationAbs(norm).[[TotalNanoseconds]] < nsPerDay.
  9. Return norm.

4.5.3 ToTemporalTime ( item [ , options ] )

The abstract operation ToTemporalTime takes argument item (an ECMAScript language value) and optional argument options (an ECMAScript language value) and returns either a normal completion containing a Temporal.PlainTime or a throw Completion. It returns its argument item if it is already a Temporal.PlainTime instance, converts item to a new Temporal.PlainTime instance if possible, and throws otherwise. It performs the following steps when called:

  1. If options is not present, set options to undefined.
  2. If item is an Object, then
    1. If item has an [[InitializedTemporalTime]] internal slot, then
      1. Set options to ? GetOptionsObject(options).
      2. Perform ? GetTemporalOverflowOption(options).
      3. Return item.
    2. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
      1. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[Nanoseconds]]).
      2. Set options to ? GetOptionsObject(options).
      3. Perform ? GetTemporalOverflowOption(options).
      4. Return ! CreateTemporalTime(isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]]).
    3. If item has an [[InitializedTemporalDateTime]] internal slot, then
      1. Set options to ? GetOptionsObject(options).
      2. Perform ? GetTemporalOverflowOption(options).
      3. Return ! CreateTemporalTime(item.[[ISOHour]], item.[[ISOMinute]], item.[[ISOSecond]], item.[[ISOMillisecond]], item.[[ISOMicrosecond]], item.[[ISONanosecond]]).
    4. Let result be ? ToTemporalTimeRecord(item).
    5. Set options to ? GetOptionsObject(options).
    6. Let overflow be ? GetTemporalOverflowOption(options).
    7. Set result to ? RegulateTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], overflow).
  3. Else,
    1. If item is not a String, throw a TypeError exception.
    2. Let result be ? ParseTemporalTimeString(item).
    3. Assert: IsValidTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]) is true.
    4. Set options to ? GetOptionsObject(options).
    5. Perform ? GetTemporalOverflowOption(options).
  4. Return ! CreateTemporalTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]).

4.5.4 ToTemporalTimeOrMidnight ( item )

The abstract operation ToTemporalTimeOrMidnight takes argument item (an ECMAScript language value) and returns either a normal completion containing a Temporal.PlainTime or a throw completion. It returns its argument item if it is already a Temporal.PlainTime instance, converts item to a new Temporal.PlainTime instance if possible, considering undefined to be the same as midnight, and throws otherwise. It performs the following steps when called:

  1. If item is undefined, return ! CreateTemporalTime(0, 0, 0, 0, 0, 0).
  2. Return ? ToTemporalTime(item).

4.5.5 RegulateTime ( hour, minute, second, millisecond, microsecond, nanosecond, overflow )

The abstract operation RegulateTime takes arguments hour (an integer), minute (an integer), second (an integer), millisecond (an integer), microsecond (an integer), nanosecond (an integer), and overflow ("constrain" or "reject") and returns either a normal completion containing a Time Record or a throw completion. 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. It performs the following steps when called:

  1. If overflow is "constrain", then
    1. Return ConstrainTime(hour, minute, second, millisecond, microsecond, nanosecond).
  2. Else,
    1. Assert: overflow is "reject".
    2. If IsValidTime(hour, minute, second, millisecond, microsecond, nanosecond) is false, throw a RangeError exception.
    3. Return Time Record { [[Days]]: 0, [[Hour]]: hour, [[Minute]]: minute, [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]: microsecond, [[Nanosecond]]: nanosecond  }.

4.5.6 IsValidTime ( hour, minute, second, millisecond, microsecond, nanosecond )

The abstract operation IsValidTime takes arguments hour (an integer), minute (an integer), second (an integer), millisecond (an integer), microsecond (an integer), and nanosecond (an integer) and returns a Boolean. The return value is true if its arguments form a valid time of day, and false otherwise. Leap seconds are not taken into account. It performs the following steps when called:

  1. If hour < 0 or hour > 23, then
    1. Return false.
  2. If minute < 0 or minute > 59, then
    1. Return false.
  3. If second < 0 or second > 59, then
    1. Return false.
  4. If millisecond < 0 or millisecond > 999, then
    1. Return false.
  5. If microsecond < 0 or microsecond > 999, then
    1. Return false.
  6. If nanosecond < 0 or nanosecond > 999, then
    1. Return false.
  7. Return true.

4.5.7 BalanceTime ( hour, minute, second, millisecond, microsecond, nanosecond )

The abstract operation BalanceTime takes arguments hour (an integer), minute (an integer), second (an integer), millisecond (an integer), microsecond (an integer), and nanosecond (an integer) and returns a Time Record. It performs the following steps when called:

  1. Set microsecond to microsecond + floor(nanosecond / 1000).
  2. Set nanosecond to nanosecond modulo 1000.
  3. Set millisecond to millisecond + floor(microsecond / 1000).
  4. Set microsecond to microsecond modulo 1000.
  5. Set second to second + floor(millisecond / 1000).
  6. Set millisecond to millisecond modulo 1000.
  7. Set minute to minute + floor(second / 60).
  8. Set second to second modulo 60.
  9. Set hour to hour + floor(minute / 60).
  10. Set minute to minute modulo 60.
  11. Let days be floor(hour / 24).
  12. Set hour to hour modulo 24.
  13. Return Time Record { [[Days]]: days, [[Hour]]: hour, [[Minute]]: minute, [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]: microsecond, [[Nanosecond]]: nanosecond  }.

4.5.8 ConstrainTime ( hour, minute, second, millisecond, microsecond, nanosecond )

The abstract operation ConstrainTime takes arguments hour (an integer), minute (an integer), second (an integer), millisecond (an integer), microsecond (an integer), and nanosecond (an integer) and returns a Time Record. It clamps any out-of-range components of the given time so they are in range. It performs the following steps when called:

  1. Set hour to the result of clamping hour between 0 and 23.
  2. Set minute to the result of clamping minute between 0 and 59.
  3. Set second to the result of clamping second between 0 and 59.
  4. Set millisecond to the result of clamping millisecond between 0 and 999.
  5. Set microsecond to the result of clamping microsecond between 0 and 999.
  6. Set nanosecond to the result of clamping nanosecond between 0 and 999.
  7. Return Time Record { [[Days]]: 0, [[Hour]]: hour, [[Minute]]: minute, [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]: microsecond, [[Nanosecond]]: nanosecond  }.

4.5.9 CreateTemporalTime ( hour, minute, second, millisecond, microsecond, nanosecond [ , newTarget ] )

The abstract operation CreateTemporalTime takes arguments hour (an integer), minute (an integer), second (an integer), millisecond (an integer), microsecond (an integer), and nanosecond (an integer) and optional argument newTarget (a constructor) and returns either a normal completion containing a Temporal.PlainTime or a throw completion. It creates a new Temporal.PlainTime instance and fills the internal slots with valid values. It performs the following steps when called:

  1. If IsValidTime(hour, minute, second, millisecond, microsecond, nanosecond) is false, throw a RangeError exception.
  2. If newTarget is not present, set newTarget to %Temporal.PlainTime%.
  3. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.PlainTime.prototype%", « [[InitializedTemporalTime]], [[ISOHour]], [[ISOMinute]], [[ISOSecond]], [[ISOMillisecond]], [[ISOMicrosecond]], [[ISONanosecond]] »).
  4. Set object.[[ISOHour]] to hour.
  5. Set object.[[ISOMinute]] to minute.
  6. Set object.[[ISOSecond]] to second.
  7. Set object.[[ISOMillisecond]] to millisecond.
  8. Set object.[[ISOMicrosecond]] to microsecond.
  9. Set object.[[ISONanosecond]] to nanosecond.
  10. Return object.

4.5.10 ToTemporalTimeRecord ( temporalTimeLike [ , completeness ] )

The abstract operation ToTemporalTimeRecord takes argument temporalTimeLike (an Object) and optional argument completeness (partial or complete) and returns either a normal completion containing a TemporalTimeLike Record or a throw completion. It performs the following steps when called:

  1. If completeness is not present, set completeness to complete.
  2. If completeness is complete, then
    1. Let result be a new TemporalTimeLike Record with each field set to 0.
  3. Else,
    1. Let result be a new TemporalTimeLike Record with each field set to unset.
  4. Let any be false.
  5. Let hour be ? Get(temporalTimeLike, "hour").
  6. If hour is not undefined, then
    1. Set result.[[Hour]] to ? ToIntegerWithTruncation(hour).
    2. Set any to true.
  7. Let microsecond be ? Get(temporalTimeLike, "microsecond").
  8. If microsecond is not undefined, then
    1. Set result.[[Microsecond]] to ? ToIntegerWithTruncation(microsecond).
    2. Set any to true.
  9. Let millisecond be ? Get(temporalTimeLike, "millisecond").
  10. If millisecond is not undefined, then
    1. Set result.[[Millisecond]] to ? ToIntegerWithTruncation(millisecond).
    2. Set any to true.
  11. Let minute be ? Get(temporalTimeLike, "minute").
  12. If minute is not undefined, then
    1. Set result.[[Minute]] to ? ToIntegerWithTruncation(minute).
    2. Set any to true.
  13. Let nanosecond be ? Get(temporalTimeLike, "nanosecond").
  14. If nanosecond is not undefined, then
    1. Set result.[[Nanosecond]] to ? ToIntegerWithTruncation(nanosecond).
    2. Set any to true.
  15. Let second be ? Get(temporalTimeLike, "second").
  16. If second is not undefined, then
    1. Set result.[[Second]] to ? ToIntegerWithTruncation(second).
    2. Set any to true.
  17. If any is false, throw a TypeError exception.
  18. Return result.
Table 5: TemporalTimeLike Record Fields
Field Name Property Name
[[Hour]] "hour"
[[Minute]] "minute"
[[Second]] "second"
[[Millisecond]] "millisecond"
[[Microsecond]] "microsecond"
[[Nanosecond]] "nanosecond"

4.5.11 TemporalTimeToString ( hour, minute, second, millisecond, microsecond, nanosecond, precision )

The abstract operation TemporalTimeToString takes arguments 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), and precision (an integer in the inclusive interval from 0 to 9, "minute", or "auto") and returns a String. It formats the given time as an ISO 8601 string, to the precision specified by precision. It performs the following steps when called:

  1. Let subSecondNanoseconds be millisecond × 106 + microsecond × 103 + nanosecond.
  2. Return FormatTimeString(hour, minute, second, subSecondNanoseconds, precision).

4.5.12 CompareTemporalTime ( h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, ns2 )

The abstract operation CompareTemporalTime takes arguments h1 (an integer in the inclusive interval from 0 to 23), min1 (an integer in the inclusive interval from 0 to 59), s1 (an integer in the inclusive interval from 0 to 59), ms1 (an integer in the inclusive interval from 0 to 999), mus1 (an integer in the inclusive interval from 0 to 999), ns1 (an integer in the inclusive interval from 0 to 999), h2 (an integer in the inclusive interval from 0 to 23), min2 (an integer in the inclusive interval from 0 to 59), s2 (an integer in the inclusive interval from 0 to 59), ms2 (an integer in the inclusive interval from 0 to 999), mus2 (an integer in the inclusive interval from 0 to 999), and ns2 (an integer in the inclusive interval from 0 to 999) and returns -1, 0, or 1. 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. It performs the following steps when called:

  1. If h1 > h2, return 1.
  2. If h1 < h2, return -1.
  3. If min1 > min2, return 1.
  4. If min1 < min2, return -1.
  5. If s1 > s2, return 1.
  6. If s1 < s2, return -1.
  7. If ms1 > ms2, return 1.
  8. If ms1 < ms2, return -1.
  9. If mus1 > mus2, return 1.
  10. If mus1 < mus2, return -1.
  11. If ns1 > ns2, return 1.
  12. If ns1 < ns2, return -1.
  13. Return 0.

4.5.13 AddTime ( hour, minute, second, millisecond, microsecond, nanosecond, norm )

The abstract operation AddTime takes arguments 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), and norm (a Normalized Time Duration Record) and returns a Time Record. It performs the following steps when called:

  1. Set second to second + NormalizedTimeDurationSeconds(norm).
  2. Set nanosecond to nanosecond + NormalizedTimeDurationSubseconds(norm).
  3. Return BalanceTime(hour, minute, second, millisecond, microsecond, nanosecond).

4.5.14 RoundTime ( hour, minute, second, millisecond, microsecond, nanosecond, increment, unit, roundingMode )

The abstract operation RoundTime takes arguments 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), increment (a positive integer), unit (a String from the "Singular" column of Table 21), and roundingMode (a String from the "Identifier" column of Table 22) and returns a Time Record. It rounds a time to the given increment. It performs the following steps when called:

  1. If unit is "day" or "hour", then
    1. Let quantity be ((((hour × 60 + minute) × 60 + second) × 1000 + millisecond) × 1000 + microsecond) × 1000 + nanosecond.
  2. Else if unit is "minute", then
    1. Let quantity be (((minute × 60 + second) × 1000 + millisecond) × 1000 + microsecond) × 1000 + nanosecond.
  3. Else if unit is "second", then
    1. Let quantity be ((second × 1000 + millisecond) × 1000 + microsecond) × 1000 + nanosecond.
  4. Else if unit is "millisecond", then
    1. Let quantity be (millisecond × 1000 + microsecond) × 1000 + nanosecond.
  5. Else if unit is "microsecond", then
    1. Let quantity be microsecond × 1000 + nanosecond.
  6. Else,
    1. Assert: unit is "nanosecond".
    2. Let quantity be nanosecond.
  7. Let unitLength be the value in the "Length in Nanoseconds" column of the row of Table 21 whose "Singular" column contains unit.
  8. Let result be RoundNumberToIncrement(quantity, increment × unitLength, roundingMode) / unitLength.
  9. If unit is "day", then
    1. Return Time Record { [[Days]]: result, [[Hour]]: 0, [[Minute]]: 0, [[Second]]: 0, [[Millisecond]]: 0, [[Microsecond]]: 0, [[Nanosecond]]: 0  }.
  10. If unit is "hour", then
    1. Return BalanceTime(result, 0, 0, 0, 0, 0).
  11. If unit is "minute", then
    1. Return BalanceTime(hour, result, 0, 0, 0, 0).
  12. If unit is "second", then
    1. Return BalanceTime(hour, minute, result, 0, 0, 0).
  13. If unit is "millisecond", then
    1. Return BalanceTime(hour, minute, second, result, 0, 0).
  14. If unit is "microsecond", then
    1. Return BalanceTime(hour, minute, second, millisecond, result, 0).
  15. Assert: unit is "nanosecond".
  16. Return BalanceTime(hour, minute, second, millisecond, microsecond, result).

4.5.15 DifferenceTemporalPlainTime ( operation, temporalTime, other, options )

The abstract operation DifferenceTemporalPlainTime takes arguments operation (since or until), temporalTime (a Temporal.PlainTime), other (an ECMAScript language value), and options (an ECMAScript language value) and returns either a normal completion containing a Temporal.Duration or a throw completion. It computes the difference between the two times represented by temporalTime and other, optionally rounds it, and returns it as a Temporal.Duration object. It performs the following steps when called:

  1. If operation is since, let sign be -1. Otherwise, let sign be 1.
  2. Set other to ? ToTemporalTime(other).
  3. Let resolvedOptions be ? GetOptionsObject(options).
  4. Let settings be ? GetDifferenceSettings(operation, resolvedOptions, time, « », "nanosecond", "hour").
  5. Let norm be DifferenceTime(temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]], other.[[ISOHour]], other.[[ISOMinute]], other.[[ISOSecond]], other.[[ISOMillisecond]], other.[[ISOMicrosecond]], other.[[ISONanosecond]]).
  6. If settings.[[SmallestUnit]] is not "nanosecond" or settings.[[RoundingIncrement]] ≠ 1, then
    1. Let roundRecord be ! RoundTimeDuration(0, norm, settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
    2. Set norm to roundRecord.[[NormalizedDuration]].[[NormalizedTime]].
  7. Let result be ! BalanceTimeDuration(norm, settings.[[LargestUnit]]).
  8. Return ! CreateTemporalDuration(0, 0, 0, 0, sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]).

4.5.16 AddDurationToOrSubtractDurationFromPlainTime ( operation, temporalTime, temporalDurationLike )

The abstract operation AddDurationToOrSubtractDurationFromPlainTime takes arguments operation (add or subtract), temporalTime (a Temporal.PlainTime), and temporalDurationLike (an ECMAScript language value) and returns either a normal completion containing a Temporal.PlainTime or a throw completion. It adds/subtracts temporalDurationLike to/from temporalTime, returning a point in time that is in the future/past relative to temporalTime. It performs the following steps when called:

  1. If operation is subtract, let sign be -1. Otherwise, let sign be 1.
  2. Let duration be ? ToTemporalDurationRecord(temporalDurationLike).
  3. Let norm be NormalizeTimeDuration(sign × duration.[[Hours]], sign × duration.[[Minutes]], sign × duration.[[Seconds]], sign × duration.[[Milliseconds]], sign × duration.[[Microseconds]], sign × duration.[[Nanoseconds]]).
  4. Let result be AddTime(temporalTime.[[ISOHour]], temporalTime.[[ISOMinute]], temporalTime.[[ISOSecond]], temporalTime.[[ISOMillisecond]], temporalTime.[[ISOMicrosecond]], temporalTime.[[ISONanosecond]], norm).
  5. Return ! CreateTemporalTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]).

5 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.

5.1 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.

5.1.1 Temporal.PlainDateTime ( isoYear, isoMonth, isoDay [ , hour [ , minute [ , second [ , millisecond [ , microsecond [ , nanosecond [ , calendar ] ] ] ] ] ] ] )

This function performs the following steps when called:

  1. If NewTarget is undefined, then
    1. Throw a TypeError exception.
  2. Set isoYear to ? ToIntegerWithTruncation(isoYear).
  3. Set isoMonth to ? ToIntegerWithTruncation(isoMonth).
  4. Set isoDay to ? ToIntegerWithTruncation(isoDay).
  5. If hour is undefined, set hour to 0; else set hour to ? ToIntegerWithTruncation(hour).
  6. If minute is undefined, set minute to 0; else set minute to ? ToIntegerWithTruncation(minute).
  7. If second is undefined, set second to 0; else set second to ? ToIntegerWithTruncation(second).
  8. If millisecond is undefined, set millisecond to 0; else set millisecond to ? ToIntegerWithTruncation(millisecond).
  9. If microsecond is undefined, set microsecond to 0; else set microsecond to ? ToIntegerWithTruncation(microsecond).
  10. If nanosecond is undefined, set nanosecond to 0; else set nanosecond to ? ToIntegerWithTruncation(nanosecond).
  11. If calendar is undefined, set calendar to "iso8601".
  12. If calendar is not a String, throw a TypeError exception.
  13. If IsBuiltinCalendar(calendar) is false, throw a RangeError exception.
  14. Set calendar to CanonicalizeUValue("ca", calendar).
  15. Return ? CreateTemporalDateTime(isoYear, isoMonth, isoDay, hour, minute, second, millisecond, microsecond, nanosecond, calendar, NewTarget).

5.2 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:

5.2.1 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 }.

5.2.2 Temporal.PlainDateTime.from ( item [ , options ] )

This function performs the following steps when called:

  1. If item is an Object and item has an [[InitializedTemporalDateTime]] internal slot, then
    1. Set options to ? GetOptionsObject(options).
    2. Perform ? GetTemporalOverflowOption(options).
    3. Return ! CreateTemporalDateTime(item.[[ISOYear]], item.[[ISOMonth]], item.[[ISODay]], item.[[ISOHour]], item.[[ISOMinute]], item.[[ISOSecond]], item.[[ISOMillisecond]], item.[[ISOMicrosecond]], item.[[ISONanosecond]], item.[[Calendar]]).
  2. Return ? ToTemporalDateTime(item, options).

5.2.3 Temporal.PlainDateTime.compare ( one, two )

This function performs the following steps when called:

  1. Set one to ? ToTemporalDateTime(one).
  2. Set two to ? ToTemporalDateTime(two).
  3. Return 𝔽(CompareISODateTime(one.[[ISOYear]], one.[[ISOMonth]], one.[[ISODay]], one.[[ISOHour]], one.[[ISOMinute]], one.[[ISOSecond]], one.[[ISOMillisecond]], one.[[ISOMicrosecond]], one.[[ISONanosecond]], two.[[ISOYear]], two.[[ISOMonth]], two.[[ISODay]], two.[[ISOHour]], two.[[ISOMinute]], two.[[ISOSecond]], two.[[ISOMillisecond]], two.[[ISOMicrosecond]], two.[[ISONanosecond]])).

5.3 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%.
Note
An ECMAScript implementation that includes the ECMA-402 Internationalization API extends this prototype with additional properties in order to represent calendar data.

5.3.1 Temporal.PlainDateTime.prototype.constructor

The initial value of Temporal.PlainDateTime.prototype.constructor is %Temporal.PlainDateTime%.

5.3.2 Temporal.PlainDateTime.prototype[ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Temporal.PlainDateTime".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

5.3.3 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return dateTime.[[Calendar]].

5.3.4 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.
  2. Perform ? RequireInternalSlot(plainDateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(plainDateTime).
  4. Return CalendarEra(plainDateTime.[[Calendar]], isoDate).

5.3.5 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.
  2. Perform ? RequireInternalSlot(plainDateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(plainDateTime).
  4. Let result be CalendarEraYear(plainDateTime.[[Calendar]], isoDate).
  5. If result is undefined, return undefined.
  6. Return 𝔽(result).

5.3.6 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(dateTime).
  4. Return 𝔽(CalendarYear(dateTime.[[Calendar]], isoDate)).

5.3.7 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(dateTime).
  4. Return 𝔽(CalendarMonth(dateTime.[[Calendar]], isoDate)).

5.3.8 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(dateTime).
  4. Return CalendarMonthCode(dateTime.[[Calendar]], isoDate).

5.3.9 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(dateTime).
  4. Return 𝔽(CalendarDay(dateTime.[[Calendar]], isoDate)).

5.3.10 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return 𝔽(dateTime.[[ISOHour]]).

5.3.11 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return 𝔽(dateTime.[[ISOMinute]]).

5.3.12 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return 𝔽(dateTime.[[ISOSecond]]).

5.3.13 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return 𝔽(dateTime.[[ISOMillisecond]]).

5.3.14 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return 𝔽(dateTime.[[ISOMicrosecond]]).

5.3.15 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return 𝔽(dateTime.[[ISONanosecond]]).

5.3.16 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(dateTime).
  4. Return 𝔽(CalendarDayOfWeek(dateTime.[[Calendar]], isoDate)).

5.3.17 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(dateTime).
  4. Return 𝔽(CalendarDayOfYear(dateTime.[[Calendar]], isoDate)).

5.3.18 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(dateTime).
  4. Let result be CalendarWeekOfYear(dateTime.[[Calendar]], isoDate).
  5. If result is undefined, return undefined.
  6. Return 𝔽(result).

5.3.19 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(dateTime).
  4. Let result be CalendarYearOfWeek(dateTime.[[Calendar]], isoDate).
  5. If result is undefined, return undefined.
  6. Return 𝔽(result).

5.3.20 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(dateTime).
  4. Return 𝔽(CalendarDaysInWeek(dateTime.[[Calendar]], isoDate)).

5.3.21 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(dateTime).
  4. Return 𝔽(CalendarDaysInMonth(dateTime.[[Calendar]], isoDate)).

5.3.22 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(dateTime).
  4. Return 𝔽(CalendarDaysInYear(dateTime.[[Calendar]], isoDate)).

5.3.23 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(dateTime).
  4. Return 𝔽(CalendarMonthsInYear(dateTime.[[Calendar]], isoDate)).

5.3.24 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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let isoDate be TemporalObjectToISODateRecord(dateTime).
  4. Return CalendarInLeapYear(dateTime.[[Calendar]], isoDate).

5.3.25 Temporal.PlainDateTime.prototype.with ( temporalDateTimeLike [ , options ] )

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. If ? IsPartialTemporalObject(temporalDateTimeLike) is false, throw a TypeError exception.
  4. Let calendar be dateTime.[[Calendar]].
  5. Let fields be TemporalObjectToFields(dateTime).
  6. Set fields.[[Hour]] to dateTime.[[ISOHour]].
  7. Set fields.[[Minute]] to dateTime.[[ISOMinute]].
  8. Set fields.[[Second]] to dateTime.[[ISOSecond]].
  9. Set fields.[[Millisecond]] to dateTime.[[ISOMillisecond]].
  10. Set fields.[[Microsecond]] to dateTime.[[ISOMicrosecond]].
  11. Set fields.[[Nanosecond]] to dateTime.[[ISONanosecond]].
  12. Let partialDateTime be ? PrepareCalendarFields(calendar, temporalDateTimeLike, « day, month, month-code, year », « hour, microsecond, millisecond, minute, nanosecond, second », partial).
  13. Set fields to CalendarMergeFields(calendar, fields, partialDateTime).
  14. Let resolvedOptions be ? GetOptionsObject(options).
  15. Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
  16. Let result be ? InterpretTemporalDateTimeFields(calendar, fields, overflow).
  17. Assert: IsValidISODate(result.[[Year]], result.[[Month]], result.[[Day]]) is true.
  18. Assert: IsValidTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]) is true.
  19. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], calendar).

5.3.26 Temporal.PlainDateTime.prototype.withPlainTime ( [ plainTimeLike ] )

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let plainTime be ? ToTemporalTimeOrMidnight(plainTimeLike).
  4. Return ? CreateTemporalDateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], plainTime.[[ISOHour]], plainTime.[[ISOMinute]], plainTime.[[ISOSecond]], plainTime.[[ISOMillisecond]], plainTime.[[ISOMicrosecond]], plainTime.[[ISONanosecond]], dateTime.[[Calendar]]).

5.3.27 Temporal.PlainDateTime.prototype.withCalendar ( calendarLike )

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let calendar be ? ToTemporalCalendarIdentifier(calendarLike).
  4. Return ? CreateTemporalDateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]], calendar).

5.3.28 Temporal.PlainDateTime.prototype.add ( temporalDurationLike [ , options ] )

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return ? AddDurationToOrSubtractDurationFromPlainDateTime(add, dateTime, temporalDurationLike, options).

5.3.29 Temporal.PlainDateTime.prototype.subtract ( temporalDurationLike [ , options ] )

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return ? AddDurationToOrSubtractDurationFromPlainDateTime(subtract, dateTime, temporalDurationLike, options).

5.3.30 Temporal.PlainDateTime.prototype.until ( other [ , options ] )

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return ? DifferenceTemporalPlainDateTime(until, dateTime, other, options).

5.3.31 Temporal.PlainDateTime.prototype.since ( other [ , options ] )

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return ? DifferenceTemporalPlainDateTime(since, dateTime, other, options).

5.3.32 Temporal.PlainDateTime.prototype.round ( roundTo )

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. If roundTo is undefined, then
    1. Throw a TypeError exception.
  4. If roundTo is a String, then
    1. Let paramString be roundTo.
    2. Set roundTo to OrdinaryObjectCreate(null).
    3. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString).
  5. Else,
    1. Set roundTo to ? GetOptionsObject(roundTo).
  6. NOTE: The following steps read options and perform independent validation in alphabetical order (ToTemporalRoundingIncrement reads "roundingIncrement" and ToTemporalRoundingMode reads "roundingMode").
  7. Let roundingIncrement be ? GetRoundingIncrementOption(roundTo).
  8. Let roundingMode be ? GetRoundingModeOption(roundTo, "halfExpand").
  9. Let smallestUnit be ? GetTemporalUnitValuedOption(roundTo, "smallestUnit", time, required, « "day" »).
  10. If smallestUnit is "day", then
    1. Let maximum be 1.
    2. Let inclusive be true.
  11. Else,
    1. Let maximum be MaximumTemporalDurationRoundingIncrement(smallestUnit).
    2. Assert: maximum is not undefined.
    3. Let inclusive be false.
  12. Perform ? ValidateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive).
  13. If smallestUnit is "nanosecond" and roundingIncrement = 1, then
    1. Return ! CreateTemporalDateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]], dateTime.[[Calendar]]).
  14. Let result be RoundISODateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]], roundingIncrement, smallestUnit, roundingMode).
  15. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], dateTime.[[Calendar]]).

5.3.33 Temporal.PlainDateTime.prototype.equals ( other )

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Set other to ? ToTemporalDateTime(other).
  4. Let result be CompareISODateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]], other.[[ISOYear]], other.[[ISOMonth]], other.[[ISODay]], other.[[ISOHour]], other.[[ISOMinute]], other.[[ISOSecond]], other.[[ISOMillisecond]], other.[[ISOMicrosecond]], other.[[ISONanosecond]]).
  5. If result is not 0, return false.
  6. Return CalendarEquals(dateTime.[[Calendar]], other.[[Calendar]]).

5.3.34 Temporal.PlainDateTime.prototype.toString ( [ options ] )

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Set options to ? GetOptionsObject(options).
  4. NOTE: The following steps read options and perform independent validation in alphabetical order (ToCalendarNameOption reads "calendarName", ToFractionalSecondDigits reads "fractionalSecondDigits", and ToTemporalRoundingMode reads "roundingMode").
  5. Let showCalendar be ? GetTemporalShowCalendarNameOption(options).
  6. Let digits be ? GetTemporalFractionalSecondDigitsOption(options).
  7. Let roundingMode be ? GetRoundingModeOption(options, "trunc").
  8. Let smallestUnit be ? GetTemporalUnitValuedOption(options, "smallestUnit", time, undefined).
  9. If smallestUnit is "hour", throw a RangeError exception.
  10. Let precision be ToSecondsStringPrecisionRecord(smallestUnit, digits).
  11. Let result be RoundISODateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]], precision.[[Increment]], precision.[[Unit]], roundingMode).
  12. If ISODateTimeWithinLimits(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]) is false, throw a RangeError exception.
  13. Return TemporalDateTimeToString(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], dateTime.[[Calendar]], precision.[[Precision]], showCalendar).

5.3.35 Temporal.PlainDateTime.prototype.toLocaleString ( [ locales [ , options ] ] )

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 dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return TemporalDateTimeToString(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]], dateTime.[[Calendar]], "auto", "auto").

5.3.36 Temporal.PlainDateTime.prototype.toJSON ( )

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return TemporalDateTimeToString(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]], dateTime.[[Calendar]], "auto", "auto").

5.3.37 Temporal.PlainDateTime.prototype.valueOf ( )

This method performs the following steps when called:

  1. Throw a TypeError exception.
Note

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().

5.3.38 Temporal.PlainDateTime.prototype.toZonedDateTime ( temporalTimeZoneLike [ , options ] )

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let timeZone be ? ToTemporalTimeZoneIdentifier(temporalTimeZoneLike).
  4. Set options to ? GetOptionsObject(options).
  5. Let disambiguation be ? GetTemporalDisambiguationOption(options).
  6. Let isoDateTime be PlainDateTimeToISODateTimeRecord(dateTime).
  7. Let epochNs be ? GetEpochNanosecondsFor(timeZone, isoDateTime, disambiguation).
  8. Return ! CreateTemporalZonedDateTime(epochNs, timeZone, dateTime.[[Calendar]]).

5.3.39 Temporal.PlainDateTime.prototype.toPlainDate ( )

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return ! CreateTemporalDate(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[Calendar]]).

5.3.40 Temporal.PlainDateTime.prototype.toPlainTime ( )

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Return ! CreateTemporalTime(dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]]).

5.4 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 Table 6.

Table 6: Internal Slots of Temporal.PlainDateTime Instances
Internal Slot Description
[[InitializedTemporalDateTime]] The only specified use of this slot is for distinguishing Temporal.PlainDateTime instances from other objects.
[[ISOYear]] An integer representing the year in the ISO 8601 calendar.
[[ISOMonth]] An integer between 1 and 12, inclusive, representing the month of the year in the ISO 8601 calendar.
[[ISODay]] An integer between 1 and ISODaysInMonth([[ISOYear]], [[ISOMonth]]), inclusive, representing the day of the month in the ISO 8601 calendar.
[[ISOHour]] An integer between 0 and 23, inclusive, representing the hour of the day.
[[ISOMinute]] An integer between 0 and 59, inclusive, representing the minute of the hour.
[[ISOSecond]] An integer between 0 and 59, inclusive, representing the second within the minute.
[[ISOMillisecond]] An integer between 0 and 999, inclusive, representing the millisecond within the second.
[[ISOMicrosecond]] An integer between 0 and 999, inclusive, representing the microsecond within the millisecond.
[[ISONanosecond]] An integer between 0 and 999, inclusive, representing the nanosecond within the microsecond.
[[Calendar]] A String representing the calendar.

5.5 Abstract Operations

5.5.1 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.[[Year]], r.[[Month]], r.[[Day]]) must return true, and IsValidTime(r.[[Hour]], r.[[Minute]], r.[[Second]], r.[[Millisecond]], r.[[Microsecond]], r.[[Nanosecond]]) must return true. It is not necessary for ISODateTimeWithinLimits(r.[[Year]], r.[[Month]], r.[[Day]], r.[[Hour]], r.[[Minute]], r.[[Second]], r.[[Millisecond]], r.[[Microsecond]], r.[[Nanosecond]]) to return true.

ISO Date-Time Records have the fields listed in Table 7.

Table 7: ISO Date-Time Record Fields
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.
[[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.

5.5.2 PlainDateTimeToISODateTimeRecord ( plainDateTime )

The abstract operation PlainDateTimeToISODateTimeRecord takes argument plainDateTime (a Temporal.PlainDateTime) and returns an ISO Date-Time Record. It performs the following steps when called:

  1. Return ISO Date-Time Record { [[Year]]: plainDateTime.[[ISOYear]], [[Month]]: plainDateTime.[[ISOMonth]], [[Day]]: plainDateTime.[[ISODay]], [[Hour]]: plainDateTime.[[ISOHour]], [[Minute]]: plainDateTime.[[ISOMinute]], [[Second]]: plainDateTime.[[ISOSecond]], [[Millisecond]]: plainDateTime.[[ISOMillisecond]], [[Microsecond]]: plainDateTime.[[ISOMicrosecond]], [[Nanosecond]]: plainDateTime.[[ISONanosecond]] }.

5.5.3 CombineISODateAndTimeRecord ( isoDate, time )

The abstract operation CombineISODateAndTimeRecord takes arguments isoDate (an ISO Date Record) and time (a Time Record or ISO Date-Time Record) and returns an ISO Date-Time Record. It combines an ISO Date Record and a time into one ISO Date-Time Record. The time may come from a Time Record or another ISO Date-Time Record. It performs the following steps when called:

  1. NOTE: time.[[Days]] is ignored.
  2. Return ISO Date-Time Record { [[Year]]: isoDate.[[Year]], [[Month]]: isoDate.[[Month]], [[Day]]: isoDate.[[Day]], [[Hour]]: time.[[Hour]], [[Minute]]: time.[[Minute]], [[Second]]: time.[[Second]], [[Millisecond]]: time.[[Millisecond]], [[Microsecond]]: time.[[Microsecond]], [[Nanosecond]]: time.[[Nanosecond]] }.

5.5.4 ISODateTimeWithinLimits ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond )

The abstract operation ISODateTimeWithinLimits takes arguments year (an integer), month (an integer between 1 and 12 inclusive), day (an integer between 1 and 31 inclusive), hour (an integer between 0 and 23 inclusive), minute (an integer between 0 and 59 inclusive), second (an integer between 0 and 59 inclusive), millisecond (an integer between 0 and 999 inclusive), microsecond (an integer between 0 and 999 inclusive), and nanosecond (an integer between 0 and 999 inclusive) and returns a Boolean. 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.

Note

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.

It performs the following steps when called:

  1. Assert: IsValidISODate(year, month, day) is true.
  2. If abs(ISODateToEpochDays(year, month - 1, day)) > 108 + 1, return false.
  3. Let ns be (GetUTCEpochNanoseconds(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond)).
  4. If nsnsMinInstant - nsPerDay, then
    1. Return false.
  5. If nsnsMaxInstant + nsPerDay, then
    1. Return false.
  6. Return true.

5.5.5 InterpretTemporalDateTimeFields ( calendar, fields, overflow )

The abstract operation InterpretTemporalDateTimeFields takes arguments calendar (a String), fields (a Calendar Fields Record), and overflow ("constrain" or "reject") and returns either a normal completion containing an ISO Date-Time Record or a throw completion. It interprets the date/time fields in the object fields using the given calendar, and returns a Record with the fields according to the ISO 8601 calendar. It performs the following steps when called:

  1. Let isoDate be ? CalendarDateFromFields(calendar, fields, overflow).
  2. Let time be ? RegulateTime(fields.[[Hour]], fields.[[Minute]], fields.[[Second]], fields.[[Millisecond]], fields.[[Microsecond]], fields.[[Nanosecond]], overflow).
  3. Return CombineISODateAndTimeRecord(isoDate, time).

5.5.6 ToTemporalDateTime ( item [ , options ] )

The abstract operation ToTemporalDateTime takes argument item (an ECMAScript language value) and optional argument options (an ECMAScript language value) and returns either a normal completion containing a Temporal.PlainDateTime or a throw completion. It returns its argument item if it is already a Temporal.PlainDateTime instance, converts item to a new Temporal.PlainDateTime instance if possible, and throws otherwise. It performs the following steps when called:

  1. If options is not present, set options to undefined.
  2. If item is an Object, then
    1. If item has an [[InitializedTemporalDateTime]] internal slot, then
      1. Set options to ? GetOptionsObject(options).
      2. Perform ? GetTemporalOverflowOption(options).
      3. Return item.
    2. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
      1. Let isoDateTime be GetISODateTimeFor(item.[[TimeZone]], item.[[Nanoseconds]]).
      2. Set options to ? GetOptionsObject(options).
      3. Perform ? GetTemporalOverflowOption(options).
      4. Return ! CreateTemporalDateTime(isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]], isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]], item.[[Calendar]]).
    3. If item has an [[InitializedTemporalDate]] internal slot, then
      1. Set options to ? GetOptionsObject(options).
      2. Perform ? GetTemporalOverflowOption(options).
      3. Return ? CreateTemporalDateTime(item.[[ISOYear]], item.[[ISOMonth]], item.[[ISODay]], 0, 0, 0, 0, 0, 0, item.[[Calendar]]).
    4. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(item).
    5. Let fields be ? PrepareCalendarFields(calendar, item, « day, month, month-code, year », « hour, microsecond, millisecond, minute, nanosecond, second », «»).
    6. Set options to ? GetOptionsObject(options).
    7. Let overflow be ? GetTemporalOverflowOption(options).
    8. Let result be ? InterpretTemporalDateTimeFields(calendar, fields, overflow).
  3. Else,
    1. If item is not a String, throw a TypeError exception.
    2. Let result be ? ParseTemporalDateTimeString(item).
    3. Assert: IsValidISODate(result.[[Year]], result.[[Month]], result.[[Day]]) is true.
    4. Assert: IsValidTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]) is true.
    5. Let calendar be result.[[Calendar]].
    6. If calendar is empty, set calendar to "iso8601".
    7. If IsBuiltinCalendar(calendar) is false, throw a RangeError exception.
    8. Set calendar to CanonicalizeUValue("ca", calendar).
    9. Set options to ? GetOptionsObject(options).
    10. Perform ? GetTemporalOverflowOption(options).
  4. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], calendar).

5.5.7 BalanceISODateTime ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond )

The abstract operation BalanceISODateTime takes arguments year (an integer), month (an integer), day (an integer), hour (an integer), minute (an integer), second (an integer), millisecond (an integer), microsecond (an integer), and nanosecond (an integer) and returns an ISO Date-Time Record. It performs the following steps when called:

  1. Let balancedTime be BalanceTime(hour, minute, second, millisecond, microsecond, nanosecond).
  2. Let balancedDate be BalanceISODate(year, month, day + balancedTime.[[Days]]).
  3. Return CombineISODateAndTimeRecord(balancedDate, balancedTime).

5.5.8 CreateTemporalDateTime ( isoYear, isoMonth, isoDay, hour, minute, second, millisecond, microsecond, nanosecond, calendar [ , newTarget ] )

The abstract operation CreateTemporalDateTime takes arguments isoYear (an integer), isoMonth (an integer), isoDay (an integer), hour (an integer), minute (an integer), second (an integer), millisecond (an integer), microsecond (an integer), nanosecond (an integer), and calendar (a String or Object) and optional argument newTarget (a constructor) and returns either a normal completion containing a Temporal.PlainDateTime or a throw completion. It creates a Temporal.PlainDateTime instance and fills the internal slots with valid values. It performs the following steps when called:

  1. If IsValidISODate(isoYear, isoMonth, isoDay) is false, throw a RangeError exception.
  2. If IsValidTime(hour, minute, second, millisecond, microsecond, nanosecond) is false, throw a RangeError exception.
  3. If ISODateTimeWithinLimits(isoYear, isoMonth, isoDay, hour, minute, second, millisecond, microsecond, nanosecond) is false, then
    1. Throw a RangeError exception.
  4. If newTarget is not present, set newTarget to %Temporal.PlainDateTime%.
  5. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.PlainDateTime.prototype%", « [[InitializedTemporalDateTime]], [[ISOYear]], [[ISOMonth]], [[ISODay]], [[ISOHour]], [[ISOMinute]], [[ISOSecond]], [[ISOMillisecond]], [[ISOMicrosecond]], [[ISONanosecond]], [[Calendar]] »).
  6. Set object.[[ISOYear]] to isoYear.
  7. Set object.[[ISOMonth]] to isoMonth.
  8. Set object.[[ISODay]] to isoDay.
  9. Set object.[[ISOHour]] to hour.
  10. Set object.[[ISOMinute]] to minute.
  11. Set object.[[ISOSecond]] to second.
  12. Set object.[[ISOMillisecond]] to millisecond.
  13. Set object.[[ISOMicrosecond]] to microsecond.
  14. Set object.[[ISONanosecond]] to nanosecond.
  15. Set object.[[Calendar]] to calendar.
  16. Return object.

5.5.9 TemporalDateTimeToString ( isoYear, isoMonth, isoDay, hour, minute, second, millisecond, microsecond, nanosecond, calendar, precision, showCalendar )

The abstract operation TemporalDateTimeToString takes arguments isoYear (an integer), isoMonth (an integer), isoDay (an integer), 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), calendar (a String or Object), precision (an integer in the inclusive interval from 0 to 9, "minute", or "auto"), and showCalendar ("auto", "always", "never", or "critical") and returns a String. It formats the internal slots of a Temporal.PlainDateTime into an ISO 8601 string, to the precision specified by precision. It performs the following steps when called:

  1. Assert: IsValidISODate(isoYear, isoMonth, isoDay) is true.
  2. Let yearString be PadISOYear(isoYear).
  3. Let monthString be ToZeroPaddedDecimalString(isoMonth, 2).
  4. Let dayString be ToZeroPaddedDecimalString(isoDay, 2).
  5. Let subSecondNanoseconds be millisecond × 106 + microsecond × 103 + nanosecond.
  6. Let timeString be FormatTimeString(hour, minute, second, subSecondNanoseconds, precision).
  7. Let calendarString be MaybeFormatCalendarAnnotation(calendar, showCalendar).
  8. 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.

5.5.10 CompareISODateTime ( y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2 )

The abstract operation CompareISODateTime takes arguments y1 (an integer), mon1 (an integer), d1 (an integer), h1 (an integer in the inclusive interval from 0 to 23), min1 (an integer in the inclusive interval from 0 to 59), s1 (an integer in the inclusive interval from 0 to 59), ms1 (an integer in the inclusive interval from 0 to 999), mus1 (an integer in the inclusive interval from 0 to 999), ns1 (an integer in the inclusive interval from 0 to 999), y2 (an integer), mon2 (an integer), d2 (an integer), h2 (an integer in the inclusive interval from 0 to 23), min2 (an integer in the inclusive interval from 0 to 59), s2 (an integer in the inclusive interval from 0 to 59), ms2 (an integer in the inclusive interval from 0 to 999), mus2 (an integer in the inclusive interval from 0 to 999), and ns2 (an integer in the inclusive interval from 0 to 999) and returns -1, 0, or 1. It performs a comparison of two date-times according to ISO 8601 calendar arithmetic. It performs the following steps when called:

  1. Assert: IsValidISODate(y1, mon1, d1) is true.
  2. Assert: IsValidISODate(y2, mon2, d2) is true.
  3. Let dateResult be CompareISODate(y1, mon1, d1, y2, mon2, d2).
  4. If dateResult is not 0, then
    1. Return dateResult.
  5. Return CompareTemporalTime(h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, ns2).

5.5.11 AddDateTime ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, calendar, years, months, weeks, days, norm, overflow )

The abstract operation AddDateTime takes arguments year (an integer), month (an integer), day (an integer), 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), calendar (a String), years (an integer), months (an integer), weeks (an integer), days (an integer), norm (a Normalized Time Duration Record), and overflow ("constrain" or "reject") and returns either a normal completion containing an ISO Date-Time Record or a throw completion. It adds a duration to a combined date and time, according to the reckoning of the given calendar, and returns the result as a Record. It performs the following steps when called:

  1. Assert: IsValidISODate(year, month, day) is true.
  2. Assert: ISODateTimeWithinLimits(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond) is true.
  3. Let timeResult be AddTime(hour, minute, second, millisecond, microsecond, nanosecond, norm).
  4. Let datePart be CreateISODateRecord(year, month, day).
  5. If IsValidDuration(years, months, weeks, days + timeResult.[[Days]], 0, 0, 0, 0, 0, 0) is false, throw a RangeError exception.
  6. Let dateDuration be ? CreateDateDurationRecord(years, months, weeks, days + timeResult.[[Days]]).
  7. Let addedDate be ? CalendarDateAdd(calendar, datePart, dateDuration, overflow).
  8. Return CombineISODateAndTimeRecord(addedDate, timeResult).

5.5.12 RoundISODateTime ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, increment, unit, roundingMode )

The abstract operation RoundISODateTime takes arguments year (an integer), month (an integer), day (an integer), 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), increment (a positive integer), unit ("day", "hour", "minute", "second", "millisecond", "microsecond", or "nanosecond"), and roundingMode (a String from the "Identifier" column of Table 22) and returns an ISO Date-Time Record. It rounds the time part of a combined date and time, carrying over any excess into the date part. It performs the following steps when called:

  1. Assert: IsValidISODate(year, month, day) is true.
  2. Assert: ISODateTimeWithinLimits(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond) is true.
  3. Let roundedTime be RoundTime(hour, minute, second, millisecond, microsecond, nanosecond, increment, unit, roundingMode).
  4. Let balanceResult be BalanceISODate(year, month, day + roundedTime.[[Days]]).
  5. Return CombineISODateAndTimeRecord(balanceResult, roundedTime).

5.5.13 DifferenceISODateTime ( y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2, calendar, largestUnit )

The abstract operation DifferenceISODateTime takes arguments y1 (an integer), mon1 (an integer between 1 and 12 inclusive), d1 (an integer between 1 and 31 inclusive), h1 (an integer between 0 and 23 inclusive), min1 (an integer between 0 and 59 inclusive), s1 (an integer between 0 and 59 inclusive), ms1 (an integer between 0 and 999 inclusive), mus1 (an integer between 0 and 999 inclusive), ns1 (an integer between 0 and 999 inclusive), y2 (an integer), mon2 (an integer between 1 and 12 inclusive), d2 (an integer between 1 and 31 inclusive), h2 (an integer between 0 and 23 inclusive), min2 (an integer between 0 and 59 inclusive), s2 (an integer between 0 and 59 inclusive), ms2 (an integer between 0 and 999 inclusive), mus2 (an integer between 0 and 999 inclusive), ns2 (an integer between 0 and 999 inclusive), calendar (a String), and largestUnit (a String) and returns either a normal completion containing a Normalized Duration Record or a throw completion. The returned 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. It performs the following steps when called:

  1. Assert: ISODateTimeWithinLimits(y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1) is true.
  2. Assert: ISODateTimeWithinLimits(y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2) is true.
  3. Let timeDuration be DifferenceTime(h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, ns2).
  4. Let timeSign be NormalizedTimeDurationSign(timeDuration).
  5. Let dateSign be CompareISODate(y2, mon2, d2, y1, mon1, d1).
  6. Let adjustedDate be CreateISODateRecord(y2, mon2, d2).
  7. If timeSign = -dateSign, then
    1. Set adjustedDate to BalanceISODate(adjustedDate.[[Year]], adjustedDate.[[Month]], adjustedDate.[[Day]] + timeSign).
    2. Set timeDuration to ? Add24HourDaysToNormalizedTimeDuration(timeDuration, -timeSign).
  8. Let date1 be CreateISODateRecord(y1, mon1, d1).
  9. Let date2 be adjustedDate.
  10. Let dateLargestUnit be LargerOfTwoTemporalUnits("day", largestUnit).
  11. Let dateDifference be CalendarDateUntil(calendar, date1, date2, dateLargestUnit).
  12. Let days be dateDifference.[[Days]].
  13. If largestUnit is not dateLargestUnit, then
    1. Set timeDuration to ? Add24HourDaysToNormalizedTimeDuration(timeDuration, dateDifference.[[Days]]).
    2. Set days to 0.
  14. Return ? CreateNormalizedDurationRecord(dateDifference.[[Years]], dateDifference.[[Months]], dateDifference.[[Weeks]], days, timeDuration).

5.5.14 DifferencePlainDateTimeWithRounding ( y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2, calendar, largestUnit, roundingIncrement, smallestUnit, roundingMode )

The abstract operation DifferencePlainDateTimeWithRounding takes arguments y1 (an integer), mon1 (an integer), d1 (an integer), h1 (an integer in the inclusive interval from 0 to 23), min1 (an integer in the inclusive interval from 0 to 59), s1 (an integer in the inclusive interval from 0 to 59), ms1 (an integer in the inclusive interval from 0 to 999), mus1 (an integer in the inclusive interval from 0 to 999), ns1 (an integer in the inclusive interval from 0 to 999), y2 (an integer), mon2 (an integer), d2 (an integer), h2 (an integer in the inclusive interval from 0 to 23), min2 (an integer in the inclusive interval from 0 to 59), s2 (an integer in the inclusive interval from 0 to 59), ms2 (an integer in the inclusive interval from 0 to 999), mus2 (an integer in the inclusive interval from 0 to 999), ns2 (an integer in the inclusive interval from 0 to 999), calendar (a String), largestUnit (a String etc), roundingIncrement (a positive integer), smallestUnit (a String), and roundingMode (a String) and returns either a normal completion containing a Record with fields [[DurationRecord]] (a Duration Record) and [[Total]] (a mathematical value), or a throw completion. It performs the following steps when called:

  1. Assert: IsValidISODate(y1, mon1, d1) is true.
  2. Assert: IsValidISODate(y2, mon2, d2) is true.
  3. If CompareISODateTime(y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2) = 0, then
    1. Let durationRecord be CreateDurationRecord(0, 0, 0, 0, 0, 0, 0, 0, 0, 0).
    2. Return the Record { [[DurationRecord]]: durationRecord, [[Total]]: 0 }.
  4. Let diff be ? DifferenceISODateTime(y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2, calendar, largestUnit).
  5. If smallestUnit is "nanosecond" and roundingIncrement = 1, then
    1. Let normWithDays be ? Add24HourDaysToNormalizedTimeDuration(diff.[[NormalizedTime]], diff.[[Days]]).
    2. Let timeResult be ! BalanceTimeDuration(normWithDays, largestUnit).
    3. Let total be NormalizedTimeDurationSeconds(normWithDays) × 109 + NormalizedTimeDurationSubseconds(normWithDays).
    4. Let durationRecord be CreateDurationRecord(diff.[[Years]], diff.[[Months]], diff.[[Weeks]], timeResult.[[Days]], timeResult.[[Hours]], timeResult.[[Minutes]], timeResult.[[Seconds]], timeResult.[[Milliseconds]], timeResult.[[Microseconds]], timeResult.[[Nanoseconds]]).
    5. Return the Record { [[DurationRecord]]: durationRecord, [[Total]]: total }.
  6. Let dateTime be ISO Date-TimeRecord { [[Year]]: y1, [[Month]]: mon1, [[Day]]: d1, [[Hour]]: h1, [[Minute]]: min1, [[Second]]: s1, [[Millisecond]]: ms1, [[Microsecond]]: mus1, [[Nanosecond]]: ns1 }.
  7. Let destEpochNs be GetUTCEpochNanoseconds(y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2).
  8. Return ? RoundRelativeDuration(diff, destEpochNs, dateTime, calendar, unset, largestUnit, roundingIncrement, smallestUnit, roundingMode).

5.5.15 DifferenceTemporalPlainDateTime ( operation, dateTime, other, options )

The abstract operation DifferenceTemporalPlainDateTime takes arguments operation (since or until), dateTime (a Temporal.PlainDateTime), other (an ECMAScript language value), and options (an ECMAScript language value) and returns either a normal completion containing a Temporal.Duration or a throw completion. It computes the difference between the two times represented by dateTime and other, optionally rounds it, and returns it as a Temporal.Duration object. It performs the following steps when called:

  1. If operation is since, let sign be -1. Otherwise, let sign be 1.
  2. Set other to ? ToTemporalDateTime(other).
  3. If CalendarEquals(dateTime.[[Calendar]], other.[[Calendar]]) is false, throw a RangeError exception.
  4. Let resolvedOptions be ? GetOptionsObject(options).
  5. Let settings be ? GetDifferenceSettings(operation, resolvedOptions, datetime, « », "nanosecond", "day").
  6. If dateTime.[[ISOYear]] = other.[[ISOYear]], and dateTime.[[ISOMonth]] = other.[[ISOMonth]], and dateTime.[[ISODay]] = other.[[ISODay]], and dateTime.[[ISOHour]] = other.[[ISOHour]], and dateTime.[[ISOMinute]] = other.[[ISOMinute]], and dateTime.[[ISOSecond]] = other.[[ISOSecond]], and dateTime.[[ISOMillisecond]] = other.[[ISOMillisecond]], and dateTime.[[ISOMicrosecond]] = other.[[ISOMicrosecond]], and dateTime.[[ISONanosecond]] = other.[[ISONanosecond]], then
    1. Return ! CreateTemporalDuration(0, 0, 0, 0, 0, 0, 0, 0, 0, 0).
  7. Let plainDate be ! CreateTemporalDate(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[Calendar]]).
  8. Let resultRecord be ? DifferencePlainDateTimeWithRounding(plainDate.[[ISOYear]], plainDate.[[ISOMonth]], plainDate.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]], other.[[ISOYear]], other.[[ISOMonth]], other.[[ISODay]], other.[[ISOHour]], other.[[ISOMinute]], other.[[ISOSecond]], other.[[ISOMillisecond]], other.[[ISOMicrosecond]], other.[[ISONanosecond]], dateTime.[[Calendar]], settings.[[LargestUnit]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
  9. Let result be resultRecord.[[DurationRecord]].
  10. Return ? CreateTemporalDuration(sign × result.[[Years]], sign × result.[[Months]], sign × result.[[Weeks]], sign × result.[[Days]], sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]).

5.5.16 AddDurationToOrSubtractDurationFromPlainDateTime ( operation, dateTime, temporalDurationLike, options )

The abstract operation AddDurationToOrSubtractDurationFromPlainDateTime takes arguments operation (add or subtract), dateTime (a Temporal.PlainDateTime), temporalDurationLike (an ECMAScript language value), and options (an ECMAScript language value) and returns either a normal completion containing a Temporal.PlainDateTime or a throw completion. It adds/subtracts temporalDurationLike to/from dateTime, returning a point in time that is in the future/past relative to datetime. It performs the following steps when called:

  1. If operation is subtract, let sign be -1. Otherwise, let sign be 1.
  2. Let duration be ? ToTemporalDurationRecord(temporalDurationLike).
  3. Set options to ? GetOptionsObject(options).
  4. Let overflow be ? GetTemporalOverflowOption(options).
  5. Let norm be NormalizeTimeDuration(sign × duration.[[Hours]], sign × duration.[[Minutes]], sign × duration.[[Seconds]], sign × duration.[[Milliseconds]], sign × duration.[[Microseconds]], sign × duration.[[Nanoseconds]]).
  6. Let result be ? AddDateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]], dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]], dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]], dateTime.[[ISONanosecond]], dateTime.[[Calendar]], sign × duration.[[Years]], sign × duration.[[Months]], sign × duration.[[Weeks]], sign × duration.[[Days]], norm, overflow).
  7. Assert: IsValidISODate(result.[[Year]], result.[[Month]], result.[[Day]]) is true.
  8. Assert: IsValidTime(result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]) is true.
  9. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], dateTime.[[Calendar]]).

6 Temporal.ZonedDateTime Objects

A Temporal.ZonedDateTime object is an Object referencing a fixed point in time with nanoseconds precision, and containing Object values corresponding to a particular time zone and calendar system.

6.1 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.

6.1.1 Temporal.ZonedDateTime ( epochNanoseconds, timeZone [ , calendar ] )

This function performs the following steps when called:

  1. If NewTarget is undefined, then
    1. Throw a TypeError exception.
  2. Set epochNanoseconds to ? ToBigInt(epochNanoseconds).
  3. If IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
  4. If timeZone is not a String, throw a TypeError exception.
  5. Let timeZoneParse be ? ParseTimeZoneIdentifier(timeZone).
  6. If timeZoneParse.[[OffsetMinutes]] is empty, then
    1. Let identifierRecord be GetAvailableNamedTimeZoneIdentifier(timeZoneParse.[[Name]]).
    2. If identifierRecord is empty, throw a RangeError exception.
    3. Set timeZone to identifierRecord.[[Identifier]].
  7. Else,
    1. Set timeZone to FormatOffsetTimeZoneIdentifier(timeZoneParse.[[OffsetMinutes]]).
  8. If calendar is undefined, set calendar to "iso8601".
  9. If calendar is not a String, throw a TypeError exception.
  10. If IsBuiltinCalendar(calendar) is false, throw a RangeError exception.
  11. Set calendar to CanonicalizeUValue("ca", calendar).
  12. Return ? CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar, NewTarget).

6.2 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:

6.2.1 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 }.

6.2.2 Temporal.ZonedDateTime.from ( item [ , options ] )

This function performs the following steps when called:

  1. If item is an Object and item has an [[InitializedTemporalZonedDateTime]] internal slot, then
    1. Set options to ? GetOptionsObject(options).
    2. Perform ? GetTemporalDisambiguationOption(options).
    3. Perform ? GetTemporalOffsetOption(options, "reject").
    4. Perform ? GetTemporalOverflowOption(options).
    5. Return ! CreateTemporalZonedDateTime(item.[[Nanoseconds]], item.[[TimeZone]], item.[[Calendar]]).
  2. Return ? ToTemporalZonedDateTime(item, options).

6.2.3 Temporal.ZonedDateTime.compare ( one, two )

This function performs the following steps when called:

  1. Set one to ? ToTemporalZonedDateTime(one).
  2. Set two to ? ToTemporalZonedDateTime(two).
  3. Return 𝔽(CompareEpochNanoseconds(one.[[Nanoseconds]], two.[[Nanoseconds]])).

6.3 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%.
Note
An ECMAScript implementation that includes the ECMA-402 Internationalization API extends this prototype with additional properties in order to represent calendar data.

6.3.1 Temporal.ZonedDateTime.prototype.constructor

The initial value of Temporal.ZonedDateTime.prototype.constructor is %Temporal.ZonedDateTime%.

6.3.2 Temporal.ZonedDateTime.prototype[ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Temporal.ZonedDateTime".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

6.3.3 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Return zonedDateTime.[[Calendar]].

6.3.4 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Return zonedDateTime.[[TimeZone]].

6.3.5 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return CalendarEra(zonedDateTime.[[Calendar]], isoDateTime).

6.3.6 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Let result be CalendarEraYear(zonedDateTime.[[Calendar]], isoDateTime).
  5. If result is undefined, return undefined.
  6. Return 𝔽(result).

6.3.7 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(CalendarYear(zonedDateTime.[[Calendar]], isoDateTime)).

6.3.8 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(CalendarMonth(zonedDateTime.[[Calendar]], isoDateTime)).

6.3.9 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return CalendarMonthCode(zonedDateTime.[[Calendar]], isoDateTime).

6.3.10 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(CalendarDay(zonedDateTime.[[Calendar]], isoDateTime)).

6.3.11 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(isoDateTime.[[Hour]]).

6.3.12 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(isoDateTime.[[Minute]]).

6.3.13 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(isoDateTime.[[Second]]).

6.3.14 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(isoDateTime.[[Millisecond]]).

6.3.15 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(isoDateTime.[[Microsecond]]).

6.3.16 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(isoDateTime.[[Nanosecond]]).

6.3.17 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let ns be zonedDateTime.[[Nanoseconds]].
  4. Let ms be floor((ns) / 106).
  5. Return 𝔽(ms).

6.3.18 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Return zonedDateTime.[[Nanoseconds]].

6.3.19 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(CalendarDayOfWeek(zonedDateTime.[[Calendar]], isoDateTime)).

6.3.20 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(CalendarDayOfYear(zonedDateTime.[[Calendar]], isoDateTime)).

6.3.21 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Let result be CalendarWeekOfYear(zonedDateTime.[[Calendar]], isoDateTime).
  5. If result is undefined, return undefined.
  6. Return 𝔽(result).

6.3.22 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Let result be CalendarYearOfWeek(zonedDateTime.[[Calendar]], isoDateTime).
  5. If result is undefined, return undefined.
  6. Return 𝔽(result).

6.3.23 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let timeZone be zonedDateTime.[[TimeZone]].
  4. Let isoDateTime be GetISODateTimeFor(timeZone, zonedDateTime.[[Nanoseconds]]).
  5. Let midnight be a Time Record with all fields set to 0.
  6. Let today be CombineISODateAndTimeRecord(isoDateTime, midnight).
  7. Let tomorrowISODate be BalanceISODate(today.[[Year]], today.[[Month]], today.[[Day]] + 1).
  8. Let tomorrow be CombineISODateAndTimeRecord(tomorrowISODate, midnight).
  9. Let todayNs be ? GetEpochNanosecondsFor(timeZone, today, "compatible").
  10. Let tomorrowNs be ? GetEpochNanosecondsFor(timeZone, tomorrow, "compatible").
  11. Let diff be NormalizedTimeDurationFromEpochNanosecondsDifference(tomorrowNs, todayNs).
  12. Return 𝔽(DivideNormalizedTimeDuration(diff, 3.6 × 1012)).

6.3.24 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(CalendarDaysInWeek(zonedDateTime.[[Calendar]], isoDateTime)).

6.3.25 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(CalendarDaysInMonth(zonedDateTime.[[Calendar]], isoDateTime)).

6.3.26 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(CalendarDaysInYear(zonedDateTime.[[Calendar]], isoDateTime)).

6.3.27 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return 𝔽(CalendarMonthsInYear(zonedDateTime.[[Calendar]], isoDateTime)).

6.3.28 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return CalendarInLeapYear(zonedDateTime.[[Calendar]], isoDateTime).

6.3.29 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Return 𝔽(GetOffsetNanosecondsFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]])).

6.3.30 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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let offsetNanoseconds be GetOffsetNanosecondsFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return FormatUTCOffsetNanoseconds(offsetNanoseconds).

6.3.31 Temporal.ZonedDateTime.prototype.with ( temporalZonedDateTimeLike [ , options ] )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. If ? IsPartialTemporalObject(temporalZonedDateTimeLike) is false, throw a TypeError exception.
  4. Let epochNs be zonedDateTime.[[Nanoseconds]].
  5. Let timeZone be zonedDateTime.[[TimeZone]].
  6. Let calendar be zonedDateTime.[[Calendar]].
  7. Let offsetNanoseconds be GetOffsetNanosecondsFor(timeZone, epochNs).
  8. Let isoDateTime be GetISODateTimeFor(timeZone, epochNs).
  9. Let fields be ISODateToFields(calendar, isoDateTime, date).
  10. Set fields.[[Hour]] to isoDateTime.[[Hour]].
  11. Set fields.[[Minute]] to isoDateTime.[[Minute]].
  12. Set fields.[[Second]] to isoDateTime.[[Second]].
  13. Set fields.[[Millisecond]] to isoDateTime.[[Millisecond]].
  14. Set fields.[[Microsecond]] to isoDateTime.[[Microsecond]].
  15. Set fields.[[Nanosecond]] to isoDateTime.[[Nanosecond]].
  16. Set fields.[[OffsetString]] to FormatUTCOffsetNanoseconds(offsetNanoseconds).
  17. Let partialZonedDateTime be ? PrepareCalendarFields(calendar, temporalZonedDateTimeLike, « day, month, month-code, year », « hour, microsecond, millisecond, minute, nanosecond, offset, second », partial).
  18. Set fields to CalendarMergeFields(calendar, fields, partialZonedDateTime).
  19. Let resolvedOptions be ? GetOptionsObject(options).
  20. Let disambiguation be ? GetTemporalDisambiguationOption(resolvedOptions).
  21. Let offset be ? GetTemporalOffsetOption(resolvedOptions, "prefer").
  22. Let overflow be ? GetTemporalOverflowOption(options).
  23. Let dateTimeResult be ? InterpretTemporalDateTimeFields(calendar, fields, overflow).
  24. Let newOffsetNanoseconds be ? ParseDateTimeUTCOffset(fields.[[OffsetString]]).
  25. Let epochNanoseconds be ? InterpretISODateTimeOffset(dateTimeResult.[[Year]], dateTimeResult.[[Month]], dateTimeResult.[[Day]], dateTimeResult.[[Hour]], dateTimeResult.[[Minute]], dateTimeResult.[[Second]], dateTimeResult.[[Millisecond]], dateTimeResult.[[Microsecond]], dateTimeResult.[[Nanosecond]], option, newOffsetNanoseconds, timeZone, disambiguation, offset, match-exactly).
  26. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).

6.3.32 Temporal.ZonedDateTime.prototype.withPlainTime ( [ plainTimeLike ] )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let plainTime be ? ToTemporalTimeOrMidnight(plainTimeLike).
  4. Let time be Time Record { [[Days]]: 0, [[Hour]]: plainTime.[[ISOHour]], [[Minute]]: plainTime.[[ISOMinute]], [[Second]]: plainTime.[[ISOSecond]], [[Millisecond]]: plainTime.[[ISOMillisecond]], [[Microsecond]]: plainTime.[[ISOMicrosecond]], [[Nanosecond]]: plainTime.[[ISONanosecond]] }.
  5. Let timeZone be zonedDateTime.[[TimeZone]].
  6. Let calendar be zonedDateTime.[[Calendar]].
  7. Let isoDateTime be GetISODateTimeFor(timeZone, zonedDateTime.[[Nanoseconds]]).
  8. Let resultISODateTime be CombineISODateAndTimeRecord(isoDateTime, time).
  9. Let epochNs be ? GetEpochNanosecondsFor(timeZone, resultISODateTime, "compatible").
  10. Return ! CreateTemporalZonedDateTime(epochNs, timeZone, calendar).

6.3.33 Temporal.ZonedDateTime.prototype.withTimeZone ( timeZoneLike )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let timeZone be ? ToTemporalTimeZoneIdentifier(timeZoneLike).
  4. Return ! CreateTemporalZonedDateTime(zonedDateTime.[[Nanoseconds]], timeZone, zonedDateTime.[[Calendar]]).

6.3.34 Temporal.ZonedDateTime.prototype.withCalendar ( calendarLike )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let calendar be ? ToTemporalCalendarIdentifier(calendarLike).
  4. Return ! CreateTemporalZonedDateTime(zonedDateTime.[[Nanoseconds]], zonedDateTime.[[TimeZone]], calendar).

6.3.35 Temporal.ZonedDateTime.prototype.add ( temporalDurationLike [ , options ] )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Return ? AddDurationToOrSubtractDurationFromZonedDateTime(add, zonedDateTime, temporalDurationLike, options).

6.3.36 Temporal.ZonedDateTime.prototype.subtract ( temporalDurationLike [ , options ] )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Return ? AddDurationToOrSubtractDurationFromZonedDateTime(subtract, zonedDateTime, temporalDurationLike, options).

6.3.37 Temporal.ZonedDateTime.prototype.until ( other [ , options ] )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Return ? DifferenceTemporalZonedDateTime(until, zonedDateTime, other, options).

6.3.38 Temporal.ZonedDateTime.prototype.since ( other [ , options ] )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Return ? DifferenceTemporalZonedDateTime(since, zonedDateTime, other, options).

6.3.39 Temporal.ZonedDateTime.prototype.round ( roundTo )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. If roundTo is undefined, then
    1. Throw a TypeError exception.
  4. If roundTo is a String, then
    1. Let paramString be roundTo.
    2. Set roundTo to OrdinaryObjectCreate(null).
    3. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString).
  5. Else,
    1. Set roundTo to ? GetOptionsObject(roundTo).
  6. NOTE: The following steps read options and perform independent validation in alphabetical order (ToTemporalRoundingIncrement reads "roundingIncrement" and ToTemporalRoundingMode reads "roundingMode").
  7. Let roundingIncrement be ? GetRoundingIncrementOption(roundTo).
  8. Let roundingMode be ? GetRoundingModeOption(roundTo, "halfExpand").
  9. Let smallestUnit be ? GetTemporalUnitValuedOption(roundTo, "smallestUnit", time, required, « "day" »).
  10. If smallestUnit is "day", then
    1. Let maximum be 1.
    2. Let inclusive be true.
  11. Else,
    1. Let maximum be MaximumTemporalDurationRoundingIncrement(smallestUnit).
    2. Assert: maximum is not undefined.
    3. Let inclusive be false.
  12. Perform ? ValidateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive).
  13. If smallestUnit is "nanosecond" and roundingIncrement = 1, then
    1. Return ! CreateTemporalZonedDateTime(zonedDateTime.[[Nanoseconds]], zonedDateTime.[[TimeZone]], zonedDateTime.[[Calendar]]).
  14. Let thisNs be zonedDateTime.[[Nanoseconds]].
  15. Let timeZone be zonedDateTime.[[TimeZone]].
  16. Let calendar be zonedDateTime.[[Calendar]].
  17. Let isoDateTime be GetISODateTimeFor(timeZone, thisNs).
  18. If smallestUnit is "day", then
    1. Let midnight be a Time Record with all fields set to 0.
    2. Let dtStart be CombineISODateAndTimeRecord(isoDateTime, midnight).
    3. Let dateEnd be BalanceISODate(isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]] + 1).
    4. Let dtEnd be CombineISODateAndTimeRecord(dateEnd, midnight).
    5. Let startNs be ? GetEpochNanosecondsFor(timeZone, dtStart, "compatible").
    6. Assert: thisNsstartNs.
    7. Let endNs be ? GetEpochNanosecondsFor(timeZone, dtEnd, "compatible").
    8. Assert: thisNs < endNs.
    9. Let dayLengthNs be (endNs - startNs).
    10. Let dayProgressNs be NormalizedTimeDurationFromEpochNanosecondsDifference(thisNs, startNs).
    11. Let roundedDayNs be ! RoundNormalizedTimeDurationToIncrement(dayProgressNs, dayLengthNs, roundingMode).
    12. Let epochNanoseconds be startNs + roundedDayNs.[[TotalNanoseconds]].
  19. Else,
    1. Let roundResult be RoundISODateTime(isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]], isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]], roundingIncrement, smallestUnit, roundingMode).
    2. Let offsetNanoseconds be GetOffsetNanosecondsFor(timeZone, thisNs).
    3. Let epochNanoseconds be ? InterpretISODateTimeOffset(roundResult.[[Year]], roundResult.[[Month]], roundResult.[[Day]], roundResult.[[Hour]], roundResult.[[Minute]], roundResult.[[Second]], roundResult.[[Millisecond]], roundResult.[[Microsecond]], roundResult.[[Nanosecond]], option, offsetNanoseconds, timeZone, "compatible", "prefer", match-exactly).
  20. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).

6.3.40 Temporal.ZonedDateTime.prototype.equals ( other )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Set other to ? ToTemporalZonedDateTime(other).
  4. If zonedDateTime.[[Nanoseconds]]other.[[Nanoseconds]], return false.
  5. If TimeZoneEquals(zonedDateTime.[[TimeZone]], other.[[TimeZone]]) is false, return false.
  6. Return CalendarEquals(zonedDateTime.[[Calendar]], other.[[Calendar]]).

6.3.41 Temporal.ZonedDateTime.prototype.toString ( [ options ] )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Set options to ? GetOptionsObject(options).
  4. NOTE: The following steps read options and perform independent validation in alphabetical order (ToCalendarNameOption reads "calendarName", ToFractionalSecondDigits reads "fractionalSecondDigits", ToShowOffsetOption reads "offset", and ToTemporalRoundingMode reads "roundingMode").
  5. Let showCalendar be ? GetTemporalShowCalendarNameOption(options).
  6. Let digits be ? GetTemporalFractionalSecondDigitsOption(options).
  7. Let showOffset be ? GetTemporalShowOffsetOption(options).
  8. Let roundingMode be ? GetRoundingModeOption(options, "trunc").
  9. Let smallestUnit be ? GetTemporalUnitValuedOption(options, "smallestUnit", time, undefined).
  10. If smallestUnit is "hour", throw a RangeError exception.
  11. Let showTimeZone be ? GetTemporalShowTimeZoneNameOption(options).
  12. Let precision be ToSecondsStringPrecisionRecord(smallestUnit, digits).
  13. Return TemporalZonedDateTimeToString(zonedDateTime, precision.[[Precision]], showCalendar, showTimeZone, showOffset, precision.[[Increment]], precision.[[Unit]], roundingMode).

6.3.42 Temporal.ZonedDateTime.prototype.toLocaleString ( [ locales [ , options ] ] )

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.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Return TemporalZonedDateTimeToString(zonedDateTime, "auto", "auto", "auto", "auto").

6.3.43 Temporal.ZonedDateTime.prototype.toJSON ( )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Return TemporalZonedDateTimeToString(zonedDateTime, "auto", "auto", "auto", "auto").

6.3.44 Temporal.ZonedDateTime.prototype.valueOf ( )

This method performs the following steps when called:

  1. Throw a TypeError exception.
Note

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().

6.3.45 Temporal.ZonedDateTime.prototype.startOfDay ( )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let timeZone be zonedDateTime.[[TimeZone]].
  4. Let calendar be zonedDateTime.[[Calendar]].
  5. Let isoDateTime be GetISODateTimeFor(timeZone, zonedDateTime.[[Nanoseconds]]).
  6. Let midnight be a Time Record with all fields set to 0.
  7. Let startDateTime be CombineISODateAndTimeRecord(isoDateTime, midnight).
  8. Let epochNanoseconds be ? GetEpochNanosecondsFor(timeZone, startDateTime, "compatible").
  9. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).

6.3.46 Temporal.ZonedDateTime.prototype.getTimeZoneTransition ( directionParam )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let timeZone be zonedDateTime.[[TimeZone]].
  4. If directionParam is undefined, throw a TypeError exception.
  5. If directionParam is a String, then
    1. Let paramString be directionParam.
    2. Set directionParam to OrdinaryObjectCreate(null).
    3. Perform ! CreateDataPropertyOrThrow(directionParam, "direction", paramString).
  6. Else,
    1. Set directionParam to ? GetOptionsObject(directionParam).
  7. Let direction be ? GetDirectionOption(directionParam).
  8. If IsOffsetTimeZoneIdentifier(timeZone) is true or timeZone is "UTC", return null.
  9. If direction is "next", then
    1. Let transition be GetNamedTimeZoneNextTransition(timeZone, zonedDateTime.[[Nanoseconds]]).
  10. Else,
    1. Assert: direction is "previous".
    2. Let transition be GetNamedTimeZonePreviousTransition(timeZone, zonedDateTime.[[Nanoseconds]]).
  11. If transition is null, return null.
  12. Return ! CreateTemporalZonedDateTime(transition, timeZone, zonedDateTime.[[Calendar]]).

6.3.47 Temporal.ZonedDateTime.prototype.toInstant ( )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Return ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).

6.3.48 Temporal.ZonedDateTime.prototype.toPlainDate ( )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return ! CreateTemporalDate(isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]], zonedDateTime.[[Calendar]].).

6.3.49 Temporal.ZonedDateTime.prototype.toPlainTime ( )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return ! CreateTemporalTime(isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]]).

6.3.50 Temporal.ZonedDateTime.prototype.toPlainDateTime ( )

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let isoDateTime be GetISODateTimeFor(zonedDateTime.[[TimeZone]], zonedDateTime.[[Nanoseconds]]).
  4. Return ! CreateTemporalDateTime(isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]], isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]], zonedDateTime.[[Calendar]]).

6.4 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 Table 8.

Table 8: Internal Slots of Temporal.ZonedDateTime Instances
Internal Slot Description
[[InitializedTemporalZonedDateTime]] The only specified use of this slot is for distinguishing Temporal.ZonedDateTime instances from other objects.
[[Nanoseconds]] A BigInt value representing the number of nanoseconds since the epoch.
[[TimeZone]] A String representing the time zone.
[[Calendar]] A String representing the calendar.

6.5 Abstract Operations

6.5.1 InterpretISODateTimeOffset ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, offsetBehaviour, offsetNanoseconds, timeZone, disambiguation, offsetOption, matchBehaviour )

The abstract operation InterpretISODateTimeOffset takes arguments year (an integer), month (an integer), day (an integer), 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), offsetBehaviour (one of option, exact, or wall), offsetNanoseconds (an integer), timeZone (a String), disambiguation (one of "earlier", "later", "compatible", or "reject"), offsetOption (one of "ignore", "use", "prefer", or "reject"), and matchBehaviour (one of match-exactly or match-minutes) and returns either a normal completion containing a BigInt or a throw completion.

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 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.

It performs the following steps when called:

  1. Assert: IsValidISODate(year, month, day) is true.
  2. Let isoDateTime be ISO Date-Time Record { [[Year]]: year, [[Month]]: month, [[Day]]: day, [[Hour]]: hour, [[Minute]]: minute, [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]: microsecond, [[Nanosecond]]: nanosecond }.
  3. If offsetBehaviour is wall, or offsetBehaviour is option and offsetOption is "ignore", then
    1. Return ? GetEpochNanosecondsFor(timeZone, isoDateTime, disambiguation).
  4. If offsetBehaviour is exact, or offsetBehaviour is option and offsetOption is "use", then
    1. Let epochNanoseconds be GetUTCEpochNanoseconds(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, offsetNanoseconds).
    2. If IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
    3. Return epochNanoseconds.
  5. Assert: offsetBehaviour is option.
  6. Assert: offsetOption is "prefer" or "reject".
  7. Let possibleEpochNs be ? GetPossibleEpochNanoseconds(timeZone, isoDateTime).
  8. If possibleEpochNs is not empty, then
    1. For each element candidate of possibleEpochNs, do
      1. Let candidateOffset be GetOffsetNanosecondsFor(timeZone, candidate).
      2. If candidateOffset = offsetNanoseconds, then
        1. Return candidate.
      3. If matchBehaviour is match-minutes, then
        1. Let roundedCandidateNanoseconds be RoundNumberToIncrement(candidateOffset, 60 × 109, "halfExpand").
        2. If roundedCandidateNanoseconds = offsetNanoseconds, then
          1. Return candidate.
  9. If offsetOption is "reject", throw a RangeError exception.
  10. Return ? DisambiguatePossibleEpochNanoseconds(possibleEpochNs, timeZone, isoDateTime, disambiguation).

6.5.2 ToTemporalZonedDateTime ( item [ , options ] )

The abstract operation ToTemporalZonedDateTime takes argument item (an ECMAScript language value) and optional argument options (an ECMAScript language value) and returns either a normal completion containing a Temporal.ZonedDateTime, or a throw completion. It returns its argument item if it is already a Temporal.ZonedDateTime instance, converts item to a new Temporal.ZonedDateTime instance if possible, and throws otherwise. It performs the following steps when called:

  1. If options is not present, set options to undefined.
  2. Let offsetBehaviour be option.
  3. Let matchBehaviour be match-exactly.
  4. 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").
      2. Set options to ? GetOptionsObject(options).
      3. Perform ? GetTemporalDisambiguationOption(options).
      4. Perform ? GetTemporalOffsetOption(options, "reject").
      5. Perform ? GetTemporalOverflowOption(options).
      6. Return item.
    2. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(item).
    3. Let fields be ? PrepareCalendarFields(calendar, item, « day, month, month-code, year », « hour, microsecond, millisecond, minute, nanosecond, offset, second, time-zone », « time-zone »).
    4. Let timeZone be ? ToTemporalTimeZoneIdentifier(fields.[[TimeZone]]).
    5. Let offsetString be fields.[[OffsetString]].
    6. If offsetString is undefined, then
      1. Set offsetBehaviour to wall.
    7. Set options to ? GetOptionsObject(options).
    8. Let disambiguation be ? GetTemporalDisambiguationOption(options).
    9. Let offsetOption be ? GetTemporalOffsetOption(options, "reject").
    10. Let overflow be ? GetTemporalOverflowOption(options).
    11. Let result be ? InterpretTemporalDateTimeFields(calendar, fields, overflow).
  5. Else,
    1. If item is not a String, throw a TypeError exception.
    2. Let result be ? ParseTemporalZonedDateTimeString(item).
    3. Let annotation be result.[[TimeZone]].[[TimeZoneAnnotation]].
    4. Assert: annotation is not undefined.
    5. Let timeZone be ? ToTemporalTimeZoneIdentifier(annotation).
    6. Let offsetString be result.[[TimeZone]].[[OffsetString]].
    7. If result.[[TimeZone]].[[Z]] is true, then
      1. Set offsetBehaviour to exact.
    8. Else if offsetString is undefined, then
      1. Set offsetBehaviour to wall.
    9. Let calendar be result.[[Calendar]].
    10. If calendar is undefined, set calendar to "iso8601".
    11. If IsBuiltinCalendar(calendar) is false, throw a RangeError exception.
    12. Set calendar to CanonicalizeUValue("ca", calendar).
    13. Set matchBehaviour to match-minutes.
    14. Set options to ? GetOptionsObject(options).
    15. Let disambiguation be ? GetTemporalDisambiguationOption(options).
    16. Let offsetOption be ? GetTemporalOffsetOption(options, "reject").
    17. Perform ? GetTemporalOverflowOption(options).
  6. Let offsetNanoseconds be 0.
  7. If offsetBehaviour is option, then
    1. Set offsetNanoseconds to ? ParseDateTimeUTCOffset(offsetString).
  8. Let epochNanoseconds be ? InterpretISODateTimeOffset(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], offsetBehaviour, offsetNanoseconds, timeZone, disambiguation, offsetOption, matchBehaviour).
  9. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).

6.5.3 CreateTemporalZonedDateTime ( epochNanoseconds, timeZone, calendar [ , newTarget ] )

The abstract operation CreateTemporalZonedDateTime takes arguments epochNanoseconds (a BigInt), timeZone (a String or Object), and calendar (a String or Object) and optional argument newTarget (a constructor) and returns either a normal completion containing a Temporal.ZonedDateTime or a throw completion. It creates a Temporal.ZonedDateTime instance and fills the internal slots with valid values. It performs the following steps when called:

  1. Assert: IsValidEpochNanoseconds(epochNanoseconds) is true.
  2. If newTarget is not present, set newTarget to %Temporal.ZonedDateTime%.
  3. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.ZonedDateTime.prototype%", « [[InitializedTemporalZonedDateTime]], [[Nanoseconds]], [[TimeZone]], [[Calendar]] »).
  4. Set object.[[Nanoseconds]] to epochNanoseconds.
  5. Set object.[[TimeZone]] to timeZone.
  6. Set object.[[Calendar]] to calendar.
  7. Return object.

6.5.4 TemporalZonedDateTimeToString ( zonedDateTime, precision, showCalendar, showTimeZone, showOffset [ , increment [ , unit [ , roundingMode ] ] ] )

The abstract operation TemporalZonedDateTimeToString takes arguments zonedDateTime (a Temporal.ZonedDateTime), precision (one of "auto", "minute", or an integer between 0 and 9 inclusive), showCalendar (one of "auto", "always", "never", or "critical"), showTimeZone (one of "auto", "never", or "critical"), and showOffset (one of "auto" or "never") and optional arguments increment (a positive integer), unit (one of "minute", "second", "millisecond", "microsecond", or "nanosecond"), and roundingMode (a String from the "Identifier" column of Table 22) and returns a String. It returns an ISO 8601 string representation of its argument, including a time zone name annotation and calendar annotation, which are extensions to the ISO 8601 format. It performs the following steps when called:

  1. If increment is not present, set increment to 1.
  2. If unit is not present, set unit to "nanosecond".
  3. If roundingMode is not present, set roundingMode to "trunc".
  4. Let epochNs be zonedDateTime.[[Nanoseconds]].
  5. Set epochNs to RoundTemporalInstant(epochNs, increment, unit, roundingMode).
  6. Let timeZone be zonedDateTime.[[TimeZone]].
  7. Let offsetNanoseconds be GetOffsetNanosecondsFor(timeZone, epochNs).
  8. Let isoDateTime be GetISODateTimeFor(timeZone, epochNs).
  9. Let dateTimeString be TemporalDateTimeToString(isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]], isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]], "iso8601", precision, "never").
  10. If showOffset is "never", then
    1. Let offsetString be the empty String.
  11. Else,
    1. Let offsetString be FormatDateTimeUTCOffsetRounded(offsetNanoseconds).
  12. If showTimeZone is "never", then
    1. Let timeZoneString be the empty String.
  13. Else,
    1. If showTimeZone is "critical", let flag be "!"; else let flag be the empty String.
    2. Let timeZoneString be the string-concatenation of the code unit 0x005B (LEFT SQUARE BRACKET), flag, timeZone, and the code unit 0x005D (RIGHT SQUARE BRACKET).
  14. Let calendarString be MaybeFormatCalendarAnnotation(zonedDateTime.[[Calendar]], showCalendar).
  15. Return the string-concatenation of dateTimeString, offsetString, timeZoneString, and calendarString.

6.5.5 AddZonedDateTime ( epochNanoseconds, timeZone, calendar, years, months, weeks, days, norm [ , overflow ] )

The abstract operation AddZonedDateTime takes arguments epochNanoseconds (a BigInt), timeZone (a String), calendar (a String), years (an integer), months (an integer), weeks (an integer), days (an integer), and norm (a Normalized Time Duration Record) and optional argument overflow ("constrain" or "reject") and returns either a normal completion containing a BigInt or a throw completion. 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, and returns the result as a BigInt value. 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. It performs the following steps when called:

  1. If overflow is not present, set overflow to "constrain".
  2. If years = 0, months = 0, weeks = 0, and days = 0, then
    1. Return ? AddInstant(epochNanoseconds, norm).
  3. Let isoDateTime be GetISODateTimeFor(timeZone, epochNanoseconds).
  4. Let datePart be ISODateTimeToDateRecord(isoDateTime).
  5. Let dateDuration be CreateDurationRecord(years, months, weeks, days, 0, 0, 0, 0, 0, 0).
  6. Let addedDate be ? CalendarDateAdd(calendar, datePart, dateDuration, overflow).
  7. Let intermediateDateTime be CombineISODateAndTimeRecord(addedDate, isoDateTime).
  8. If ISODateTimeWithinLimits(intermediateDateTime.[[Year]], intermediateDateTime.[[Month]], intermediateDateTime.[[Day]], intermediateDateTime.[[Hour]], intermediateDateTime.[[Minute]], intermediateDateTime.[[Second]], intermediateDateTime.[[Millisecond]], intermediateDateTime.[[Microsecond]], intermediateDateTime.[[Nanosecond]]) is false, throw a RangeError exception.
  9. Let intermediateNs be ! GetEpochNanosecondsFor(timeZone, intermediateDateTime, "compatible").
  10. Return ? AddInstant(intermediateNs, norm).

6.5.6 DifferenceZonedDateTime ( ns1, ns2, timeZone, calendar, largestUnit )

The abstract operation DifferenceZonedDateTime takes arguments ns1 (a BigInt), ns2 (a BigInt), timeZone (a String), calendar (a String), and largestUnit (a String) and returns either a normal completion containing a Normalized Duration Record, or a throw completion. 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. It performs the following steps when called:

  1. If ns1 = ns2, then
    1. Return ! CreateNormalizedDurationRecord(0, 0, 0, 0, ZeroTimeDuration()).
  2. Let startDateTime be GetISODateTimeFor(timeZone, ns1).
  3. Let endDateTime be GetISODateTimeFor(timeZone, ns2).
  4. If ns2 - ns1 < 0, let sign be -1; else let sign be 1.
  5. If sign = 1, let maxDayCorrection be 2; else let maxDayCorrection be 1.
  6. Let dayCorrection be 0.
  7. Let timeDuration be DifferenceTime(startDateTime.[[Hour]], startDateTime.[[Minute]], startDateTime.[[Second]], startDateTime.[[Millisecond]], startDateTime.[[Microsecond]], startDateTime.[[Nanosecond]], endDateTime.[[Hour]], endDateTime.[[Minute]], endDateTime.[[Second]], endDateTime.[[Millisecond]], endDateTime.[[Microsecond]], endDateTime.[[Nanosecond]]).
  8. If NormalizedTimeDurationSign(timeDuration) = -sign, set dayCorrection to dayCorrection + 1.
  9. Let success be false.
  10. Repeat, while dayCorrectionmaxDayCorrection and success is false,
    1. Let intermediateDate be BalanceISODate(endDateTime.[[Year]], endDateTime.[[Month]], endDateTime.[[Day]] - dayCorrection × sign).
    2. Let intermediateDateTime be CombineISODateAndTimeRecord(intermediateDate, startDateTime).
    3. Let intermediateNs be ? GetEpochNanosecondsFor(timeZone, intermediateDateTime, "compatible").
    4. Let norm be NormalizedTimeDurationFromEpochNanosecondsDifference(ns2, intermediateNs).
    5. Let timeSign be NormalizedTimeDurationSign(norm).
    6. If sign ≠ -timeSign, then
      1. Set success to true.
    7. Set dayCorrection to dayCorrection + 1.
  11. Assert: success is true.
  12. Let date1 be ISODateTimeToDateRecord(startDateTime).
  13. Let date2 be ISODateTimeToDateRecord(intermediateDateTime).
  14. Let dateLargestUnit be LargerOfTwoTemporalUnits(largestUnit, "day").
  15. Let dateDifference be CalendarDateUntil(calendar, date1, date2, dateLargestUnit).
  16. Return ? CreateNormalizedDurationRecord(dateDifference.[[Years]], dateDifference.[[Months]], dateDifference.[[Weeks]], dateDifference.[[Days]], norm).

6.5.7 DifferenceZonedDateTimeWithRounding ( ns1, ns2, calendar, timeZone, largestUnit, roundingIncrement, smallestUnit, roundingMode )

The abstract operation DifferenceZonedDateTimeWithRounding takes arguments ns1 (a BigInt), ns2 (a BigInt), calendar (a String), timeZone (a String), largestUnit (a String), roundingIncrement (a positive integer), smallestUnit (a String), and roundingMode (a String) and returns either a normal completion containing a Record with fields [[DurationRecord]] (a Duration Record) and [[Total]] (a mathematical value or unset), or a throw completion. It performs the following steps when called:

  1. If IsCalendarUnit(largestUnit) is false and largestUnit is not "day", then
    1. Let diffRecord be DifferenceInstant(ns1, ns2, roundingIncrement, smallestUnit, roundingMode).
    2. Let norm be diffRecord.[[NormalizedTimeDuration]].
    3. Let result be ! BalanceTimeDuration(norm, largestUnit).
    4. Let durationRecord be CreateDurationRecord(0, 0, 0, 0, result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]).
    5. Return the Record { [[DurationRecord]]: durationRecord, [[Total]]: diffRecord.[[Total]] }.
  2. Let difference be ? DifferenceZonedDateTime(ns1, ns2, timeZone, calendar, largestUnit).
  3. If smallestUnit is "nanosecond" and roundingIncrement = 1, then
    1. Let timeResult be ! BalanceTimeDuration(difference.[[NormalizedTime]], "hour").
    2. Let total be NormalizedTimeDurationSeconds(difference.[[NormalizedTime]]) × 109 + NormalizedTimeDurationSubseconds(difference.[[NormalizedTime]]).
    3. Let durationRecord be CreateDurationRecord(difference.[[Years]], difference.[[Months]], difference.[[Weeks]], difference.[[Days]], timeResult.[[Hours]], timeResult.[[Minutes]], timeResult.[[Seconds]], timeResult.[[Milliseconds]], timeResult.[[Microseconds]], timeResult.[[Nanoseconds]]).
    4. Return the Record { [[DurationRecord]]: durationRecord, [[Total]]: total }.
  4. Let dateTime be GetISODateTimeFor(timeZone, ns1).
  5. Return ? RoundRelativeDuration(difference, ns2, dateTime, calendar, timeZone, largestUnit, roundingIncrement, smallestUnit, roundingMode).

6.5.8 DifferenceTemporalZonedDateTime ( operation, zonedDateTime, other, options )

The abstract operation DifferenceTemporalZonedDateTime takes arguments operation (until or since), zonedDateTime (a Temporal.ZonedDateTime), other (an ECMAScript language value), and options (an ECMAScript language value) and returns either a normal completion containing a Temporal.Duration or a throw completion. It computes the difference between the two times represented by zonedDateTime and other, optionally rounds it, and returns it as a Temporal.Duration object. It performs the following steps when called:

  1. If operation is since, let sign be -1. Otherwise, let sign be 1.
  2. Set other to ? ToTemporalZonedDateTime(other).
  3. If CalendarEquals(zonedDateTime.[[Calendar]], other.[[Calendar]]) is false, then
    1. Throw a RangeError exception.
  4. Let resolvedOptions be ? GetOptionsObject(options).
  5. Let settings be ? GetDifferenceSettings(operation, resolvedOptions, datetime, « », "nanosecond", "hour").
  6. If settings.[[LargestUnit]] is not one of "year", "month", "week", or "day", then
    1. Let diffRecord be DifferenceInstant(zonedDateTime.[[Nanoseconds]], other.[[Nanoseconds]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
    2. Let norm be diffRecord.[[NormalizedTimeDuration]].
    3. Let result be ! BalanceTimeDuration(norm, settings.[[LargestUnit]]).
    4. Return ! CreateTemporalDuration(0, 0, 0, 0, sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]).
  7. NOTE: To calculate differences in two different time zones, settings.[[LargestUnit]] must be "hour" or smaller, because day lengths can vary between time zones due to DST and other UTC offset shifts.
  8. If TimeZoneEquals(zonedDateTime.[[TimeZone]], other.[[TimeZone]]) is false, then
    1. Throw a RangeError exception.
  9. If zonedDateTime.[[Nanoseconds]] = other.[[Nanoseconds]], then
    1. Return ! CreateTemporalDuration(0, 0, 0, 0, 0, 0, 0, 0, 0, 0).
  10. Let resultRecord be ? DifferenceZonedDateTimeWithRounding(zonedDateTime.[[Nanoseconds]], other.[[Nanoseconds]], zonedDateTime.[[Calendar]], zonedDateTime.[[TimeZone]], settings.[[LargestUnit]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
  11. Let result be resultRecord.[[DurationRecord]].
  12. Return ! CreateTemporalDuration(sign × result.[[Years]], sign × result.[[Months]], sign × result.[[Weeks]], sign × result.[[Days]], sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]).

6.5.9 AddDurationToOrSubtractDurationFromZonedDateTime ( operation, zonedDateTime, temporalDurationLike, options )

The abstract operation AddDurationToOrSubtractDurationFromZonedDateTime takes arguments operation (add or subtract), zonedDateTime (a Temporal.ZonedDateTime), temporalDurationLike (an ECMAScript language value), and options (an ECMAScript language value) and returns either a normal completion containing a Temporal.ZonedDateTime or a throw completion. It adds/subtracts temporalDurationLike to/from zonedDateTime. It performs the following steps when called:

  1. If operation is subtract, let sign be -1. Otherwise, let sign be 1.
  2. Let duration be ? ToTemporalDurationRecord(temporalDurationLike).
  3. Set options to ? GetOptionsObject(options).
  4. Let overflow be ? GetTemporalOverflowOption(options).
  5. Let calendar be zonedDateTime.[[Calendar]].
  6. Let timeZone be zonedDateTime.[[TimeZone]].
  7. Let norm be NormalizeTimeDuration(sign × duration.[[Hours]], sign × duration.[[Minutes]], sign × duration.[[Seconds]], sign × duration.[[Milliseconds]], sign × duration.[[Microseconds]], sign × duration.[[Nanoseconds]]).
  8. Let epochNanoseconds be ? AddZonedDateTime(zonedDateTime.[[Nanoseconds]], timeZone, calendar, sign × duration.[[Years]], sign × duration.[[Months]], sign × duration.[[Weeks]], sign × duration.[[Days]], norm, overflow).
  9. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).

7 Temporal.Duration Objects

A Temporal.Duration object describes the difference in elapsed time between two other Temporal objects of the same type: Instant, PlainDate, PlainDateTime, PlainTime, PlainYearMonth, or ZonedDateTime. Objects of this type are only created via the .since() and .until() methods of these objects.

7.1 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.

7.1.1 Temporal.Duration ( [ years [ , months [ , weeks [ , days [ , hours [ , minutes [ , seconds [ , milliseconds [ , microseconds [ , nanoseconds ] ] ] ] ] ] ] ] ] ] )

The Temporal.Duration function performs the following steps when called:

  1. If NewTarget is undefined, then
    1. Throw a TypeError exception.
  2. If years is undefined, let y be 0; else let y be ? ToIntegerIfIntegral(years).
  3. If months is undefined, let mo be 0; else let mo be ? ToIntegerIfIntegral(months).
  4. If weeks is undefined, let w be 0; else let w be ? ToIntegerIfIntegral(weeks).
  5. If days is undefined, let d be 0; else let d be ? ToIntegerIfIntegral(days).
  6. If hours is undefined, let h be 0; else let h be ? ToIntegerIfIntegral(hours).
  7. If minutes is undefined, let m be 0; else let m be ? ToIntegerIfIntegral(minutes).
  8. If seconds is undefined, let s be 0; else let s be ? ToIntegerIfIntegral(seconds).
  9. If milliseconds is undefined, let ms be 0; else let ms be ? ToIntegerIfIntegral(milliseconds).
  10. If microseconds is undefined, let mis be 0; else let mis be ? ToIntegerIfIntegral(microseconds).
  11. If nanoseconds is undefined, let ns be 0; else let ns be ? ToIntegerIfIntegral(nanoseconds).
  12. Return ? CreateTemporalDuration(y, mo, w, d, h, m, s, ms, mis, ns, NewTarget).

7.2 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:

7.2.1 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 }.

7.2.2 Temporal.Duration.from ( item )

The Temporal.Duration.from function performs the following steps when called:

  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]]).
  2. Return ? ToTemporalDuration(item).

7.2.3 Temporal.Duration.compare ( one, two [ , options ] )

The Temporal.Duration.compare function performs the following steps when called:

  1. Set one to ? ToTemporalDuration(one).
  2. Set two to ? ToTemporalDuration(two).
  3. Set options to ? GetOptionsObject(options).
  4. Let relativeToRecord be ? GetTemporalRelativeToOption(options).
  5. 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.[[Millieconds]] = two.[[Millieconds]], and one.[[Microseconds]] = two.[[Microseconds]], and one.[[Nanoseconds]] = two.[[Nanoseconds]], then
    1. Return +0𝔽.
  6. Let zonedRelativeTo be relativeToRecord.[[ZonedRelativeTo]].
  7. Let plainRelativeTo be relativeToRecord.[[PlainRelativeTo]].
  8. Let calendarUnitsPresent be false.
  9. If one.[[Years]] ≠ 0, or two.[[Years]] ≠ 0, or one.[[Months]] ≠ 0, or two.[[Months]] ≠ 0, or one.[[Weeks]] ≠ 0, or two.[[Weeks]] ≠ 0, set calendarUnitsPresent to true.
  10. If zonedRelativeTo is not undefined, and either calendarUnitsPresent is true, or one.[[Days]] ≠ 0, or two.[[Days]] ≠ 0, then
    1. Let timeZone be zonedRelativeTo.[[TimeZone]].
    2. Let calendar be zonedRelativeTo.[[Calendar]].
    3. Let norm1 be NormalizeTimeDuration(one.[[Hours]], one.[[Minutes]], one.[[Seconds]], one.[[Milliseconds]], one.[[Microseconds]], one.[[Nanoseconds]]).
    4. Let norm2 be NormalizeTimeDuration(two.[[Hours]], two.[[Minutes]], two.[[Seconds]], two.[[Milliseconds]], two.[[Microseconds]], two.[[Nanoseconds]]).
    5. Let after1 be ? AddZonedDateTime(zonedRelativeTo.[[Nanoseconds]], timeZone, calendar, one.[[Years]], one.[[Months]], one.[[Weeks]], one.[[Days]], norm1).
    6. Let after2 be ? AddZonedDateTime(zonedRelativeTo.[[Nanoseconds]], timeZone, calendar, two.[[Years]], two.[[Months]], two.[[Weeks]], two.[[Days]], norm2).
    7. If after1 > after2, return 1𝔽.
    8. If after1 < after2, return -1𝔽.
    9. Return +0𝔽.
  11. If calendarUnitsPresent is true, then
    1. If plainRelativeTo is undefined, throw a RangeError exception.
    2. Let days1 be ? UnbalanceDateDurationRelative(one.[[Years]], one.[[Months]], one.[[Weeks]], one.[[Days]], plainRelativeTo).
    3. Let days2 be ? UnbalanceDateDurationRelative(two.[[Years]], two.[[Months]], two.[[Weeks]], two.[[Days]], plainRelativeTo).
  12. Else,
    1. Let days1 be one.[[Days]].
    2. Let days2 be two.[[Days]].
  13. Let norm1 be NormalizeTimeDuration(one.[[Hours]], one.[[Minutes]], one.[[Seconds]], one.[[Milliseconds]], one.[[Microseconds]], one.[[Nanoseconds]]).
  14. Set norm1 to ? Add24HourDaysToNormalizedTimeDuration(norm1, days1).
  15. Let norm2 be NormalizeTimeDuration(two.[[Hours]], two.[[Minutes]], two.[[Seconds]], two.[[Milliseconds]], two.[[Microseconds]], two.[[Nanoseconds]]).
  16. Set norm2 to ? Add24HourDaysToNormalizedTimeDuration(norm2, days2).
  17. Return 𝔽(CompareNormalizedTimeDuration(norm1, norm2)).

7.3 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%.

7.3.1 Temporal.Duration.prototype.constructor

The initial value of Temporal.Duration.prototype.constructor is %Temporal.Duration%.

7.3.2 Temporal.Duration.prototype[ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Temporal.Duration".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

7.3.3 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.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return 𝔽(duration.[[Years]]).

7.3.4 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.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return 𝔽(duration.[[Months]]).

7.3.5 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.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return 𝔽(duration.[[Weeks]]).

7.3.6 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.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return 𝔽(duration.[[Days]]).

7.3.7 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.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return 𝔽(duration.[[Hours]]).

7.3.8 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.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return 𝔽(duration.[[Minutes]]).

7.3.9 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.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return 𝔽(duration.[[Seconds]]).

7.3.10 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.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return 𝔽(duration.[[Milliseconds]]).

7.3.11 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.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return 𝔽(duration.[[Microseconds]]).

7.3.12 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.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return 𝔽(duration.[[Nanoseconds]]).

7.3.13 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.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return 𝔽(DurationSign(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]])).

7.3.14 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.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Let sign be DurationSign(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]]).
  4. If sign = 0, return true.
  5. Return false.

7.3.15 Temporal.Duration.prototype.with ( temporalDurationLike )

The Temporal.Duration.prototype.with method performs the following steps when called:

  1. Let duration be the this value.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Let temporalDurationLike be ? ToTemporalPartialDurationRecord(temporalDurationLike).
  4. If temporalDurationLike.[[Years]] is not undefined, then
    1. Let years be temporalDurationLike.[[Years]].
  5. Else,
    1. Let years be duration.[[Years]].
  6. If temporalDurationLike.[[Months]] is not undefined, then
    1. Let months be temporalDurationLike.[[Months]].
  7. Else,
    1. Let months be duration.[[Months]].
  8. If temporalDurationLike.[[Weeks]] is not undefined, then
    1. Let weeks be temporalDurationLike.[[Weeks]].
  9. Else,
    1. Let weeks be duration.[[Weeks]].
  10. If temporalDurationLike.[[Days]] is not undefined, then
    1. Let days be temporalDurationLike.[[Days]].
  11. Else,
    1. Let days be duration.[[Days]].
  12. If temporalDurationLike.[[Hours]] is not undefined, then
    1. Let hours be temporalDurationLike.[[Hours]].
  13. Else,
    1. Let hours be duration.[[Hours]].
  14. If temporalDurationLike.[[Minutes]] is not undefined, then
    1. Let minutes be temporalDurationLike.[[Minutes]].
  15. Else,
    1. Let minutes be duration.[[Minutes]].
  16. If temporalDurationLike.[[Seconds]] is not undefined, then
    1. Let seconds be temporalDurationLike.[[Seconds]].
  17. Else,
    1. Let seconds be duration.[[Seconds]].
  18. If temporalDurationLike.[[Milliseconds]] is not undefined, then
    1. Let milliseconds be temporalDurationLike.[[Milliseconds]].
  19. Else,
    1. Let milliseconds be duration.[[Milliseconds]].
  20. If temporalDurationLike.[[Microseconds]] is not undefined, then
    1. Let microseconds be temporalDurationLike.[[Microseconds]].
  21. Else,
    1. Let microseconds be duration.[[Microseconds]].
  22. If temporalDurationLike.[[Nanoseconds]] is not undefined, then
    1. Let nanoseconds be temporalDurationLike.[[Nanoseconds]].
  23. Else,
    1. Let nanoseconds be duration.[[Nanoseconds]].
  24. Return ? CreateTemporalDuration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds).

7.3.16 Temporal.Duration.prototype.negated ( )

The Temporal.Duration.prototype.negated method performs the following steps when called:

  1. Let duration be the this value.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return CreateNegatedTemporalDuration(duration).

7.3.17 Temporal.Duration.prototype.abs ( )

The Temporal.Duration.prototype.abs method performs the following steps when called:

  1. Let duration be the this value.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return ! CreateTemporalDuration(abs(duration.[[Years]]), abs(duration.[[Months]]), abs(duration.[[Weeks]]), abs(duration.[[Days]]), abs(duration.[[Hours]]), abs(duration.[[Minutes]]), abs(duration.[[Seconds]]), abs(duration.[[Milliseconds]]), abs(duration.[[Microseconds]]), abs(duration.[[Nanoseconds]])).

7.3.18 Temporal.Duration.prototype.add ( other )

The Temporal.Duration.prototype.add method performs the following steps when called:

  1. Let duration be the this value.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return ? AddDurations(add, duration, other).

7.3.19 Temporal.Duration.prototype.subtract ( other )

The Temporal.Duration.prototype.subtract method performs the following steps when called:

  1. Let duration be the this value.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Return ? AddDurations(subtract, duration, other).

7.3.20 Temporal.Duration.prototype.round ( roundTo )

The Temporal.Duration.prototype.round method performs the following steps when called:

  1. Let duration be the this value.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. If roundTo is undefined, then
    1. Throw a TypeError exception.
  4. If roundTo is a String, then
    1. Let paramString be roundTo.
    2. Set roundTo to OrdinaryObjectCreate(null).
    3. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString).
  5. Else,
    1. Set roundTo to ? GetOptionsObject(roundTo).
  6. Let smallestUnitPresent be true.
  7. Let largestUnitPresent be true.
  8. NOTE: The following steps read options and perform independent validation in alphabetical order (ToRelativeTemporalObject reads "relativeTo", ToTemporalRoundingIncrement reads "roundingIncrement" and ToTemporalRoundingMode reads "roundingMode").
  9. Let largestUnit be ? GetTemporalUnitValuedOption(roundTo, "largestUnit", datetime, undefined, « "auto" »).
  10. Let relativeToRecord be ? GetTemporalRelativeToOption(roundTo).
  11. Let zonedRelativeTo be relativeToRecord.[[ZonedRelativeTo]].
  12. Let plainRelativeTo be relativeToRecord.[[PlainRelativeTo]].
  13. Let roundingIncrement be ? GetRoundingIncrementOption(roundTo).
  14. Let roundingMode be ? GetRoundingModeOption(roundTo, "halfExpand").
  15. Let smallestUnit be ? GetTemporalUnitValuedOption(roundTo, "smallestUnit", datetime, undefined).
  16. If smallestUnit is undefined, then
    1. Set smallestUnitPresent to false.
    2. Set smallestUnit to "nanosecond".
  17. Let existingLargestUnit be DefaultTemporalLargestUnit(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]]).
  18. Let defaultLargestUnit be LargerOfTwoTemporalUnits(existingLargestUnit, smallestUnit).
  19. If largestUnit is undefined, then
    1. Set largestUnitPresent to false.
    2. Set largestUnit to defaultLargestUnit.
  20. Else if largestUnit is "auto", then
    1. Set largestUnit to defaultLargestUnit.
  21. If smallestUnitPresent is false and largestUnitPresent is false, then
    1. Throw a RangeError exception.
  22. If LargerOfTwoTemporalUnits(largestUnit, smallestUnit) is not largestUnit, throw a RangeError exception.
  23. Let maximum be MaximumTemporalDurationRoundingIncrement(smallestUnit).
  24. If maximum is not undefined, perform ? ValidateTemporalRoundingIncrement(roundingIncrement, maximum, false).
  25. If roundingIncrement > 1, and largestUnit is not smallestUnit, and IsCalendarUnit(smallestUnit) is true or smallestUnit is "day", then
    1. Throw a RangeError exception.
  26. Let norm be NormalizeTimeDuration(duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]]).
  27. If zonedRelativeTo is not undefined, then
    1. Let timeZone be zonedRelativeTo.[[TimeZone]].
    2. Let calendar be zonedRelativeTo.[[Calendar]].
    3. Let relativeEpochNs be zonedRelativeTo.[[Nanoseconds]].
    4. Let targetEpochNs be ? AddZonedDateTime(relativeEpochNs, timeZone, calendar, duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], norm).
    5. Let roundRecord be ? DifferenceZonedDateTimeWithRounding(relativeEpochNs, targetEpochNs, calendar, timeZone, largestUnit, roundingIncrement, smallestUnit, roundingMode).
    6. Let roundResult be roundRecord.[[DurationRecord]].
  28. Else if plainRelativeTo is not undefined, then
    1. Let targetTime be AddTime(0, 0, 0, 0, 0, 0, norm).
    2. If IsValidDuration(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]] + targetTime.[[Days]], 0, 0, 0, 0, 0, 0) is false, throw a RangeError exception.
    3. Let isoRelativeToDate be TemporalObjectToISODateRecord(plainRelativeTo).
    4. Let calendar be plainRelativeTo.[[Calendar]].
    5. Let dateDuration be CreateDurationRecord(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]] + targetTime.[[Days]], 0, 0, 0, 0, 0, 0).
    6. Let targetDate be ? CalendarDateAdd(calendar, isoRelativeToDate, dateDuration, "constrain").
    7. Let roundRecord be ? DifferencePlainDateTimeWithRounding(isoRelativeToDate.[[Year]], isoRelativeToDate.[[Month]], isoRelativeToDate.[[Day]], 0, 0, 0, 0, 0, 0, targetDate.[[Year]], targetDate.[[Month]], targetDate.[[Day]], targetTime.[[Hours]], targetTime.[[Minutes]], targetTime.[[Seconds]], targetTime.[[Milliseconds]], targetTime.[[Microseconds]], targetTime.[[Nanoseconds]], calendar, largestUnit, roundingIncrement, smallestUnit, roundingMode).
    8. Let roundResult be roundRecord.[[DurationRecord]].
  29. Else,
    1. If duration.[[Years]] ≠ 0, or duration.[[Months]] ≠ 0, or duration.[[Weeks]] ≠ 0, or IsCalendarUnit(largestUnit) is true, throw a RangeError exception.
    2. Assert: IsCalendarUnit(smallestUnit) is false.
    3. Let roundRecord be ? RoundTimeDuration(duration.[[Days]], norm, roundingIncrement, smallestUnit, roundingMode).
    4. Let normWithDays be ? Add24HourDaysToNormalizedTimeDuration(roundRecord.[[NormalizedDuration]].[[NormalizedTime]], roundRecord.[[NormalizedDuration]].[[Days]]).
    5. Let balanceResult be ? BalanceTimeDuration(normWithDays, largestUnit).
    6. Let roundResult be CreateDurationRecord(0, 0, 0, balanceResult.[[Days]], balanceResult.[[Hours]], balanceResult.[[Minutes]], balanceResult.[[Seconds]], balanceResult.[[Milliseconds]], balanceResult.[[Microseconds]], balanceResult.[[Nanoseconds]]).
  30. Return ? CreateTemporalDuration(roundResult.[[Years]], roundResult.[[Months]], roundResult.[[Weeks]], roundResult.[[Days]], roundResult.[[Hours]], roundResult.[[Minutes]], roundResult.[[Seconds]], roundResult.[[Milliseconds]], roundResult.[[Microseconds]], roundResult.[[Nanoseconds]]).

7.3.21 Temporal.Duration.prototype.total ( totalOf )

The Temporal.Duration.prototype.total method performs the following steps when called:

  1. Let duration be the this value.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. If totalOf is undefined, throw a TypeError exception.
  4. If totalOf is a String, then
    1. Let paramString be totalOf.
    2. Set totalOf to OrdinaryObjectCreate(null).
    3. Perform ! CreateDataPropertyOrThrow(totalOf, "unit", paramString).
  5. Else,
    1. Set totalOf to ? GetOptionsObject(totalOf).
  6. NOTE: The following steps read options and perform independent validation in alphabetical order (ToRelativeTemporalObject reads "relativeTo").
  7. Let relativeToRecord be ? GetTemporalRelativeToOption(totalOf).
  8. Let zonedRelativeTo be relativeToRecord.[[ZonedRelativeTo]].
  9. Let plainRelativeTo be relativeToRecord.[[PlainRelativeTo]].
  10. Let unit be ? GetTemporalUnitValuedOption(totalOf, "unit", datetime, required).
  11. Let norm be NormalizeTimeDuration(duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]]).
  12. If zonedRelativeTo is not undefined, then
    1. Let timeZone be zonedRelativeTo.[[TimeZone]].
    2. Let calendar be zonedRelativeTo.[[Calendar]].
    3. Let relativeEpochNs be zonedRelativeTo.[[Nanoseconds]].
    4. Let targetEpochNs be ? AddZonedDateTime(relativeEpochNs, timeZone, calendar, duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], norm).
    5. Let roundRecord be ? DifferenceZonedDateTimeWithRounding(relativeEpochNs, targetEpochNs, calendar, timeZone, unit, 1, unit, "trunc").
  13. Else if plainRelativeTo is not undefined, then
    1. Let targetTime be AddTime(0, 0, 0, 0, 0, 0, norm).
    2. If IsValidDuration(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]] + targetTime.[[Days]], 0, 0, 0, 0, 0, 0) is false, throw a RangeError exception.
    3. Let isoRelativeToDate be TemporalObjectToISODateRecord(plainRelativeTo).
    4. Let calendar be plainRelativeTo.[[Calendar]].
    5. Let dateDuration be CreateDurationRecord(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]] + targetTime.[[Days]], 0, 0, 0, 0, 0, 0).
    6. Let targetDate be ? CalendarDateAdd(calendar, isoRelativeToDate, dateDuration, "constrain").
    7. Let roundRecord be ? DifferencePlainDateTimeWithRounding(isoRelativeToDate.[[Year]], isoRelativeToDate.[[Month]], isoRelativeToDate.[[Day]], 0, 0, 0, 0, 0, 0, targetDate.[[Year]], targetDate.[[Month]], targetDate.[[Day]], targetTime.[[Hours]], targetTime.[[Minutes]], targetTime.[[Seconds]], targetTime.[[Milliseconds]], targetTime.[[Microseconds]], targetTime.[[Nanoseconds]], calendar, unit, 1, unit, "trunc").
  14. Else,
    1. If duration.[[Years]] ≠ 0, or duration.[[Months]] ≠ 0, or duration.[[Weeks]] ≠ 0, or IsCalendarUnit(unit) is true, throw a RangeError exception.
    2. Let normWithDays be ? Add24HourDaysToNormalizedTimeDuration(norm, duration.[[Days]]).
    3. Let roundRecord be ? RoundTimeDuration(0, normWithDays, 1, unit, "trunc").
  15. Assert: roundRecord.[[Total]] is not unset.
  16. Return 𝔽(roundRecord.[[Total]]).

7.3.22 Temporal.Duration.prototype.toString ( [ options ] )

The Temporal.Duration.prototype.toString method performs the following steps when called:

  1. Let duration be the this value.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Set options to ? GetOptionsObject(options).
  4. NOTE: The following steps read options and perform independent validation in alphabetical order (ToFractionalSecondDigits reads "fractionalSecondDigits" and ToTemporalRoundingMode reads "roundingMode").
  5. Let digits be ? GetTemporalFractionalSecondDigitsOption(options).
  6. Let roundingMode be ? GetRoundingModeOption(options, "trunc").
  7. Let smallestUnit be ? GetTemporalUnitValuedOption(options, "smallestUnit", time, undefined).
  8. If smallestUnit is "hour" or "minute", throw a RangeError exception.
  9. Let precision be ToSecondsStringPrecisionRecord(smallestUnit, digits).
  10. If precision.[[Unit]] is not "nanosecond" or precision.[[Increment]] ≠ 1, then
    1. Let norm be NormalizeTimeDuration(duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]]).
    2. Let largestUnit be DefaultTemporalLargestUnit(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]]).
    3. Let roundRecord be ? RoundTimeDuration(0, norm, precision.[[Increment]], precision.[[Unit]], roundingMode).
    4. Set norm to roundRecord.[[NormalizedDuration]].[[NormalizedTime]].
    5. Let result be ! BalanceTimeDuration(norm, LargerOfTwoTemporalUnits(largestUnit, "second")).
    6. Set result to CreateDurationRecord(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]] + result.[[Days]], result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]).
  11. Else,
    1. Let result be duration.
  12. Let normSeconds be NormalizeTimeDuration(0, 0, result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]).
  13. Return TemporalDurationToString(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]], normSeconds, precision.[[Precision]]).

7.3.23 Temporal.Duration.prototype.toJSON ( )

The Temporal.Duration.prototype.toJSON method performs the following steps when called:

  1. Let duration be the this value.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Let normSeconds be NormalizeTimeDuration(0, 0, duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]]).
  4. Return TemporalDurationToString(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], duration.[[Hours]], duration.[[Minutes]], normSeconds, "auto").

7.3.24 Temporal.Duration.prototype.toLocaleString ( [ locales [ , options ] ] )

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.
  2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]).
  3. Let normSeconds be NormalizeTimeDuration(0, 0, duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]]).
  4. Return TemporalDurationToString(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], duration.[[Hours]], duration.[[Minutes]], normSeconds, "auto").

7.3.25 Temporal.Duration.prototype.valueOf ( )

The Temporal.Duration.prototype.valueOf method performs the following steps when called:

  1. Throw a TypeError exception.
Note

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().

7.4 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 Table 9.

A float64-representable integer is an integer that is exactly representable as a Number value. That is, for a float64-representable integer x, it must hold that (𝔽(x)) = x.

Note
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.
Table 9: Internal Slots of Temporal.Duration Instances
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.

7.5 Abstract Operations

7.5.1 Duration Records

A Duration Record is a Record value used to represent a Temporal.Duration object. Duration Records are produced by the abstract operation CreateDurationRecord, among others.

Duration Records have the fields listed in Table 10.

Table 10: Duration Record Fields
Field Name Property Name Value Meaning
[[Years]] "years" a float64-representable integer The number of years in the duration.
[[Months]] "months" a float64-representable integer The number of months in the duration.
[[Weeks]] "weeks" a float64-representable integer The number of weeks in the duration.
[[Days]] "days" a float64-representable integer The number of days in the duration.
[[Hours]] "hours" a float64-representable integer The number of hours in the duration.
[[Minutes]] "minutes" a float64-representable integer The number of minutes in the duration.
[[Seconds]] "seconds" a float64-representable integer The number of seconds in the duration.
[[Milliseconds]] "milliseconds" a float64-representable integer The number of milliseconds in the duration.
[[Microseconds]] "microseconds" a float64-representable integer The number of microseconds in the duration.
[[Nanoseconds]] "nanoseconds" a float64-representable integer The number of nanoseconds in the duration.

7.5.2 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.

Of the fields listed in Table 10, Date Duration Records have [[Years]], [[Months]], [[Weeks]], and [[Days]].

7.5.3 Time Duration Records

A Time Duration Record is a Record value used to represent the portion of a Temporal.Duration object that deals with exact time units. Time Duration Records are produced by the abstract operation CreateTimeDurationRecord, among others.

Of the fields listed in Table 10, Time Duration Records have [[Days]], [[Hours]], [[Minutes]], [[Seconds]], [[Milliseconds]], [[Microseconds]], and [[Nanoseconds]].

7.5.4 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 same fields listed in Table 10. Unlike Duration Records, each field of a partial Duration Record may also have the value undefined as long as there is at least one field that is not undefined.

7.5.5 Normalized Time Duration Records

A Normalized Time Duration Record is a Record value used to represent the portion of a Temporal.Duration object that deals with time units, but as a combined value. Normalized Time Duration Records are produced by the abstract operation NormalizeTimeDuration, among others.

Normalized Time Duration Records have the fields listed in Table 11.

Table 11: Normalized Time Duration Record Fields
Field Name Value Meaning
[[TotalNanoseconds]] an integer in the inclusive interval from -maxTimeDuration to maxTimeDuration, where maxTimeDuration = 253 × 109 - 1 = 9,007,199,254,740,991,999,999,999 The number of nanoseconds in the duration.

7.5.6 Normalized Duration Records

A Normalized Duration Record is a Record value used to represent the combination of a Date Duration Record with a Normalized Time Duration Record. Such Records are used by operations that deal with both date and time portions of durations, such as RoundTimeDuration.

Normalized Duration Records have the fields listed in Table 12.

Table 12: Normalized Duration Record Fields
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.
[[NormalizedTime]] a Normalized Time Duration Record The time portion of the duration.

7.5.7 CreateDurationRecord ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds )

The abstract operation CreateDurationRecord takes arguments 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), and nanoseconds (an integer) and returns a Duration Record. It performs the following steps when called:

  1. Assert: IsValidDuration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds) is true.
  2. Return Duration Record { [[Years]]: (𝔽(years)), [[Months]]: (𝔽(months)), [[Weeks]]: (𝔽(weeks)), [[Days]]: (𝔽(days)), [[Hours]]: (𝔽(hours)), [[Minutes]]: (𝔽(minutes)), [[Seconds]]: (𝔽(seconds)), [[Milliseconds]]: (𝔽(milliseconds)), [[Microseconds]]: (𝔽(microseconds)), [[Nanoseconds]]: (𝔽(nanoseconds))  }.

7.5.8 CreateDateDurationRecord ( years, months, weeks, days )

The abstract operation CreateDateDurationRecord takes arguments years (an integer), months (an integer), weeks (an integer), and days (an integer) and returns either a normal completion containing a Date Duration Record or a throw completion. It performs the following steps when called:

  1. If IsValidDuration(years, months, weeks, days, 0, 0, 0, 0, 0, 0) is false, throw a RangeError exception.
  2. Return Date Duration Record { [[Years]]: (𝔽(years)), [[Months]]: (𝔽(months)), [[Weeks]]: (𝔽(weeks)), [[Days]]: (𝔽(days))  }.

7.5.9 CreateTimeDurationRecord ( days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds )

The abstract operation CreateTimeDurationRecord takes arguments days (an integer), hours (an integer), minutes (an integer), seconds (an integer), milliseconds (an integer), microseconds (an integer), and nanoseconds (an integer) and returns a Time Duration Record. It performs the following steps when called:

  1. Assert: IsValidDuration(0, 0, 0, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds) is true.
  2. Return Time Duration Record { [[Days]]: (𝔽(days)), [[Hours]]: (𝔽(hours)), [[Minutes]]: (𝔽(minutes)), [[Seconds]]: (𝔽(seconds)), [[Milliseconds]]: (𝔽(milliseconds)), [[Microseconds]]: (𝔽(microseconds)), [[Nanoseconds]]: (𝔽(nanoseconds))  }.

7.5.10 CreateNormalizedDurationRecord ( years, months, weeks, days, norm )

The abstract operation CreateNormalizedDurationRecord takes arguments years (an integer), months (an integer), weeks (an integer), days (an integer), and norm (a Normalized Time Duration Record) and returns either a normal completion containing a Normalized Duration Record or a throw completion. It performs the following steps when called:

  1. Let dateDurationRecord be ? CreateDateDurationRecord(years, months, weeks, days).
  2. Return ? CombineDateAndNormalizedTimeDuration(dateDurationRecord, norm).

7.5.11 CombineDateAndNormalizedTimeDuration ( dateDurationRecord, norm )

The abstract operation CombineDateAndNormalizedTimeDuration takes arguments dateDurationRecord (a Date Duration Record) and norm (a Normalized Time Duration Record) and returns either a normal completion containing a Normalized Duration Record or a throw completion. It performs the following steps when called:

  1. Let dateSign be DurationSign(dateDurationRecord.[[Years]], dateDurationRecord.[[Months]], dateDurationRecord.[[Weeks]], dateDurationRecord.[[Days]], 0, 0, 0, 0, 0, 0).
  2. Let timeSign be NormalizedTimeDurationSign(norm).
  3. If dateSign ≠ 0 and timeSign ≠ 0 and dateSigntimeSign, throw a RangeError exception.
  4. Return Normalized Duration Record { [[Years]]: dateDurationRecord.[[Years]], [[Months]]: dateDurationRecord.[[Months]], [[Weeks]]: dateDurationRecord.[[Weeks]], [[Days]]: dateDurationRecord.[[Days]], [[NormalizedTime]]: norm  }.

7.5.12 ToTemporalDuration ( item )

The abstract operation ToTemporalDuration takes argument item (an ECMAScript language value) and returns either a normal completion containing a Temporal.Duration or a throw completion. It returns its argument item if it is already a Temporal.Duration instance, converts item to a new Temporal.Duration instance if possible and returns that, and throws otherwise. It performs the following steps when called:

  1. If item is an Object and item has an [[InitializedTemporalDuration]] internal slot, then
    1. Return item.
  2. Let result be ? ToTemporalDurationRecord(item).
  3. Return ! CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]).

7.5.13 ToTemporalDurationRecord ( temporalDurationLike )

The abstract operation ToTemporalDurationRecord takes argument temporalDurationLike (an ECMAScript language value) and returns either a normal completion containing a Duration Record or a throw completion. The returned Record has its fields set according to the properties of temporalDurationLike, with absent or undefined properties corresponding to fields containing 0. It performs the following steps when called:

  1. If temporalDurationLike is not an Object, then
    1. If temporalDurationLike is not a String, throw a TypeError exception.
    2. Return ? ParseTemporalDurationString(temporalDurationLike).
  2. If temporalDurationLike has an [[InitializedTemporalDuration]] internal slot, then
    1. Return CreateDurationRecord(temporalDurationLike.[[Years]], temporalDurationLike.[[Months]], temporalDurationLike.[[Weeks]], temporalDurationLike.[[Days]], temporalDurationLike.[[Hours]], temporalDurationLike.[[Minutes]], temporalDurationLike.[[Seconds]], temporalDurationLike.[[Milliseconds]], temporalDurationLike.[[Microseconds]], temporalDurationLike.[[Nanoseconds]]).
  3. Let result be a new Duration Record with each field set to 0.
  4. Let partial be ? ToTemporalPartialDurationRecord(temporalDurationLike).
  5. If partial.[[Years]] is not undefined, set result.[[Years]] to partial.[[Years]].
  6. If partial.[[Months]] is not undefined, set result.[[Months]] to partial.[[Months]].
  7. If partial.[[Weeks]] is not undefined, set result.[[Weeks]] to partial.[[Weeks]].
  8. If partial.[[Days]] is not undefined, set result.[[Days]] to partial.[[Days]].
  9. If partial.[[Hours]] is not undefined, set result.[[Hours]] to partial.[[Hours]].
  10. If partial.[[Minutes]] is not undefined, set result.[[Minutes]] to partial.[[Minutes]].
  11. If partial.[[Seconds]] is not undefined, set result.[[Seconds]] to partial.[[Seconds]].
  12. If partial.[[Milliseconds]] is not undefined, set result.[[Milliseconds]] to partial.[[Milliseconds]].
  13. If partial.[[Microseconds]] is not undefined, set result.[[Microseconds]] to partial.[[Microseconds]].
  14. If partial.[[Nanoseconds]] is not undefined, set result.[[Nanoseconds]] to partial.[[Nanoseconds]].
  15. If IsValidDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]) is false, then
    1. Throw a RangeError exception.
  16. Return result.

7.5.14 DurationSign ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds )

The abstract operation DurationSign takes arguments 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), and nanoseconds (an integer) and returns -1, 0, or 1. It returns 1 if the most significant non-zero element in its arguments is positive, and -1 if the most significant non-zero element is negative. If all of its arguments are zero, it returns 0. It performs the following steps when called:

  1. For each value v of « years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds », do
    1. If v < 0, return -1.
    2. If v > 0, return 1.
  2. Return 0.

7.5.15 IsValidDuration ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds )

The abstract operation IsValidDuration takes arguments 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), and nanoseconds (an integer) and returns a Boolean. It returns true if its arguments form valid input from which to construct a Temporal.Duration, and false otherwise. It performs the following steps when called:

  1. Let sign be DurationSign(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
  2. For each value v of « years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds », do
    1. If 𝔽(v) is not finite, return false.
    2. If v < 0 and sign > 0, return false.
    3. If v > 0 and sign < 0, return false.
  3. If abs(years) ≥ 232, return false.
  4. If abs(months) ≥ 232, return false.
  5. If abs(weeks) ≥ 232, return false.
  6. Let normalizedSeconds be days × 86,400 + hours × 3600 + minutes × 60 + seconds + (𝔽(milliseconds)) × 10-3 + (𝔽(microseconds)) × 10-6 + (𝔽(nanoseconds)) × 10-9.
  7. NOTE: The above step cannot be implemented directly using 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. This multiplication can 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.
  8. If abs(normalizedSeconds) ≥ 253, return false.
  9. Return true.

7.5.16 DefaultTemporalLargestUnit ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds )

The abstract operation DefaultTemporalLargestUnit takes arguments years (an integer), months (an integer), weeks (an integer), days (an integer), hours (an integer), minutes (an integer), seconds (an integer), milliseconds (an integer), and microseconds (an integer) and returns a String from the "Singular" column of Table 21. 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 non-zero unit in the input Temporal.Duration. It performs the following steps when called:

  1. If years ≠ 0, return "year".
  2. If months ≠ 0, return "month".
  3. If weeks ≠ 0, return "week".
  4. If days ≠ 0, return "day".
  5. If hours ≠ 0, return "hour".
  6. If minutes ≠ 0, return "minute".
  7. If seconds ≠ 0, return "second".
  8. If milliseconds ≠ 0, return "millisecond".
  9. If microseconds ≠ 0, return "microsecond".
  10. Return "nanosecond".

7.5.17 ToTemporalPartialDurationRecord ( temporalDurationLike )

The abstract operation ToTemporalPartialDurationRecord takes argument temporalDurationLike (an ECMAScript language value) and returns either a normal completion containing a partial Duration Record or a throw completion. The returned Record has its fields set according to the properties of temporalDurationLike. It performs the following steps when called:

  1. If temporalDurationLike is not an Object, then
    1. Throw a TypeError exception.
  2. Let result be a new partial Duration Record with each field set to undefined.
  3. NOTE: The following steps read properties and perform independent validation in alphabetical order.
  4. Let days be ? Get(temporalDurationLike, "days").
  5. If days is not undefined, set result.[[Days]] to ? ToIntegerIfIntegral(days).
  6. Let hours be ? Get(temporalDurationLike, "hours").
  7. If hours is not undefined, set result.[[Hours]] to ? ToIntegerIfIntegral(hours).
  8. Let microseconds be ? Get(temporalDurationLike, "microseconds").
  9. If microseconds is not undefined, set result.[[Microseconds]] to ? ToIntegerIfIntegral(microseconds).
  10. Let milliseconds be ? Get(temporalDurationLike, "milliseconds").
  11. If milliseconds is not undefined, set result.[[Milliseconds]] to ? ToIntegerIfIntegral(milliseconds).
  12. Let minutes be ? Get(temporalDurationLike, "minutes").
  13. If minutes is not undefined, set result.[[Minutes]] to ? ToIntegerIfIntegral(minutes).
  14. Let months be ? Get(temporalDurationLike, "months").
  15. If months is not undefined, set result.[[Months]] to ? ToIntegerIfIntegral(months).
  16. Let nanoseconds be ? Get(temporalDurationLike, "nanoseconds").
  17. If nanoseconds is not undefined, set result.[[Nanoseconds]] to ? ToIntegerIfIntegral(nanoseconds).
  18. Let seconds be ? Get(temporalDurationLike, "seconds").
  19. If seconds is not undefined, set result.[[Seconds]] to ? ToIntegerIfIntegral(seconds).
  20. Let weeks be ? Get(temporalDurationLike, "weeks").
  21. If weeks is not undefined, set result.[[Weeks]] to ? ToIntegerIfIntegral(weeks).
  22. Let years be ? Get(temporalDurationLike, "years").
  23. If years is not undefined, set result.[[Years]] to ? ToIntegerIfIntegral(years).
  24. 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.
  25. Return result.

7.5.18 CreateTemporalDuration ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds [ , newTarget ] )

The abstract operation CreateTemporalDuration takes arguments 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), and nanoseconds (an integer) and optional argument newTarget (a constructor) and returns either a normal completion containing a Temporal.Duration or a throw completion. It creates a Temporal.Duration instance and fills the internal slots with valid values. It performs the following steps when called:

  1. If IsValidDuration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds) is false, throw a RangeError exception.
  2. If newTarget is not present, set newTarget to %Temporal.Duration%.
  3. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.Duration.prototype%", « [[InitializedTemporalDuration]], [[Years]], [[Months]], [[Weeks]], [[Days]], [[Hours]], [[Minutes]], [[Seconds]], [[Milliseconds]], [[Microseconds]], [[Nanoseconds]] »).
  4. Set object.[[Years]] to (𝔽(years)).
  5. Set object.[[Months]] to (𝔽(months)).
  6. Set object.[[Weeks]] to (𝔽(weeks)).
  7. Set object.[[Days]] to (𝔽(days)).
  8. Set object.[[Hours]] to (𝔽(hours)).
  9. Set object.[[Minutes]] to (𝔽(minutes)).
  10. Set object.[[Seconds]] to (𝔽(seconds)).
  11. Set object.[[Milliseconds]] to (𝔽(milliseconds)).
  12. Set object.[[Microseconds]] to (𝔽(microseconds)).
  13. Set object.[[Nanoseconds]] to (𝔽(nanoseconds)).
  14. Return object.

7.5.19 CreateNegatedTemporalDuration ( duration )

The abstract operation CreateNegatedTemporalDuration takes argument duration (a Temporal.Duration) and returns a Temporal.Duration. It returns a new Temporal.Duration instance that is the negation of duration. It performs the following steps when called:

  1. Return ! CreateTemporalDuration(-duration.[[Years]], -duration.[[Months]], -duration.[[Weeks]], -duration.[[Days]], -duration.[[Hours]], -duration.[[Minutes]], -duration.[[Seconds]], -duration.[[Milliseconds]], -duration.[[Microseconds]], -duration.[[Nanoseconds]]).

7.5.20 NormalizeTimeDuration ( hours, minutes, seconds, milliseconds, microseconds, nanoseconds )

The abstract operation NormalizeTimeDuration takes arguments hours (an integer), minutes (an integer), seconds (an integer), milliseconds (an integer), microseconds (an integer), and nanoseconds (an integer) and returns a Normalized Time Duration Record. From the given units, it computes a normalized time duration consisting of whole seconds, and subseconds expressed in nanoseconds. The normalized time duration can be stored losslessly in two 64-bit floating point numbers. Alternatively, normalizedSeconds × 109 + subseconds can be stored as a 96-bit integer. It performs the following steps when called:

  1. Set minutes to minutes + hours × 60.
  2. Set seconds to seconds + minutes × 60.
  3. Set milliseconds to milliseconds + seconds × 1000.
  4. Set microseconds to microseconds + milliseconds × 1000.
  5. Set nanoseconds to nanoseconds + microseconds × 1000.
  6. Assert: abs(nanoseconds) ≤ maxTimeDuration.
  7. Return Normalized Time Duration Record { [[TotalNanoseconds]]: nanoseconds }.

7.5.21 NormalizedTimeDurationAbs ( d )

The abstract operation NormalizedTimeDurationAbs takes argument d (a Normalized Time Duration Record) and returns a Normalized Time Duration Record. It returns a new normalized time duration that is the absolute value of d. It performs the following steps when called:

  1. Return Normalized Time Duration Record { [[TotalNanoseconds]]: abs(d.[[TotalNanoseconds]]) }.

7.5.22 AddNormalizedTimeDuration ( one, two )

The abstract operation AddNormalizedTimeDuration takes arguments one (a Normalized Time Duration Record) and two (a Normalized Time Duration Record) and returns either a normal completion containing a Normalized Time Duration Record or a throw completion. It returns a normalized time duration that is the sum of one and two, throwing an exception if the result is greater than the maximum normalized time duration. It performs the following steps when called:

  1. Let result be one.[[TotalNanoseconds]] + two.[[TotalNanoseconds]].
  2. If abs(result) > maxTimeDuration, throw a RangeError exception.
  3. Return Normalized Time Duration Record { [[TotalNanoseconds]]: result }.

7.5.23 Add24HourDaysToNormalizedTimeDuration ( d, days )

The abstract operation Add24HourDaysToNormalizedTimeDuration takes arguments d (a Normalized Time Duration Record) and days (an integer) and returns either a normal completion containing a Normalized Time Duration Record or a throw completion. It returns a normalized 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 normalized 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. It performs the following steps when called:

  1. Let result be d.[[TotalNanoseconds]] + days × nsPerDay.
  2. If abs(result) > maxTimeDuration, throw a RangeError exception.
  3. Return Normalized Time Duration Record { [[TotalNanoseconds]]: result }.

7.5.24 AddNormalizedTimeDurationToEpochNanoseconds ( d, epochNs )

The abstract operation AddNormalizedTimeDurationToEpochNanoseconds takes arguments d (a Normalized Time Duration Record) and epochNs (a BigInt) and returns a BigInt. It adds a normalized 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. It performs the following steps when called:

  1. Return epochNs + (d.[[TotalNanoseconds]]).

7.5.25 CompareNormalizedTimeDuration ( one, two )

The abstract operation CompareNormalizedTimeDuration takes arguments one (a Normalized Time Duration Record) and two (a Normalized Time Duration Record) and returns -1, 0, or 1. It performs a comparison of two Normalized Time Duration Records. It performs the following steps when called:

  1. If one.[[TotalNanoseconds]] > two.[[TotalNanoseconds]], return 1.
  2. If one.[[TotalNanoseconds]] < two.[[TotalNanoseconds]], return -1.
  3. Return 0.

7.5.26 DivideNormalizedTimeDuration ( d, divisor )

The abstract operation DivideNormalizedTimeDuration takes arguments d (a Normalized Time Duration Record) and divisor (an integer) and returns a mathematical value. It divides the total number of nanoseconds in the normalized time duration d by divisor. It performs the following steps when called:

  1. Assert: divisor ≠ 0.
  2. NOTE: The following step cannot be implemented directly using floating-point arithmetic when 𝔽(d.[[TotalNanoseconds]]) 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.
  3. Return d.[[TotalNanoseconds]] / divisor.

7.5.27 NormalizedTimeDurationFromEpochNanosecondsDifference ( one, two )

The abstract operation NormalizedTimeDurationFromEpochNanosecondsDifference takes arguments one (a BigInt) and two (a BigInt) and returns a Normalized Time Duration Record. It creates a Normalized Time Duration Record with the difference between two exact times in nanoseconds since the epoch, which must not be greater than the maximum normalized time duration. It performs the following steps when called:

  1. Let result be (one) - (two).
  2. Assert: abs(result) ≤ maxTimeDuration.
  3. Return Normalized Time Duration Record { [[TotalNanoseconds]]: result }.

7.5.28 NormalizedTimeDurationIsZero ( d )

The abstract operation NormalizedTimeDurationIsZero takes argument d (a Normalized Time Duration Record) and returns a Boolean. It returns true if d is a zero duration, false otherwise. It performs the following steps when called:

  1. If d.[[TotalNanoseconds]] = 0, return true.
  2. Return false.

7.5.29 RoundNormalizedTimeDurationToIncrement ( d, increment, roundingMode )

The abstract operation RoundNormalizedTimeDurationToIncrement takes arguments d (a Normalized Time Duration Record), increment (a positive integer), and roundingMode (a String from the "Identifier" column of Table 22) and returns either a normal completion containing a Normalized Time Duration Record or a throw completion. It rounds the total number of nanoseconds in the normalized time duration d to the nearest multiple of increment, up or down according to roundingMode. It performs the following steps when called:

  1. Let rounded be RoundNumberToIncrement(d.[[TotalNanoseconds]], increment, roundingMode).
  2. If abs(rounded) > maxTimeDuration, throw a RangeError exception.
  3. Return Normalized Time Duration Record { [[TotalNanoseconds]]: rounded }.

7.5.30 NormalizedTimeDurationSeconds ( d )

The abstract operation NormalizedTimeDurationSeconds takes argument d (a Normalized Time Duration Record) and returns an integer in the interval from -253 (exclusive) to 253 (exclusive). It returns the integer number of seconds in d. It performs the following steps when called:

  1. Return truncate(d.[[TotalNanoseconds]] / 109).

7.5.31 NormalizedTimeDurationSign ( d )

The abstract operation NormalizedTimeDurationSign takes argument d (a Normalized Time Duration Record) and returns -1, 0, or 1. It returns 0 if the duration is zero, or ±1 depending on the sign of the duration. It performs the following steps when called:

  1. If d.[[TotalNanoseconds]] < 0, return -1.
  2. If d.[[TotalNanoseconds]] > 0, return 1.
  3. Return 0.

7.5.32 NormalizedTimeDurationSubseconds ( d )

The abstract operation NormalizedTimeDurationSubseconds takes argument d (a Normalized Time Duration Record) and returns an integer in the interval from -109 (exclusive) to 109 (exclusive). It returns the integer number of nanoseconds in the subsecond part of d. It performs the following steps when called:

  1. Return remainder(d.[[TotalNanoseconds]], 109).

7.5.33 SubtractNormalizedTimeDuration ( one, two )

The abstract operation SubtractNormalizedTimeDuration takes arguments one (a Normalized Time Duration Record) and two (a Normalized Time Duration Record) and returns either a normal completion containing a Normalized Time Duration Record or a throw completion. It returns a normalized time duration that is the difference between one and two, throwing an exception if the result is greater than the maximum normalized time duration. It performs the following steps when called:

  1. Let result be one.[[TotalNanoseconds]] - two.[[TotalNanoseconds]].
  2. If abs(result) > maxTimeDuration, throw a RangeError exception.
  3. Return Normalized Time Duration Record { [[TotalNanoseconds]]: result }.

7.5.34 ZeroTimeDuration ( )

The abstract operation ZeroTimeDuration takes no arguments and returns a Normalized Time Duration Record. It returns a normalized time duration of zero length. It performs the following steps when called:

  1. Return Normalized Time Duration Record { [[TotalNanoseconds]]: 0 }.

7.5.35 BalanceTimeDuration ( norm, largestUnit )

The abstract operation BalanceTimeDuration takes arguments norm (a Normalized Time Duration Record) and largestUnit (a String) and returns either a normal completion containing a Time Duration Record or a throw completion. It converts a normalized time duration into a time duration with separated units, up to largestUnit. The conversion may be lossy if largestUnit is "milliseconds", "microseconds", or "nanoseconds". In that case, the fields of the returned Time Duration Record may be 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. It performs the following steps when called:

  1. Let days, hours, minutes, seconds, milliseconds, and microseconds be 0.
  2. Let sign be NormalizedTimeDurationSign(norm).
  3. Let nanoseconds be NormalizedTimeDurationAbs(norm).[[TotalNanoseconds]].
  4. If largestUnit is "year", "month", "week", or "day", then
    1. Set microseconds to floor(nanoseconds / 1000).
    2. Set nanoseconds to nanoseconds modulo 1000.
    3. Set milliseconds to floor(microseconds / 1000).
    4. Set microseconds to microseconds modulo 1000.
    5. Set seconds to floor(milliseconds / 1000).
    6. Set milliseconds to milliseconds modulo 1000.
    7. Set minutes to floor(seconds / 60).
    8. Set seconds to seconds modulo 60.
    9. Set hours to floor(minutes / 60).
    10. Set minutes to minutes modulo 60.
    11. Set days to floor(hours / 24).
    12. Set hours to hours modulo 24.
  5. Else if largestUnit is "hour", then
    1. Set microseconds to floor(nanoseconds / 1000).
    2. Set nanoseconds to nanoseconds modulo 1000.
    3. Set milliseconds to floor(microseconds / 1000).
    4. Set microseconds to microseconds modulo 1000.
    5. Set seconds to floor(milliseconds / 1000).
    6. Set milliseconds to milliseconds modulo 1000.
    7. Set minutes to floor(seconds / 60).
    8. Set seconds to seconds modulo 60.
    9. Set hours to floor(minutes / 60).
    10. Set minutes to minutes modulo 60.
  6. Else if largestUnit is "minute", then
    1. Set microseconds to floor(nanoseconds / 1000).
    2. Set nanoseconds to nanoseconds modulo 1000.
    3. Set milliseconds to floor(microseconds / 1000).
    4. Set microseconds to microseconds modulo 1000.
    5. Set seconds to floor(milliseconds / 1000).
    6. Set milliseconds to milliseconds modulo 1000.
    7. Set minutes to floor(seconds / 60).
    8. Set seconds to seconds modulo 60.
  7. Else if largestUnit is "second", then
    1. Set microseconds to floor(nanoseconds / 1000).
    2. Set nanoseconds to nanoseconds modulo 1000.
    3. Set milliseconds to floor(microseconds / 1000).
    4. Set microseconds to microseconds modulo 1000.
    5. Set seconds to floor(milliseconds / 1000).
    6. Set milliseconds to milliseconds modulo 1000.
  8. Else if largestUnit is "millisecond", then
    1. Set microseconds to floor(nanoseconds / 1000).
    2. Set nanoseconds to nanoseconds modulo 1000.
    3. Set milliseconds to floor(microseconds / 1000).
    4. Set microseconds to microseconds modulo 1000.
  9. Else if largestUnit is "microsecond", then
    1. Set microseconds to floor(nanoseconds / 1000).
    2. Set nanoseconds to nanoseconds modulo 1000.
  10. Else,
    1. Assert: largestUnit is "nanosecond".
  11. 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.
  12. If IsValidDuration(0, 0, 0, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds) is false, throw a RangeError exception.
  13. Return CreateTimeDurationRecord(days × sign, hours × sign, minutes × sign, seconds × sign, milliseconds × sign, microseconds × sign, nanoseconds × sign).

7.5.36 UnbalanceDateDurationRelative ( years, months, weeks, days, plainRelativeTo )

The abstract operation UnbalanceDateDurationRelative takes arguments years (an integer), months (an integer), weeks (an integer), days (an integer), and plainRelativeTo (a Temporal.PlainDate) and returns either a normal completion containing an integer or a throw completion. It converts the calendar units of a duration into a number of days, and returns the result. It performs the following steps when called:

  1. If years = 0 and months = 0 and weeks = 0, return days.
  2. Let isoDate be TemporalObjectToISODateRecord(plainRelativeTo).
  3. Let yearsMonthsWeeksDuration be CreateDurationRecord(years, months, weeks, 0, 0, 0, 0, 0, 0, 0).
  4. Let later be ? CalendarDateAdd(plainRelativeTo.[[Calendar]], isoDate, yearsMonthsWeeksDuration, "constrain").
  5. Let epochDays1 be ISODateToEpochDays(isoDate.[[Year]], isoDate.[[Month]] - 1, isoDate.[[Day]]).
  6. Let epochDays2 be ISODateToEpochDays(later.[[Year]], later.[[Month]] - 1, later.[[Day]]).
  7. Let yearsMonthsWeeksInDays be epochDays2 - epochDays1.
  8. Return days + yearsMonthsWeeksInDays.

7.5.37 RoundTimeDuration ( days, norm, increment, unit, roundingMode )

The abstract operation RoundTimeDuration takes arguments days (an integer), norm (a Normalized Time Duration Record), increment (a positive integer), unit (a String from the "Singular" column of Table 21), and roundingMode (a String from the "Identifier" column of Table 22) and returns either a normal completion containing a Record with fields [[NormalizedDuration]] (a Normalized Duration Record) and [[Total]] (a mathematical value), or a throw completion. It rounds a duration (denoted by days and norm) according to the rounding parameters unit, increment, and roundingMode, and returns a Record with the Normalized Duration Record result in its [[NormalizedDuration]] field. It also returns the total of the smallest unit before the rounding operation in its [[Total]] field, for use in Temporal.Duration.prototype.total. It performs the following steps when called:

  1. Assert: IsCalendarUnit(unit) is false.
  2. If unit is "day", then
    1. Let fractionalDays be days + DivideNormalizedTimeDuration(norm, nsPerDay).
    2. Set days to RoundNumberToIncrement(fractionalDays, increment, roundingMode).
    3. Let total be fractionalDays.
    4. Set norm to ZeroTimeDuration().
  3. Else,
    1. Assert: The value in the "Category" column of the row of Table 21 whose "Singular" column contains unit, is time.
    2. Let divisor be the value in the "Length in Nanoseconds" column of the row of Table 21 whose "Singular" column contains unit.
    3. Let total be DivideNormalizedTimeDuration(norm, divisor).
    4. Set norm to ? RoundNormalizedTimeDurationToIncrement(norm, divisor × increment, roundingMode).
  4. Return the Record { [[NormalizedDuration]]: ? CreateNormalizedDurationRecord(0, 0, 0, days, norm), [[Total]]: total  }.

7.5.38 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 Table 13.

Table 13: Duration Nudge Result Record Fields
Field Name Value Meaning
[[Duration]] a Normalized Duration Record The resulting duration.
[[Total]] a mathematical value or unset The possibly fractional total of the smallest unit before the rounding operation, for use in Temporal.Duration.prototype.total, or unset if not relevant.
[[NudgedEpochNs]] a BigInt 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.

7.5.39 NudgeToCalendarUnit ( sign, duration, destEpochNs, dateTime, calendar, timeZone, increment, unit, roundingMode )

The abstract operation NudgeToCalendarUnit takes arguments sign (-1 or 1), duration (a Normalized Duration Record), destEpochNs (a BigInt), dateTime (an ISO Date-Time Record), calendar (a String), timeZone (a String or unset), increment (a positive integer), unit (a String from the "Singular" column of Table 21), and roundingMode (a String from the "Identifier" column of Table 22) and returns either a normal completion containing a Duration Nudge Result Record or a throw completion. 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. It performs the following steps when called:

  1. If unit is "year", then
    1. Let years be RoundNumberToIncrement(duration.[[Years]], increment, "trunc").
    2. Let r1 be years.
    3. Let r2 be years + increment × sign.
    4. Let startDuration be ? CreateDateDurationRecord(r1, 0, 0, 0).
    5. Let endDuration be ? CreateDateDurationRecord(r2, 0, 0, 0).
  2. Else if unit is "month", then
    1. Let months be RoundNumberToIncrement(duration.[[Months]], increment, "trunc").
    2. Let r1 be months.
    3. Let r2 be months + increment × sign.
    4. Let startDuration be ? CreateDateDurationRecord(duration.[[Years]], r1, 0, 0).
    5. Let endDuration be ? CreateDateDurationRecord(duration.[[Years]], r2, 0, 0).
  3. Else if unit is "week", then
    1. Let weeksStart be BalanceISODate(dateTime.[[Year]] + duration.[[Years]], dateTime.[[Month]] + duration.[[Months]], dateTime.[[Day]]).
    2. Let weeksEnd be BalanceISODate(dateTime.[[Year]] + duration.[[Years]], dateTime.[[Month]] + duration.[[Months]], dateTime.[[Day]] + duration.[[Days]]).
    3. Let untilResult be CalendarDateUntil(calendar, weeksStart, weeksEnd, "week").
    4. Let weeks be RoundNumberToIncrement(duration.[[Weeks]] + untilResult.[[Weeks]], increment, "trunc").
    5. Let r1 be weeks.
    6. Let r2 be weeks + increment × sign.
    7. Let startDuration be ? CreateDateDurationRecord(duration.[[Years]], duration.[[Months]], r1, 0).
    8. Let endDuration be ? CreateDateDurationRecord(duration.[[Years]], duration.[[Months]], r2, 0).
  4. Else,
    1. Assert: unit is "day".
    2. Let days be RoundNumberToIncrement(duration.[[Days]], increment, "trunc").
    3. Let r1 be days.
    4. Let r2 be days + increment × sign.
    5. Let startDuration be ? CreateDateDurationRecord(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], r1).
    6. Let endDuration be ? CreateDateDurationRecord(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], r2).
  5. Assert: If sign is 1, r1 ≥ 0 and r1 < r2.
  6. Assert: If sign is -1, r1 ≤ 0 and r1 > r2.
  7. Let startDate be ISODateTimeToDateRecord(dateTime).
  8. Let start be ? CalendarDateAdd(calendar, startDate, startDuration, "constrain").
  9. Let end be ? CalendarDateAdd(calendar, startDate, endDuration, "constrain").
  10. If timeZone is unset, then
    1. Let startEpochNs be GetUTCEpochNanoseconds(start.[[Year]], start.[[Month]], start.[[Day]], dateTime.[[Hour]], dateTime.[[Minute]], dateTime.[[Second]], dateTime.[[Millisecond]], dateTime.[[Microsecond]], dateTime.[[Nanosecond]]).
    2. Let endEpochNs be GetUTCEpochNanoseconds(end.[[Year]], end.[[Month]], end.[[Day]], dateTime.[[Hour]], dateTime.[[Minute]], dateTime.[[Second]], dateTime.[[Millisecond]], dateTime.[[Microsecond]], dateTime.[[Nanosecond]]).
  11. Else,
    1. Let startDateTime be CombineISODateAndTimeRecord(start, dateTime).
    2. Let startEpochNs be ? GetEpochNanosecondsFor(timeZone, startDateTime, "compatible").
    3. Let endDateTime be CombineISODateAndTimeRecord(end, dateTime).
    4. Let endEpochNs be ? GetEpochNanosecondsFor(timeZone, endDateTime, "compatible").
  12. If sign is 1, then
    1. Assert: startEpochNsdestEpochNsendEpochNs.
  13. Else,
    1. Assert: endEpochNsdestEpochNsstartEpochNs.
  14. Assert: startEpochNsendEpochNs.
  15. Let progress be (destEpochNs - startEpochNs) / (endEpochNs - startEpochNs).
  16. Let total be r1 + progress × increment × sign.
  17. NOTE: The above two steps cannot be implemented directly using floating-point arithmetic. This division can be implemented as if constructing Normalized Time Duration Records for the denominator and numerator of total and performing one division operation with a floating-point result.
  18. Assert: 0 ≤ progress ≤ 1.
  19. If sign < 0, let isNegative be negative; else let isNegative be positive.
  20. Let unsignedRoundingMode be GetUnsignedRoundingMode(roundingMode, isNegative).
  21. If progress = 1, then
    1. Let roundedUnit be abs(r2).
  22. Else,
    1. Assert: abs(r1) ≤ abs(total) < abs(r2).
    2. Let roundedUnit be ApplyUnsignedRoundingMode(abs(total), abs(r1), abs(r2), unsignedRoundingMode).
  23. If roundedUnit is abs(r2), then
    1. Let didExpandCalendarUnit be true.
    2. Let resultDuration be endDuration.
    3. Let nudgedEpochNs be endEpochNs.
  24. Else,
    1. Let didExpandCalendarUnit be false.
    2. Let resultDuration be startDuration.
    3. Let nudgedEpochNs be startEpochNs.
  25. Set resultDuration to ! CombineDateAndNormalizedTimeDuration(resultDuration, ZeroTimeDuration()).
  26. Return Duration Nudge Result Record { [[Duration]]: resultDuration, [[Total]]: total, [[NudgedEpochNs]]: nudgedEpochNs, [[DidExpandCalendarUnit]]: didExpandCalendarUnit }.
Editor's Note
startDate and endDate are distinct objects because they're potentially passed to user-code when calendarRec.[[Receiver]] is a user-defined calendar.

7.5.40 NudgeToZonedTime ( sign, duration, dateTime, calendar, timeZone, increment, unit, roundingMode )

The abstract operation NudgeToZonedTime takes arguments sign (-1 or 1), duration (a Normalized Duration Record), dateTime (an ISO Date-Time Record), calendar (a String), timeZone (a String), increment (a positive integer), unit (a String from the "Singular" column of Table 21), and roundingMode (a String from the "Identifier" column of Table 22) and returns either a normal completion containing a Duration Nudge Result Record or a throw completion. 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. It performs the following steps when called:

  1. Assert: The value in the "Category" column of the row of Table 21 whose "Singular" column contains unit, is time.
  2. Let date be ISODateTimeToDateRecord(dateTime).
  3. Let dateDuration be ! CreateDateDurationRecord(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]]).
  4. Let start be ? CalendarDateAdd(calendar, date, dateDuration, "constrain").
  5. Let startDateTime be CombineISODateAndTimeRecord(start, dateTime).
  6. Let endDate be BalanceISODate(start.[[ISOYear]], start.[[ISOMonth]], start.[[ISODay]] + sign).
  7. Let endDateTime be CombineISODateAndTimeRecord(endDate, dateTime).
  8. Let startEpochNs be ? GetEpochNanosecondsFor(timeZone, startDateTime, "compatible").
  9. Let endEpochNs be ? GetEpochNanosecondsFor(timeZone, endDateTime, "compatible").
  10. Let daySpan be NormalizedTimeDurationFromEpochNanosecondsDifference(endEpochNs, startEpochNs).
  11. Assert: NormalizedTimeDurationSign(daySpan) = sign.
  12. Let unitLength be the value in the "Length in Nanoseconds" column of the row of Table 21 whose "Singular" column contains unit.
  13. Let roundedNorm be ? RoundNormalizedTimeDurationToIncrement(duration.[[NormalizedTime]], increment × unitLength, roundingMode).
  14. Let beyondDaySpan be ? SubtractNormalizedTimeDuration(roundedNorm, daySpan).
  15. If NormalizedTimeDurationSign(beyondDaySpan) ≠ -sign, then
    1. Let didRoundBeyondDay be true.
    2. Let dayDelta be sign.
    3. Set roundedNorm to ? RoundNormalizedTimeDurationToIncrement(beyondDaySpan, increment × unitLength, roundingMode).
    4. Let nudgedEpochNs be AddNormalizedTimeDurationToEpochNanoseconds(roundedNorm, endEpochNs).
  16. Else,
    1. Let didRoundBeyondDay be false.
    2. Let dayDelta be 0.
    3. Let nudgedEpochNs be AddNormalizedTimeDurationToEpochNanoseconds(roundedNorm, startEpochNs).
  17. Let resultDuration be ? CreateNormalizedDurationRecord(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]] + dayDelta, roundedNorm).
  18. Return Duration Nudge Result Record { [[Duration]]: resultDuration, [[Total]]: unset, [[NudgedEpochNs]]: nudgedEpochNs, [[DidExpandCalendarUnit]]: didRoundBeyondDay }.

7.5.41 NudgeToDayOrTime ( duration, destEpochNs, largestUnit, increment, smallestUnit, roundingMode )

The abstract operation NudgeToDayOrTime takes arguments duration (a Normalized Duration Record), destEpochNs (a BigInt), largestUnit (a String from the "Singular" column of Table 21), increment (a positive integer), smallestUnit (a String from the "Singular" column of Table 21), and roundingMode (a String from the "Identifier" column of Table 22) and returns either a normal completion containing a Duration Nudge Result Record or a throw completion. It implements rounding a duration to an increment of a time unit, in cases unaffected by the calendar or time zone. It performs the following steps when called:

  1. Assert: If smallestUnit is not "day", the value in the "Category" column of the row of Table 21 whose "Singular" column contains smallestUnit, is time.
  2. Let norm be ! Add24HourDaysToNormalizedTimeDuration(duration.[[NormalizedTime]], duration.[[Days]]).
  3. Let unitLength be the value in the "Length in Nanoseconds" column of the row of Table 21 whose "Singular" column contains smallestUnit.
  4. Let total be DivideNormalizedTimeDuration(norm, unitLength).
  5. Let roundedNorm be ? RoundNormalizedTimeDurationToIncrement(norm, unitLength × increment, roundingMode).
  6. Let diffNorm be ! SubtractNormalizedTimeDuration(roundedNorm, norm).
  7. Let wholeDays be truncate(DivideNormalizedTimeDuration(norm, nsPerDay)).
  8. Let roundedWholeDays be truncate(DivideNormalizedTimeDuration(roundedNorm, nsPerDay)).
  9. Let dayDelta be roundedWholeDays - wholeDays.
  10. If dayDelta < 0, let dayDeltaSign be -1; else if dayDelta > 0, let dayDeltaSign be 1; else let dayDeltaSign be 0.
  11. If dayDeltaSign = NormalizedTimeDurationSign(norm), let didExpandDays be true; else let didExpandDays be false.
  12. Let nudgedEpochNs be AddNormalizedTimeDurationToEpochNanoseconds(diffNorm, destEpochNs).
  13. Let days be 0.
  14. Let remainder be roundedNorm.
  15. If LargerOfTwoTemporalUnits(largestUnit, "day") is largestUnit, then
    1. Set days to roundedWholeDays.
    2. Set remainder to ! SubtractNormalizedTimeDuration(roundedNorm, NormalizeTimeDuration(roundedWholeDays * HoursPerDay, 0, 0, 0, 0, 0)).
  16. Let resultDuration be ? CreateNormalizedDurationRecord(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], days, remainder).
  17. Return Duration Nudge Result Record { [[Duration]]: resultDuration, [[Total]]: total, [[NudgedEpochNs]]: nudgedEpochNs, [[DidExpandCalendarUnit]]: didExpandDays }.

7.5.42 BubbleRelativeDuration ( sign, duration, nudgedEpochNs, dateTime, calendar, timeZone, largestUnit, smallestUnit )

The abstract operation BubbleRelativeDuration takes arguments sign (-1 or 1), duration (a Normalized Duration Record), nudgedEpochNs (a BigInt), dateTime (an ISO Date-Time Record), calendar (a String), timeZone (a String or unset), largestUnit (a String from the "Singular" column of Table 21), and smallestUnit (a String from the "Singular" column of Table 21) and returns either a normal completion containing a Normalized Duration Record or a throw completion. 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. It performs the following steps when called:

  1. Assert: The value in the "Category" column of the row of Table 21 whose "Singular" column contains largestUnit, is date.
  2. Assert: The value in the "Category" column of the row of Table 21 whose "Singular" column contains smallestUnit, is date.
  3. If smallestUnit is "year", return duration.
  4. Let largestUnitIndex be the ordinal index of the row of Table 21 whose "Singular" column contains largestUnit.
  5. Let smallestUnitIndex be the ordinal index of the row of Table 21 whose "Singular" column contains smallestUnit.
  6. Let unitIndex be smallestUnitIndex - 1.
  7. Let done be false.
  8. Repeat, while unitIndexlargestUnitIndex and done is false,
    1. Let unit be the value in the "Singular" column of Table 21 in the row whose ordinal index is unitIndex.
    2. If unit is not "week", or largestUnit is "week", then
      1. If unit is "year", then
        1. Let years be duration.[[Years]] + sign.
        2. Let endDuration be ? CreateDateDurationRecord(years, 0, 0, 0).
      2. Else if unit is "month", then
        1. Let months be duration.[[Months]] + sign.
        2. Let endDuration be ? CreateDateDurationRecord(duration.[[Years]], months, 0, 0).
      3. Else if unit is "week", then
        1. Let weeks be duration.[[Weeks]] + sign.
        2. Let endDuration be ? CreateDateDurationRecord(duration.[[Years]], duration.[[Months]], weeks, 0).
      4. Else,
        1. Assert: unit is "day".
        2. Let days be duration.[[Days]] + sign.
        3. Let endDuration be ? CreateDateDurationRecord(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], days).
      5. Let date be ISODateTimeToDateRecord(dateTime).
      6. Let end be ? CalendarDateAdd(calendar, date, endDuration, "constrain").
      7. If timeZone is unset, then
        1. Let endEpochNs be GetUTCEpochNanoseconds(end.[[Year]], end.[[Month]], end.[[Day]], dateTime.[[Hour]], dateTime.[[Minute]], dateTime.[[Second]], dateTime.[[Millisecond]], dateTime.[[Microsecond]], dateTime.[[Nanosecond]]).
      8. Else,
        1. Let endDateTime be CombineISODateAndTimeRecord(end, dateTime).
        2. Let endEpochNs be ? GetEpochNanosecondsFor(timeZone, endDateTime, "compatible").
      9. Let beyondEnd be nudgedEpochNs - endEpochNs.
      10. If beyondEnd < 0, let beyondEndSign be -1; else if beyondEnd > 0, let beyondEndSign be 1; else let beyondEndSign be 0.
      11. If beyondEndSign ≠ -sign, then
        1. Set duration to ! CombineDateAndNormalizedTimeDuration(endDuration, ZeroTimeDuration()).
      12. Else,
        1. Set done to true.
    3. Set unitIndex to unitIndex - 1.
  9. Return duration.

7.5.43 RoundRelativeDuration ( duration, destEpochNs, dateTime, calendar, timeZone, largestUnit, increment, smallestUnit, roundingMode )

The abstract operation RoundRelativeDuration takes arguments duration (a Normalized Duration Record), destEpochNs (a BigInt), dateTime (an ISO Date-Time Record), calendar (a String), timeZone (a String or unset), largestUnit (a String from the "Singular" column of Table 21), increment (a positive integer), smallestUnit (a String from the "Singular" column of Table 21), and roundingMode (a String from the "Identifier" column of Table 22) and returns either a normal completion containing a Record with fields [[Duration]] (a Duration Record) and [[Total]] (a mathematical value or unset), or a throw completion. It rounds a duration duration relative to dateTime according to the rounding parameters smallestUnit, increment, and roundingMode, bubbles overflows up to the next highest unit until largestUnit, and returns a Record with the balanced result in its [[Duration]] field. It also returns the total of the smallest unit before the rounding operation in its [[Total]] field, for use in Temporal.Duration.prototype.total. It performs the following steps when called:

  1. Let irregularLengthUnit be false.
  2. If IsCalendarUnit(smallestUnit) is true, set irregularLengthUnit to true.
  3. If timeZone is not unset and smallestUnit is "day", set irregularLengthUnit to true.
  4. If DurationSign(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], NormalizedTimeDurationSign(duration.[[NormalizedTime]]), 0, 0, 0, 0, 0) < 0, let sign be -1; else let sign be 1.
  5. If irregularLengthUnit is true, then
    1. Let nudgeResult be ? NudgeToCalendarUnit(sign, duration, destEpochNs, dateTime, calendar, timeZone, increment, smallestUnit, roundingMode).
  6. Else if timeZone is not unset, then
    1. Let nudgeResult be ? NudgeToZonedTime(sign, duration, dateTime, calendar, timeZone, increment, smallestUnit, roundingMode).
  7. Else,
    1. Let nudgeResult be ? NudgeToDayOrTime(duration, destEpochNs, largestUnit, increment, smallestUnit, roundingMode).
  8. Set duration to nudgeResult.[[Duration]].
  9. If nudgeResult.[[DidExpandCalendarUnit]] is true and smallestUnit is not "week", then
    1. Let startUnit be LargerOfTwoTemporalUnits(smallestUnit, "day").
    2. Set duration to ? BubbleRelativeDuration(sign, duration, nudgeResult.[[NudgedEpochNs]], dateTime, calendar, timeZone, largestUnit, startUnit).
  10. If IsCalendarUnit(largestUnit) is true or largestUnit is "day", then
    1. Set largestUnit to "hour".
  11. Let balanceResult be ? BalanceTimeDuration(duration.[[NormalizedTime]], largestUnit).
  12. Return the Record { [[Duration]]: CreateDurationRecord(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], balanceResult.[[Hours]], balanceResult.[[Minutes]], balanceResult.[[Seconds]], balanceResult.[[Milliseconds]], balanceResult.[[Microseconds]], balanceResult.[[Nanoseconds]]), [[Total]]: nudgeResult.[[Total]]  }.

7.5.44 TemporalDurationToString ( years, months, weeks, days, hours, minutes, normSeconds, precision )

The abstract operation TemporalDurationToString takes arguments years (an integer), months (an integer), weeks (an integer), days (an integer), hours (an integer), minutes (an integer), normSeconds (a Normalized Time Duration Record), and precision (an integer between 0 and 9 inclusive, or "auto") and returns a String. It returns a String which is the ISO 8601 representation of the duration denoted by years through nanoseconds, with the number of decimal places in the seconds value controlled by precision. It performs the following steps when called:

  1. Let sign be DurationSign(years, months, weeks, days, hours, minutes, NormalizedTimeDurationSeconds(normSeconds), 0, 0, NormalizedTimeDurationSubseconds(normSeconds)).
  2. Let datePart be "".
  3. If years is not 0, then
    1. Set datePart to the string concatenation of abs(years) formatted as a decimal number and the code unit 0x0059 (LATIN CAPITAL LETTER Y).
  4. If months is not 0, then
    1. Set datePart to the string concatenation of datePart, abs(months) formatted as a decimal number, and the code unit 0x004D (LATIN CAPITAL LETTER M).
  5. If weeks is not 0, then
    1. Set datePart to the string concatenation of datePart, abs(weeks) formatted as a decimal number, and the code unit 0x0057 (LATIN CAPITAL LETTER W).
  6. If days is not 0, then
    1. Set datePart to the string concatenation of datePart, abs(days) formatted as a decimal number, and the code unit 0x0044 (LATIN CAPITAL LETTER D).
  7. Let timePart be "".
  8. If hours is not 0, then
    1. Set timePart to the string concatenation of abs(hours) formatted as a decimal number and the code unit 0x0048 (LATIN CAPITAL LETTER H).
  9. If minutes is not 0, then
    1. Set timePart to the string concatenation of timePart, abs(minutes) formatted as a decimal number, and the code unit 0x004D (LATIN CAPITAL LETTER M).
  10. Let zeroMinutesAndHigher be false.
  11. If years = 0, and months = 0, and weeks = 0, and days = 0, and hours = 0, and minutes = 0, set zeroMinutesAndHigher to true.
  12. If NormalizedTimeDurationIsZero(normSeconds) is false, or zeroMinutesAndHigher is true, or precision is not "auto", then
    1. Let secondsPart be abs(NormalizedTimeDurationSeconds(normSeconds)) formatted as a decimal number.
    2. Let subSecondsPart be FormatFractionalSeconds(abs(NormalizedTimeDurationSubseconds(normSeconds)), precision).
    3. Set timePart to the string concatenation of timePart, secondsPart, subSecondsPart, and the code unit 0x0053 (LATIN CAPITAL LETTER S).
  13. Let signPart be the code unit 0x002D (HYPHEN-MINUS) if sign < 0, and otherwise the empty String.
  14. Let result be the string concatenation of signPart, the code unit 0x0050 (LATIN CAPITAL LETTER P) and datePart.
  15. If timePart is not "", then
    1. Set result to the string concatenation of result, the code unit 0x0054 (LATIN CAPITAL LETTER T), and timePart.
  16. Return result.

7.5.45 AddDurations ( operation, duration, other )

The abstract operation AddDurations takes arguments operation (add or subtract), duration (a Temporal.Duration), and other (an ECMAScript language value) and returns either a normal completion containing a Temporal.Duration or a throw completion. 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. It performs the following steps when called:

  1. If operation is subtract, let sign be -1. Otherwise, let sign be 1.
  2. Set other to ? ToTemporalDurationRecord(other).
  3. Let y1 be duration.[[Years]].
  4. Let mon1 be duration.[[Months]].
  5. Let w1 be duration.[[Weeks]].
  6. Let d1 be duration.[[Days]].
  7. Let h1 be duration.[[Hours]].
  8. Let min1 be duration.[[Minutes]].
  9. Let s1 be duration.[[Seconds]].
  10. Let ms1 be duration.[[Milliseconds]].
  11. Let mus1 be duration.[[Microseconds]].
  12. Let ns1 be duration.[[Nanoseconds]].
  13. Let y2 be sign × other.[[Years]].
  14. Let mon2 be sign × other.[[Months]].
  15. Let w2 be sign × other.[[Weeks]].
  16. Let d2 be sign × other.[[Days]].
  17. Let h2 be sign × other.[[Hours]].
  18. Let min2 be sign × other.[[Minutes]].
  19. Let s2 be sign × other.[[Seconds]].
  20. Let ms2 be sign × other.[[Milliseconds]].
  21. Let mus2 be sign × other.[[Microseconds]].
  22. Let ns2 be sign × other.[[Nanoseconds]].
  23. Let largestUnit1 be DefaultTemporalLargestUnit(y1, mon1, w1, d1, h1, min1, s1, ms1, mus1).
  24. Let largestUnit2 be DefaultTemporalLargestUnit(y2, mon2, w2, d2, h2, min2, s2, ms2, mus2).
  25. Let largestUnit be LargerOfTwoTemporalUnits(largestUnit1, largestUnit2).
  26. Let norm1 be NormalizeTimeDuration(h1, min1, s1, ms1, mus1, ns1).
  27. Let norm2 be NormalizeTimeDuration(h2, min2, s2, ms2, mus2, ns2).
  28. If IsCalendarUnit(largestUnit), throw a RangeError exception.
  29. Let normResult be ? AddNormalizedTimeDuration(norm1, norm2).
  30. Set normResult to ? Add24HourDaysToNormalizedTimeDuration(normResult, d1 + d2).
  31. Let result be ? BalanceTimeDuration(normResult, largestUnit).
  32. Return ! CreateTemporalDuration(0, 0, 0, result.[[Days]], result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]).

8 Temporal.Instant Objects

A Temporal.Instant object is an Object referencing a fixed point in time with nanoseconds precision.

8.1 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.

8.1.1 Temporal.Instant ( epochNanoseconds )

This function performs the following steps when called:

  1. If NewTarget is undefined, then
    1. Throw a TypeError exception.
  2. Let epochNanoseconds be ? ToBigInt(epochNanoseconds).
  3. If IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
  4. Return ? CreateTemporalInstant(epochNanoseconds, NewTarget).

8.2 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:

8.2.1 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 }.

8.2.2 Temporal.Instant.from ( item )

This function performs the following steps when called:

  1. If item is an Object and item has an [[InitializedTemporalInstant]] internal slot, then
    1. Return ! CreateTemporalInstant(item.[[Nanoseconds]]).
  2. Return ? ToTemporalInstant(item).

8.2.3 Temporal.Instant.fromEpochMilliseconds ( epochMilliseconds )

This function performs the following steps when called:

  1. Set epochMilliseconds to ? ToNumber(epochMilliseconds).
  2. Set epochMilliseconds to ? NumberToBigInt(epochMilliseconds).
  3. Let epochNanoseconds be epochMilliseconds × (106).
  4. If IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
  5. Return ! CreateTemporalInstant(epochNanoseconds).

8.2.4 Temporal.Instant.fromEpochNanoseconds ( epochNanoseconds )

This function performs the following steps when called:

  1. Set epochNanoseconds to ? ToBigInt(epochNanoseconds).
  2. If IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
  3. Return ! CreateTemporalInstant(epochNanoseconds).

8.2.5 Temporal.Instant.compare ( one, two )

This function performs the following steps when called:

  1. Set one to ? ToTemporalInstant(one).
  2. Set two to ? ToTemporalInstant(two).
  3. Return 𝔽(CompareEpochNanoseconds(one.[[Nanoseconds]], two.[[Nanoseconds]])).

8.3 Properties of the Temporal.Instant Prototype Object

The Temporal.Instant prototype object

  • is itself an ordinary object.
  • is not a Temporal.Instant instance and does not have a [[InitializedTemporalInstant]] internal slot.
  • has a [[Prototype]] internal slot whose value is %Object.prototype%.

8.3.1 Temporal.Instant.prototype.constructor

The initial value of Temporal.Instant.prototype.constructor is %Temporal.Instant%.

8.3.2 Temporal.Instant.prototype[ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Temporal.Instant".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

8.3.3 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.
  2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
  3. Let ns be instant.[[Nanoseconds]].
  4. Let ms be floor((ns) / 106).
  5. Return 𝔽(ms).

8.3.4 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.
  2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
  3. Let ns be instant.[[Nanoseconds]].
  4. Return ns.

8.3.5 Temporal.Instant.prototype.add ( temporalDurationLike )

This method performs the following steps when called:

  1. Let instant be the this value.
  2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
  3. Return ? AddDurationToOrSubtractDurationFromInstant(add, instant, temporalDurationLike).

8.3.6 Temporal.Instant.prototype.subtract ( temporalDurationLike )

This method performs the following steps when called:

  1. Let instant be the this value.
  2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
  3. Return ? AddDurationToOrSubtractDurationFromInstant(subtract, instant, temporalDurationLike).

8.3.7 Temporal.Instant.prototype.until ( other [ , options ] )

This method performs the following steps when called:

  1. Let instant be the this value.
  2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
  3. Return ? DifferenceTemporalInstant(until, instant, other, options).

8.3.8 Temporal.Instant.prototype.since ( other [ , options ] )

This method performs the following steps when called:

  1. Let instant be the this value.
  2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
  3. Return ? DifferenceTemporalInstant(since, instant, other, options).

8.3.9 Temporal.Instant.prototype.round ( roundTo )

This method performs the following steps when called:

  1. Let instant be the this value.
  2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
  3. If roundTo is undefined, then
    1. Throw a TypeError exception.
  4. If roundTo is a String, then
    1. Let paramString be roundTo.
    2. Set roundTo to OrdinaryObjectCreate(null).
    3. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString).
  5. Else,
    1. Set roundTo to ? GetOptionsObject(roundTo).
  6. NOTE: The following steps read options and perform independent validation in alphabetical order (ToTemporalRoundingIncrement reads "roundingIncrement" and ToTemporalRoundingMode reads "roundingMode").
  7. Let roundingIncrement be ? GetRoundingIncrementOption(roundTo).
  8. Let roundingMode be ? GetRoundingModeOption(roundTo, "halfExpand").
  9. Let smallestUnit be ? GetTemporalUnitValuedOption(roundTo, "smallestUnit", time, required).
  10. If smallestUnit is "hour", then
    1. Let maximum be HoursPerDay.
  11. Else if smallestUnit is "minute", then
    1. Let maximum be MinutesPerHour × HoursPerDay.
  12. Else if smallestUnit is "second", then
    1. Let maximum be SecondsPerMinute × MinutesPerHour × HoursPerDay.
  13. Else if smallestUnit is "millisecond", then
    1. Let maximum be (msPerDay).
  14. Else if smallestUnit is "microsecond", then
    1. Let maximum be 103 × (msPerDay).
  15. Else,
    1. Assert: smallestUnit is "nanosecond".
    2. Let maximum be nsPerDay.
  16. Perform ? ValidateTemporalRoundingIncrement(roundingIncrement, maximum, true).
  17. Let roundedNs be RoundTemporalInstant(instant.[[Nanoseconds]], roundingIncrement, smallestUnit, roundingMode).
  18. Return ! CreateTemporalInstant(roundedNs).

8.3.10 Temporal.Instant.prototype.equals ( other )

This method performs the following steps when called:

  1. Let instant be the this value.
  2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
  3. Set other to ? ToTemporalInstant(other).
  4. If instant.[[Nanoseconds]]other.[[Nanoseconds]], return false.
  5. Return true.

8.3.11 Temporal.Instant.prototype.toString ( [ options ] )

This method performs the following steps when called:

  1. Let instant be the this value.
  2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
  3. Set options to ? GetOptionsObject(options).
  4. NOTE: The following steps read options and perform independent validation in alphabetical order (ToFractionalSecondDigits reads "fractionalSecondDigits" and ToTemporalRoundingMode reads "roundingMode").
  5. Let digits be ? GetTemporalFractionalSecondDigitsOption(options).
  6. Let roundingMode be ? GetRoundingModeOption(options, "trunc").
  7. Let smallestUnit be ? GetTemporalUnitValuedOption(options, "smallestUnit", time, undefined).
  8. If smallestUnit is "hour", throw a RangeError exception.
  9. Let timeZone be ? Get(options, "timeZone").
  10. If timeZone is not undefined, then
    1. Set timeZone to ? ToTemporalTimeZoneIdentifier(timeZone).
  11. Let precision be ToSecondsStringPrecisionRecord(smallestUnit, digits).
  12. Let roundedNs be RoundTemporalInstant(instant.[[Nanoseconds]], precision.[[Increment]], precision.[[Unit]], roundingMode).
  13. Let roundedInstant be ! CreateTemporalInstant(roundedNs).
  14. Return TemporalInstantToString(roundedInstant, timeZone, precision.[[Precision]]).

8.3.12 Temporal.Instant.prototype.toLocaleString ( [ locales [ , options ] ] )

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.
  2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
  3. Return TemporalInstantToString(instant, undefined, "auto").

8.3.13 Temporal.Instant.prototype.toJSON ( )

This method performs the following steps when called:

  1. Let instant be the this value.
  2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
  3. Return TemporalInstantToString(instant, undefined, "auto").

8.3.14 Temporal.Instant.prototype.valueOf ( )

This method performs the following steps when called:

  1. Throw a TypeError exception.
Note

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().

8.3.15 Temporal.Instant.prototype.toZonedDateTimeISO ( timeZone )

This method performs the following steps when called:

  1. Let instant be the this value.
  2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
  3. Set timeZone to ? ToTemporalTimeZoneIdentifier(timeZone).
  4. Return ! CreateTemporalZonedDateTime(instant.[[Nanoseconds]], timeZone, "iso8601").

8.4 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 Table 14.

Table 14: Internal Slots of Temporal.Instant Instances
Internal Slot Description
[[InitializedTemporalInstant]] The only specified use of this slot is for distinguishing Temporal.Instant instances from other objects.
[[Nanoseconds]] A BigInt value representing the number of nanoseconds since the epoch.

8.4.1 Temporal.Instant range

The [[Nanoseconds]] internal slot of a Temporal.Instant object supports a range of exactly -100,000,000 to 100,000,000 days relative to midnight at the beginning of 1 January 1970 UTC, as in 21.4.1.1.

The exact moment of midnight at the beginning of 1 January 1970 UTC is represented by the value 0.

The maximum value is (nsMaxInstant), where

nsMaxInstant = 108 × nsPerDay = 8.64 × 1021

where the number of nanoseconds per day is

nsPerDay = 106 × (msPerDay) = 8.64 × 1013

The minimum value is (nsMinInstant), where

nsMinInstant = -nsMaxInstant = -8.64 × 1021

8.5 Abstract Operations

8.5.1 IsValidEpochNanoseconds ( epochNanoseconds )

The abstract operation IsValidEpochNanoseconds takes argument epochNanoseconds (a BigInt) and returns a Boolean. 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. It performs the following steps when called:

  1. If (epochNanoseconds) < nsMinInstant or (epochNanoseconds) > nsMaxInstant, then
    1. Return false.
  2. Return true.

8.5.2 CreateTemporalInstant ( epochNanoseconds [ , newTarget ] )

The abstract operation CreateTemporalInstant takes argument epochNanoseconds (a BigInt) and optional argument newTarget (a constructor) and returns either a normal completion containing a Temporal.Instant or a throw completion. It creates a Temporal.Instant instance and fills the internal slots with valid values. It performs the following steps when called:

  1. Assert: IsValidEpochNanoseconds(epochNanoseconds) is true.
  2. If newTarget is not present, set newTarget to %Temporal.Instant%.
  3. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.Instant.prototype%", « [[InitializedTemporalInstant]], [[Nanoseconds]] »).
  4. Set object.[[Nanoseconds]] to epochNanoseconds.
  5. Return object.

8.5.3 ToTemporalInstant ( item )

The abstract operation ToTemporalInstant takes argument item (an ECMAScript language value) and returns either a normal completion containing a Temporal.Instant or a throw completion. It returns its argument item if it is already a Temporal.Instant instance, converts item to a new Temporal.Instant instance if possible, and throws otherwise. It performs the following steps when called:

  1. If item is an Object, then
    1. If item has an [[InitializedTemporalInstant]] internal slot, then
      1. Return item.
    2. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
      1. Return ! CreateTemporalInstant(item.[[Nanoseconds]]).
    3. NOTE: This use of ToPrimitive allows Instant-like objects to be converted.
    4. Set item to ? ToPrimitive(item, string).
  2. If item is not a String, throw a TypeError exception.
  3. Let parsed be ? ParseTemporalInstantString(item).
  4. If parsed.[[TimeZone]].[[Z]] is true, let offsetNanoseconds be 0; otherwise, let offsetNanoseconds be ! ParseDateTimeUTCOffset(parsed.[[TimeZone]].[[OffsetString]]).
  5. If abs(ISODateToEpochDays(parsed.[[Year]], parsed.[[Month]] - 1, parsed.[[Day]])) > 108, throw a RangeError exception.
  6. Let epochNanoseconds be GetUTCEpochNanoseconds(parsed.[[Year]], parsed.[[Month]], parsed.[[Day]], parsed.[[Hour]], parsed.[[Minute]], parsed.[[Second]], parsed.[[Millisecond]], parsed.[[Microsecond]], parsed.[[Nanosecond]], offsetNanoseconds).
  7. If IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
  8. Return ! CreateTemporalInstant(epochNanoseconds).

8.5.4 CompareEpochNanoseconds ( epochNanosecondsOne, epochNanosecondsTwo )

The abstract operation CompareEpochNanoseconds takes arguments epochNanosecondsOne (a BigInt) and epochNanosecondsTwo (a BigInt) and returns either -1, 0, or 1. It performs the following steps when called:

  1. If epochNanosecondsOne > epochNanosecondsTwo, return 1.
  2. If epochNanosecondsOne < epochNanosecondsTwo, return -1.
  3. Return 0.

8.5.5 AddInstant ( epochNanoseconds, norm )

The abstract operation AddInstant takes arguments epochNanoseconds (a BigInt value) and norm (a Normalized Time Duration Record) and returns either a normal completion containing a BigInt or a throw completion. It adds a duration to a number of nanoseconds since the epoch. It performs the following steps when called:

  1. Let result be AddNormalizedTimeDurationToEpochNanoseconds(norm, epochNanoseconds).
  2. If IsValidEpochNanoseconds(result) is false, throw a RangeError exception.
  3. Return result.

8.5.6 DifferenceInstant ( ns1, ns2, roundingIncrement, smallestUnit, roundingMode )

The abstract operation DifferenceInstant takes arguments ns1 (a BigInt), ns2 (a BigInt), roundingIncrement (a positive integer), smallestUnit (a String), and roundingMode (a String from the "Identifier" column of Table 22) and returns a Record with fields [[NormalizedTimeDuration]] (a Normalized Time Duration Record) and [[Total]] (a mathematical value). 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. It performs the following steps when called:

  1. Let difference be NormalizedTimeDurationFromEpochNanosecondsDifference(ns2, ns1).
  2. Let roundRecord be ! RoundTimeDuration(0, difference, roundingIncrement, smallestUnit, roundingMode).
  3. Return the Record { [[NormalizedTimeDuration]]: roundRecord.[[NormalizedDuration]].[[NormalizedTime]], [[Total]]: roundRecord.[[Total]] }.

8.5.7 RoundTemporalInstant ( ns, increment, unit, roundingMode )

The abstract operation RoundTemporalInstant takes arguments ns (a BigInt), increment (a positive integer), unit (a String from the "Singular" column of Table 21), and roundingMode (a String from the "Identifier" column of Table 22) and returns a BigInt. It rounds a number of nanoseconds ns since the epoch to the given rounding increment. It performs the following steps when called:

  1. Assert: The value in the "Category" column of the row of Table 21 whose "Singular" column contains unit, is time.
  2. Let unitLength be the value in the "Length in Nanoseconds" column of the row of Table 21 whose "Singular" column contains unit.
  3. Let incrementNs be increment × unitLength.
  4. Return (RoundNumberToIncrementAsIfPositive((ns), incrementNs, roundingMode)).

8.5.8 TemporalInstantToString ( instant, timeZone, precision )

The abstract operation TemporalInstantToString takes arguments instant (a Temporal.Instant), timeZone (a String or undefined), and precision (an integer in the inclusive interval from 0 to 9, "minute", or "auto") and returns a String. It formats instant as an ISO 8601 string, to the precision specified by precision, using the UTC offset of timeZone, or Z if timeZone is undefined. It performs the following steps when called:

  1. Let outputTimeZone be timeZone.
  2. If outputTimeZone is undefined, set outputTimeZone to "UTC".
  3. Let epochNs be instant.[[Nanoseconds]].
  4. Let isoDateTime be GetISODateTimeFor(outputTimeZone, epochNs).
  5. Let dateTimeString be TemporalDateTimeToString(isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]], isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]], "iso8601", precision, "never").
  6. If timeZone is undefined, then
    1. Let timeZoneString be "Z".
  7. Else,
    1. Let offsetNanoseconds be GetOffsetNanosecondsFor(outputTimeZone, epochNs).
    2. Let timeZoneString be FormatDateTimeUTCOffsetRounded(offsetNanoseconds).
  8. Return the string-concatenation of dateTimeString and timeZoneString.

8.5.9 DifferenceTemporalInstant ( operation, instant, other, options )

The abstract operation DifferenceTemporalInstant takes arguments operation (since or until), instant (a Temporal.Instant), other (an ECMAScript language value), and options (an ECMAScript language value) and returns either a normal completion containing a Temporal.Duration or a throw completion. It computes the difference between the two times represented by instant and other, optionally rounds it, and returns it as a Temporal.Duration object. It performs the following steps when called:

  1. If operation is since, let sign be -1. Otherwise, let sign be 1.
  2. Set other to ? ToTemporalInstant(other).
  3. Let resolvedOptions be ? GetOptionsObject(options).
  4. Let settings be ? GetDifferenceSettings(operation, resolvedOptions, time, « », "nanosecond", "second").
  5. Let diffRecord be DifferenceInstant(instant.[[Nanoseconds]], other.[[Nanoseconds]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
  6. Let norm be diffRecord.[[NormalizedTimeDuration]].
  7. Let result be ! BalanceTimeDuration(norm, settings.[[LargestUnit]]).
  8. Return ! CreateTemporalDuration(0, 0, 0, 0, sign × result.[[Hours]], sign × result.[[Minutes]], sign × result.[[Seconds]], sign × result.[[Milliseconds]], sign × result.[[Microseconds]], sign × result.[[Nanoseconds]]).

8.5.10 AddDurationToOrSubtractDurationFromInstant ( operation, instant, temporalDurationLike )

The abstract operation AddDurationToOrSubtractDurationFromInstant takes arguments operation (add or subtract), instant (a Temporal.Instant), and temporalDurationLike (an ECMAScript language value) and returns either a normal completion containing a Temporal.Instant or a throw completion. It adds/subtracts temporalDurationLike to/from instant. It performs the following steps when called:

  1. If operation is subtract, let sign be -1. Otherwise, let sign be 1.
  2. Let duration be ? ToTemporalDurationRecord(temporalDurationLike).
  3. If duration.[[Days]] is not 0, throw a RangeError exception.
  4. If duration.[[Months]] is not 0, throw a RangeError exception.
  5. If duration.[[Weeks]] is not 0, throw a RangeError exception.
  6. If duration.[[Years]] is not 0, throw a RangeError exception.
  7. Let norm be NormalizeTimeDuration(sign × duration.[[Hours]], sign × duration.[[Minutes]], sign × duration.[[Seconds]], sign × duration.[[Milliseconds]], sign × duration.[[Microseconds]], sign × duration.[[Nanoseconds]]).
  8. Let ns be ? AddInstant(instant.[[Nanoseconds]], norm).
  9. Return ! CreateTemporalInstant(ns).

9 Temporal.PlainYearMonth Objects

A Temporal.PlainYearMonth object is an Object that contains integers corresponding to a particular year and month in a particular calendar.

9.1 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.

9.1.1 Temporal.PlainYearMonth ( isoYear, isoMonth [ , calendar [ , referenceISODay ] ] )

This function performs the following steps when called:

  1. If NewTarget is undefined, then
    1. Throw a TypeError exception.
  2. If referenceISODay is undefined, then
    1. Set referenceISODay to 1𝔽.
  3. Let y be ? ToIntegerWithTruncation(isoYear).
  4. Let m be ? ToIntegerWithTruncation(isoMonth).
  5. If calendar is undefined, set calendar to "iso8601".
  6. If calendar is not a String, throw a TypeError exception.
  7. If IsBuiltinCalendar(calendar) is false, throw a RangeError exception.
  8. Set calendar to CanonicalizeUValue("ca", calendar).
  9. Let ref be ? ToIntegerWithTruncation(referenceISODay).
  10. Return ? CreateTemporalYearMonth(y, m, calendar, ref, NewTarget).

9.2 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:

9.2.1 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 }.

9.2.2 Temporal.PlainYearMonth.from ( item [ , options ] )

This function performs the following steps when called:

  1. If item is an Object and item has an [[InitializedTemporalYearMonth]] internal slot, then
    1. Set options to ? GetOptionsObject(options).
    2. Perform ? GetTemporalOverflowOption(options).
    3. Return ! CreateTemporalYearMonth(item.[[ISOYear]], item.[[ISOMonth]], item.[[Calendar]], item.[[ISODay]]).
  2. Return ? ToTemporalYearMonth(item, options).

9.2.3 Temporal.PlainYearMonth.compare ( one, two )

This function performs the following steps when called:

  1. Set one to ? ToTemporalYearMonth(one).
  2. Set two to ? ToTemporalYearMonth(two).
  3. Return 𝔽(CompareISODate(one.[[ISOYear]], one.[[ISOMonth]], one.[[ISODay]], two.[[ISOYear]], two.[[ISOMonth]], two.[[ISODay]])).

9.3 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%.
Note
An ECMAScript implementation that includes the ECMA-402 Internationalization API extends this prototype with additional properties in order to represent calendar data.

9.3.1 Temporal.PlainYearMonth.prototype.constructor

The initial value of Temporal.PlainYearMonth.prototype.constructor is %Temporal.PlainYearMonth%.

9.3.2 Temporal.PlainYearMonth.prototype[ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Temporal.PlainYearMonth".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

9.3.3 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 yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Return yearMonth.[[Calendar]].

9.3.4 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.
  2. Perform ? RequireInternalSlot(plainYearMonth, [[InitializedTemporalYearMonth]]).
  3. Let isoDate be TemporalObjectToISODateRecord(plainYearMonth).
  4. Return CalendarEra(plainYearMonth.[[Calendar]], isoDate).

9.3.5 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.
  2. Perform ? RequireInternalSlot(plainYearMonth, [[InitializedTemporalYearMonth]]).
  3. Let isoDate be TemporalObjectToISODateRecord(plainYearMonth).
  4. Let result be CalendarEraYear(plainYearMonth.[[Calendar]], isoDate).
  5. If result is undefined, return undefined.
  6. Return 𝔽(result).

9.3.6 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 yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Let isoDate be TemporalObjectToISODateRecord(yearMonth).
  4. Return 𝔽(CalendarYear(yearMonth.[[Calendar]], isoDate)).

9.3.7 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 yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Let isoDate be TemporalObjectToISODateRecord(yearMonth).
  4. Return 𝔽(CalendarMonth(yearMonth.[[Calendar]], isoDate)).

9.3.8 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 yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Let isoDate be TemporalObjectToISODateRecord(yearMonth).
  4. Return CalendarMonthCode(yearMonth.[[Calendar]], isoDate).

9.3.9 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 yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Let isoDate be TemporalObjectToISODateRecord(yearMonth).
  4. Return 𝔽(CalendarDaysInYear(yearMonth.[[Calendar]], isoDate)).

9.3.10 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 yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Let isoDate be TemporalObjectToISODateRecord(yearMonth).
  4. Return 𝔽(CalendarDaysInMonth(yearMonth.[[Calendar]], isoDate)).

9.3.11 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 yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Let isoDate be TemporalObjectToISODateRecord(yearMonth).
  4. Return 𝔽(CalendarMonthsInYear(yearMonth.[[Calendar]], isoDate)).

9.3.12 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 yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Let isoDate be TemporalObjectToISODateRecord(yearMonth).
  4. Return CalendarInLeapYear(yearMonth.[[Calendar]], isoDate).

9.3.13 Temporal.PlainYearMonth.prototype.with ( temporalYearMonthLike [ , options ] )

This method performs the following steps when called:

  1. Let yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. If ? IsPartialTemporalObject(temporalYearMonthLike) is false, throw a TypeError exception.
  4. Let calendar be yearMonth.[[Calendar]].
  5. Let fields be TemporalObjectToFields(yearMonth).
  6. Let partialYearMonth be ? PrepareCalendarFields(calendar, temporalYearMonthLike, « month, month-code, year », « », partial).
  7. Set fields to CalendarMergeFields(calendar, fields, partialYearMonth).
  8. Let resolvedOptions be ? GetOptionsObject(options).
  9. Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
  10. Let isoDate be ? CalendarYearMonthFromFields(calendar, fields, overflow).
  11. Return ! CreateTemporalYearMonth(isoDate.[[Year]], isoDate.[[Month]], calendar, isoDate.[[Day]]).

9.3.14 Temporal.PlainYearMonth.prototype.add ( temporalDurationLike [ , options ] )

This method performs the following steps when called:

  1. Let yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Return ? AddDurationToOrSubtractDurationFromPlainYearMonth(add, yearMonth, temporalDurationLike, options).

9.3.15 Temporal.PlainYearMonth.prototype.subtract ( temporalDurationLike [ , options ] )

This method performs the following steps when called:

  1. Let yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Return ? AddDurationToOrSubtractDurationFromPlainYearMonth(subtract, yearMonth, temporalDurationLike, options).

9.3.16 Temporal.PlainYearMonth.prototype.until ( other [ , options ] )

This method performs the following steps when called:

  1. Let yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Return ? DifferenceTemporalPlainYearMonth(until, yearMonth, other, options).

9.3.17 Temporal.PlainYearMonth.prototype.since ( other [ , options ] )

This method performs the following steps when called:

  1. Let yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Return ? DifferenceTemporalPlainYearMonth(since, yearMonth, other, options).

9.3.18 Temporal.PlainYearMonth.prototype.equals ( other )

This method performs the following steps when called:

  1. Let yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Set other to ? ToTemporalYearMonth(other).
  4. If yearMonth.[[ISOYear]]other.[[ISOYear]], return false.
  5. If yearMonth.[[ISOMonth]]other.[[ISOMonth]], return false.
  6. If yearMonth.[[ISODay]]other.[[ISODay]], return false.
  7. Return CalendarEquals(yearMonth.[[Calendar]], other.[[Calendar]]).

9.3.19 Temporal.PlainYearMonth.prototype.toString ( [ options ] )

This method performs the following steps when called:

  1. Let yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Set options to ? GetOptionsObject(options).
  4. Let showCalendar be ? GetTemporalShowCalendarNameOption(options).
  5. Return TemporalYearMonthToString(yearMonth, showCalendar).

9.3.20 Temporal.PlainYearMonth.prototype.toLocaleString ( [ locales [ , options ] ] )

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 yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Return TemporalYearMonthToString(yearMonth, "auto").

9.3.21 Temporal.PlainYearMonth.prototype.toJSON ( )

This method performs the following steps when called:

  1. Let yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Return TemporalYearMonthToString(yearMonth, "auto").

9.3.22 Temporal.PlainYearMonth.prototype.valueOf ( )

This method performs the following steps when called:

  1. Throw a TypeError exception.
Note

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().

9.3.23 Temporal.PlainYearMonth.prototype.toPlainDate ( item )

This method performs the following steps when called:

  1. Let yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. If item is not an Object, then
    1. Throw a TypeError exception.
  4. Let calendar be yearMonth.[[Calendar]].
  5. Let fields be TemporalObjectToFields(yearMonth).
  6. Let inputFields be ? PrepareCalendarFields(calendar, item, « day », « », « »).
  7. Let mergedFields be CalendarMergeFields(calendar, fields, inputFields).
  8. Let isoDate be ? CalendarDateFromFields(calendar, mergedFields, "constrain").
  9. Return ! CreateTemporalDate(isoDate.[[Year]], isoDate.[[Month]], isoDate.[[Day]], calendar).

9.4 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 Table 15.

Table 15: Internal Slots of Temporal.PlainYearMonth Instances
Internal Slot Description
[[InitializedTemporalYearMonth]] The only specified use of this slot is for distinguishing Temporal.PlainYearMonth instances from other objects.
[[ISOYear]] An integer representing the year in the ISO 8601 calendar.
[[ISOMonth]] An integer between 1 and 12, inclusive, representing the month of the year in the ISO 8601 calendar.
[[ISODay]] An integer between 1 and ISODaysInMonth([[ISOYear]], [[ISOMonth]]), inclusive, representing a reference day of the month in the ISO 8601 calendar. This slot is used by the calendar object in the [[Calendar]] slot to disambiguate if the [[ISOYear]] and [[ISOMonth]] slots are not enough to uniquely identify a year and month in that calendar.
[[Calendar]] A String representing the calendar.

9.5 Abstract Operations

9.5.1 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 Table 16.

Table 16: ISO Year-Month Record Fields
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.

9.5.2 ToTemporalYearMonth ( item [ , options ] )

The abstract operation ToTemporalYearMonth takes argument item (an ECMAScript language value) and optional argument options (an ECMAScript language value) and returns either a normal completion containing a Temporal.PlainYearMonth, or a throw completion. It returns its argument item if it is already a Temporal.PlainYearMonth instance, converts item to a new Temporal.PlainYearMonth instance if possible, and throws otherwise. It performs the following steps when called:

  1. If options is not present, set options to undefined.
  2. If item is an Object, then
    1. If item has an [[InitializedTemporalYearMonth]] internal slot, then
      1. Set options to ? GetOptionsObject(options).
      2. Perform ? GetTemporalOverflowOption(options).
      3. Return item.
    2. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(item).
    3. Let fields be ? PrepareCalendarFields(calendar, item, « month, month-code, year », «», «»).
    4. Set options to ? GetOptionsObject(options).
    5. Let overflow be ? GetTemporalOverflowOption(options).
    6. Let isoDate be ? CalendarYearMonthFromFields(calendar, fields, overflow).
    7. Return ! CreateTemporalYearMonth(isoDate.[[Year]], isoDate.[[Month]], calendar, isoDate.[[Day]]).
  3. If item is not a String, throw a TypeError exception.
  4. Let result be ? ParseTemporalYearMonthString(item).
  5. Let calendar be result.[[Calendar]].
  6. If calendar is empty, set calendar to "iso8601".
  7. If IsBuiltinCalendar(calendar) is false, throw a RangeError exception.
  8. Set calendar to CanonicalizeUValue("ca", calendar).
  9. Let isoDate be CreateISODateRecord(result.[[Year]], result.[[Month]], result.[[Day]]).
  10. Set result to ISODateToFields(calendar, isoDate, year-month).
  11. NOTE: The following operation is called with "constrain" regardless of the value of overflow, in order for the calendar to store a canonical value in the [[ISODay]] internal slot of the result.
  12. Set options to ? GetOptionsObject(options).
  13. Perform ? GetTemporalOverflowOption(options).
  14. Set isoDate to ? CalendarYearMonthFromFields(calendar, result, "constrain").
  15. Return ! CreateTemporalYearMonth(isoDate.[[Year]], isoDate.[[Month]], calendar, isoDate.[[Day]]).

9.5.3 RegulateISOYearMonth ( year, month, overflow )

The abstract operation RegulateISOYearMonth takes arguments year (an integer), month (an integer), and overflow ("constrain" or "reject") and returns either a normal completion containing an ISO Year-Month Record or a throw completion. It applies the correction given by overflow to the given month. If overflow is "constrain", month is clamped to a valid value. If overflow is "reject" and month is out of range, a RangeError is thrown. It performs the following steps when called:

  1. If overflow is "constrain", then
    1. Set month to the result of clamping month between 1 and 12.
    2. Return ISO Year-Month Record { [[Year]]: year, [[Month]]: month  }.
  2. Else,
    1. Assert: overflow is "reject".
    2. If month < 1 or month > 12, throw a RangeError exception.
    3. Return ISO Year-Month Record { [[Year]]: year, [[Month]]: month  }.

9.5.4 ISOYearMonthWithinLimits ( year, month )

The abstract operation ISOYearMonthWithinLimits takes arguments year (an integer) and month (an integer in the inclusive interval from 1 to 12) and returns a Boolean. It returns true if its arguments represent a month within the range that a Temporal.PlainYearMonth object can represent, and false otherwise. It performs the following steps when called:

  1. If year < -271821 or year > 275760, then
    1. Return false.
  2. If year = -271821 and month < 4, then
    1. Return false.
  3. If year = 275760 and month > 9, then
    1. Return false.
  4. Return true.
Note

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.

9.5.5 BalanceISOYearMonth ( year, month )

The abstract operation BalanceISOYearMonth takes arguments year (an integer) and month (an integer) and returns an ISO Year-Month Record. It performs the following steps when called:

  1. Set year to year + floor((month - 1) / 12).
  2. Set month to ((month - 1) modulo 12) + 1.
  3. Return ISO Year-Month Record { [[Year]]: year, [[Month]]: month  }.

9.5.6 CreateTemporalYearMonth ( isoYear, isoMonth, calendar, referenceISODay [ , newTarget ] )

The abstract operation CreateTemporalYearMonth takes arguments isoYear (an integer), isoMonth (an integer), calendar (a String or Object), and referenceISODay (an integer) and optional argument newTarget (a constructor) and returns either a normal completion containing a Temporal.PlainYearMonth or a throw completion. It creates a Temporal.PlainYearMonth instance and fills the internal slots with valid values. It performs the following steps when called:

  1. If IsValidISODate(isoYear, isoMonth, referenceISODay) is false, throw a RangeError exception.
  2. If ISOYearMonthWithinLimits(isoYear, isoMonth) is false, throw a RangeError exception.
  3. If newTarget is not present, set newTarget to %Temporal.PlainYearMonth%.
  4. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.PlainYearMonth.prototype%", « [[InitializedTemporalYearMonth]], [[ISOYear]], [[ISOMonth]], [[ISODay]], [[Calendar]] »).
  5. Set object.[[ISOYear]] to isoYear.
  6. Set object.[[ISOMonth]] to isoMonth.
  7. Set object.[[Calendar]] to calendar.
  8. Set object.[[ISODay]] to referenceISODay.
  9. Return object.

9.5.7 TemporalYearMonthToString ( yearMonth, showCalendar )

The abstract operation TemporalYearMonthToString takes arguments yearMonth (a Temporal.PlainYearMonth) and showCalendar ("auto", "always", "never", or "critical") and returns a String. It formats yearMonth as an ISO 8601 string. It performs the following steps when called:

  1. Let year be PadISOYear(yearMonth.[[ISOYear]]).
  2. Let month be ToZeroPaddedDecimalString(yearMonth.[[ISOMonth]], 2).
  3. Let result be the string-concatenation of year, the code unit 0x002D (HYPHEN-MINUS), and month.
  4. If showCalendar is one of "always" or "critical", or if yearMonth.[[Calendar]] is not "iso8601", then
    1. Let day be ToZeroPaddedDecimalString(yearMonth.[[ISODay]], 2).
    2. Set result to the string-concatenation of result, the code unit 0x002D (HYPHEN-MINUS), and day.
  5. Let calendarString be FormatCalendarAnnotation(yearMonth.[[Calendar]], showCalendar).
  6. Set result to the string-concatenation of result and calendarString.
  7. Return result.

9.5.8 DifferenceTemporalPlainYearMonth ( operation, yearMonth, other, options )

The abstract operation DifferenceTemporalPlainYearMonth takes arguments operation (since or until), yearMonth (a Temporal.PlainYearMonth), other (an ECMAScript language value), and options (an ECMAScript language value) and returns either a normal completion containing a Temporal.Duration or a throw completion. It computes the difference between the two times represented by yearMonth and other, optionally rounds it, and returns it as a Temporal.Duration object. It performs the following steps when called:

  1. If operation is since, let sign be -1. Otherwise, let sign be 1.
  2. Set other to ? ToTemporalYearMonth(other).
  3. Let calendar be yearMonth.[[Calendar]].
  4. If CalendarEquals(calendar, other.[[Calendar]]) is false, throw a RangeError exception.
  5. Let resolvedOptions be ? GetOptionsObject(options).
  6. Let settings be ? GetDifferenceSettings(operation, resolvedOptions, date, « "week", "day" », "month", "year").
  7. If yearMonth.[[ISOYear]] = other.[[ISOYear]] and yearMonth.[[ISOMonth]] = other.[[ISOMonth]] and yearMonth.[[ISODay]] = other.[[ISODay]], then
    1. Return ! CreateTemporalDuration(0, 0, 0, 0, 0, 0, 0, 0, 0, 0).
  8. Let thisFields be TemporalObjectToFields(yearMonth).
  9. Set thisFields.[[Day]] to 1.
  10. Let thisDate be ? CalendarDateFromFields(calendar, thisFields, "constrain").
  11. Let otherFields be TemporalObjectToFields(other).
  12. Set otherFields.[[Day]] to 1.
  13. Let otherDate be ? CalendarDateFromFields(calendar, otherFields, "constrain").
  14. Let result be CalendarDateUntil(calendar, thisDate, otherDate, settings.[[LargestUnit]]).
  15. Let duration be ! CreateNormalizedDurationRecord(result.[[Years]], result.[[Months]], 0, 0, ZeroTimeDuration()).
  16. If settings.[[SmallestUnit]] is not "month" or settings.[[RoundingIncrement]] ≠ 1, then
    1. Let destEpochNs be GetUTCEpochNanoseconds(otherDate.[[Year]], otherDate.[[Month]], otherDate.[[Day]], 0, 0, 0, 0, 0, 0).
    2. Let midnight be a Time Record with all fields set to 0.
    3. Let dateTime be CombineISODateAndTimeRecord(thisDate, midnight).
    4. Set duration to ? RoundRelativeDuration(duration, destEpochNs, dateTime, calendar, unset, settings.[[LargestUnit]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
  17. Return ! CreateTemporalDuration(sign × duration.[[Years]], sign × duration.[[Months]], 0, 0, 0, 0, 0, 0, 0, 0).

9.5.9 AddDurationToOrSubtractDurationFromPlainYearMonth ( operation, yearMonth, temporalDurationLike, options )

The abstract operation AddDurationToOrSubtractDurationFromPlainYearMonth takes arguments operation (add or subtract), yearMonth (a Temporal.PlainYearMonth), temporalDurationLike (an ECMAScript language value), and options (an ECMAScript language value) and returns either a normal completion containing a Temporal.PlainYearMonth or a throw completion. It adds/subtracts temporalDurationLike to/from yearMonth, returning a point in time that is in the future/past relative to yearMonth. It performs the following steps when called:

  1. Let duration be ? ToTemporalDuration(temporalDurationLike).
  2. If operation is subtract, then
    1. Set duration to CreateNegatedTemporalDuration(duration).
  3. Set options to ? GetOptionsObject(options).
  4. Let overflow be ? GetTemporalOverflowOption(options).
  5. Let norm be NormalizeTimeDuration(duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]]).
  6. Let balanceResult be ! BalanceTimeDuration(norm, "day").
  7. Let days be duration.[[Days]] + balanceResult.[[Days]].
  8. Let sign be DurationSign(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], days, 0, 0, 0, 0, 0, 0).
  9. Let calendar be yearMonth.[[Calendar]].
  10. Let fields be TemporalObjectToFields(yearMonth).
  11. Set fields.[[Day]] to 1.
  12. Let intermediateDate be ? CalendarDateFromFields(calendar, fields, "constrain").
  13. If sign < 0, then
    1. Let oneMonthDuration be ! CreateDateDurationRecord(0, 1, 0, 0).
    2. Let nextMonth be ? CalendarDateAdd(calendar, intermediateDate, oneMonthDuration, "constrain").
    3. Let endOfMonth be BalanceISODate(nextMonth.[[Year]], nextMonth.[[Month]], nextMonth.[[Day]] - 1).
    4. Assert: ISODateWithinLimits(endOfMonth.[[Year]], endOfMonth.[[Month]], endOfMonth.[[Day]]) is true.
    5. Set fields.[[Day]] to CalendarDay(calendar, endOfMonth).
    6. Let date be ? CalendarDateFromFields(calendar, fields, "constrain").
  14. Else,
    1. Let date be intermediateDate.
  15. Let durationToAdd be ? CreateDateDurationRecord(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], days).
  16. Let addedDate be ? CalendarDateAdd(calendar, date, durationToAdd, overflow).
  17. Let addedDateFields be ISODateToFields(calendar, addedDate, year-month).
  18. Let isoDate be ? CalendarYearMonthFromFields(calendar, addedDateFields, overflow).
  19. Return ! CreateTemporalYearMonth(isoDate.[[Year]], isoDate.[[Month]], calendar, isoDate.[[Day]]).

10 Temporal.PlainMonthDay Objects

A Temporal.PlainMonthDay object is an Object that contains integers corresponding to a particular month and day in a particular calendar.

10.1 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.

10.1.1 Temporal.PlainMonthDay ( isoMonth, isoDay [ , calendar [ , referenceISOYear ] ] )

This function performs the following steps when called:

  1. If NewTarget is undefined, then
    1. Throw a TypeError exception.
  2. If referenceISOYear is undefined, then
    1. Set referenceISOYear to 1972𝔽 (the first ISO 8601 leap year after the epoch).
  3. Let m be ? ToIntegerWithTruncation(isoMonth).
  4. Let d be ? ToIntegerWithTruncation(isoDay).
  5. If calendar is undefined, set calendar to "iso8601".
  6. If calendar is not a String, throw a TypeError exception.
  7. If IsBuiltinCalendar(calendar) is false, throw a RangeError exception.
  8. Set calendar to CanonicalizeUValue("ca", calendar).
  9. Let y be ? ToIntegerWithTruncation(referenceISOYear).
  10. Return ? CreateTemporalMonthDay(m, d, calendar, y, NewTarget).

10.2 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:

10.2.1 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 }.

10.2.2 Temporal.PlainMonthDay.from ( item [ , options ] )

This function performs the following steps when called:

  1. If item is an Object and item has an [[InitializedTemporalMonthDay]] internal slot, then
    1. Set options to ? GetOptionsObject(options).
    2. Perform ? GetTemporalOverflowOption(options).
    3. Return ! CreateTemporalMonthDay(item.[[ISOMonth]], item.[[ISODay]], item.[[Calendar]], item.[[ISOYear]]).
  2. Return ? ToTemporalMonthDay(item, options).

10.3 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%.
Note
An ECMAScript implementation that includes the ECMA-402 Internationalization API extends this prototype with additional properties in order to represent calendar data.

10.3.1 Temporal.PlainMonthDay.prototype.constructor

The initial value of Temporal.PlainMonthDay.prototype.constructor is %Temporal.PlainMonthDay%.

10.3.2 Temporal.PlainMonthDay.prototype[ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Temporal.PlainMonthDay".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

10.3.3 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 monthDay be the this value.
  2. Perform ? RequireInternalSlot(monthDay, [[InitializedTemporalMonthDay]]).
  3. Return monthDay.[[Calendar]].

10.3.4 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 monthDay be the this value.
  2. Perform ? RequireInternalSlot(monthDay, [[InitializedTemporalMonthDay]]).
  3. Let isoDate be TemporalObjectToISODateRecord(monthDay).
  4. Return CalendarMonthCode(monthDay.[[Calendar]], isoDate).

10.3.5 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 monthDay be the this value.
  2. Perform ? RequireInternalSlot(monthDay, [[InitializedTemporalMonthDay]]).
  3. Let isoDate be TemporalObjectToISODateRecord(monthDay).
  4. Return 𝔽(CalendarDay(monthDay.[[Calendar]], isoDate)).

10.3.6 Temporal.PlainMonthDay.prototype.with ( temporalMonthDayLike [ , options ] )

This method performs the following steps when called:

  1. Let monthDay be the this value.
  2. Perform ? RequireInternalSlot(monthDay, [[InitializedTemporalMonthDay]]).
  3. If ? IsPartialTemporalObject(temporalMonthDayLike) is false, throw a TypeError exception.
  4. Let calendar be monthDay.[[Calendar]].
  5. Let fields be TemporalObjectToFields(monthDay).
  6. Let partialMonthDay be ? PrepareCalendarFields(calendar, temporalMonthDayLike, « day, month, month-code, year », « », partial).
  7. Set fields to CalendarMergeFields(calendar, fields, partialMonthDay).
  8. Let resolvedOptions be ? GetOptionsObject(options).
  9. Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
  10. Let isoDate be ? CalendarMonthDayFromFields(calendar, fields, overflow).
  11. Return ! CreateTemporalMonthDay(isoDate.[[Month]], isoDate.[[Day]], calendar, isoDate.[[Year]]).

10.3.7 Temporal.PlainMonthDay.prototype.equals ( other )

This method performs the following steps when called:

  1. Let monthDay be the this value.
  2. Perform ? RequireInternalSlot(monthDay, [[InitializedTemporalMonthDay]]).
  3. Set other to ? ToTemporalMonthDay(other).
  4. If monthDay.[[ISOMonth]]other.[[ISOMonth]], return false.
  5. If monthDay.[[ISODay]]other.[[ISODay]], return false.
  6. If monthDay.[[ISOYear]]other.[[ISOYear]], return false.
  7. Return CalendarEquals(monthDay.[[Calendar]], other.[[Calendar]]).

10.3.8 Temporal.PlainMonthDay.prototype.toString ( [ options ] )

This method performs the following steps when called:

  1. Let monthDay be the this value.
  2. Perform ? RequireInternalSlot(monthDay, [[InitializedTemporalMonthDay]]).
  3. Set options to ? GetOptionsObject(options).
  4. Let showCalendar be ? GetTemporalShowCalendarNameOption(options).
  5. Return TemporalMonthDayToString(monthDay, showCalendar).

10.3.9 Temporal.PlainMonthDay.prototype.toLocaleString ( [ locales [ , options ] ] )

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 monthDay be the this value.
  2. Perform ? RequireInternalSlot(monthDay, [[InitializedTemporalMonthDay]]).
  3. Return TemporalMonthDayToString(monthDay, "auto").

10.3.10 Temporal.PlainMonthDay.prototype.toJSON ( )

This method performs the following steps when called:

  1. Let monthDay be the this value.
  2. Perform ? RequireInternalSlot(monthDay, [[InitializedTemporalMonthDay]]).
  3. Return TemporalMonthDayToString(monthDay, "auto").

10.3.11 Temporal.PlainMonthDay.prototype.valueOf ( )

This method performs the following steps when called:

  1. Throw a TypeError exception.
Note

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().

10.3.12 Temporal.PlainMonthDay.prototype.toPlainDate ( item )

This method performs the following steps when called:

  1. Let monthDay be the this value.
  2. Perform ? RequireInternalSlot(monthDay, [[InitializedTemporalMonthDay]]).
  3. If item is not an Object, then
    1. Throw a TypeError exception.
  4. Let calendar be monthDay.[[Calendar]].
  5. Let fields be TemporalObjectToFields(monthDay).
  6. Let inputFields be ? PrepareCalendarFields(calendar, item, « year », « », « »).
  7. Let mergedFields be CalendarMergeFields(calendar, fields, inputFields).
  8. Let isoDate be ? CalendarDateFromFields(calendar, mergedFields, "constrain").
  9. Return ! CreateTemporalDate(isoDate.[[Year]], isoDate.[[Month]], isoDate.[[Day]], calendar).

10.4 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 Table 17.

Table 17: Internal Slots of Temporal.PlainMonthDay Instances
Internal Slot Description
[[InitializedTemporalMonthDay]] The only specified use of this slot is for distinguishing Temporal.PlainMonthDay instances from other objects.
[[ISOYear]] An integer representing the year in the ISO 8601 calendar. This slot is used by the calendar object in the [[Calendar]] slot to disambiguate if the [[ISOMonth]] and [[ISODay]] slots are not enough to uniquely identify a month and day in that calendar.
[[ISOMonth]] An integer between 1 and 12, inclusive, representing the month of the year in the ISO 8601 calendar.
[[ISODay]] An integer between 1 and ISODaysInMonth([[ISOYear]], [[ISOMonth]]), inclusive, representing the day of the month in the ISO 8601 calendar.
[[Calendar]] A String representing the calendar.

10.5 Abstract Operations

10.5.1 ToTemporalMonthDay ( item [ , options ] )

The abstract operation ToTemporalMonthDay takes argument item (an ECMAScript language value) and optional argument options (an ECMAScript language value) and returns either a normal completion containing a Temporal.PlainMonthDay or a throw completion. It returns its argument item if it is already a Temporal.PlainMonthDay instance, converts item to a new Temporal.PlainMonthDay instance if possible, and throws otherwise. It performs the following steps when called:

  1. If options is not present, set options to undefined.
  2. If item is a Object, then
    1. If item has an [[InitializedTemporalMonthDay]] internal slot, then
      1. Set options to ? GetOptionsObject(options).
      2. Perform ? GetTemporalOverflowOption(options).
      3. Return item.
    2. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(item).
    3. Let fields be ? PrepareCalendarFields(calendar, item, « day, month, month-code, year », «», «»).
    4. Set options to ? GetOptionsObject(options).
    5. Let overflow be ? GetTemporalOverflowOption(options).
    6. Let isoDate be ? CalendarMonthDayFromFields(calendar, fields, overflow).
    7. Return ! CreateTemporalMonthDay(isoDate.[[Month]], isoDate.[[Day]], calendar, isoDate.[[Year]]).
  3. If item is not a String, throw a TypeError exception.
  4. Let result be ? ParseTemporalMonthDayString(item).
  5. Let calendar be result.[[Calendar]].
  6. If calendar is empty, set calendar to "iso8601".
  7. If IsBuiltinCalendar(calendar) is false, throw a RangeError exception.
  8. Set calendar to CanonicalizeUValue("ca", calendar).
  9. Set options to ? GetOptionsObject(options).
  10. Perform ? GetTemporalOverflowOption(options).
  11. If result.[[Year]] is empty, then
    1. Assert: calendar is "iso8601".
    2. Let referenceISOYear be 1972 (the first ISO 8601 leap year after the epoch).
    3. Return ! CreateTemporalMonthDay(result.[[Month]], result.[[Day]], calendar, referenceISOYear).
  12. Let isoDate be CreateISODateRecord(result.[[Year]], result.[[Month]], result.[[Day]]).
  13. Set result to ISODateToFields(calendar, isoDate, month-day).
  14. NOTE: The following operation is called with "constrain" regardless of the value of overflow, in order for the calendar to store a canonical value in the [[ISOYear]] internal slot of the result.
  15. Set isoDate to ? CalendarMonthDayFromFields(calendar, result, "constrain").
  16. Return ! CreateTemporalMonthDay(isoDate.[[Month]], isoDate.[[Day]], calendar, isoDate.[[Year]]).

10.5.2 CreateTemporalMonthDay ( isoMonth, isoDay, calendar, referenceISOYear [ , newTarget ] )

The abstract operation CreateTemporalMonthDay takes arguments isoMonth (an integer), isoDay (an integer), calendar (a String or Object), and referenceISOYear (an integer) and optional argument newTarget (a constructor) and returns either a normal completion containing a Temporal.PlainMonthDay or a throw completion. It creates a Temporal.PlainMonthDay instance and fills the internal slots with valid values. It performs the following steps when called:

  1. If IsValidISODate(referenceISOYear, isoMonth, isoDay) is false, throw a RangeError exception.
  2. If ISODateWithinLimits(referenceISOYear, isoMonth, isoDay) is false, throw a RangeError exception.
  3. If newTarget is not present, set newTarget to %Temporal.PlainMonthDay%.
  4. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.PlainMonthDay.prototype%", « [[InitializedTemporalMonthDay]], [[ISOMonth]], [[ISODay]], [[ISOYear]], [[Calendar]] »).
  5. Set object.[[ISOMonth]] to isoMonth.
  6. Set object.[[ISODay]] to isoDay.
  7. Set object.[[Calendar]] to calendar.
  8. Set object.[[ISOYear]] to referenceISOYear.
  9. Return object.

10.5.3 TemporalMonthDayToString ( monthDay, showCalendar )

The abstract operation TemporalMonthDayToString takes arguments monthDay (a Temporal.MonthDay) and showCalendar ("auto", "always", "never", or "critical") and returns a String. It formats monthDay into an ISO 8601 string. It performs the following steps when called:

  1. Let month be ToZeroPaddedDecimalString(monthDay.[[ISOMonth]], 2).
  2. Let day be ToZeroPaddedDecimalString(monthDay.[[ISODay]], 2).
  3. Let result be the string-concatenation of month, the code unit 0x002D (HYPHEN-MINUS), and day.
  4. If showCalendar is one of "always" or "critical", or if monthDay.[[Calendar]] is not "iso8601", then
    1. Let year be PadISOYear(monthDay.[[ISOYear]]).
    2. Set result to the string-concatenation of year, the code unit 0x002D (HYPHEN-MINUS), and result.
  5. Let calendarString be FormatCalendarAnnotation(monthDay.[[Calendar]], showCalendar).
  6. Set result to the string-concatenation of result and calendarString.
  7. Return result.

11 Time Zones

11.1 Abstract Operations

Editor's Note
In ECMA-262, many time-zone-related sections and abstract operations are contained in the Date Objects section of the specification. It may be appropriate to move those sections here, for example:

11.1.1 GetAvailableNamedTimeZoneIdentifier ( timeZoneIdentifier )

The abstract operation GetAvailableNamedTimeZoneIdentifier takes argument timeZoneIdentifier (a String) and returns either a Time Zone Identifier Record or empty. 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. It performs the following steps when called:

  1. For each element record of AvailableNamedTimeZoneIdentifiers(), do
    1. If record.[[Identifier]] is an ASCII-case-insensitive match for timeZoneIdentifier, return record.
  2. Return empty.
Note

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.

11.1.2 GetISOPartsFromEpoch ( epochNanoseconds )

The abstract operation GetISOPartsFromEpoch takes argument epochNanoseconds (an integer) and returns an ISO Date-Time Record. It returns the components of a date in UTC corresponding to the given number of nanoseconds since the epoch. It performs the following steps when called:

  1. Assert: IsValidEpochNanoseconds((epochNanoseconds)) is true.
  2. Let remainderNs be epochNanoseconds modulo 106.
  3. Let epochMilliseconds be 𝔽((epochNanoseconds - remainderNs) / 106).
  4. Let year be EpochTimeToEpochYear(epochMilliseconds).
  5. Let month be EpochTimeToMonthInYear(epochMilliseconds) + 1.
  6. Let day be EpochTimeToDate(epochMilliseconds).
  7. Let hour be (HourFromTime(epochMilliseconds)).
  8. Let minute be (MinFromTime(epochMilliseconds)).
  9. Let second be (SecFromTime(epochMilliseconds)).
  10. Let millisecond be (msFromTime(epochMilliseconds)).
  11. Let microsecond be floor(remainderNs / 1000).
  12. Assert: microsecond < 1000.
  13. Let nanosecond be remainderNs modulo 1000.
  14. Return ISO Date-Time Record { [[Year]]: year, [[Month]]: month, [[Day]]: day, [[Hour]]: hour, [[Minute]]: minute, [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]: microsecond, [[Nanosecond]]: nanosecond  }.

11.1.3 GetNamedTimeZoneNextTransition ( timeZoneIdentifier, epochNanoseconds )

The implementation-defined abstract operation GetNamedTimeZoneNextTransition takes arguments timeZoneIdentifier (a String) and epochNanoseconds (a BigInt) and returns a BigInt or null.

The returned value t represents the number of nanoseconds since the epoch that corresponds to the first time zone transition after epochNanoseconds in the IANA time zone identified by timeZoneIdentifier. The operation returns null if no such transition exists for which t(nsMaxInstant).

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.

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:

  1. Assert: timeZoneIdentifier is "UTC".
  2. Return null.

11.1.4 GetNamedTimeZonePreviousTransition ( timeZoneIdentifier, epochNanoseconds )

The implementation-defined abstract operation GetNamedTimeZonePreviousTransition takes arguments timeZoneIdentifier (a String) and epochNanoseconds (a BigInt) and returns a BigInt or null.

The returned value t represents the number of nanoseconds since the epoch that corresponds to the last time zone transition before epochNanoseconds in the IANA time zone identified by timeZoneIdentifier. The operation returns null if no such transition exists for which t(nsMinInstant).

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.

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:

  1. Assert: timeZoneIdentifier is "UTC".
  2. Return null.

11.1.5 FormatOffsetTimeZoneIdentifier ( offsetMinutes [ , style ] )

The abstract operation FormatOffsetTimeZoneIdentifier takes argument offsetMinutes (an integer) and optional argument style (separated or unseparated) and returns a String. 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. It performs the following steps when called:

  1. If offsetMinutes ≥ 0, let sign be the code unit 0x002B (PLUS SIGN); otherwise, let sign be the code unit 0x002D (HYPHEN-MINUS).
  2. Let absoluteMinutes be abs(offsetMinutes).
  3. Let hour be floor(absoluteMinutes / 60).
  4. Let minute be absoluteMinutes modulo 60.
  5. Let timeString be FormatTimeString(hour, minute, 0, 0, "minute", style).
  6. Return the string-concatenation of sign and timeString.

11.1.6 FormatUTCOffsetNanoseconds ( offsetNanoseconds )

The abstract operation FormatUTCOffsetNanoseconds takes argument offsetNanoseconds (an integer) and returns a String. 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. It performs the following steps when called:

  1. If offsetNanoseconds ≥ 0, let sign be the code unit 0x002B (PLUS SIGN); otherwise, let sign be the code unit 0x002D (HYPHEN-MINUS).
  2. Let absoluteNanoseconds be abs(offsetNanoseconds).
  3. Let hour be floor(absoluteNanoseconds / (3600 × 109)).
  4. Let minute be floor(absoluteNanoseconds / (60 × 109)) modulo 60.
  5. Let second be floor(absoluteNanoseconds / 109) modulo 60.
  6. Let subSecondNanoseconds be absoluteNanoseconds modulo 109.
  7. If second = 0 and subSecondNanoseconds = 0, let precision be "minute"; otherwise, let precision be "auto".
  8. Let timeString be FormatTimeString(hour, minute, second, subSecondNanoseconds, precision).
  9. Return the string-concatenation of sign and timeString.

11.1.7 FormatDateTimeUTCOffsetRounded ( offsetNanoseconds )

The abstract operation FormatDateTimeUTCOffsetRounded takes argument offsetNanoseconds (an integer) and returns a String. 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. It performs the following steps when called:

  1. Set offsetNanoseconds to RoundNumberToIncrement(offsetNanoseconds, 60 × 109, "halfExpand").
  2. Let offsetMinutes be offsetNanoseconds / (60 × 109).
  3. Assert: offsetMinutes is an integer.
  4. Return FormatOffsetTimeZoneIdentifier(offsetMinutes).

11.1.8 ToTemporalTimeZoneIdentifier ( temporalTimeZoneLike )

The abstract operation ToTemporalTimeZoneIdentifier takes argument temporalTimeZoneLike (an ECMAScript value) and returns either a normal completion containing a String or a throw completion. It attempts to derive a value from temporalTimeZoneLike that is a time zone identifier according to GetAvailableNamedTimeZoneIdentifier, and returns that value if found or throws an exception if not. It performs the following steps when called:

  1. If temporalTimeZoneLike is an Object, then
    1. If temporalTimeZoneLike has an [[InitializedTemporalZonedDateTime]] internal slot, then
      1. Return temporalTimeZoneLike.[[TimeZone]].
  2. If temporalTimeZoneLike is not a String, throw a TypeError exception.
  3. Let parseResult be ? ParseTemporalTimeZoneString(temporalTimeZoneLike).
  4. Let offsetMinutes be parseResult.[[OffsetMinutes]].
  5. If offsetMinutes is not empty, return FormatOffsetTimeZoneIdentifier(offsetMinutes).
  6. Let name be parseResult.[[Name]].
  7. Let timeZoneIdentifierRecord be GetAvailableNamedTimeZoneIdentifier(name).
  8. If timeZoneIdentifierRecord is empty, throw a RangeError exception.
  9. Return timeZoneIdentifierRecord.[[Identifier]].

11.1.9 GetOffsetNanosecondsFor ( timeZone, epochNs )

The abstract operation GetOffsetNanosecondsFor takes arguments timeZone (a String) and epochNs (a BigInt) and returns an integer in the interval from -86400 × 109 (exclusive) to 86400 × 109 (exclusive). It determines the UTC offset of an exact time epochNs, in nanoseconds. It performs the following steps when called:

  1. Let parseResult be ! ParseTimeZoneIdentifier(timeZone).
  2. If parseResult.[[OffsetMinutes]] is not empty, return parseResult.[[OffsetMinutes]] × (60 × 109).
  3. Return GetNamedTimeZoneOffsetNanoseconds(parseResult.[[Name]], epochNs).

11.1.10 GetISODateTimeFor ( timeZone, epochNs )

The abstract operation GetISODateTimeFor takes arguments timeZone (a String) and epochNs (a BigInt) and returns an ISO Date-Time Record.

It performs the following steps when called:

  1. Let offsetNanoseconds be GetOffsetNanosecondsFor(timeZone, epochNs).
  2. Let result be GetISOPartsFromEpoch((epochNs)).
  3. Return BalanceISODateTime(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]] + offsetNanoseconds).

11.1.11 GetEpochNanosecondsFor ( timeZone, isoDateTime, disambiguation )

The abstract operation GetEpochNanosecondsFor takes arguments timeZone (a String), isoDateTime (an ISO Date-Time Record), and disambiguation ("compatible", "earlier", "later", or "reject") and returns either a normal completion containing a BigInt or a throw completion.

It performs the following steps when called:

  1. Let possibleEpochNs be ? GetPossibleEpochNanoseconds(timeZone, isoDateTime).
  2. Return ? DisambiguatePossibleEpochNanoseconds(possibleEpochNs, timeZone, isoDateTime, disambiguation).

11.1.12 DisambiguatePossibleEpochNanoseconds ( possibleEpochNs, timeZone, isoDateTime, disambiguation )

The abstract operation DisambiguatePossibleEpochNanoseconds takes arguments possibleEpochNs (a List of BigInts), timeZone (a String), isoDateTime (an ISO Date-Time Record), and disambiguation ("compatible", "earlier", "later", or "reject") and returns either a normal completion containing a BigInt or a throw completion. It chooses from a List of possible exact times the one indicated by the disambiguation parameter. It performs the following steps when called:

  1. Let n be possibleEpochNs's length.
  2. If n = 1, then
    1. Return possibleEpochNs[0].
  3. If n ≠ 0, then
    1. If disambiguation is "earlier" or "compatible", then
      1. Return possibleEpochNs[0].
    2. If disambiguation is "later", then
      1. Return possibleEpochNs[n - 1].
    3. Assert: disambiguation is "reject".
    4. Throw a RangeError exception.
  4. Assert: n = 0.
  5. If disambiguation is "reject", then
    1. Throw a RangeError exception.
  6. Let before be the latest possible ISO Date-Time Record for which CompareISODateTime(before.[[Year]], before.[[Month]], before.[[Day]], before.[[Hour]], before.[[Minute]], before.[[Second]], before.[[Millisecond]], before.[[Microsecond]], before.[[Nanosecond]], isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]], isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]]) = -1 and ! GetPossibleEpochNanoseconds(timeZone, before) is not empty.
  7. Let after be the earliest possible ISO Date-Time Record for which CompareISODateTime(after.[[Year]], after.[[Month]], after.[[Day]], after.[[Hour]], after.[[Minute]], after.[[Second]], after.[[Millisecond]], after.[[Microsecond]], after.[[Nanosecond]], isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]], isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]]) = 1 and ! GetPossibleEpochNanoseconds(timeZone, after) is not empty.
  8. Let offsetBefore be GetOffsetNanosecondsFor(timeZone, before).
  9. Let offsetAfter be GetOffsetNanosecondsFor(timeZone, after).
  10. Let nanoseconds be offsetAfter - offsetBefore.
  11. Assert: abs(nanoseconds) ≤ nsPerDay.
  12. If disambiguation is "earlier", then
    1. Let norm be NormalizeTimeDuration(0, 0, 0, 0, 0, -nanoseconds).
    2. Let earlierTime be AddTime(isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]], norm).
    3. Let earlierDate be BalanceISODate(isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]] + earlierTime.[[Days]]).
    4. Let earlierDateTime be CombineISODateAndTimeRecord(earlierDate, earlierTime).
    5. Set possibleEpochNs to ? GetPossibleEpochNanoseconds(timeZone, earlierDateTime).
    6. Assert: possibleEpochNs is not empty.
    7. Return possibleEpochNs[0].
  13. Assert: disambiguation is "compatible" or "later".
  14. Let norm be NormalizeTimeDuration(0, 0, 0, 0, 0, nanoseconds).
  15. Let laterTime be AddTime(isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]], norm).
  16. Let laterDate be BalanceISODate(isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]] + laterTime.[[Days]]).
  17. Let laterDateTime be CombineISODateAndTimeRecord(laterDate, laterTime).
  18. Set possibleEpochNs to ? GetPossibleEpochNanoseconds(timeZone, laterDateTime).
  19. Set n to possibleEpochNs's length.
  20. Assert: n ≠ 0.
  21. Return possibleEpochNs[n - 1].

11.1.13 GetPossibleEpochNanoseconds ( timeZone, isoDateTime )

The abstract operation GetPossibleEpochNanoseconds takes arguments timeZone (a String) and isoDateTime (an ISO Date-Time Record) and returns either a normal completion containing a List of BigInts or a throw completion. It determines the possible exact times that may correspond to isoDateTime. It performs the following steps when called:

  1. Let parseResult be ! ParseTimeZoneIdentifier(timeZone).
  2. If parseResult.[[OffsetMinutes]] is not empty, then
    1. Let epochNanoseconds be GetUTCEpochNanoseconds(isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]], isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]], parseResult.[[OffsetMinutes]] × (60 × 109)).
    2. Let possibleEpochNanoseconds be « epochNanoseconds ».
  3. Else,
    1. Let possibleEpochNanoseconds be GetNamedTimeZoneEpochNanoseconds(parseResult.[[Name]], isoDateTime.[[Year]], isoDateTime.[[Month]], isoDateTime.[[Day]], isoDateTime.[[Hour]], isoDateTime.[[Minute]], isoDateTime.[[Second]], isoDateTime.[[Millisecond]], isoDateTime.[[Microsecond]], isoDateTime.[[Nanosecond]]).
  4. For each value epochNanoseconds in possibleEpochNanoseconds, do
    1. If IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
  5. Return possibleEpochNanoseconds.

11.1.14 TimeZoneEquals ( one, two )

The abstract operation TimeZoneEquals takes arguments one (a String) and two (a String) and returns a Boolean. It returns true if its arguments represent time zones using the same identifier. It performs the following steps when called:

  1. If one is two, return true.
  2. Let offsetMinutesOne be ! ParseTimeZoneIdentifier(one).[[OffsetMinutes]].
  3. Let offsetMinutesTwo be ! ParseTimeZoneIdentifier(two).[[OffsetMinutes]].
  4. If offsetMinutesOne is empty and offsetMinutesTwo is empty, then
    1. Let recordOne be GetAvailableNamedTimeZoneIdentifier(one).
    2. Let recordTwo be GetAvailableNamedTimeZoneIdentifier(two).
    3. If recordOne is not empty and recordTwo is not empty and recordOne.[[PrimaryIdentifier]] is recordTwo.[[PrimaryIdentifier]], return true.
  5. Else,
    1. If offsetMinutesOne is not empty and offsetMinutesTwo is not empty and offsetMinutesOne = offsetMinutesTwo, return true.
  6. Return false.

11.1.15 ParseTimeZoneIdentifier ( identifier )

The abstract operation ParseTimeZoneIdentifier takes argument identifier (a String) and returns either a normal completion containing a Record with fields [[Name]] (a String or empty) and [[OffsetMinutes]] (an integer or empty), or a throw completion. If identifier is a named time zone identifier, [[Name]] will be identifier and [[OffsetMinutes]] will be empty. If identifier is an offset time zone identifier, [[Name]] will be empty and [[OffsetMinutes]] will be a signed integer. Otherwise, a RangeError will be thrown. It performs the following steps when called:

  1. Let parseResult be ParseText(StringToCodePoints(identifier), TimeZoneIdentifier).
  2. If parseResult is a List of errors, throw a RangeError exception.
  3. If parseResult contains a TimeZoneIANAName Parse Node, then
    1. Let name be the source text matched by the TimeZoneIANAName Parse Node contained within parseResult.
    2. 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.
    3. Return the Record { [[Name]]: CodePointsToString(name), [[OffsetMinutes]]: empty }.
  4. Else,
    1. Assert: parseResult contains a UTCOffset[~SubMinutePrecision] Parse Node.
    2. Let offsetString be the source text matched by the UTCOffset[~SubMinutePrecision] Parse Node contained within parseResult.
    3. Let offsetNanoseconds be ! ParseDateTimeUTCOffset(offsetString).
    4. Let offsetMinutes be offsetNanoseconds / (60 × 109).
    5. Assert: offsetMinutes is an integer.
    6. Return the Record { [[Name]]: empty, [[OffsetMinutes]]: offsetMinutes }.

12 Calendars

12.1 Calendar Types

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 as defined by Unicode Technical Standard #35, Part 4, Section 2. 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).

12.1.1 IsBuiltinCalendar ( id )

The abstract operation IsBuiltinCalendar takes argument id (a String) and returns a Boolean. The returned value is true if id is a calendar type denoting a built-in calendar, and false otherwise. It performs the following steps when called:

  1. Let calendars be AvailableCalendars().
  2. If calendars contains the ASCII-lowercase of id, return true.
  3. Return false.

12.1.2 AvailableCalendars ( )

The implementation-defined abstract operation AvailableCalendars takes no arguments and returns a List of Strings. The returned List is sorted according to lexicographic code unit order, and contains unique calendar types in canonical form (12.1) identifying the calendars for which the implementation provides the functionality of Intl.DateTimeFormat objects, including their aliases (e.g., either both or neither of "islamicc" and "islamic-civil"). The List must include "iso8601".

12.2 Abstract Operations

12.2.1 Calendar Date Records

An Calendar Date Record is a Record value used to represent a valid calendar date in a non-ISO 8601 calendar. Calendar Date Records are produced by the abstract operation CalendarISOToDate.

Calendar Date Records have the fields listed in Table 18.

Table 18: Calendar Date Record Fields
Field Name Value Meaning
[[Era]] a String or undefined A lowercase String value 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. Note 1
Era years are 1-indexed for many calendars, but not all (e.g., the eras of the Burmese calendar 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". Note 2
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. Note 3
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 String The month code of the date's month. 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 should be the string-concatenation of "M" and ToZeroPaddedDecimalString(n, 2), and the month code for a month that is a leap month inserted after a month whose 1-based ordinal position in a common year of the calendar is p should be the string-concatenation of "M", ToZeroPaddedDecimalString(p, 2), and "L". Note 4
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". In a calendar with a leap month at the start of some years, the month code of that month would be "M00L".
[[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 ToISOWeekOfYear.

The Year-Week Record contains undefined in [[Week]] and [[Year]] field for calendars that do not have a well-defined week calendar system.

Editor's Note

More details about this field will be specified in the Intl era and monthCode proposal.

[[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. Note 5
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).

12.2.2 Calendar Fields Records

An 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 TemporalObjectToFields 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 ISOFieldKeysToIgnore to denote a subset of fields to operate on.

Calendar Fields Records have the fields listed in Table 19.

Table 19: Calendar Fields Record Fields
Field Name Value Default Property Key Enumeration Key Conversion Meaning
[[Era]] a String or unset unset "era" era to-string A lowercase String value 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 String or unset unset "monthCode" month-code to-primitive-and-require-string 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-primitive-and-require-string A string of the form ±HH:MM that can be parsed by ParseTimeZoneOffsetString.
[[TimeZone]] a String or unset unset "timeZone" time-zone to-temporal-time-zone-identifier A time zone identifier.

12.2.3 CalendarFieldKeysPresent ( fields )

The abstract operation CalendarFieldKeysPresent takes argument fields (a Calendar Fields Record) and returns a List of values from the Enumeration Key column of Table 19. The returned List contains the enumeration keys for all fields of fields that are not unset. It performs the following steps when called:

  1. Let list be « ».
  2. For each row of Table 19, except the header row, do
    1. Let value be fields' field whose name is given in the Field Name column of the row.
    2. Let enumerationKey be the value in the Enumeration Key column of the row.
    3. If value is not unset, append enumerationKey to list.
  3. Return list.

12.2.4 CalendarMergeFields ( calendar, fields, additionalFields )

The abstract operation CalendarMergeFields takes arguments calendar (a String), fields (a Calendar Fields Record), and additionalFields (a Calendar Fields Record) and returns a Calendar Fields Record. It merges the properties of fields and additionalFields. It performs the following steps when called:

  1. Let additionalKeys be CalendarFieldKeysPresent(additionalFields).
  2. If calendar is "iso8601", then
    1. Let overriddenKeys be ISOFieldKeysToIgnore(additionalKeys).
  3. Else,
    1. Let overriddenKeys be CalendarFieldKeysToIgnore(calendar, additionalKeys).
  4. Let merged be a Calendar Fields Record with all fields set to unset.
  5. Let fieldsKeys be CalendarFieldKeysPresent(fields).
  6. For each row of Table 19, except the header row, do
    1. Let key be the value in the Enumeration Key column of the row.
    2. 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.
      2. Set merged's field whose name is given in the Field Name column of the row to propValue.
    3. If additionalKeys contains key, then
      1. Let propValue be additionalFields' field whose name is given in the Field Name column of the row.
      2. Set merged's field whose name is given in the Field Name column of the row to propValue.
  7. Return merged.

12.2.5 CalendarDateAdd ( calendar, isoDate, duration, overflow )

The abstract operation CalendarDateAdd takes arguments calendar (a String), isoDate (an ISO Date Record), duration (a Date Duration Record), and overflow ("constrain" or "reject") and returns either a normal completion containing an ISO Date Record or a throw completion. It adds dateDuration to isoDate using the years, months, and weeks reckoning of calendar. It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. Return ? AddISODate(isoDate.[[Year]], isoDate.[[Month]], isoDate.[[Day]], duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], overflow).
  2. 1. Return ? CalendarDateAddition(calendar, isoDate, duration, overflow).

12.2.6 CalendarDateUntil ( calendar, one, two, largestUnit )

The abstract operation CalendarDateUntil takes arguments calendar (a String), one (an ISO Date Record), two (an ISO Date Record), and largestUnit (a String from the "Singular" column of Table 21) and returns a Temporal.Duration. It determines the difference between the dates one and two using the years, months, and weeks reckoning of calendar. It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. Return DifferenceISODate(one.[[Year]], one.[[Month]], one.[[Day]], two.[[Year]], two.[[Month]], two.[[Day]], largestUnit).
  2. Else,
    1. Return CalendarDateDifference(calendar, one, two, largestUnit).

12.2.7 CalendarEra ( calendar, isoDate )

The abstract operation CalendarEra takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns a String or undefined. It performs the following steps when called:

  1. If calendar is "iso8601", return undefined.
  2. Return CalendarISOToDate(calendar, isoDate).[[Era]].

12.2.8 CalendarEraYear ( calendar, isoDate )

The abstract operation CalendarEraYear takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns an integer or undefined. It performs the following steps when called:

  1. If calendar is "iso8601", return undefined.
  2. Return CalendarISOToDate(calendar, isoDate).[[EraYear]].

12.2.9 CalendarYear ( calendar, isoDate )

The abstract operation CalendarYear takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns an integer. It performs the following steps when called:

  1. If calendar is "iso8601", return isoDate.[[Year]].
  2. Return CalendarISOToDate(calendar, isoDate).[[Year]].

12.2.10 CalendarMonth ( calendar, isoDate )

The abstract operation CalendarMonth takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns a positive integer. It performs the following steps when called:

  1. If calendar is "iso8601", return isoDate.[[Month]].
  2. Return CalendarISOToDate(calendar, isoDate).[[Month]].

12.2.11 CalendarMonthCode ( calendar, isoDate )

The abstract operation CalendarMonthCode takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns a String. It performs the following steps when called:

  1. If calendar is "iso8601", return ISOMonthCode(isoDate.[[Month]]).
  2. Return CalendarISOToDate(calendar, isoDate).[[MonthCode]].

12.2.12 CalendarDay ( calendar, isoDate )

The abstract operation CalendarDay takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns a positive integer. It performs the following steps when called:

  1. If calendar is "iso8601", return isoDate.[[Day]].
  2. Return CalendarISOToDate(calendar, isoDate).[[Day]].

12.2.13 CalendarDayOfWeek ( calendar, isoDate )

The abstract operation CalendarDayOfWeek takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns a positive integer. It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. Return ToISODayOfWeek(isoDate.[[Year]], isoDate.[[Month]], isoDate.[[Day]]).
  2. Return CalendarISOToDate(calendar, isoDate).[[DayOfWeek]].

12.2.14 CalendarDayOfYear ( calendar, isoDate )

The abstract operation CalendarDayOfYear takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns a positive integer. It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. Return ToISODayOfYear(isoDate.[[Year]], isoDate.[[Month]], isoDate.[[Day]]).
  2. Return CalendarISOToDate(calendar, isoDate).[[DayOfYear]].

12.2.15 CalendarWeekOfYear ( calendar, isoDate )

The abstract operation CalendarWeekOfYear takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns a positive integer or undefined. It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. Let yearWeek be ToISOWeekOfYear(isoDate.[[Year]], isoDate.[[Month]], isoDate.[[Day]]).
  2. Else,
    1. Let yearWeek be CalendarISOToDate(calendar, isoDate).[[WeekOfYear]].
  3. Return yearWeek.[[Week]].

12.2.16 CalendarYearOfWeek ( calendar, isoDate )

The abstract operation CalendarYearOfWeek takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns a positive integer or undefined. It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. Let yearWeek be ToISOWeekOfYear(isoDate.[[Year]], isoDate.[[Month]], isoDate.[[Day]]).
  2. Else,
    1. Let yearWeek be CalendarISOToDate(calendar, isoDate).[[WeekOfYear]].
  3. Return yearWeek.[[Year]].

12.2.17 CalendarDaysInWeek ( calendar, isoDate )

The abstract operation CalendarDaysInWeek takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns a positive integer. It performs the following steps when called:

  1. If calendar is "iso8601", return 7.
  2. Return CalendarISOToDate(calendar, isoDate).[[DaysInWeek]].

12.2.18 CalendarDaysInMonth ( calendar, isoDate )

The abstract operation CalendarDaysInMonth takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns a positive integer. It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. Return ISODaysInMonth(isoDate.[[Year]], isoDate.[[Month]]).
  2. Return CalendarISOToDate(calendar, isoDate).[[DaysInMonth]].

12.2.19 CalendarDaysInYear ( calendar, isoDate )

The abstract operation CalendarDaysInYear takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns a positive integer. It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. Return MathematicalDaysInYear(isoDate.[[Year]]).
  2. Return CalendarISOToDate(calendar, isoDate).[[DaysInYear]].

12.2.20 CalendarMonthsInYear ( calendar, isoDate )

The abstract operation CalendarMonthsInYear takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns a positive integer. It performs the following steps when called:

  1. If calendar is "iso8601", return 12.
  2. Return CalendarISOToDate(calendar, isoDate).[[MonthsInYear]].

12.2.21 CalendarInLeapYear ( calendar, isoDate )

The abstract operation CalendarInLeapYear takes arguments calendar (a String) and isoDate (an ISO Date Record) and returns a Boolean. It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. If MathematicalInLeapYear(EpochTimeForYear(isoDate.[[Year]])) = 1, return true.
    2. Return false.
  2. Return CalendarISOToDate(calendar, isoDate).[[InLeapYear]].

12.2.22 ToTemporalCalendarIdentifier ( temporalCalendarLike )

The abstract operation ToTemporalCalendarIdentifier takes argument temporalCalendarLike (an ECMAScript value) and returns either a normal completion containing a String or a throw completion. It attempts to derive a value from temporalCalendarLike that is a calendar identifier according to IsBuiltinCalendar, and returns that value if found or throws an exception if not. It performs the following steps when called:

  1. If temporalCalendarLike is an Object, then
    1. If temporalCalendarLike has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
      1. Return temporalCalendarLike.[[Calendar]].
  2. If temporalCalendarLike is not a String, throw a TypeError exception.
  3. Let identifier be ? ParseTemporalCalendarString(temporalCalendarLike).
  4. If IsBuiltinCalendar(identifier) is false, throw a RangeError exception.
  5. Return CanonicalizeUValue("ca", identifier).

12.2.23 GetTemporalCalendarIdentifierWithISODefault ( item )

The abstract operation GetTemporalCalendarIdentifierWithISODefault takes argument item (an Object) and returns either a normal completion containing a String or a throw completion. 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. It performs the following steps when called:

  1. If item has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
    1. Return item.[[Calendar]].
  2. Let calendarLike be ? Get(item, "calendar").
  3. If calendarLike is undefined, then
    1. Return "iso8601".
  4. Return ? ToTemporalCalendarIdentifier(calendarLike).

12.2.24 CalendarDateFromFields ( calendar, fields, overflow )

The abstract operation CalendarDateFromFields takes arguments calendar (a String), fields (a Calendar Fields Record), and overflow ("constrain" or "reject") and returns either a normal completion containing an ISO Date Record or a throw completion. 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. It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. If fields.[[Year]] is unset or fields.[[Day]] is unset, throw a TypeError exception.
    2. Perform ? ISOResolveMonth(fields).
    3. Return ? ISODateFromFields(fields, overflow).
  2. Perform ? CalendarResolveFields(calendar, fields, date).
  3. Return ? CalendarDateToISO(calendar, fields, overflow).

12.2.25 CalendarYearMonthFromFields ( calendar, fields, overflow )

The abstract operation CalendarYearMonthFromFields takes arguments calendar (a String), fields (a Calendar Fields Record), and overflow ("constrain" or "reject") and returns either a normal completion containing an ISO Date Record or a throw completion. 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. It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. If fields.[[Year]] is unset, throw a TypeError exception.
    2. Perform ? ISOResolveMonth(fields).
    3. Return ? ISOYearMonthFromFields(fields, overflow).
  2. Let firstDayIndex be the 1-based index of the first day of the month described by fields (i.e., 1 unless the month's first day is skipped by this calendar.)
  3. Set fields.[[Day]] to firstDayIndex.
  4. Perform ? CalendarResolveFields(calendar, fields, year-month).
  5. Return ? CalendarDateToISO(calendar, fields, overflow).

12.2.26 CalendarMonthDayFromFields ( calendar, fields, overflow )

The abstract operation CalendarMonthDayFromFields takes arguments calendar (a String), fields (a Calendar Fields Record), and overflow ("constrain" or "reject") and returns either a normal completion containing an ISO Date Record or a throw completion. 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. It performs the following steps when called:

  1. If calendar is "iso8601", then
    1. If fields.[[Day]] is unset, throw a TypeError exception.
    2. Perform ? ISOResolveMonth(fields).
    3. Return ? ISOMonthDayFromFields(fields, overflow).
  2. Perform ? CalendarResolveFields(calendar, fields, month-day).
  3. Return ? CalendarMonthDayToISOReferenceDate(calendar, fields, overflow).

12.2.27 MaybeFormatCalendarAnnotation ( calendar, showCalendar )

The abstract operation MaybeFormatCalendarAnnotation takes arguments calendar (a String) and showCalendar (one of "auto", "always", "never", or "critical") and returns a String. It returns a string with a calendar annotation suitable for concatenating to the end of an ISO 8601 string. Depending on the given calendar and the value of showCalendar, the string may be empty if no calendar annotation need be included. It performs the following steps when called:

  1. If showCalendar is "never", return the empty String.
  2. Return FormatCalendarAnnotation(calendar, showCalendar).

12.2.28 FormatCalendarAnnotation ( id, showCalendar )

The abstract operation FormatCalendarAnnotation takes arguments id (a String) and showCalendar (one of "auto", "always", "never", or "critical") and returns a String. It returns a string with a calendar annotation suitable for concatenating to the end of an ISO 8601 string. Depending on the given id and value of showCalendar, the string may be empty if no calendar annotation need be included. It performs the following steps when called:

  1. If showCalendar is "never", return the empty String.
  2. If showCalendar is "auto" and id is "iso8601", return the empty String.
  3. If showCalendar is "critical", let flag be "!"; else, let flag be the empty String.
  4. Return the string-concatenation of "[", flag, "u-ca=", id, and "]".

12.2.29 CalendarEquals ( one, two )

The abstract operation CalendarEquals takes arguments one (a String) and two (a String) and returns a Boolean. It returns true if its arguments represent calendars using the same identifier. It performs the following steps when called:

  1. If CanonicalizeUValue("ca", one) is CanonicalizeUValue("ca", two), return true.
  2. Return false.

12.2.30 ISODaysInMonth ( year, month )

The abstract operation ISODaysInMonth takes arguments year (an integer) and month (an integer in the inclusive interval from 1 to 12) and returns a positive integer. It returns the number of days in the given year and month in the ISO 8601 calendar. It performs the following steps when called:

  1. If month is 1, 3, 5, 7, 8, 10, or 12, return 31.
  2. If month is 4, 6, 9, or 11, return 30.
  3. Assert: month = 2.
  4. Return 28 + MathematicalInLeapYear(EpochTimeForYear(year)).

12.2.31 ToISOWeekOfYear ( year, month, day )

The abstract operation ToISOWeekOfYear takes arguments year (an integer), month (an integer), and day (an integer) and returns a Year-Week Record. 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). It performs the following steps when called:

  1. Assert: IsValidISODate(year, month, day) is true.
  2. Let wednesday be 3.
  3. Let thursday be 4.
  4. Let friday be 5.
  5. Let saturday be 6.
  6. Let daysInWeek be 7.
  7. Let maxWeekNumber be 53.
  8. Let dayOfYear be ToISODayOfYear(year, month, day).
  9. Let dayOfWeek be ToISODayOfWeek(year, month, day).
  10. Let week be floor((dayOfYear + daysInWeek - dayOfWeek + wednesday ) / daysInWeek).
  11. If week < 1, then
    1. NOTE: This is the last week of the previous year.
    2. Let dayOfJan1st be ToISODayOfWeek(year, 1, 1).
    3. If dayOfJan1st = friday, then
      1. Return Year-Week Record { [[Week]]: maxWeekNumber, [[Year]]: year - 1 }.
    4. If dayOfJan1st = saturday, and MathematicalInLeapYear(EpochTimeForYear(year - 1)) = 1, then
      1. Return Year-Week Record { [[Week]]: maxWeekNumber. [[Year]]: year - 1 }.
    5. Return Year-Week Record { [[Week]]: maxWeekNumber - 1, [[Year]]: year - 1 }.
  12. If week = maxWeekNumber, then
    1. Let daysInYear be MathematicalDaysInYear(year).
    2. Let daysLaterInYear be daysInYear - dayOfYear.
    3. Let daysAfterThursday be thursday - dayOfWeek.
    4. If daysLaterInYear < daysAfterThursday, then
      1. Return Year-Week Record { [[Week]]: 1, [[Year]]: year + 1 }.
  13. Return Year-Week Record { [[Week]]: week, [[Year]]: year }.
Note 1
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.
Note 2
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).

12.2.32 ISOMonthCode ( month )

The abstract operation ISOMonthCode takes argument month (an integer in the inclusive interval from 1 to 12) and returns a String. It returns the string month code for a month in the ISO 8601 calendar. It performs the following steps when called:

  1. Let numberPart be ToZeroPaddedDecimalString(month, 2).
  2. Return the string-concatenation of "M" and numberPart.

12.2.33 ISOResolveMonth ( fields )

The abstract operation ISOResolveMonth takes argument fields (a Calendar Fields Record) and returns either a normal completion containing unused or a throw completion. It ensures that the [[Month]] field of fields, if unset, is set to the integral Number value in the inclusive interval from 1 to 12 that corresponds to the [[MonthCode]] field of fields. It throws an exception if both fields are unset, or if either field is invalid, or if the fields are inconsistent. It performs the following steps when called:

  1. Let month be fields.[[Month]].
  2. Let monthCode be fields.[[MonthCode]].
  3. If monthCode is unset, then
    1. If month is unset, throw a TypeError exception.
    2. Return unused.
  4. Assert: monthCode is a String.
  5. NOTE: The ISO 8601 calendar does not include leap months.
  6. If the length of monthCode is not 3, throw a RangeError exception.
  7. If the first code unit of monthCode is not 0x004D (LATIN CAPITAL LETTER M), throw a RangeError exception.
  8. Let monthCodeDigits be the substring of monthCode from 1.
  9. If ParseText(StringToCodePoints(monthCodeDigits), DateMonth) is a List of errors, throw a RangeError exception.
  10. Let monthCodeInteger be (StringToNumber(monthCodeDigits)).
  11. Assert: SameValue(monthCode, ISOMonthCode(monthCodeInteger)) is true.
  12. If month is not unset and monthmonthCodeInteger, throw a RangeError exception.
  13. Set fields.[[Month]] to monthCodeInteger.
  14. Return unused.

12.2.34 ISODateFromFields ( fields, overflow )

The abstract operation ISODateFromFields takes arguments fields (a Calendar Fields Record) and overflow ("constrain" or "reject") and returns either a normal completion containing an ISO Date Record or a throw completion. It performs the conversion operation of a Calendar Fields Record to an ISO Date Record for the ISO 8601 calendar, as CalendarDateFromFields does for other calendars. It performs the following steps when called:

  1. Let year be fields.[[Year]].
  2. Let month be fields.[[Month]].
  3. Let day be fields.[[Day]].
  4. Assert: None of year, month, and day are unset.
  5. Let result be ? RegulateISODate(year, month, day, overflow).
  6. If ISODateWithinLimits(result.[[Year]], result.[[Month]], result.[[Day]]) is false, throw a RangeError exception.
  7. Return result.

12.2.35 ISOYearMonthFromFields ( fields, overflow )

The abstract operation ISOYearMonthFromFields takes arguments fields (a Calendar Fields Record) and overflow (either "constrain" or "reject") and returns either a normal completion containing an ISO Date Record or a throw completion. It performs the conversion operation of a Calendar Fields Record to an ISO Date Record for the ISO 8601 calendar in the context of Temporal.PlainYearMonth, as CalendarYearMonthFromFields does for other calendars. It performs the following steps when called:

  1. Let year be fields.[[Year]].
  2. Let month be fields.[[Month]].
  3. Assert: year and month are not unset.
  4. Let result be ? RegulateISOYearMonth(year, month, overflow).
  5. If ISOYearMonthWithinLimits(result.[[Year]], result.[[Month]]) is false, throw a RangeError exception.
  6. Return ISO Date Record { [[Year]]: result.[[Year]], [[Month]]: result.[[Month]], [[Day]]: 1  }.

12.2.36 ISOMonthDayFromFields ( fields, overflow )

The abstract operation ISOMonthDayFromFields takes arguments fields (a Calendar Fields Record) and overflow (either "constrain" or "reject") and returns either a normal completion containing an ISO Date Record or a throw completion. It performs the conversion operation of a Calendar Fields Record to an ISO Date Record for the ISO 8601 calendar in the context of Temporal.PlainMonthDay, as CalendarMonthDayFromFields does for other calendars. It performs the following steps when called:

  1. Let month be fields.[[Month]].
  2. Let day be fields.[[Day]].
  3. Assert: month and day are not unset.
  4. Let year be fields.[[Year]].
  5. Let referenceISOYear be 1972 (the first ISO 8601 leap year after the epoch).
  6. If year is unset, then
    1. Let result be ? RegulateISODate(referenceISOYear, month, day, overflow).
  7. Else,
    1. Let result be ? RegulateISODate(year, month, day, overflow).
  8. Return ISO Date Record { [[Year]]: referenceISOYear, [[Month]]: result.[[Month]], [[Day]]: result.[[Day]]  }.

12.2.37 ISOFieldKeysToIgnore ( keys )

The abstract operation ISOFieldKeysToIgnore takes argument keys (a List of values from the Enumeration Key column of Table 19) and returns a List of values from the Enumeration Key column of Table 19. It determines which calendar date fields changing any of the fields named in keys can potentially conflict with or invalidate, for the ISO 8601 calendar. It performs the following steps when called:

  1. Let ignoredKeys be an empty List.
  2. For each element key of keys, do
    1. Append key to ignoredKeys.
    2. If key is month, append month-code to ignoredKeys.
    3. Else if key is month-code, append month to ignoredKeys.
  3. 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.
  4. Return ignoredKeys.

12.2.38 ToISODayOfYear ( year, month, day )

The abstract operation ToISODayOfYear takes arguments year (an integer), month (an integer), and day (an integer) and returns an integer. 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. It performs the following steps when called:

  1. Assert: IsValidISODate(year, month, day) is true.
  2. Let epochDays be ISODateToEpochDays(year, month - 1, day).
  3. Return EpochTimeToDayInYear(EpochDaysToEpochMs(epochDays, 0)) + 1.

12.2.39 ToISODayOfWeek ( year, month, day )

The abstract operation ToISODayOfWeek takes arguments year (an integer), month (an integer), and day (an integer) and returns an integer. 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. It performs the following steps when called:

  1. Assert: IsValidISODate(year, month, day) is true.
  2. Let epochDays be ISODateToEpochDays(year, month - 1, day).
  3. Let dayOfWeek be EpochTimeToWeekDay(EpochDaysToEpochMs(epochDays, 0)).
  4. If dayOfWeek = 0, return 7.
  5. Return dayOfWeek.

12.2.40 CalendarDateToISO ( calendar, fields, overflow )

The implementation-defined abstract operation CalendarDateToISO takes arguments calendar (a String that is not "iso8601" for which IsBuiltinCalendar returns true), fields (a Calendar Fields Record), and overflow ("constrain" or "reject") and returns either a normal completion containing an ISO Date Record or a throw completion. It performs implementation-defined processing to convert fields, which represents a date or year and month or month and day in the built-in calendar identified by calendar, to a corresponding representative date in the ISO 8601 calendar, subject to processing 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 the correct range. It then returns an ISO Date Record with the corresponding ISO 8601 date.

Clamping an invalid date to the correct range when overflow is "constrain" is a behaviour specific to each built-in calendar, but all built-in 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.

Like RegulateISODate, the operation throws a RangeError exception if overflow is "reject" and the date described by fields does not exist. It also throws a RangeError exception if the date described by fields is outside the range allowed by ISODateWithinLimits.

12.2.41 CalendarMonthDayToISOReferenceDate ( calendar, fields, overflow )

The implementation-defined abstract operation CalendarMonthDayToISOReferenceDate takes arguments calendar (a String that is not "iso8601" for which IsBuiltinCalendar returns true), fields (a Calendar Fields Record), and overflow ("constrain" or "reject") and returns either a normal completion containing an ISO Date Record or a throw completion. 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 processing 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 the correct range as in CalendarDateToISO. It then returns a Record representing the reference ISO 8601 date.

The fields of the returned Record represent a reference date in the ISO 8601 calendar that, when converted to the built-in calendar identified by 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 also earlier than or equal to the ISO 8601 date December 31, 1972. If that calendar date never occurs on or before the ISO 8601 date December 31, 1972, then the reference date is the earliest ISO 8601 date corresponding to that calendar date. 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 was a part of calendar years 5730 and 5733 (respectively overlapping ISO 8601 February/March 1970 and February/March 1973), but did not occur between them.

Like RegulateISODate, the operation throws a RangeError exception if overflow is "reject" and the month and day described by fields does not exist. 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.

12.2.42 CalendarDateAddition ( calendar, date, duration, overflow )

The implementation-defined abstract operation CalendarDateAddition takes arguments calendar (a String that is not "iso8601" for which IsBuiltinCalendar returns true), date (an ISO Date Record), duration (a Date Duration Record), and overflow ("constrain" or "reject") and returns either a normal completion containing an ISO Date Record or a throw completion. It 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, or if the date resulting from the addition is outside the range allowed by ISODateTimeWithinLimits.

12.2.43 CalendarDateDifference ( calendar, one, two, largestUnit )

The implementation-defined abstract operation CalendarDateDifference takes arguments calendar (a String that is not "iso8601" for which IsBuiltinCalendar returns true), one (an ISO Date Record), two (an ISO Date Record), and largestUnit ("year", "month", "week", or "day") and returns a Date Duration Record. It performs implementation-defined processing to find the difference between the two dates one and two in the context of the calendar represented by calendar and returns the corresponding duration.

12.2.44 CalendarISOToDate ( calendar, isoDate )

The implementation-defined abstract operation CalendarISOToDate takes arguments calendar (a String that is not "iso8601" for which IsBuiltinCalendar returns true) and isoDate (an ISO Date Record) and returns a Calendar Date Record. It performs implementation-defined processing to find the 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.

12.2.45 CalendarExtraFields ( calendar, type )

The implementation-defined abstract operation CalendarExtraFields takes arguments calendar (a String that is not "iso8601" for which IsBuiltinCalendar returns true) and type (date, year-month, month-day, or a List of property keys) and returns a List of property keys. It characterizes calendar-specific fields that are relevant for values of the provided type in the built-in calendar identified by calendar (inferring the type when type is a List by interpreting its elements as field names). For example, « "era", "eraYear" » is returned when calendar is "gregory" or "japanese" and type is date or year-month or a List containing "year".

12.2.46 CalendarFieldKeysToIgnore ( calendar, keys )

The implementation-defined abstract operation CalendarFieldKeysToIgnore takes arguments calendar (a String that is not "iso8601" for which IsBuiltinCalendar returns true) and keys (a List of values from the Enumeration Key column of Table 19) and returns a List of values from the Enumeration Key column of Table 19. 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.

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 as in ISOFieldKeysToIgnore, a possible implementation might produce the following results when calendar is "gregory":

Table 20: Example results of CalendarFieldKeysToIgnore
keys Returned List
« era » « era, era-year, year »
« era-year » « era, era-year, year »
« year » « era, era-year, year »
« month » « month, month-code »
« month-code » « month, month-code »
« day » « day »
« year, month, day » « era, era-year, year, month, month-code, day »
Note
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.

12.2.47 CalendarResolveFields ( calendar, fields, type )

The implementation-defined abstract operation CalendarResolveFields takes arguments calendar (a String that is not "iso8601" for which IsBuiltinCalendar returns true), fields (a Calendar Fields Record), and type (date, year-month, or month-day) and returns either a normal completion containing unused or a throw completion. 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 CalendarDateToISO ( calendar, fields, overflow ) or CalendarMonthDayToISOReferenceDate ( calendar, fields, overflow ) by merging data that can be represented in multiple forms into standard properties and removing redundant properties (for example, merging "month" and "monthCode" into "month" and merging "era" and "eraYear" into "year").

The operation throws a TypeError exception if the fields of fields are internally inconsistent within the calendar or insufficient to identify a unique instance of type in the calendar. For example:

  • If type is date or month-day and day in the calendar has an interpretation analogous to ISO 8601 and fields.[[Day]] is unset.
  • If month and month-code in the calendar have interpretations analogous to ISO 8601 and either the corresponding values for both are 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 year cannot be determined from fields.
  • If type is date or year-month and 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:
    • 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]].
Note
When type is month-day and fields.[[Month]] is provided without fields.[[MonthCode]], 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]]), including those that always use exactly the same months as the ISO 8601 calendar (which receives special handling in this specification as a default calendar that is permanently stable for automated processing).

13 Abstract Operations

13.1 ISODateToEpochDays ( year, month, date )

The abstract operation ISODateToEpochDays takes arguments year (an integer), month (an integer), and date (an integer) and returns an integer. It calculates a number of days. It performs the following steps when called:

  1. Let resolvedYear be year + floor(month / 12).
  2. Let resolvedMonth be month modulo 12.
  3. Find a time t such that EpochTimeToEpochYear(t) = resolvedYear, EpochTimeToMonthInYear(t) = resolvedMonth, and EpochTimeToDate(t) = 1.
  4. Return EpochTimeToDayNumber(t) + date - 1.
Editor's Note
This operation corresponds to ECMA-262 operation MakeDay(year, month, date). It calculates the result in mathematical values instead of Number values. These two operations would be unified when https://github.com/tc39/ecma262/issues/1087 is fixed.

13.2 EpochDaysToEpochMs ( day, time )

The abstract operation EpochDaysToEpochMs takes arguments day (an integer) and time (an integer) and returns an integer. It calculates a number of milliseconds. It performs the following steps when called:

  1. Return day × (msPerDay) + time.
Editor's Note
This operation corresponds to ECMA-262 operation MakeDate(date, time). It calculates the result in mathematical values instead of Number values. These two operations would be unified when https://github.com/tc39/ecma262/issues/1087 is fixed.

13.3 Date Equations

A given time t belongs to day number

EpochTimeToDayNumber(t) = floor(t / (msPerDay))

Number of days in year are given by:

MathematicalDaysInYear(y)
= 365 if ((y) modulo 4) ≠ 0
= 366 if ((y) modulo 4) = 0 and ((y) modulo 100) ≠ 0
= 365 if ((y) modulo 100) = 0 and ((y) modulo 400) ≠ 0
= 366 if ((y) modulo 400) = 0

The day number of the first day of year y is given by:

EpochDayNumberForYear(y) = 365 × (y - 1970) + floor((y - 1969) / 4) - floor((y - 1901) / 100) + floor((y - 1601) / 400)

The time of the start of a year is:

EpochTimeForYear(y) = (msPerDay) × EpochDayNumberForYear(y)

Epoch year from time t is given by:

EpochTimeToEpochYear(t) = the largest integral Number y (closest to +∞) such that EpochTimeForYear(y) ≤ t

The following function returns 1 for a time within leap year otherwise it returns 0:

MathematicalInLeapYear(t)

The month number for a time t is given by:

EpochTimeToMonthInYear(t)
= 0 if 0 ≤ EpochTimeToDayInYear(t) < 31
= 1 if 31 ≤ EpochTimeToDayInYear(t) < 59 + MathematicalInLeapYear(t)

where

A month value of 0 specifies January; 1 specifies February; 2 specifies March; 3 specifies April; 4 specifies May; 5 specifies June; 6 specifies July; 7 specifies August; 8 specifies September; 9 specifies October; 10 specifies November; and 11 specifies December. Note that EpochTimeToMonthInYear(0) = 0, corresponding to Thursday, 1 January 1970.

The date number for a time t is given by:

EpochTimeToDate(t)

The weekday for a particular time t is defined as:

EpochTimeToWeekDay(t) =(EpochTimeToDayNumber(t) + 4) modulo 7

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.

Editor's Note
These equations correspond to ECMA-262 equations defined in Days in Year, Month from Time, Date from Time, Week Day respectively. These calculate the result in mathematical values instead of Number values. These equations would be unified when https://github.com/tc39/ecma262/issues/1087 is fixed.
Editor's Note
Note that the operation EpochTimeToMonthInYear(t) uses 0-based months unlike rest of Temporal since it's intended to be unified with MonthFromTime(t) when the above mentioned issue is fixed.

13.4 Units

Time is reckoned using multiple units. These units are listed in Table 21.

Table 21: Temporal units by descending magnitude
Singular Plural Category Length in nanoseconds
"year" "years" date calendar-dependent
"month" "months" date calendar-dependent
"week" "weeks" date calendar-dependent
"day" "days" date nsPerDay
"hour" "hours" time 3.6 × 1012
"minute" "minutes" time 6 × 1010
"second" "seconds" time 109
"millisecond" "milliseconds" time 106
"microsecond" "microseconds" time 103
"nanosecond" "nanoseconds" time 1
Note
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.

13.5 GetOptionsObject ( options )

The abstract operation GetOptionsObject takes argument options (an ECMAScript language value) and returns either a normal completion containing an Object or a throw completion. It returns an Object suitable for use with GetOption, either options itself or a default empty Object. It throws a TypeError if options is not undefined and not an Object. It performs the following steps when called:

  1. If options is undefined, then
    1. Return OrdinaryObjectCreate(null).
  2. If options is an Object, then
    1. Return options.
  3. Throw a TypeError exception.

13.6 GetOption ( options, property, type, values, default )

The abstract operation GetOption takes arguments options (an Object), property (a property key), type (boolean or string), values (empty or a List of ECMAScript language values), and default (required or an ECMAScript language value) and returns either a normal completion containing an ECMAScript language value or a throw completion. It extracts the value of the specified property of options, converts it to the required type, checks whether it is allowed by values if values is not empty, and substitutes default if the value is undefined. It performs the following steps when called:

  1. Let value be ? Get(options, property).
  2. If value is undefined, then
    1. If default is required, throw a RangeError exception.
    2. Return default.
  3. If type is boolean, then
    1. Set value to ToBoolean(value).
  4. Else,
    1. Assert: type is string.
    2. Set value to ? ToString(value).
  5. If values is not empty and values does not contain value, throw a RangeError exception.
  6. Return value.

13.7 GetTemporalOverflowOption ( options )

The abstract operation GetTemporalOverflowOption takes argument options (an Object or undefined) and returns either a normal completion containing either "constrain" or "reject", or a throw completion. It fetches and validates the "overflow" property of options, returning a default if absent. It performs the following steps when called:

  1. If options is undefined, return "constrain".
  2. Return ? GetOption(options, "overflow", string, « "constrain", "reject" », "constrain").

13.8 GetTemporalDisambiguationOption ( options )

The abstract operation GetTemporalDisambiguationOption takes argument options (an Object or undefined) and returns either a normal completion containing either "compatible", "earlier", "later", or "reject", or a throw completion. It fetches and validates the "disambiguation" property of options, returning a default if absent. It performs the following steps when called:

  1. If options is undefined, return "compatible".
  2. Return ? GetOption(options, "disambiguation", string, « "compatible", "earlier", "later", "reject" », "compatible").

13.9 GetRoundingModeOption ( options, fallback )

The abstract operation GetRoundingModeOption takes arguments options (an Object) and fallback (a String from the "Identifier" column of Table 22) and returns either a normal completion containing a String from the "Identifier" column of Table 22, or a throw completion. It fetches and validates the "roundingMode" property from options, returning fallback as a default if absent. It performs the following steps when called:

  1. Let roundingModes be the List of Strings from the "Identifier" column of Table 22.
  2. Return ? GetOption(options, "roundingMode", string, roundingModes, fallback).
Table 22: Rounding modes
Identifier Description Examples: Round to 0 fraction digits
-1.5 0.4 0.5 0.6 1.5
"ceil" Toward positive infinity ⬆️ [-1] ⬆️ [1] ⬆️ [1] ⬆️ [1] ⬆️ [2]
"floor" Toward negative infinity ⬇️ [-2] ⬇️ [0] ⬇️ [0] ⬇️ [0] ⬇️ [1]
"expand" Away from zero ⬇️ [-2] ⬆️ [1] ⬆️ [1] ⬆️ [1] ⬆️ [2]
"trunc" Toward zero ⬆️ [-1] ⬇️ [0] ⬇️ [0] ⬇️ [0] ⬇️ [1]
"halfCeil" Ties toward positive infinity ⬆️ [-1] ⬇️ [0] ⬆️ [1] ⬆️ [1] ⬆️ [2]
"halfFloor" Ties toward negative infinity ⬇️ [-2] ⬇️ [0] ⬇️ [0] ⬆️ [1] ⬇️ [1]
"halfExpand" Ties away from zero ⬇️ [-2] ⬇️ [0] ⬆️ [1] ⬆️ [1] ⬆️ [2]
"halfTrunc" Ties toward zero ⬆️ [-1] ⬇️ [0] ⬇️ [0] ⬆️ [1] ⬇️ [1]
"halfEven" Ties toward an even rounding increment multiple ⬇️ [-2] ⬇️ [0] ⬇️ [0] ⬆️ [1] ⬆️ [2]
Note
The examples are illustrative of the unique behaviour of each option. ⬆️ means "resolves toward positive infinity"; ⬇️ means "resolves toward negative infinity".

13.10 NegateRoundingMode ( roundingMode )

The abstract operation NegateRoundingMode takes argument roundingMode (a String from the "Identifier" column of Table 22) and returns a String from the "Identifier" column of Table 22. It returns the correct rounding mode to use when rounding the negative of a value that was originally given with roundingMode It performs the following steps when called:

  1. If roundingMode is "ceil", return "floor".
  2. If roundingMode is "floor", return "ceil".
  3. If roundingMode is "halfCeil", return "halfFloor".
  4. If roundingMode is "halfFloor", return "halfCeil".
  5. Return roundingMode.

13.11 GetTemporalOffsetOption ( options, fallback )

The abstract operation GetTemporalOffsetOption takes arguments options (an Object or undefined) and fallback ("prefer", "use", "ignore", or "reject") and returns either a normal completion containing either "prefer", "use", "ignore", or "reject", or a throw completion. It fetches and validates the "offset" property of options, returning fallback as a default if absent. It performs the following steps when called:

  1. If options is undefined, return fallback.
  2. Return ? GetOption(options, "offset", string, « "prefer", "use", "ignore", "reject" », fallback).

13.12 GetTemporalShowCalendarNameOption ( options )

The abstract operation GetTemporalShowCalendarNameOption takes argument options (an Object) and returns either a normal completion containing either "auto", "always", "never", or "critical", or a throw completion. It fetches and validates the "calendarName" property from options, returning a default if absent.

Note
This property is used in toString methods in Temporal to control whether a calendar annotation should be output.

It performs the following steps when called:

  1. Return ? GetOption(options, "calendarName", string, « "auto", "always", "never", "critical" », "auto").

13.13 GetTemporalShowTimeZoneNameOption ( options )

The abstract operation GetTemporalShowTimeZoneNameOption takes argument options (an Object) and returns either a normal completion containing either "auto", "never", or "critical", or a throw completion. It fetches and validates the "timeZoneName" property from options, returning a default if absent.

Note
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().

It performs the following steps when called:

  1. Return ? GetOption(options, "timeZoneName", string, « "auto", "never", "critical" », "auto").

13.14 GetTemporalShowOffsetOption ( options )

The abstract operation GetTemporalShowOffsetOption takes argument options (an Object) and returns either a normal completion containing either "auto" or "never", or a throw completion. It fetches and validates the "offset" property from options, returning a default if absent.

Note
This property is used in Temporal.ZonedDateTime.prototype.toString(). It is different from the offset property passed to Temporal.ZonedDateTime.from().

It performs the following steps when called:

  1. Return ? GetOption(options, "offset", string, « "auto", "never" », "auto").

13.15 GetDirectionOption ( options )

The abstract operation GetDirectionOption takes argument options (an Object) and returns either a normal completion containing either "next" or "previous", or a throw completion. It fetches and validates the "direction" property from options, throwing if absent. It performs the following steps when called:

  1. Return ? GetOption(options, "direction", string, « "next", "previous" », required).

13.16 GetRoundingIncrementOption ( options )

The abstract operation GetRoundingIncrementOption takes argument options (an Object) and returns either a normal completion containing a positive integer in the inclusive interval from 1 to 109, or a throw completion. It fetches and validates the "roundingIncrement" property from options, returning a default if absent. It performs the following steps when called:

  1. Let value be ? Get(options, "roundingIncrement").
  2. If value is undefined, return 1𝔽.
  3. Let increment be ? ToNumber(value).
  4. If increment is not finite, throw a RangeError exception.
  5. Let integerIncrement be truncate((increment)).
  6. If integerIncrement < 1 or integerIncrement > 109, throw a RangeError exception.
  7. Return integerIncrement.

13.17 ValidateTemporalRoundingIncrement ( increment, dividend, inclusive )

The abstract operation ValidateTemporalRoundingIncrement takes arguments increment (a positive integer), dividend (a positive integer), and inclusive (a Boolean) and returns either a normal completion containing unused or a throw completion. It verifies that increment evenly divides dividend, otherwise throwing a RangeError. dividend must be divided into more than one part unless inclusive is true. It performs the following steps when called:

  1. If inclusive is true, then
    1. Let maximum be dividend.
  2. Else,
    1. Assert: dividend > 1.
    2. Let maximum be dividend - 1.
  3. If increment > maximum, throw a RangeError exception.
  4. If dividend modulo increment ≠ 0, then
    1. Throw a RangeError exception.
  5. Return unused.

13.18 GetTemporalFractionalSecondDigitsOption ( options )

The abstract operation GetTemporalFractionalSecondDigitsOption takes argument options (an Object) and returns either a normal completion containing either "auto" or an integer in the inclusive interval from 0 to 9, or a throw completion. It fetches and validates the "fractionalSecondDigits" property from options, returning a default if absent. It performs the following steps when called:

  1. Let digitsValue be ? Get(options, "fractionalSecondDigits").
  2. If digitsValue is undefined, return "auto".
  3. If digitsValue is not a Number, then
    1. If ? ToString(digitsValue) is not "auto", throw a RangeError exception.
    2. Return "auto".
  4. If digitsValue is NaN, +∞𝔽, or -∞𝔽, throw a RangeError exception.
  5. Let digitCount be floor((digitsValue)).
  6. If digitCount < 0 or digitCount > 9, throw a RangeError exception.
  7. Return digitCount.

13.19 ToSecondsStringPrecisionRecord ( smallestUnit, fractionalDigitCount )

The abstract operation ToSecondsStringPrecisionRecord takes arguments smallestUnit ("minute", "second", "millisecond", "microsecond", "nanosecond", or undefined) and fractionalDigitCount ("auto" or an integer in the inclusive interval from 0 to 9) and returns a Record with fields [[Precision]] ("minute", "auto", or an integer in the inclusive interval from 0 to 9), [[Unit]] ("minute", "second", "millisecond", "microsecond", or "nanosecond"), and [[Increment]] (1, 10, or 100). The returned Record represents details for serializing minutes and seconds to a string subject to the specified smallestUnit or (when smallestUnit is undefined) fractionalDigitCount digits after the decimal point in the seconds. Its [[Precision]] field is either that count of digits, the string "auto" signifying that there should be no insignificant trailing zeroes, or the string "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. It performs the following steps when called:

  1. If smallestUnit is "minute", then
    1. Return the Record { [[Precision]]: "minute", [[Unit]]: "minute", [[Increment]]: 1  }.
  2. If smallestUnit is "second", then
    1. Return the Record { [[Precision]]: 0, [[Unit]]: "second", [[Increment]]: 1  }.
  3. If smallestUnit is "millisecond", then
    1. Return the Record { [[Precision]]: 3, [[Unit]]: "millisecond", [[Increment]]: 1  }.
  4. If smallestUnit is "microsecond", then
    1. Return the Record { [[Precision]]: 6, [[Unit]]: "microsecond", [[Increment]]: 1  }.
  5. If smallestUnit is "nanosecond", then
    1. Return the Record { [[Precision]]: 9, [[Unit]]: "nanosecond", [[Increment]]: 1  }.
  6. Assert: smallestUnit is undefined.
  7. If fractionalDigitCount is "auto", then
    1. Return the Record { [[Precision]]: "auto", [[Unit]]: "nanosecond", [[Increment]]: 1  }.
  8. If fractionalDigitCount = 0, then
    1. Return the Record { [[Precision]]: 0, [[Unit]]: "second", [[Increment]]: 1  }.
  9. If fractionalDigitCount is in the inclusive interval from 1 to 3, then
    1. Return the Record { [[Precision]]: fractionalDigitCount, [[Unit]]: "millisecond", [[Increment]]: 103 - fractionalDigitCount  }.
  10. If fractionalDigitCount is in the inclusive interval from 4 to 6, then
    1. Return the Record { [[Precision]]: fractionalDigitCount, [[Unit]]: "microsecond", [[Increment]]: 106 - fractionalDigitCount  }.
  11. Assert: fractionalDigitCount is in the inclusive interval from 7 to 9.
  12. Return the Record { [[Precision]]: fractionalDigitCount, [[Unit]]: "nanosecond", [[Increment]]: 109 - fractionalDigitCount  }.

13.20 GetTemporalUnitValuedOption ( options, key, unitGroup, default [ , extraValues ] )

The abstract operation GetTemporalUnitValuedOption takes arguments options (an Object), key (a property key), unitGroup (date, time, or datetime), and default (required or an ECMAScript language value) and optional argument extraValues (a List of ECMAScript language values) and returns either a normal completion containing an ECMAScript language value or a throw completion. It attempts to read from the specified property of options a Temporal unit that is covered by the union of unitGroup and extraValues, substituting default if the property value is undefined.

Both singular and plural unit names are accepted, but only the singular form is used internally.

  1. Let singularNames be a new empty List.
  2. For each row of Table 21, except the header row, in table order, do
    1. Let unit be the value in the "Singular" column of the row.
    2. If the "Category" column of the row is date and unitGroup is date or datetime, append unit to singularNames.
    3. Else if the "Category" column of the row is time and unitGroup is time or datetime, append unit to singularNames.
  3. If extraValues is present, then
    1. Set singularNames to the list-concatenation of singularNames and extraValues.
  4. If default is required, then
    1. Let defaultValue be undefined.
  5. Else,
    1. Let defaultValue be default.
    2. If defaultValue is not undefined and singularNames does not contain defaultValue, then
      1. Append defaultValue to singularNames.
  6. Let allowedValues be a copy of singularNames.
  7. For each element singularName of singularNames, do
    1. If singularName is listed in the "Singular" column of Table 21, then
      1. Let pluralName be the value in the "Plural" column of the corresponding row.
      2. Append pluralName to allowedValues.
  8. NOTE: For each singular Temporal unit name that is contained within allowedValues, the corresponding plural name is also contained within it.
  9. Let value be ? GetOption(options, key, string, allowedValues, defaultValue).
  10. If value is undefined and default is required, throw a RangeError exception.
  11. If value is listed in the "Plural" column of Table 21, then
    1. Set value to the value in the "Singular" column of the corresponding row.
  12. Return value.

13.21 GetTemporalRelativeToOption ( options )

The abstract operation GetTemporalRelativeToOption takes argument options (an Object) and returns 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. 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. It performs the following steps when called:

  1. Let value be ? Get(options, "relativeTo").
  2. If value is undefined, return the Record { [[PlainRelativeTo]]: undefined, [[ZonedRelativeTo]]: undefined }.
  3. Let offsetBehaviour be option.
  4. Let matchBehaviour be match-exactly.
  5. If value is an Object, then
    1. If value has an [[InitializedTemporalZonedDateTime]] internal slot, then
      1. Return the Record { [[PlainRelativeTo]]: undefined, [[ZonedRelativeTo]]: value }.
    2. If value has an [[InitializedTemporalDate]] internal slot, then
      1. Return the Record { [[PlainRelativeTo]]: value, [[ZonedRelativeTo]]: undefined }.
    3. If value has an [[InitializedTemporalDateTime]] internal slot, then
      1. Let plainDate be ! CreateTemporalDate(value.[[ISOYear]], value.[[ISOMonth]], value.[[ISODay]], value.[[Calendar]]).
      2. Return the Record { [[PlainRelativeTo]]: plainDate, [[ZonedRelativeTo]]: undefined }.
    4. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(value).
    5. Let fields be ? PrepareCalendarFields(calendar, value, « day, month, month-code, year », « hour, microsecond, millisecond, minute, nanosecond, offset, second, time-zone », «»).
    6. Let result be ? InterpretTemporalDateTimeFields(calendar, fields, "constrain").
    7. Let offsetString be fields.[[Offset]].
    8. Let timeZone be fields.[[TimeZone]].
    9. If timeZone is not unset, then
      1. Set timeZone to ? ToTemporalTimeZoneIdentifier(timeZone).
    10. If offsetString is unset, then
      1. Set offsetBehaviour to wall.
  6. Else,
    1. If value is not a String, throw a TypeError exception.
    2. Let result be ? ParseTemporalRelativeToString(value).
    3. Let offsetString be result.[[TimeZone]].[[OffsetString]].
    4. Let annotation be result.[[TimeZone]].[[TimeZoneAnnotation]].
    5. If annotation is empty, then
      1. Let timeZone be undefined.
    6. Else,
      1. Let timeZone be ? ToTemporalTimeZoneIdentifier(annotation).
      2. If result.[[TimeZone]].[[Z]] is true, then
        1. Set offsetBehaviour to exact.
      3. Else if offsetString is empty, then
        1. Set offsetBehaviour to wall.
      4. Set matchBehaviour to match-minutes.
    7. Let calendar be result.[[Calendar]].
    8. If calendar is empty, set calendar to "iso8601".
    9. If IsBuiltinCalendar(calendar) is false, throw a RangeError exception.
    10. Set calendar to CanonicalizeUValue("ca", calendar).
  7. If timeZone is undefined, then
    1. Let plainDate be ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar).
    2. Return the Record { [[PlainRelativeTo]]: plainDate, [[ZonedRelativeTo]]: undefined }.
  8. If offsetBehaviour is option, then
    1. Let offsetNs be ? ParseDateTimeUTCOffset(offsetString).
  9. Else,
    1. Let offsetNs be 0.
  10. Let epochNanoseconds be ? InterpretISODateTimeOffset(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], offsetBehaviour, offsetNs, timeZone, "compatible", "reject", matchBehaviour).
  11. Let zonedRelativeTo be ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).
  12. Return the Record { [[PlainRelativeTo]]: undefined, [[ZonedRelativeTo]]: zonedRelativeTo }.

13.22 LargerOfTwoTemporalUnits ( u1, u2 )

The abstract operation LargerOfTwoTemporalUnits takes arguments u1 (a String from the "Singular" column of Table 21) and u2 (a String from the "Singular" column of Table 21) and returns a String from the "Singular" column of Table 21. Given two strings representing Temporal units, it returns the string representing the larger of the two units. It performs the following steps when called:

  1. For each row of Table 21, except the header row, in table order, do
    1. Let unit be the value in the "Singular" column of the row.
    2. If SameValue(u1, unit) is true, return unit.
    3. If SameValue(u2, unit) is true, return unit.

13.23 IsCalendarUnit ( unit )

The abstract operation IsCalendarUnit takes argument unit (a String from the "Singular" column of Table 21) and returns a Boolean. It returns whether unit is a Temporal unit for which rounding would require calendar calculations. It performs the following steps when called:

  1. If unit is "year", return true.
  2. If unit is "month", return true.
  3. If unit is "week", return true.
  4. Return false.

13.24 MaximumTemporalDurationRoundingIncrement ( unit )

The abstract operation MaximumTemporalDurationRoundingIncrement takes argument unit (a String from the "Singular" column of Table 21) and returns 24, 60, 1000, or undefined. Given a string representing a Temporal.Duration unit, it returns the maximum rounding increment for that unit, or undefined if there is no maximum. It performs the following steps when called:

  1. If unit is "year", "month", "week", or "day", then
    1. Return undefined.
  2. If unit is "hour", then
    1. Return 24.
  3. If unit is "minute" or "second", then
    1. Return 60.
  4. Assert: unit is "millisecond", "microsecond", or "nanosecond".
  5. Return 1000.

13.25 IsPartialTemporalObject ( object )

The abstract operation IsPartialTemporalObject takes argument object (an ECMAScript language value) and returns either a normal completion containing a Boolean or a throw completion. 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. It performs the following steps when called:

  1. If value is not an Object, return false.
  2. If value has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, return false.
  3. Let calendarProperty be ? Get(value, "calendar").
  4. If calendarProperty is not undefined, return false.
  5. Let timeZoneProperty be ? Get(value, "timeZone").
  6. If timeZoneProperty is not undefined, return false.
  7. Return true.

13.26 FormatFractionalSeconds ( subSecondNanoseconds, precision )

The abstract operation FormatFractionalSeconds takes arguments subSecondNanoseconds (an integer in the inclusive interval from 0 to 999999999) and precision (either an integer in the inclusive interval from 0 to 9 or "auto") and returns a String. If precision is zero, or if precision is "auto" and subSecondNanoseconds is zero, 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. It performs the following steps when called:

  1. If precision is "auto", then
    1. If subSecondNanoseconds = 0, return the empty String.
    2. Let fractionString be ToZeroPaddedDecimalString(subSecondNanoseconds, 9).
    3. Set fractionString to the longest prefix of fractionString ending with a code unit other than 0x0030 (DIGIT ZERO).
  2. Else,
    1. If precision = 0, return the empty String.
    2. Let fractionString be ToZeroPaddedDecimalString(subSecondNanoseconds, 9).
    3. Set fractionString to the substring of fractionString from 0 to precision.
  3. Return the string-concatenation of the code unit 0x002E (FULL STOP) and fractionString.

13.27 FormatTimeString ( hour, minute, second, subSecondNanoseconds, precision [ , style ] )

The abstract operation FormatTimeString takes arguments 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), and precision (an integer in the inclusive interval from 0 to 9, "minute", or "auto") and optional argument style (separated or unseparated) and returns a String. 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 is zero, or if subSecondNanoseconds is zero 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. It performs the following steps when called:

  1. If style is present and style is unseparated, let separator be the empty String; otherwise, let separator be ":".
  2. Let hh be ToZeroPaddedDecimalString(hour, 2).
  3. Let mm be ToZeroPaddedDecimalString(minute, 2).
  4. If precision is "minute", return the string-concatenation of hh, separator, and mm.
  5. Let ss be ToZeroPaddedDecimalString(second, 2).
  6. Let subSecondsPart be FormatFractionalSeconds(subSecondNanoseconds, precision).
  7. Return the string-concatenation of hh, separator, mm, separator, ss, and subSecondsPart.

13.28 GetUnsignedRoundingMode ( roundingMode, sign )

The abstract operation GetUnsignedRoundingMode takes arguments roundingMode (a String from the "Identifier" column of Table 22) and sign (negative or positive) and returns a specification type from the "Unsigned Rounding Mode" column of Table 23. It returns the rounding mode that should be applied to the absolute value of a number to produce the same result as if roundingMode, one of the String values in the "Identifier" column of Table 22, were applied to the signed value of the number (negative if sign is negative, or positive otherwise). It performs the following steps when called:

  1. Return the specification type in the "Unsigned Rounding Mode" column of Table 23 for the row where the value in the "Identifier" column is roundingMode and the value in the "Sign" column is sign.
Table 23: Conversion from rounding mode to unsigned rounding mode
Identifier Sign Unsigned Rounding Mode
"ceil" positive infinity
negative zero
"floor" positive zero
negative infinity
"expand" positive infinity
negative infinity
"trunc" positive zero
negative zero
"halfCeil" positive half-infinity
negative half-zero
"halfFloor" positive half-zero
negative half-infinity
"halfExpand" positive half-infinity
negative half-infinity
"halfTrunc" positive half-zero
negative half-zero
"halfEven" positive half-even
negative half-even

13.29 ApplyUnsignedRoundingMode ( x, r1, r2, unsignedRoundingMode )

The abstract operation ApplyUnsignedRoundingMode takes arguments x (a mathematical value), r1 (a mathematical value), r2 (a mathematical value), and unsignedRoundingMode (a specification type from the "Unsigned Rounding Mode" column of Table 23, or undefined) and returns a mathematical value. It considers x, bracketed below by r1 and above by r2, and returns either r1 or r2 according to unsignedRoundingMode. It performs the following steps when called:

  1. If x = r1, return r1.
  2. Assert: r1 < x < r2.
  3. Assert: unsignedRoundingMode is not undefined.
  4. If unsignedRoundingMode is zero, return r1.
  5. If unsignedRoundingMode is infinity, return r2.
  6. Let d1 be xr1.
  7. Let d2 be r2x.
  8. If d1 < d2, return r1.
  9. If d2 < d1, return r2.
  10. Assert: d1 is equal to d2.
  11. If unsignedRoundingMode is half-zero, return r1.
  12. If unsignedRoundingMode is half-infinity, return r2.
  13. Assert: unsignedRoundingMode is half-even.
  14. Let cardinality be (r1 / (r2r1)) modulo 2.
  15. If cardinality = 0, return r1.
  16. Return r2.

13.30 RoundNumberToIncrement ( x, increment, roundingMode )

The abstract operation RoundNumberToIncrement takes arguments x (a mathematical value), increment (a positive integer), and roundingMode (a String from the "Identifier" column of Table 22) and returns an integer. It rounds x to the nearest multiple of increment, up or down according to roundingMode. It performs the following steps when called:

  1. Let quotient be x / increment.
  2. If quotient < 0, then
    1. Let isNegative be negative.
    2. Set quotient to -quotient.
  3. Else,
    1. Let isNegative be positive.
  4. Let unsignedRoundingMode be GetUnsignedRoundingMode(roundingMode, isNegative).
  5. Let r1 be the largest integer such that r1quotient.
  6. Let r2 be the smallest integer such that r2 > quotient.
  7. Let rounded be ApplyUnsignedRoundingMode(quotient, r1, r2, unsignedRoundingMode).
  8. If isNegative is negative, set rounded to -rounded.
  9. Return rounded × increment.

13.31 RoundNumberToIncrementAsIfPositive ( x, increment, roundingMode )

The abstract operation RoundNumberToIncrementAsIfPositive takes arguments x (a mathematical value), increment (a positive integer), and roundingMode (a String from the "Identifier" column of Table 22) and returns an integer. 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. It performs the following steps when called:

  1. Let quotient be x / increment.
  2. Let unsignedRoundingMode be GetUnsignedRoundingMode(roundingMode, positive).
  3. Let r1 be the largest integer such that r1quotient.
  4. Let r2 be the smallest integer such that r2 > quotient.
  5. Let rounded be ApplyUnsignedRoundingMode(quotient, r1, r2, unsignedRoundingMode).
  6. Return rounded × increment.

13.32 ISO 8601 grammar

Several operations in this section are intended to parse ISO 8601 strings representing a date, a time, a duration, or a combined date and time. For the purposes of these operations, a valid ISO 8601 string is defined as a string that can be generated by one of the goal elements of the following grammar.

This grammar is adapted from the ABNF grammar of ISO 8601 that is given in appendix A of RFC 3339, augmented with the grammar of annotations in section 3.1 of Date and Time on the Internet: Timestamps with additional information

The grammar deviates from the standard given in ISO 8601 in the following ways:

  • Only the calendar date format is supported, not the weekdate or ordinal date format.
  • Two-digit years are disallowed.
  • Expanded Years of 6 digits are allowed.
  • 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.
  • Any number of conforming 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.
  • 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 the standard as requiring mutual agreement between communicating parties, is disallowed.
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 DateMonth ::: 0 NonZeroDigit 10 11 12 DateDay ::: 0 NonZeroDigit 1 DecimalDigit 2 DecimalDigit 30 31 DateSpecYearMonth ::: DateYear DateSeparator[+Extended] DateMonth DateYear DateSeparator[~Extended] DateMonth DateSpecMonthDay ::: --opt DateMonth DateSeparator[+Extended] DateDay --opt DateMonth DateSeparator[~Extended] DateDay DateSpec[Extended] ::: DateYear DateSeparator[?Extended] DateMonth DateSeparator[?Extended] DateDay Date ::: DateSpec[+Extended] DateSpec[~Extended] TimeSecond ::: MinuteSecond 60 NormalizedUTCOffset ::: ASCIISign Hour TimeSeparator[+Extended] MinuteSecond UTCOffset[SubMinutePrecision] ::: ASCIISign Hour ASCIISign Hour TimeSeparator[+Extended] MinuteSecond ASCIISign Hour TimeSeparator[~Extended] MinuteSecond [+SubMinutePrecision] ASCIISign Hour TimeSeparator[+Extended] MinuteSecond TimeSeparator[+Extended] MinuteSecond TemporalDecimalFractionopt [+SubMinutePrecision] ASCIISign Hour TimeSeparator[~Extended] MinuteSecond TimeSeparator[~Extended] MinuteSecond TemporalDecimalFractionopt DateTimeUTCOffset[Z] ::: [+Z] UTCDesignator UTCOffset[+SubMinutePrecision] TZLeadingChar ::: Alpha . _ TZChar ::: TZLeadingChar DecimalDigit - + TimeZoneIANANameComponent ::: TZLeadingChar TimeZoneIANANameComponent TZChar TimeZoneIANAName ::: TimeZoneIANANameComponent TimeZoneIANAName / TimeZoneIANANameComponent TimeZoneIdentifier ::: UTCOffset[~SubMinutePrecision] TimeZoneIANAName TimeZoneAnnotation ::: [ AnnotationCriticalFlagopt TimeZoneIdentifier ] AKeyLeadingChar ::: LowercaseAlpha _ AKeyChar ::: AKeyLeadingChar DecimalDigit - AnnotationKey ::: AKeyLeadingChar AnnotationKey AKeyChar AnnotationValueComponent ::: Alpha AnnotationValueComponentopt DecimalDigit AnnotationValueComponentopt AnnotationValue ::: AnnotationValueComponent AnnotationValueComponent - AnnotationValue Annotation ::: [ AnnotationCriticalFlagopt AnnotationKey = AnnotationValue ] Annotations ::: Annotation Annotationsopt TimeSpec[Extended] ::: Hour Hour TimeSeparator[?Extended] MinuteSecond Hour TimeSeparator[?Extended] MinuteSecond TimeSeparator[?Extended] TimeSecond TemporalDecimalFractionopt Time ::: TimeSpec[+Extended] TimeSpec[~Extended] DateTime[Z, TimeRequired] ::: [~TimeRequired] Date Date DateTimeSeparator Time DateTimeUTCOffset[?Z]opt AnnotatedTime ::: TimeDesignator Time DateTimeUTCOffset[~Z]opt TimeZoneAnnotationopt Annotationsopt Time DateTimeUTCOffset[~Z]opt TimeZoneAnnotationopt Annotationsopt AnnotatedDateTime[Zoned, TimeRequired] ::: [~Zoned] DateTime[~Z, ?TimeRequired] TimeZoneAnnotationopt Annotationsopt [+Zoned] DateTime[+Z, ?TimeRequired] TimeZoneAnnotation Annotationsopt AnnotatedYearMonth ::: DateSpecYearMonth TimeZoneAnnotationopt Annotationsopt AnnotatedMonthDay ::: DateSpecMonthDay TimeZoneAnnotationopt Annotationsopt DurationSecondsPart ::: DecimalDigits[~Sep] TemporalDecimalFractionopt SecondsDesignator DurationMinutesPart ::: DecimalDigits[~Sep] TemporalDecimalFraction MinutesDesignator DecimalDigits[~Sep] MinutesDesignator DurationSecondsPartopt DurationHoursPart ::: DecimalDigits[~Sep] TemporalDecimalFraction HoursDesignator DecimalDigits[~Sep] HoursDesignator DurationMinutesPart DecimalDigits[~Sep] HoursDesignator DurationSecondsPartopt DurationTime ::: TimeDesignator DurationHoursPart TimeDesignator DurationMinutesPart TimeDesignator DurationSecondsPart DurationDaysPart ::: DecimalDigits[~Sep] DaysDesignator DurationWeeksPart ::: DecimalDigits[~Sep] WeeksDesignator DurationDaysPartopt DurationMonthsPart ::: DecimalDigits[~Sep] MonthsDesignator DurationWeeksPart DecimalDigits[~Sep] MonthsDesignator DurationDaysPartopt DurationYearsPart ::: DecimalDigits[~Sep] YearsDesignator DurationMonthsPart DecimalDigits[~Sep] YearsDesignator DurationWeeksPart DecimalDigits[~Sep] YearsDesignator DurationDaysPartopt DurationDate ::: DurationYearsPart DurationTimeopt DurationMonthsPart DurationTimeopt DurationWeeksPart DurationTimeopt DurationDaysPart DurationTimeopt Duration ::: ASCIISignopt DurationDesignator DurationDate ASCIISignopt DurationDesignator DurationTime TemporalInstantString ::: Date DateTimeSeparator Time DateTimeUTCOffset[+Z] TimeZoneAnnotationopt Annotationsopt TemporalDateTimeString[Zoned] ::: AnnotatedDateTime[?Zoned, ~TimeRequired] TemporalDurationString ::: Duration TemporalMonthDayString ::: AnnotatedMonthDay AnnotatedDateTime[~Zoned, ~TimeRequired] TemporalTimeString ::: AnnotatedTime AnnotatedDateTime[~Zoned, +TimeRequired] TemporalYearMonthString ::: AnnotatedYearMonth AnnotatedDateTime[~Zoned, ~TimeRequired]

13.32.1 Static Semantics: IsValidMonthDay

The syntax-directed operation IsValidMonthDay takes no arguments and returns a Boolean. It is defined piecewise over the following productions:

DateSpec[Extended] ::: DateYear DateSeparator[?Extended] DateMonth DateSeparator[?Extended] DateDay DateSpecMonthDay ::: --opt DateMonth DateSeparator[+Extended] DateDay --opt DateMonth DateSeparator[~Extended] DateDay
  1. If DateDay is "31" and DateMonth is "02", "04", "06", "09", "11", return false.
  2. If DateMonth is "02" and DateDay is "30", return false.
  3. Return true.

13.32.2 Static Semantics: IsValidDate

The syntax-directed operation IsValidDate takes no arguments and returns a Boolean. It is defined piecewise over the following productions:

DateSpec[Extended] ::: DateYear DateSeparator[?Extended] DateMonth DateSeparator[?Extended] DateDay
  1. If IsValidMonthDay of DateSpec is false, return false.
  2. Let year be (StringToNumber(CodePointsToString(DateYear))).
  3. If DateMonth is "02" and DateDay is "29" and MathematicalInLeapYear(EpochTimeForYear(year)) = 0, return false.
  4. Return true.

13.32.3 Static Semantics: Early Errors

AnnotatedTime ::: Time DateTimeUTCOffset[~Z]opt TimeZoneAnnotationopt Annotationsopt DateSpec[Extended] ::: DateYear DateSeparator[?Extended] DateMonth DateSeparator[?Extended] DateDay DateSpecMonthDay ::: --opt DateMonth DateSeparator[+Extended] DateDay --opt DateMonth DateSeparator[~Extended] DateDay DateYear ::: ASCIISign DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit DecimalDigit
  • It is a Syntax Error if DateYear is "-000000".

13.33 ISO String Time Zone Parse Records

A ISO String 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 string.

ISO String Time Zone Parse Records have the fields listed in Table 24.

Table 24: ISO String Time Zone Parse Record Fields
Field Name Value Meaning
[[Z]] a Boolean Whether the ISO 8601 string contained the Z UTC designator.
[[OffsetString]] a String or empty The UTC offset from the ISO 8601 string, or empty if none was present.
[[TimeZoneAnnotation]] a String or empty The time zone annotation from the ISO 8601 string, or empty if none was present.

13.34 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 string.

ISO Date-Time Parse Records have all the fields of ISO Date-Time Records, in addition to those listed in Table 25.

Table 25: ISO Date-Time Parse Record Fields
Field Name Value Meaning
[[TimeZone]] an ISO String Time Zone Parse Record A representation of how the time zone was expressed in the ISO 8601 string.
[[Calendar]] a String or empty The calendar type from the ISO 8601 string, or empty if none was present.

13.35 ParseISODateTime ( isoString )

The abstract operation ParseISODateTime takes argument isoString (a String) and returns either a normal completion containing an ISO Date-Time Parse Record or a throw completion. It parses the argument as an ISO 8601 string and returns a Record representing each date and time component as a distinct field. It performs the following steps when called:

  1. Let parseResult be empty.
  2. Let calendar be empty.
  3. For each nonterminal goal of « TemporalDateTimeString, TemporalInstantString, TemporalTimeString, TemporalMonthDayString, TemporalYearMonthString », do
    1. If parseResult is not a Parse Node, then
      1. Set parseResult to ParseText(StringToCodePoints(isoString), goal).
      2. If parseResult is a Parse Node, then
        1. Let calendarWasCritical be false.
        2. 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.
          2. Let value be the source text matched by the AnnotationValue Parse Node contained within annotation.
          3. If CodePointsToString(key) is "u-ca", then
            1. If calendar is empty, then
              1. Set calendar to CodePointsToString(value).
              2. If annotation contains an AnnotationCriticalFlag Parse Node, set calendarWasCritical to true.
            2. Else,
              1. If annotation contains an AnnotationCriticalFlag Parse Node, or calendarWasCritical is true, throw a RangeError exception.
          4. Else,
            1. If annotation contains an AnnotationCriticalFlag Parse Node, throw a RangeError exception.
        3. If goal is TemporalMonthDayString or TemporalYearMonthString, calendar is not empty, and the ASCII-lowercase of calendar is not "iso8601", throw a RangeError exception.
  4. If parseResult is not a Parse Node, throw a RangeError exception.
  5. 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.
  6. 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.
  7. Let yearMV be (StringToNumber(CodePointsToString(year))).
  8. If month is empty, then
    1. Let monthMV be 1.
  9. Else,
    1. Let monthMV be (StringToNumber(CodePointsToString(month))).
  10. If day is empty, then
    1. Let dayMV be 1.
  11. Else,
    1. Let dayMV be (StringToNumber(CodePointsToString(day))).
  12. If hour is empty, then
    1. Let hourMV be 0.
  13. Else,
    1. Let hourMV be (StringToNumber(CodePointsToString(hour))).
  14. If minute is empty, then
    1. Let minuteMV be 0.
  15. Else,
    1. Let minuteMV be (StringToNumber(CodePointsToString(minute))).
  16. If second is empty, then
    1. Let secondMV be 0.
  17. Else,
    1. Let secondMV be (StringToNumber(CodePointsToString(second))).
    2. If secondMV = 60, then
      1. Set secondMV to 59.
  18. If fSeconds is not empty, then
    1. Let fSecondsDigits be the substring of CodePointsToString(fSeconds) from 1.
    2. Let fSecondsDigitsExtended be the string-concatenation of fSecondsDigits and "000000000".
    3. Let millisecond be the substring of fSecondsDigitsExtended from 0 to 3.
    4. Let microsecond be the substring of fSecondsDigitsExtended from 3 to 6.
    5. Let nanosecond be the substring of fSecondsDigitsExtended from 6 to 9.
    6. Let millisecondMV be (StringToNumber(millisecond)).
    7. Let microsecondMV be (StringToNumber(microsecond)).
    8. Let nanosecondMV be (StringToNumber(nanosecond)).
  19. Else,
    1. Let millisecondMV be 0.
    2. Let microsecondMV be 0.
    3. Let nanosecondMV be 0.
  20. Assert: IsValidISODate(yearMV, monthMV, dayMV) is true.
  21. Assert: IsValidTime(hourMV, minuteMV, secondMV, millisecondMV, microsecondMV, nanosecondMV) is true.
  22. Let timeZoneResult be ISO String Time Zone Parse Record { [[Z]]: false, [[OffsetString]]: empty, [[TimeZoneAnnotation]]: empty }.
  23. If parseResult contains a TimeZoneIdentifier Parse Node, then
    1. Let identifier be the source text matched by the TimeZoneIdentifier Parse Node contained within parseResult.
    2. Set timeZoneResult.[[TimeZoneAnnotation]] to CodePointsToString(identifier).
  24. If parseResult contains a UTCDesignator Parse Node, then
    1. Set timeZoneResult.[[Z]] to true.
  25. 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.
    2. Set timeZoneResult.[[OffsetString]] to CodePointsToString(offset).
  26. Return ISO Date-Time Parse Record { [[Year]]: yearMV, [[Month]]: monthMV, [[Day]]: dayMV, [[Hour]]: hourMV, [[Minute]]: minuteMV, [[Second]]: secondMV, [[Millisecond]]: millisecondMV, [[Microsecond]]: microsecondMV, [[Nanosecond]]: nanosecondMV, [[TimeZone]]: timeZoneResult, [[Calendar]]: calendar  }.

13.36 ParseTemporalInstantString ( isoString )

The abstract operation ParseTemporalInstantString takes argument isoString (a String) and returns either a normal completion containing an ISO Date-Time Parse Record or a throw completion. It parses the argument as an ISO 8601 string and returns a Record representing each date and time component needed to construct a Temporal.Instant instance as a distinct field. It performs the following steps when called:

  1. If ParseText(StringToCodePoints(isoString), TemporalInstantString) is a List of errors, throw a RangeError exception.
  2. Let result be ? ParseISODateTime(isoString).
  3. Assert: Either result.[[TimeZone]].[[OffsetString]] is not empty or result.[[TimeZone]].[[Z]] is true, but not both.
  4. Return result.

13.37 ParseTemporalZonedDateTimeString ( isoString )

The abstract operation ParseTemporalZonedDateTimeString takes argument isoString (a String) and returns either a normal completion containing an ISO Date-Time Parse Record or a throw completion. It parses the argument as an ISO 8601 string and returns a Record representing each date and time component needed to construct a Temporal.ZonedDateTime instance as a distinct field. It performs the following steps when called:

  1. If ParseText(StringToCodePoints(isoString), TemporalDateTimeString[+Zoned]) is a List of errors, throw a RangeError exception.
  2. Return ? ParseISODateTime(isoString).

13.38 ParseTemporalCalendarString ( string )

The abstract operation ParseTemporalCalendarString takes argument string (a String) and returns either a normal completion containing a String or a throw completion. It parses the argument either as an ISO 8601 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. It performs the following steps when called:

  1. Let parseResult be Completion(ParseISODateTime(string)).
  2. If parseResult is a normal completion, then
    1. Let calendar be parseResult.[[Value]].[[Calendar]].
    2. If calendar is empty, return "iso8601".
    3. Else, return calendar.
  3. Else,
    1. Set parseResult to ParseText(StringToCodePoints(string), AnnotationValue).
    2. If parseResult is a List of errors, throw a RangeError exception.
    3. Else, return string.

13.39 ParseTemporalDateTimeString ( isoString )

The abstract operation ParseTemporalDateTimeString takes argument isoString (a String) and returns either a normal completion containing an ISO Date-Time Parse Record or a throw completion. It parses the argument as an ISO 8601 string and returns a Record representing each date and time component needed to construct a Temporal.PlainDateTime instance as a distinct field. It performs the following steps when called:

  1. Let parseResult be ParseText(StringToCodePoints(isoString), TemporalDateTimeString[~Zoned]).
  2. If parseResult is a List of errors, throw a RangeError exception.
  3. Return ? ParseISODateTime(isoString).

13.40 ParseTemporalDurationString ( isoString )

The abstract operation ParseTemporalDurationString takes argument isoString (a String) and returns either a normal completion containing a Duration Record or a throw completion. It parses the argument as an ISO 8601 duration string.

Note 1
The value of ToIntegerWithTruncation("") is 0.
Note 2
Use of mathematical values rather than approximations is important to avoid off-by-one errors with input like "PT46H66M71.50040904S".

It performs the following steps when called:

  1. Let duration be ParseText(StringToCodePoints(isoString), TemporalDurationString).
  2. If duration is a List of errors, throw a RangeError exception.
  3. 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.
  4. If duration contains a DurationYearsPart Parse Node, then
    1. Let yearsNode be that DurationYearsPart Parse Node contained within duration.
    2. Let years be the source text matched by the DecimalDigits Parse Node contained within yearsNode.
  5. Else,
    1. Let years be an empty sequence of code points.
  6. If duration contains a DurationMonthsPart Parse Node, then
    1. Let monthsNode be the DurationMonthsPart Parse Node contained within duration.
    2. Let months be the source text matched by the DecimalDigits Parse Node contained within monthsNode.
  7. Else,
    1. Let months be an empty sequence of code points.
  8. If duration contains a DurationWeeksPart Parse Node, then
    1. Let weeksNode be the DurationWeeksPart Parse Node contained within duration.
    2. Let weeks be the source text matched by the DecimalDigits Parse Node contained within weeksNode.
  9. Else,
    1. Let weeks be an empty sequence of code points.
  10. If duration contains a DurationDaysPart Parse Node, then
    1. Let daysNode be the DurationDaysPart Parse Node contained within duration.
    2. Let days be the source text matched by the DecimalDigits Parse Node contained within daysNode.
  11. Else,
    1. Let days be an empty sequence of code points.
  12. If duration contains a DurationHoursPart Parse Node, then
    1. Let hoursNode be the DurationHoursPart Parse Node contained within duration.
    2. Let hours be the source text matched by the DecimalDigits Parse Node contained within hoursNode.
    3. 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.
  13. Else,
    1. Let hours be an empty sequence of code points.
    2. Let fHours be an empty sequence of code points.
  14. If duration contains a DurationMinutesPart Parse Node, then
    1. Let minutesNode be the DurationMinutesPart Parse Node contained within duration.
    2. Let minutes be the source text matched by the DecimalDigits Parse Node contained within minutesNode.
    3. 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.
  15. Else,
    1. Let minutes be an empty sequence of code points.
    2. Let fMinutes be an empty sequence of code points.
  16. If duration contains a DurationSecondsPart Parse Node, then
    1. Let secondsNode be the DurationSecondsPart Parse Node contained within duration.
    2. Let seconds be the source text matched by the DecimalDigits Parse Node contained within secondsNode.
    3. 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.
  17. Else,
    1. Let seconds be an empty sequence of code points.
    2. Let fSeconds be an empty sequence of code points.
  18. Let yearsMV be ? ToIntegerWithTruncation(CodePointsToString(years)).
  19. Let monthsMV be ? ToIntegerWithTruncation(CodePointsToString(months)).
  20. Let weeksMV be ? ToIntegerWithTruncation(CodePointsToString(weeks)).
  21. Let daysMV be ? ToIntegerWithTruncation(CodePointsToString(days)).
  22. Let hoursMV be ? ToIntegerWithTruncation(CodePointsToString(hours)).
  23. If fHours is not empty, then
    1. Assert: minutes, fMinutes, seconds, and fSeconds are empty.
    2. Let fHoursDigits be the substring of CodePointsToString(fHours) from 1.
    3. Let fHoursScale be the length of fHoursDigits.
    4. Let minutesMV be ? ToIntegerWithTruncation(fHoursDigits) / 10fHoursScale × 60.
  24. Else,
    1. Let minutesMV be ? ToIntegerWithTruncation(CodePointsToString(minutes)).
  25. If fMinutes is not empty, then
    1. Assert: seconds and fSeconds are empty.
    2. Let fMinutesDigits be the substring of CodePointsToString(fMinutes) from 1.
    3. Let fMinutesScale be the length of fMinutesDigits.
    4. Let secondsMV be ? ToIntegerWithTruncation(fMinutesDigits) / 10fMinutesScale × 60.
  26. Else if seconds is not empty, then
    1. Let secondsMV be ? ToIntegerWithTruncation(CodePointsToString(seconds)).
  27. Else,
    1. Let secondsMV be remainder(minutesMV, 1) × 60.
  28. If fSeconds is not empty, then
    1. Let fSecondsDigits be the substring of CodePointsToString(fSeconds) from 1.
    2. Let fSecondsScale be the length of fSecondsDigits.
    3. Let millisecondsMV be ? ToIntegerWithTruncation(fSecondsDigits) / 10fSecondsScale × 1000.
  29. Else,
    1. Let millisecondsMV be remainder(secondsMV, 1) × 1000.
  30. Let microsecondsMV be remainder(millisecondsMV, 1) × 1000.
  31. Let nanosecondsMV be remainder(microsecondsMV, 1) × 1000.
  32. If sign contains the code point U+002D (HYPHEN-MINUS), then
    1. Let factor be -1.
  33. Else,
    1. Let factor be 1.
  34. Set yearsMV to yearsMV × factor.
  35. Set monthsMV to monthsMV × factor.
  36. Set weeksMV to weeksMV × factor.
  37. Set daysMV to daysMV × factor.
  38. Set hoursMV to hoursMV × factor.
  39. Set minutesMV to floor(minutesMV) × factor.
  40. Set secondsMV to floor(secondsMV) × factor.
  41. Set millisecondsMV to floor(millisecondsMV) × factor.
  42. Set microsecondsMV to floor(microsecondsMV) × factor.
  43. Set nanosecondsMV to floor(nanosecondsMV) × factor.
  44. If IsValidDuration(yearsMV, monthsMV, weeksMV, daysMV, hoursMV, minutesMV, secondsMV, millisecondsMV, microsecondsMV, nanosecondsMV) is false, throw a RangeError exception.
  45. Return CreateDurationRecord(yearsMV, monthsMV, weeksMV, daysMV, hoursMV, minutesMV, secondsMV, millisecondsMV, microsecondsMV, nanosecondsMV).

13.41 ISO Month-Day Parse Records

An ISO Month-Day Parse Record is a Record value used to represent the ISO 8601 equivalent of a valid month and day in an arbitrary year in an arbitrary calendar. For any ISO Month-Day 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 ISODateTimeWithinLimits(r.[[Year]], r.[[Month]], r.[[Day]], 0, 0, 0, 0, 0, 0) to return true.

ISO Month-Day Parse Records have the fields listed in Table 26.

Table 26: ISO Month-Day Parse Record Fields
Field Name Value Meaning
[[Year]] an integer or empty The year in the ISO 8601 calendar, or empty if none was present in the ISO 8601 string.
[[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.
[[Calendar]] a String or empty The calendar type from the ISO 8601 string, or empty if none was present.

13.42 ParseTemporalMonthDayString ( isoString )

The abstract operation ParseTemporalMonthDayString takes argument isoString (a String) and returns either a normal completion containing an ISO Month-Day Parse Record or a throw completion. It parses the argument as an ISO 8601 string and returns a Record representing each date and time component needed to construct a Temporal.PlainMonthDay instance as a distinct field. It performs the following steps when called:

  1. Let parseResult be ParseText(StringToCodePoints(isoString), TemporalMonthDayString).
  2. If parseResult is a List of errors, throw a RangeError exception.
  3. Let result be ? ParseISODateTime(isoString).
  4. Let year be result.[[Year]].
  5. If parseResult does not contain a DateYear Parse Node, then
    1. Set year to empty.
  6. Return ISO Month-Day Parse Record { [[Year]]: year, [[Month]]: result.[[Month]], [[Day]]: result.[[Day]], [[Calendar]]: result.[[Calendar]]  }.

13.43 ParseTemporalRelativeToString ( isoString )

The abstract operation ParseTemporalRelativeToString takes argument isoString (a String) and returns either a normal completion containing an ISO Date-Time Parse Record or a throw completion. It parses the argument as an ISO 8601 string and returns the information needed to construct either a Temporal.ZonedDateTime or a Temporal.PlainDate instance, e.g. as the value of a relativeTo option. It performs the following steps when called:

  1. Let parseResult be ParseText(StringToCodePoints(isoString), TemporalDateTimeString).
  2. If parseResult is a List of errors, throw a RangeError exception.
  3. Return ? ParseISODateTime(isoString).

13.44 ParseTemporalTimeString ( isoString )

The abstract operation ParseTemporalTimeString takes argument isoString (a String) and returns either a normal completion containing an ISO Date-Time Parse Record or a throw completion. It parses the argument as an ISO 8601 time of day and returns the information needed to construct a Temporal.PlainTime instance. It performs the following steps when called:

  1. Let parseResult be ParseText(StringToCodePoints(isoString), TemporalTimeString).
  2. If parseResult is a List of errors, throw a RangeError exception.
  3. Return ? ParseISODateTime(isoString).
Note

A successful parse using TemporalTimeString guarantees absence of ambiguity with respect to any ISO 8601 date-only, year-month, or month-day representation.

13.45 ParseTemporalTimeZoneString ( timeZoneString )

The abstract operation ParseTemporalTimeZoneString takes argument timeZoneString (a String) and returns either a normal completion containing a Record containing information about the time zone, or a throw completion. It parses the argument as either a time zone identifier or an ISO 8601 string. The returned Record's fields are set as follows:

  • If timeZoneString is a named time zone identifier, then [[Name]] is timeZoneString and [[OffsetMinutes]] is empty.
  • Otherwise, if timeZoneString is an offset time zone identifier, then [[OffsetMinutes]] is a signed integer and [[Name]] is empty.
  • Otherwise, if timeZoneString is an ISO 8601 string with a time zone annotation containing a named time zone identifier, then [[Name]] is the time zone identifier contained in the annotation and [[OffsetMinutes]] is empty.
  • Otherwise, if timeZoneString is an ISO 8601 string with a time zone annotation containing an offset time zone identifier, then [[OffsetMinutes]] is a signed integer and [[Name]] is empty.
  • Otherwise, if timeZoneString is an ISO 8601 string using a Z offset designator, then [[Name]] is "UTC" and [[OffsetMinutes]] is empty.
  • Otherwise, if timeZoneString is an ISO 8601 string using a numeric UTC offset, then [[OffsetMinutes]] is a signed integer and [[Name]] is empty.
  • Otherwise, a RangeError is thrown.
It performs the following steps when called:

  1. Let parseResult be ParseText(StringToCodePoints(timeZoneString), TimeZoneIdentifier).
  2. If parseResult is a Parse Node, then
    1. Return ! ParseTimeZoneIdentifier(timeZoneString).
  3. Let result be ? ParseISODateTime(timeZoneString).
  4. Let timeZoneResult be result.[[TimeZone]].
  5. If timeZoneResult.[[TimeZoneAnnotation]] is not empty, then
    1. Return ! ParseTimeZoneIdentifier(timeZoneResult.[[TimeZoneAnnotation]]).
  6. If timeZoneResult.[[Z]] is true, then
    1. Return ! ParseTimeZoneIdentifier("UTC").
  7. If timeZoneResult.[[OffsetString]] is not empty, then
    1. Return ? ParseTimeZoneIdentifier(timeZoneResult.[[OffsetString]]).
  8. Throw a RangeError exception.

13.46 ParseTemporalYearMonthString ( isoString )

The abstract operation ParseTemporalYearMonthString takes argument isoString (a String) and returns either a normal completion containing an ISO Date-Time Parse Record or a throw completion. It parses the argument as a full or partial ISO 8601 string and returns a Record representing each date and time component needed to construct a Temporal.PlainYearMonth instance as a distinct field. It performs the following steps when called:

  1. Let parseResult be ParseText(StringToCodePoints(isoString), TemporalYearMonthString).
  2. If parseResult is a List of errors, throw a RangeError exception.
  3. Return ? ParseISODateTime(isoString).

13.47 ToPositiveIntegerWithTruncation ( argument )

The abstract operation ToPositiveIntegerWithTruncation takes argument argument (an ECMAScript language value) and returns either a normal completion containing a positive integer or a throw completion. 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. It performs the following steps when called:

  1. Let integer be ? ToIntegerWithTruncation(argument).
  2. If integer ≤ 0, throw a RangeError exception.
  3. Return integer.

13.48 ToIntegerWithTruncation ( argument )

The abstract operation ToIntegerWithTruncation takes argument argument (an ECMAScript language value) and returns either a normal completion containing an integer or a throw completion. It converts argument to an integer representing its Number value with fractional part truncated, or throws a RangeError when that value is not finite. It performs the following steps when called:

  1. Let number be ? ToNumber(argument).
  2. If number is NaN, +∞𝔽 or -∞𝔽, throw a RangeError exception.
  3. Return truncate((number)).

13.49 ToIntegerIfIntegral ( argument )

The abstract operation ToIntegerIfIntegral takes argument argument (an ECMAScript language value) and returns either a normal completion containing an integer or a throw completion. It converts argument to an integer representing its Number value, or throws a RangeError when that value is not integral. It performs the following steps when called:

  1. Let number be ? ToNumber(argument).
  2. If IsIntegralNumber(number) is false, throw a RangeError exception.
  3. Return (number).

13.50 TemporalObjectToFields ( temporalObject )

The abstract operation TemporalObjectToFields takes argument temporalObject (a Temporal.PlainDate, Temporal.PlainDateTime, Temporal.PlainMonthDay, or Temporal.PlainYearMonth) and returns a Calendar Fields Record. It performs the following steps when called:

  1. Let calendar be temporalObject.[[Calendar]].
  2. Let isoDate be TemporalObjectToISODateRecord(temporalObject).
  3. If temporalObject has an [[InitializedTemporalYearMonth]] internal slot, then
    1. Let type be year-month.
  4. Else if temporalObject has an [[InitializedTemporalMonthDay]] internal slot, then
    1. Let type be month-day.
  5. Else,
    1. Let type be date.
  6. Return ISODateToFields(calendar, isoDate, type).

13.51 ISODateToFields ( calendar, isoDate, type )

The abstract operation ISODateToFields takes arguments calendar (a String), isoDate (an ISO Date Record), and type (date, year-month, or month-day) and returns a Calendar Fields Record. It performs the following steps when called:

  1. Let fields be an empty Calendar Fields Record with all fields set to undefined.
  2. Set fields.[[MonthCode]] to CalendarMonthCode(calendar, isoDate).
  3. If type is month-day or date, then
    1. Set fields.[[Day]] to CalendarDay(calendar, isoDate).
  4. If type is year-month or date, then
    1. Set fields.[[Year]] to CalendarYear(calendar, isoDate).
  5. Return fields.

13.52 PrepareCalendarFields ( calendar, fields, calendarFieldNames, nonCalendarFieldNames, requiredFieldNames )

The abstract operation PrepareCalendarFields takes arguments calendar (a String), fields (an Object), calendarFieldNames (a List of values from the Enumeration Key column of Table 19), nonCalendarFieldNames (a List of values from the Enumeration Key column of Table 19), and requiredFieldNames (partial or a List of values from the Enumeration Key column of Table 19) and returns either a normal completion containing a Calendar Fields Record, or a throw completion. 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. It performs the following steps when called:

  1. Assert: If requiredFieldNames is a List, requiredFieldNames contains zero or one of each of the elements of calendarFieldNames and nonCalendarFieldNames.
  2. Let fieldNames be the list-concatenation of calendarFieldNames and nonCalendarFieldNames.
  3. If calendar is not "iso8601", then
    1. Let extraFieldNames be CalendarExtraFields(calendar, calendarFieldNames).
    2. Set fieldNames to the list-concatenation of fieldNames and extraFieldNames.
  4. Assert: fieldNames contains no duplicate elements.
  5. Let result be a Calendar Fields Record with all fields equal to unset.
  6. Let any be false.
  7. Let sortedPropertyNames be a List whose elements are the values in the Property Key column of Table 19 corresponding to the elements of fieldNames, sorted according to lexicographic code unit order.
  8. For each property name property of sortedPropertyNames, do
    1. Let key be the value in the Enumeration Key column of Table 19 corresponding to the row whose Property Key value is property.
    2. Let value be ? Get(fields, property).
    3. If value is not undefined, then
      1. Set any to true.
      2. Let Conversion be the Conversion value of the same row.
      3. If Conversion is to-integer-with-truncation, then
        1. Set value to ? ToIntegerWithTruncation(value).
        2. Set value to 𝔽(value).
      4. Else if Conversion is to-positive-integer-with-truncation, then
        1. Set value to ? ToPositiveIntegerWithTruncation(value).
        2. Set value to 𝔽(value).
      5. Else if Conversion is to-string, then
        1. Set value to ? ToString(value).
      6. Else if Conversion is to-temporal-time-zone-identifier, then
        1. Set value to ? ToTemporalTimeZoneIdentifier(value).
      7. Else,
        1. Assert: Conversion is to-primitive-and-require-string.
        2. NOTE: Non-primitive values are supported here for consistency with other fields, but such values must coerce to Strings.
        3. Set value to ? ToPrimitive(value, string).
        4. If value is not a String, throw a TypeError exception.
      8. Set result's field whose name is given in the Field Name column of the same row to value.
    4. Else if requiredFieldNames is a List, then
      1. If requiredFieldNames contains key, then
        1. Throw a TypeError exception.
      2. 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.
  9. If requiredFieldNames is partial and any is false, then
    1. Throw a TypeError exception.
  10. Return result.

13.53 GetDifferenceSettings ( operation, options, unitGroup, disallowedUnits, fallbackSmallestUnit, smallestLargestDefaultUnit )

The abstract operation GetDifferenceSettings takes arguments operation (since or until), options (an Object), unitGroup (date, time, or datetime), disallowedUnits (a List of Strings), fallbackSmallestUnit (a String), and smallestLargestDefaultUnit (a String) and returns either a normal completion containing a Record with fields [[SmallestUnit]] (a String), [[LargestUnit]] (a String), [[RoundingMode]] (a String from the "Identifier" column of Table 22), and [[RoundingIncrement]] (an integer in the inclusive interval from 1 to 109), or a throw completion. It reads unit and rounding options needed by difference operations. It performs the following steps when called:

  1. NOTE: The following steps read options and perform independent validation in alphabetical order.
  2. Let largestUnit be ? GetTemporalUnitValuedOption(options, "largestUnit", unitGroup, "auto").
  3. If disallowedUnits contains largestUnit, throw a RangeError exception.
  4. Let roundingIncrement be ? GetRoundingIncrementOption(options).
  5. Let roundingMode be ? GetRoundingModeOption(options, "trunc").
  6. If operation is since, then
    1. Set roundingMode to NegateRoundingMode(roundingMode).
  7. Let smallestUnit be ? GetTemporalUnitValuedOption(options, "smallestUnit", unitGroup, fallbackSmallestUnit).
  8. If disallowedUnits contains smallestUnit, throw a RangeError exception.
  9. Let defaultLargestUnit be LargerOfTwoTemporalUnits(smallestLargestDefaultUnit, smallestUnit).
  10. If largestUnit is "auto", set largestUnit to defaultLargestUnit.
  11. If LargerOfTwoTemporalUnits(largestUnit, smallestUnit) is not largestUnit, throw a RangeError exception.
  12. Let maximum be MaximumTemporalDurationRoundingIncrement(smallestUnit).
  13. If maximum is not undefined, perform ? ValidateTemporalRoundingIncrement(roundingIncrement, maximum, false).
  14. Return the Record { [[SmallestUnit]]: smallestUnit, [[LargestUnit]]: largestUnit, [[RoundingMode]]: roundingMode, [[RoundingIncrement]]: roundingIncrement,  }.

14 Amendments to the ECMAScript® 2023 Language Specification

Editor's Note

This section lists amendments which must be made to ECMA-262, the ECMAScript® 2023 Language Specification, other than the addition of the new sections specifying the Temporal object and everything related to it. Text to be added is marked like this, and text to be deleted is marked like this. Blocks of unmodified text between modified sections are marked by [...].

14.1 The String Type

Editor's Note

This section intends to move the definitions of ASCII-uppercase, ASCII-lowercase, and ASCII-case-insensitive match from ECMA-402 into ECMA-262, after the definition of the ASCII word characters.

[...]

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.

14.2 The Year-Week Record Specification Type

The Year-Week Record specification type is returned by the week number calculation in ToISOWeekOfYear, 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 Table 27.

Table 27: 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.

14.3 Mathematical Operations

[...]

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.

[...]

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.

[...]

14.4 Overview of Date Objects and Definitions of Abstract Operations

[...]

14.4.1 GetUTCEpochNanoseconds ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond [ , offsetNanoseconds ] )

The abstract operation GetUTCEpochNanoseconds takes arguments year (an integer), month (an integer), day (an integer), 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), and nanosecond (an integer in the inclusive interval from 0 to 999) and optional argument offsetNanoseconds (an integer in the interval from -nsPerDay (exclusive) to nsPerDay (exclusive)) and returns a BigInt. 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. If a UTC offset is provided, the returned value will be adjusted by that offset. It performs the following steps when called:

  1. Assert: IsValidISODate(year, month, day) is true.
  2. Let date be MakeDay(𝔽(year), 𝔽(month - 1), 𝔽(day)).
  3. Let time be MakeTime(𝔽(hour), 𝔽(minute), 𝔽(second), 𝔽(millisecond)).
  4. Let ms be MakeDate(date, time).
  5. Assert: ms is an integral Number.
  6. Return ((ms) × 106 + microsecond × 103 + nanosecond).
  7. Let epochNanoseconds be (ms) × 106 + microsecond × 103 + nanosecond.
  8. If offsetNanoseconds is present and offsetNanoseconds ≠ 0, set epochNanoseconds to epochNanoseconds - offsetNanoseconds.
  9. Return (epochNanoseconds).

14.4.2 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 0x007F0x0021 to 0x007E. 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 IsTimeZoneOffsetStringIsOffsetTimeZoneIdentifier 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.

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 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.

14.4.3 SystemTimeZoneIdentifier ( )

The implementation-defined abstract operation SystemTimeZoneIdentifier takes no arguments and returns a String. 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 identifiera primary time zone identifier or an offset time zone identifier. It performs the following steps when called:

  1. If the implementation only supports the UTC time zone, return "UTC".
  2. 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.
  3. Return systemTimeZoneString.
Note

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".

14.4.4 Time Zone Offset String FormatFormats

ECMAScript defines a string interchange format for UTC offsets, derived from ISO 8601. The format is described by the following grammar. The usage of Unicode code points in this grammar is listed in Table 61.

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 or custom time zone can be more precise, and are specified by UTCOffset[+SubMinutePrecision].

These formats are described by the ISO String grammar in 13.32. The usage of Unicode code points in this grammar is listed in Table 61.

[...]

Editor's Note
The grammar in this section should be deleted; it is replaced by the ISO 8601 String grammar in 13.32.

14.4.5 LocalTime ( t )

The abstract operation LocalTime takes argument t (a finite time value) and returns an integral Number. It converts t from UTC to local time. The local political rules for standard time and daylight saving time in effect at t should be used to determine the result in the way specified in this section. It performs the following steps when called:

  1. Let systemTimeZoneIdentifier be SystemTimeZoneIdentifier().
  2. Let parseResult be ! ParseTimeZoneIdentifier(systemTimeZoneIdentifier).
  3. If IsTimeZoneOffsetString(systemTimeZoneIdentifier) is trueparseResult.[[OffsetMinutes]] is not empty, then
    1. Let offsetNs be ParseTimeZoneOffsetString(systemTimeZoneIdentifier)parseResult.[[OffsetMinutes]] × (60 × 109).
  4. Else,
    1. Let offsetNs be GetNamedTimeZoneOffsetNanoseconds(systemTimeZoneIdentifier, ((t) × 106)).
  5. Let offsetMs be truncate(offsetNs / 106).
  6. Return t + 𝔽(offsetMs).
Note 1

If political rules for the local time t are not available within the implementation, the result is t because SystemTimeZoneIdentifier returns "UTC" and GetNamedTimeZoneOffsetNanoseconds returns 0.

Note 2

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/.

Note 3

Two different input time values tUTC are converted to the same local time tlocal at a negative time zone transition when there are repeated times (e.g. the daylight saving time ends or the time zone adjustment is decreased.).

LocalTime(UTC(tlocal)) is not necessarily always equal to tlocal. Correspondingly, UTC(LocalTime(tUTC)) is not necessarily always equal to tUTC.

14.4.6 UTC ( t )

The abstract operation UTC takes argument t (a Number) and returns a time value. It converts t from local time to a UTC time value. The local political rules for standard time and daylight saving time in effect at t should be used to determine the result in the way specified in this section. It performs the following steps when called:

  1. If t is not finite, return NaN.
  2. Let systemTimeZoneIdentifier be SystemTimeZoneIdentifier().
  3. Let parseResult be ! ParseTimeZoneIdentifier(systemTimeZoneIdentifier).
  4. If IsTimeZoneOffsetString(systemTimeZoneIdentifier) is trueparseResult.[[OffsetMinutes]] is not empty, then
    1. Let offsetNs be ParseTimeZoneOffsetString(systemTimeZoneIdentifier)parseResult.[[OffsetMinutes]] × (60 × 109).
  5. Else,
    1. Let possibleInstants be GetNamedTimeZoneEpochNanoseconds(systemTimeZoneIdentifier, (YearFromTime(t)), (MonthFromTime(t)) + 1, (DateFromTime(t)), (HourFromTime(t)), (MinFromTime(t)), (SecFromTime(t)), (msFromTime(t)), 0, 0).
    2. 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.
    3. If possibleInstants is not empty, then
      1. Let disambiguatedInstant be possibleInstants[0].
    4. 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).
      2. 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).
      3. Let disambiguatedInstant be the last element of possibleInstantsBefore.
    5. Let offsetNs be GetNamedTimeZoneOffsetNanoseconds(systemTimeZoneIdentifier, disambiguatedInstant).
  6. Let offsetMs be truncate(offsetNs / 106).
  7. Return t - 𝔽(offsetMs).

Input t is nominally a time value but may be any Number value. The algorithm must not limit t to the time value range, so that inputs corresponding with a boundary of the time value range can be supported regardless of local UTC offset. For example, the maximum time value is 8.64 × 1015, corresponding with "+275760-09-13T00:00:00Z". In an environment where the local time zone offset is ahead of UTC by 1 hour at that instant, it is represented by the larger input of 8.64 × 1015 + 3.6 × 106, corresponding with "+275760-09-13T01:00:00+01:00".

If political rules for the local time t are not available within the implementation, the result is t because SystemTimeZoneIdentifier returns "UTC" and GetNamedTimeZoneOffsetNanoseconds returns 0.

Note 1

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 (fall backward), but it must be interpreted as 1:30 AM UTC-04 instead of 1:30 AM UTC-05. In UTC(TimeClip(MakeDate(MakeDay(2017, 10, 5), MakeTime(1, 30, 0, 0)))), the value of offsetMs is -4 × msPerHour.

2:30 AM on 12 March 2017 in America/New_York does not exist, but it must be interpreted as 2:30 AM UTC-05 (equivalent to 3:30 AM UTC-04). In UTC(TimeClip(MakeDate(MakeDay(2017, 2, 12), MakeTime(2, 30, 0, 0)))), the value of offsetMs is -5 × msPerHour.

Note 2

UTC(LocalTime(tUTC)) is not necessarily always equal to tUTC. Correspondingly, LocalTime(UTC(tlocal)) is not necessarily always equal to tlocal.

[...]

14.4.7 TimeString ( tv )

The abstract operation TimeString takes argument tv (a Number, but not NaN) and returns a String. It performs the following steps when called:

  1. Let hour be ToZeroPaddedDecimalString((HourFromTime(tv)), 2).
  2. Let minute be ToZeroPaddedDecimalString((MinFromTime(tv)), 2).
  3. Let second be ToZeroPaddedDecimalString((SecFromTime(tv)), 2).
  4. Let timeString be FormatTimeString((HourFromTime(tv)), (MinFromTime(tv)), (SecFromTime(tv)), 0, 0).
  5. Return the string-concatenation of hour, ":", minute, ":", secondtimeString, the code unit 0x0020 (SPACE), and "GMT".

[...]

14.4.8 TimeZoneString ( tv )

The abstract operation TimeZoneString takes argument tv (an integral Number) and returns a String. It performs the following steps when called:

  1. Let systemTimeZoneIdentifier be SystemTimeZoneIdentifier().
  2. If IsTimeZoneOffsetString(systemTimeZoneIdentifier) is true, then
    1. Let offsetNs be ParseTimeZoneOffsetString(systemTimeZoneIdentifier).
  3. Else,
  4. Let offsetMinutes be ! ParseTimeZoneIdentifier(systemTimeZoneIdentifier).[[OffsetMinutes]].
  5. If offsetMinutes is empty, then
    1. Let offsetNs be GetNamedTimeZoneOffsetNanoseconds(systemTimeZoneIdentifier, ((tv) × 106)).
    2. Set offsetMinutes to truncate(offsetNs / (60 × 109)).
  6. Let offset be 𝔽(truncate(offsetNs / 106)).
  7. If offset is +0𝔽 or offset > +0𝔽, then
    1. Let offsetSign be "+".
    2. Let absOffset be offset.
  8. Else,
    1. Let offsetSign be "-".
    2. Let absOffset be -offset.
  9. Let offsetMin be ToZeroPaddedDecimalString((MinFromTime(absOffset)), 2).
  10. Let offsetHour be ToZeroPaddedDecimalString((HourFromTime(absOffset)), 2).
  11. Let offsetString be FormatOffsetTimeZoneIdentifier(offsetMinutes, unseparated).
  12. 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).
  13. Return the string-concatenation of offsetSign, offsetHour, offsetMin, and tzName.
  14. Return the string-concatenation of offsetString and tzName.

IsTimeZoneOffsetString ( offsetString: a String, ): a Boolean

14.4.9 IsOffsetTimeZoneIdentifier ( offsetString )

The abstract operation IsOffsetTimeZoneIdentifier takes argument offsetString (a String) and returns a Boolean. The return value indicates whether offsetString conforms to the grammar given by UTCOffsetUTCOffset[~SubMinutePrecision]. It performs the following steps when called:

  1. Let parseResult be ParseText(StringToCodePoints(offsetString), UTCOffsetUTCOffset[~SubMinutePrecision]).
  2. If parseResult is a List of errors, return false.
  3. Return true.

ParseTimeZoneOffsetString ( offsetString: a String, ): an integer

14.4.10 ParseDateTimeUTCOffset ( offsetString )

The abstract operation ParseDateTimeUTCOffset takes argument offsetString (a String) and returns either a normal completion containing an integer or a throw completion. 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. It performs the following steps when called:

  1. Let parseResult be ParseText(StringToCodePoints(offsetString), UTCOffsetUTCOffset[+SubMinutePrecision]).
  2. Assert: parseResult is not a List of errors.
  3. If parseResult is a List of errors, throw a RangeError exception.
  4. Assert: parseResult contains a ASCIISign Parse Node.
  5. Let parsedSign be the source text matched by the ASCIISign Parse Node contained within parseResult.
  6. If parsedSign is the single code point U+002D (HYPHEN-MINUS), then
    1. Let sign be -1.
  7. Else,
    1. Let sign be 1.
  8. 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.
  9. Assert: parseResult contains an Hour Parse Node.
  10. Let parsedHours be the source text matched by the Hour Parse Node contained within parseResult.
  11. Let hours be (StringToNumber(CodePointsToString(parsedHours))).
  12. If parseResult does not contain a MinuteSecond Parse Node, then
    1. Let minutes be 0.
  13. Else,
    1. Let parsedMinutes be the source text matched by the first MinuteSecond Parse Node contained within parseResult.
    2. Let minutes be (StringToNumber(CodePointsToString(parsedMinutes))).
  14. If parseResult does not contain two MinuteSecond Parse Nodes, then
    1. Let seconds be 0.
  15. Else,
    1. Let parsedSeconds be the source text matched by the second MinuteSecond Parse Node contained within parseResult.
    2. Let seconds be (StringToNumber(CodePointsToString(parsedSeconds))).
  16. If parseResult does not contain a TemporalDecimalFraction Parse Node, then
    1. Let nanoseconds be 0.
  17. Else,
    1. Let parsedFraction be the source text matched by the TemporalDecimalFraction Parse Node contained within parseResult.
    2. Let fraction be the string-concatenation of CodePointsToString(parsedFraction) and "000000000".
    3. Let nanosecondsString be the substring of fraction from 1 to 10.
    4. Let nanoseconds be (StringToNumber(nanosecondsString)).
  18. Return sign × (((hours × 60 + minutes) × 60 + seconds) × 109 + nanoseconds).

14.5 The Date Constructor

14.5.1 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.
    2. Return ToDateString(now).
  2. If NewTarget is undefined, return ToDateString(SystemUTCEpochMilliseconds()).
  3. Let numberOfArgs be the number of elements in values.
  4. If numberOfArgs = 0, then
    1. Let dv be the time value (UTC) identifying the current time SystemUTCEpochMilliseconds().
  5. Else if numberOfArgs = 1, then
    1. Let value be values[0].
    2. If value is an Object and value has a [[DateValue]] internal slot, then
      1. Let tv be value.[[DateValue]].
    3. Else,
      1. Let v be ? ToPrimitive(value).
      2. If v is a String, then
        1. Assert: The next step never returns an abrupt completion because v is a String.
        2. Let tv be the result of parsing v as a date, in exactly the same manner as for the parse method (21.4.3.2).
      3. Else,
        1. Let tv be ? ToNumber(v).
    4. Let dv be TimeClip(tv).
  6. Else,
    1. Assert: numberOfArgs ≥ 2.
    2. Let y be ? ToNumber(values[0]).
    3. Let m be ? ToNumber(values[1]).
    4. If numberOfArgs > 2, let dt be ? ToNumber(values[2]); else let dt be 1𝔽.
    5. If numberOfArgs > 3, let h be ? ToNumber(values[3]); else let h be +0𝔽.
    6. If numberOfArgs > 4, let min be ? ToNumber(values[4]); else let min be +0𝔽.
    7. If numberOfArgs > 5, let s be ? ToNumber(values[5]); else let s be +0𝔽.
    8. If numberOfArgs > 6, let milli be ? ToNumber(values[6]); else let milli be +0𝔽.
    9. Let yr be MakeFullYear(y).
    10. Let finalDate be MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli)).
    11. Let dv be TimeClip(UTC(finalDate)).
  7. Let O be ? OrdinaryCreateFromConstructor(NewTarget, "%Date.prototype%", « [[DateValue]] »).
  8. Set O.[[DateValue]] to dv.
  9. Return O.

14.6 Properties of the Date Constructor

14.6.1 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. Return SystemUTCEpochMilliseconds().

14.7 Properties of the Date Prototype Object

14.7.1 Date.prototype.toTemporalInstant ( )

This method performs the following steps when called:

  1. Let dateObject be the this value.
  2. Perform ? RequireInternalSlot(dateObject, [[DateValue]]).
  3. Let t be dateObject.[[DateValue]].
  4. Let ns be ? NumberToBigInt(t) × (106).
  5. Return ! CreateTemporalInstant(ns).

15 Amendments to the ECMAScript® 2023 Internationalization API Specification

Editor's Note

This section lists amendments which must be made to ECMA-402, the ECMAScript® 2023 Internationalization API Specification. Text to be added is marked like this, and text to be deleted is marked like this. Blocks of unmodified text between modified sections are marked by [...].

This text is based on top of the ECMA-402 spec text from commit 537afda7be28a443b79b3fd7e6c836a16ce4f75f.

15.1 Case Sensitivity and Case Mapping

Editor's Note

These definitions are moved into ECMA-262.

The String values used to identify locales, currencies, scripts, and time zones are interpreted in an ASCII-case-insensitive manner, treating the code units 0x0041 through 0x005A (corresponding to Unicode characters LATIN CAPITAL LETTER A through LATIN CAPITAL LETTER Z) as equivalent to the corresponding code units 0x0061 through 0x007A (corresponding to Unicode characters LATIN SMALL LETTER A through LATIN SMALL LETTER Z), both inclusive. No other case folding equivalences are applied.

Note
For example, "ß" (U+00DF) must not match or be mapped to "SS" (U+0053, U+0053). "ı" (U+0131) must not match or be mapped to "I" (U+0049).

The ASCII-uppercase of a String value S is the String value 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 value S is the String value 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 value A is an ASCII-case-insensitive match for String value B if the ASCII-uppercase of A is exactly the same sequence of code units as the ASCII-uppercase of B. A sequence of Unicode code points A is an ASCII-case-insensitive match for B if B is an ASCII-case-insensitive match for ! CodePointsToString(A).

15.2 Use of the IANA Time Zone Database

Editor's Note
This section replaces the Time Zone Names section in ECMA-402.

Implementations that adopt this specification are time zone aware: they use the IANA Time Zone Database https://www.iana.org/time-zones/ to supply time zone identifiers and data used in ECMAScript calculations and formatting. This section defines how the IANA Time Zone Database should be used by time zone aware implementations.

Except as overridden by AvailableNamedTimeZoneIdentifiers, each Zone in the IANA Time Zone Database must be a primary time zone identifier and each Link name in the IANA Time Zone Database must be a non-primary time zone identifier. No String may be an available named time zone identifier unless it is a Zone name or a Link name in the IANA Time Zone Database. Available named time zone identifiers returned by ECMAScript built-in objects must use the casing found in the IANA Time Zone Database.

In the IANA Time Zone Database, the UTC time zone is represented by the Zone "Etc/UTC" which is distinct from the Zone "Etc/GMT". For historical reasons, ECMAScript uses "UTC" as the primary identifier for the former Zone and does not recognize the latter Zone as distinct, instead requiring "Etc/UTC", "Etc/GMT", and "GMT" (if available) to be non-primary identifiers that resolve to "UTC". This is the only deviation from the IANA Time Zone Database that is required of a time zone aware ECMAScript implementation.

The IANA Time Zone Database is typically updated between five and ten times per year. These updates may add new Zone or Link names, may change Zones to Links, and may change the UTC offsets and transitions associated with any Zone. ECMAScript implementations are recommended to include updates to the IANA Time Zone Database as soon as possible. Such prompt action ensures that ECMAScript programs can accurately perform time-zone-sensitive calculations and can use newly-added available named time zone identifiers supplied by external input or the host environment.

Note 1

Although the IANA Time Zone Database maintainers strive for stability, in rare cases (averaging less than once per year) a Zone may be replaced by a new Zone. For example, in 2022 "Europe/Kiev" was deprecated to a Link resolving to a new "Europe/Kyiv" Zone.

To reduce disruption from renaming changes, ECMAScript implementations are encouraged to initially add the new Zone as a non-primary time zone identifier that resolves to the current primary identifier. Then, after a waiting period, implementations are recommended to promote the new Zone to a primary time zone identifier while simultaneously demoting the deprecated name to non-primary. The recommended waiting period is two years after the IANA Time Zone Database release containing the changes. This delay allows other systems, that ECMAScript programs may interact with, to be updated to recognize the new Zone.

A waiting period should only apply when a new Zone is added to replace an existing Zone. If an existing Zone and Link are swapped, then no waiting period is necessary.

If implementations revise time zone information during the lifetime of an agent, then which identifiers are supported, the primary time zone identifier associated with any identifier, and the UTC offsets and transitions associated with any Zone, must be consistent with results previously observed by that agent. Due to the complexity of supporting this requirement, it is recommended that implementations maintain a fully consistent copy of the IANA Time Zone Database for the lifetime of each agent.

This section complements but does not supersede 14.4.2.

Note 2

The IANA Time Zone Database offers build options that affect which time zone identifiers are primary. The default build options merge different countries' time zones, for example "Atlantic/Reykjavik" being a Link to the Zone "Africa/Abidjan". Geographically and politically distinct locations are likely to introduce divergent time zone rules in a future version of the IANA Time Zone Database. Therefore, it is recommended that ECMAScript implementations instead use build options such as PACKRATDATA=backzone PACKRATLIST=zone.tab or a similar alternative that ensures at least one primary identifier for each ISO 3166-1 Alpha-2 country code.

15.2.1 AvailableNamedTimeZoneIdentifiers ( )

The implementation-defined abstract operation AvailableNamedTimeZoneIdentifiers takes no arguments and returns a List of Time Zone Identifier Records. 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.

This definition supersedes the definition provided in 21.4.1.23.

  1. Let identifiers be a List containing the String value of each Zone or Link name in the IANA Time Zone Database, sorted according to lexicographic code unit order.
  2. Assert: No element of identifiers is an ASCII-case-insensitive match for any other element.
  3. Assert: Every element of identifiers identifies a Zone or Link name in the IANA Time Zone Database.
  4. Let result be a new empty List.
  5. For each element identifier of identifiers, do
    1. Let primary be identifier.
    2. If identifier is a non-primary time zone identifier and identifier is not "UTC", then
      1. Set primary to the name of the primary time zone identifier that identifier resolves to, according to the rules for resolving Link names in the IANA Time Zone Database.
      2. NOTE: An implementation may need to resolve identifier iteratively to obtain the primary time zone identifier.
    3. If primary is one of "Etc/UTC", "Etc/GMT", or "GMT", set primary to "UTC".
    4. Let record be the Time Zone Identifier Record { [[Identifier]]: identifier, [[PrimaryIdentifier]]: primary }.
    5. Append record to result.
  6. Assert: result contains a Time Zone Identifier Record r such that r.[[Identifier]] is "UTC" and r.[[PrimaryIdentifier]] is "UTC".
  7. Return result.
Note
Time zone identifiers in the IANA Time Zone Database can change over time. At a minimum, implementations must limit changes to the result of AvailableNamedTimeZoneIdentifiers to the changes allowed by GetAvailableNamedTimeZoneIdentifier, for the lifetime of the surrounding agent. That is, implementations must not remove support for or change the primary vs. non-primary status of an identifier that was already reported as available, and they must not add support for an identifier that was already reported as not available. Due to the complexity of supporting these recommendations, it is recommended that the result of AvailableNamedTimeZoneIdentifiers remains the same for the lifetime of the surrounding agent.

15.3 Time Zone Names

This specification identifies time zones using the Zone and Link names of the IANA Time Zone Database. Their canonical form is the corresponding Zone name in the casing used in the IANA Time Zone Database except as specifically overridden by CanonicalizeTimeZoneName.

A conforming implementation must recognize "UTC" and all other Zone and Link names (and only such names), and use best available current and historical information about their offsets from UTC and their daylight saving time rules in calculations. However, the set of combinations of time zone name and language tag for which localized time zone names are available is implementation dependent.

15.3.1 IsValidTimeZoneName ( timeZone )

The abstract operation IsValidTimeZoneName takes argument timeZone (a String) and returns a Boolean. It verifies that the timeZone argument represents a valid Zone or Link name of the IANA Time Zone Database. It performs the following steps when called:

  1. If one of the Zone or Link names of the IANA Time Zone Database is an ASCII-case-insensitive match for timeZone, return true.
  2. If timeZone is an ASCII-case-insensitive match for "UTC", return true.
  3. Return false.
Note
Any value returned from SystemTimeZoneIdentifier that is not recognized as valid by IsTimeZoneOffsetString must be recognized as valid by IsValidTimeZoneName.

15.3.2 CanonicalizeTimeZoneName ( timeZone )

The abstract operation CanonicalizeTimeZoneName takes argument timeZone (a String value that is a valid time zone name as verified by IsValidTimeZoneName). It returns the canonical and case-regularized form of timeZone. It performs the following steps when called:

  1. Let ianaTimeZone be the String value of the Zone or Link name of the IANA Time Zone Database that is an ASCII-case-insensitive match of timeZone.
  2. If ianaTimeZone is a Link name, set ianaTimeZone to the String value of the corresponding Zone name as specified in the file backward of the IANA Time Zone Database.
  3. If ianaTimeZone is "Etc/UTC" or "Etc/GMT", or "GMT", return "UTC".
  4. Return ianaTimeZone.

15.3.3 AvailableCanonicalTimeZones ( )

The implementation-defined abstract operation AvailableCanonicalTimeZones takes no arguments and returns a List of Strings. The returned List is a sorted List of supported Zone and Link names in the IANA Time Zone Database. It performs the following steps when called:

  1. Let names be a List of all Zone and Link names in the IANA Time Zone Database that are supported by the implementation.
  2. Let result be a new empty List.
  3. For each element name of names, do
    1. Assert: IsValidTimeZoneName( name ) is true.
    2. Let canonical be CanonicalizeTimeZoneName( name ).
    3. If result does not contain canonical, then
      1. Append canonical to result.
  4. Sort result in order as if an Array of the same values had been sorted using %Array.prototype.sort% using undefined as comparefn.
  5. Return result.

15.4 Calendar Types

This specification identifies calendars using a calendar type as defined by Unicode Technical Standard #35 Part 4 Dates, Section 2 Calendar Elements. 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) with zero or more medial hyphens (U+002D HYPHEN-MINUS).

15.4.1 AvailableCalendars ( )

The abstract operation AvailableCalendars takes no arguments and returns a List of Strings. The returned List is sorted according to lexicographic code unit order, and contains unique calendar types in canonical form (12.1) identifying the calendars for which the implementation provides the functionality of Intl.DateTimeFormat objects, including their aliases (e.g., either both or neither of "islamicc" and "islamic-civil"). The List must include "iso8601".

15.5 The Intl Object

[...]

15.5.1 Function Properties of the Intl Object

[...]

15.5.1.1 Intl.supportedValuesOf ( key )

When the supportedValuesOf method is called with argument key , the following steps are taken:

  1. Let key be ? ToString(key).
  2. If key is "calendar", then
    1. Let list be a new empty List.
    2. For each element identifier of AvailableCalendars(), do
      1. Let canonical be CanonicalizeUValue("ca", identifier).
      2. If identifier is canonical, then
        1. Append identifier to list.
  3. Else if key is "collation", then
    1. Let list be AvailableCanonicalCollations( ).
  4. Else if key is "currency", then
    1. Let list be AvailableCanonicalCurrencies( ).
  5. Else if key is "numberingSystem", then
    1. Let list be AvailableCanonicalNumberingSystems( ).
  6. Else if key is "timeZone", then
    1. Let list be AvailablePrimaryTimeZoneIdentifiers( ).
    2. Let timeZones be AvailableNamedTimeZoneIdentifiers().
    3. Let list be a List consisting of every element record of timeZones for which record.[[Identifier]] = record.[[PrimaryIdentifier]].
  7. Else if key is "unit", then
    1. Let list be AvailableCanonicalUnits( ).
  8. Else,
    1. Throw a RangeError exception.
  9. Return CreateArrayFromList( list ).

15.6 Abstract Operations

Editor's Note

In this section, some abstract operations that manipulate options objects are to be moved from ECMA-402 into ECMA-262.

15.6.1 GetOptionsObject ( options )

The abstract operation GetOptionsObject takes argument options (an ECMAScript language value) and returns either a normal completion containing an Object or a throw completion. It returns an Object suitable for use with GetOption, either options itself or a default empty Object. It throws a TypeError if options is not undefined and not an Object. It performs the following steps when called:

  1. If options is undefined, then
    1. Return OrdinaryObjectCreate(null).
  2. If Type(options) is Object, then
    1. Return options.
  3. Throw a TypeError exception.

[...]

15.6.2 GetOption ( options, property, type, values, default )

The abstract operation GetOption takes arguments options (an Object), property (a property key), type (boolean or string), values (empty or a List of ECMAScript language values), and default (required or an ECMAScript language value) and returns either a normal completion containing an ECMAScript language value or a throw completion. It extracts the value of the specified property of options, converts it to the required type, checks whether it is allowed by values if values is not empty, and substitutes default if the value is undefined. It performs the following steps when called:

  1. Let value be ? Get(options, property).
  2. If value is undefined, then
    1. If default is required, throw a RangeError exception.
    2. Return default.
  3. If type is boolean, then
    1. Set value to ToBoolean(value).
  4. Else,
    1. Assert: type is string.
    2. Set value to ? ToString(value).
  5. If values is not empty and values does not contain value, throw a RangeError exception.
  6. Return value.

[...]

Table 28: Rounding modes in Intl.NumberFormat
Identifier Description Examples: Round to 0 fraction digits
-1.5 0.4 0.5 0.6 1.5
"ceil" Toward positive infinity ⬆️ [-1] ⬆️ [1] ⬆️ [1] ⬆️ [1] ⬆️ [2]
"floor" Toward negative infinity ⬇️ [-2] ⬇️ [0] ⬇️ [0] ⬇️ [0] ⬇️ [1]
"expand" Away from zero ⬇️ [-2] ⬆️ [1] ⬆️ [1] ⬆️ [1] ⬆️ [2]
"trunc" Toward zero ⬆️ [-1] ⬇️ [0] ⬇️ [0] ⬇️ [0] ⬇️ [1]
"halfCeil" Ties toward positive infinity ⬆️ [-1] ⬇️ [0] ⬆️ [1] ⬆️ [1] ⬆️ [2]
"halfFloor" Ties toward negative infinity ⬇️ [-2] ⬇️ [0] ⬇️ [0] ⬆️ [1] ⬇️ [1]
"halfExpand" Ties away from zero ⬇️ [-2] ⬇️ [0] ⬆️ [1] ⬆️ [1] ⬆️ [2]
"halfTrunc" Ties toward zero ⬆️ [-1] ⬇️ [0] ⬇️ [0] ⬆️ [1] ⬇️ [1]
"halfEven" Ties toward an even rounding increment multiple ⬇️ [-2] ⬇️ [0] ⬇️ [0] ⬆️ [1] ⬆️ [2]
Note
The examples are illustrative of the unique behaviour of each option. ⬆️ means "resolves toward positive infinity"; ⬇️ means "resolves toward negative infinity".

15.6.3 GetUnsignedRoundingMode ( roundingMode, sign )

The abstract operation GetUnsignedRoundingMode takes arguments roundingMode (a String) and sign (negative or positive) and returns a specification type from the Unsigned Rounding Mode column of Table 29. It returns the rounding mode that should be applied to the absolute value of a number to produce the same result as if roundingMode, one of the String values in the Identifier column of Table 28, were applied to the signed value of the number (negative if sign is negative, or positive otherwise). It performs the following steps when called:

  1. Return the specification type in the Unsigned Rounding Mode column of Table 29 for the row where the value in the Identifier column is roundingMode and the value in the Sign column is sign.
Table 29: Conversion from rounding mode to unsigned rounding mode
Identifier Sign Unsigned Rounding Mode
"ceil" positive infinity
negative zero
"floor" positive zero
negative infinity
"expand" positive infinity
negative infinity
"trunc" positive zero
negative zero
"halfCeil" positive half-infinity
negative half-zero
"halfFloor" positive half-zero
negative half-infinity
"halfExpand" positive half-infinity
negative half-infinity
"halfTrunc" positive half-zero
negative half-zero
"halfEven" positive half-even
negative half-even

15.6.4 ApplyUnsignedRoundingMode ( x, r1, r2, unsignedRoundingMode )

The abstract operation ApplyUnsignedRoundingMode takes arguments x (a mathematical value), r1 (a mathematical value), r2 (a mathematical value), and unsignedRoundingMode (a specification type from the Unsigned Rounding Mode column of Table 29, or undefined) and returns a mathematical value. It considers x, bracketed below by r1 and above by r2, and returns either r1 or r2 according to unsignedRoundingMode. It performs the following steps when called:

  1. If x is equal to r1, return r1.
  2. Assert: r1 < x < r2.
  3. Assert: unsignedRoundingMode is not undefined.
  4. If unsignedRoundingMode is zero, return r1.
  5. If unsignedRoundingMode is infinity, return r2.
  6. Let d1 be xr1.
  7. Let d2 be r2x.
  8. If d1 < d2, return r1.
  9. If d2 < d1, return r2.
  10. Assert: d1 is equal to d2.
  11. If unsignedRoundingMode is half-zero, return r1.
  12. If unsignedRoundingMode is half-infinity, return r2.
  13. Assert: unsignedRoundingMode is half-even.
  14. Let cardinality be (r1 / (r2r1)) modulo 2.
  15. If cardinality is 0, return r1.
  16. Return r2.

15.7 The Intl.DateTimeFormat Constructor

[...]

15.7.1 CreateDateTimeFormat ( newTarget, locales, options, required, defaults [ , toLocaleStringTimeZone ] )

The abstract operation CreateDateTimeFormat takes arguments newTarget (a constructor), locales (an ECMAScript language value), options (an ECMAScript language value), required (date, time, or any), and defaults (date, time, or all) and optional argument toLocaleStringTimeZone (a primary time zone identifier) and returns either a normal completion containing a DateTimeFormat object or a throw completion.

If the additional toLocaleStringTimeZone argument is provided, the time zone will be overridden and some adjustments will be made to the defaults in order to implement the behaviour of Temporal.ZonedDateTime.prototype.toLocaleString.

It performs the following steps when called:

  1. Let dateTimeFormat be ? OrdinaryCreateFromConstructor(newTarget, "%Intl.DateTimeFormat.prototype%", « [[InitializedDateTimeFormat]], [[Locale]], [[Calendar]], [[NumberingSystem]], [[TimeZone]], [[HourCycle]], [[DateStyle]], [[TimeStyle]], [[DateTimeFormat]], [[TemporalPlainDateFormat]], [[TemporalPlainYearMonthFormat]], [[TemporalPlainMonthDayFormat]], [[TemporalPlainTimeFormat]], [[TemporalPlainDateTimeFormat]], [[TemporalInstantFormat]], [[BoundFormat]] »).
  2. Let requestedLocales be ? CanonicalizeLocaleList(locales).
  3. Set options to ? CoerceOptionsToObject(options).
  4. Let opt be a new Record.
  5. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
  6. Set opt.[[localeMatcher]] to matcher.
  7. Let calendar be ? GetOption(options, "calendar", string, empty, undefined).
  8. If calendar is not undefined, then
    1. If calendar cannot be matched by the type Unicode locale nonterminal, throw a RangeError exception.
  9. Set opt.[[ca]] to calendar.
  10. Let numberingSystem be ? GetOption(options, "numberingSystem", string, empty, undefined).
  11. If numberingSystem is not undefined, then
    1. If numberingSystem cannot be matched by the type Unicode locale nonterminal, throw a RangeError exception.
  12. Set opt.[[nu]] to numberingSystem.
  13. Let hour12 be ? GetOption(options, "hour12", boolean, empty, undefined).
  14. Let hourCycle be ? GetOption(options, "hourCycle", string, « "h11", "h12", "h23", "h24" », undefined).
  15. If hour12 is not undefined, then
    1. Set hourCycle to null.
  16. Set opt.[[hc]] to hourCycle.
  17. Let r be ResolveLocale(%Intl.DateTimeFormat%.[[AvailableLocales]], requestedLocales, opt, %Intl.DateTimeFormat%.[[RelevantExtensionKeys]], %Intl.DateTimeFormat%.[[LocaleData]]).
  18. Set dateTimeFormat.[[Locale]] to r.[[Locale]].
  19. Let resolvedCalendar be r.[[ca]].
  20. Set dateTimeFormat.[[Calendar]] to resolvedCalendar.
  21. Set dateTimeFormat.[[NumberingSystem]] to r.[[nu]].
  22. Let resolvedLocaleData be r.[[LocaleData]].
  23. If hour12 is true, then
    1. Let hc be resolvedLocaleData.[[hourCycle12]].
  24. Else if hour12 is false, then
    1. Let hc be resolvedLocaleData.[[hourCycle24]].
  25. Else,
    1. Assert: hour12 is undefined.
    2. Let hc be r.[[hc]].
    3. If hc is null, set hc to resolvedLocaleData.[[hourCycle]].
  26. Set dateTimeFormat.[[HourCycle]] to hc.
  27. Let timeZone be ? Get(options, "timeZone").
  28. If timeZone is undefined, then
    1. If toLocaleStringTimeZone is present, then
      1. Set timeZone to toLocaleStringTimeZone.
    2. Else,
      1. Set timeZone to SystemTimeZoneIdentifier().
  29. Else,
    1. If toLocaleStringTimeZone is present, throw a TypeError exception.
    2. Set timeZone to ? ToString(timeZone).
  30. If IsTimeZoneOffsetString(timeZone) is true, then
    1. Let parseResult be ParseText(StringToCodePoints(timeZone), UTCOffsetUTCOffset[~SubMinutePrecision]).
    2. Assert: parseResult is a Parse Node.
    3. If parseResult contains more than one MinuteSecond Parse Node, throw a RangeError exception.
    4. Let offsetNanoseconds be ParseTimeZoneOffsetStringParseDateTimeUTCOffset(timeZone).
    5. Let offsetMinutes be offsetNanoseconds / (6 × 1010).
    6. Assert: offsetMinutes is an integer.
    7. Set timeZone to FormatOffsetTimeZoneIdentifier(offsetMinutes).
  31. Else if IsValidTimeZoneName(timeZone) is true, then
  32. Else,
    1. Let timeZoneIdentifierRecord be GetAvailableNamedTimeZoneIdentifier(timeZone).
    2. If timeZoneIdentifierRecord is empty, then
      1. Throw a RangeError exception.
    3. Set timeZone to CanonicalizeTimeZoneName(timeZone)timeZoneIdentifierRecord.[[Identifier]].
  33. Else,
    1. Throw a RangeError exception.
  34. Set dateTimeFormat.[[TimeZone]] to timeZone.
  35. Let formatOptions be a new Record.
  36. Set formatOptions.[[hourCycle]] to hc.
  37. Let hasExplicitFormatComponents be false.
  38. For each row of Table 16, except the header row, in table order, do
    1. Let prop be the name given in the Property column of the row.
    2. If prop is "fractionalSecondDigits", then
      1. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined).
    3. Else,
      1. Let values be a List whose elements are the strings given in the Values column of the row.
      2. Let value be ? GetOption(options, prop, string, values, undefined).
    4. Set formatOptions.[[<prop>]] to value.
    5. If value is not undefined, then
      1. Set hasExplicitFormatComponents to true.
  39. Let formatMatcher be ? GetOption(options, "formatMatcher", string, « "basic", "best fit" », "best fit").
  40. Let dateStyle be ? GetOption(options, "dateStyle", string, « "full", "long", "medium", "short" », undefined).
  41. Set dateTimeFormat.[[DateStyle]] to dateStyle.
  42. Let timeStyle be ? GetOption(options, "timeStyle", string, « "full", "long", "medium", "short" », undefined).
  43. Set dateTimeFormat.[[TimeStyle]] to timeStyle.
  44. If dateStyle is not undefined or timeStyle is not undefined, then
    1. If hasExplicitFormatComponents is true, then
      1. Throw a TypeError exception.
    2. If required is date and timeStyle is not undefined, then
      1. Throw a TypeError exception.
    3. If required is time and dateStyle is not undefined, then
      1. Throw a TypeError exception.
    4. Let styles be resolvedLocaleData.[[styles]].[[<resolvedCalendar>]].
    5. Let bestFormat be DateTimeStyleFormat(dateStyle, timeStyle, styles).
    6. If dateStyle is not undefined, then
      1. Set dateTimeFormat.[[TemporalPlainDateFormat]] to bestFormat.
      2. Set dateTimeFormat.[[TemporalPlainYearMonthFormat]] to bestFormat.
      3. Set dateTimeFormat.[[TemporalPlainMonthDayFormat]] to bestFormat.
    7. Else,
      1. Set dateTimeFormat.[[TemporalPlainDateFormat]] to null.
      2. Set dateTimeFormat.[[TemporalPlainYearMonthFormat]] to null.
      3. Set dateTimeFormat.[[TemporalPlainMonthDayFormat]] to null.
    8. If timeStyle is not undefined, then
      1. Set dateTimeFormat.[[TemporalPlainTimeFormat]] to bestFormat.
    9. Else,
      1. Set dateTimeFormat.[[TemporalPlainTimeFormat]] to null.
    10. Set dateTimeFormat.[[TemporalPlainDateTimeFormat]] to bestFormat.
    11. Set dateTimeFormat.[[TemporalInstantFormat]] to bestFormat.
  45. Else,
    1. Let needDefaults be true.
    2. If required is date or any, then
      1. For each property name prop of « "weekday", "year", "month", "day" », do
        1. Let value be formatOptions.[[<prop>]].
        2. If value is not undefined, set needDefaults to false.
    3. If required is time or any, then
      1. For each property name prop of « "dayPeriod", "hour", "minute", "second", "fractionalSecondDigits" », do
        1. Let value be formatOptions.[[<prop>]].
        2. If value is not undefined, set needDefaults to false.
    4. If needDefaults is true and defaults is either date or all, then
      1. For each property name prop of « "year", "month", "day" », do
        1. Set formatOptions.[[<prop>]] to "numeric".
    5. If needDefaults is true and defaults is either time or all, then
      1. For each property name prop of « "hour", "minute", "second" », do
        1. Set formatOptions.[[<prop>]] to "numeric".
    6. Let formats be resolvedLocaleData.[[formats]].[[<resolvedCalendar>]].
    7. If formatMatcher is "basic", then
      1. Let bestFormat be BasicFormatMatcher(formatOptions, formats).
    8. Else,
      1. Let bestFormat be BestFitFormatMatcher(formatOptions, formats).
    9. Let bestFormat be GetDateTimeFormat(formats, formatMatcher, formatOptions, required, defaults, all).
    10. Set dateTimeFormat.[[TemporalPlainDateFormat]] to GetDateTimeFormat(formats, formatMatcher, formatOptions, date, date, relevant).
    11. Set dateTimeFormat.[[TemporalPlainYearMonthFormat]] to GetDateTimeFormat(formats, formatMatcher, formatOptions, year-month, year-month, relevant).
    12. Set dateTimeFormat.[[TemporalPlainMonthDayFormat]] to GetDateTimeFormat(formats, formatMatcher, formatOptions, month-day, month-day, relevant).
    13. Set dateTimeFormat.[[TemporalPlainTimeFormat]] to GetDateTimeFormat(formats, formatMatcher, formatOptions, time, time, relevant).
    14. Set dateTimeFormat.[[TemporalPlainDateTimeFormat]] to GetDateTimeFormat(formats, formatMatcher, formatOptions, any, all, relevant).
    15. If toLocaleStringTimeZone is present, then
      1. Set dateTimeFormat.[[TemporalInstantFormat]] to GetDateTimeFormat(formats, formatMatcher, formatOptions, any, zoned-date-time, all).
    16. Else,
      1. Set dateTimeFormat.[[TemporalInstantFormat]] to GetDateTimeFormat(formats, formatMatcher, formatOptions, any, all, all).
  46. Set dateTimeFormat.[[DateTimeFormat]] to bestFormat.
  47. If bestFormat has a field [[hour]], then
    1. Set dateTimeFormat.[[HourCycle]] to hc.
  48. Return dateTimeFormat.

15.8 Properties of the Intl.DateTimeFormat Constructor

[...]

15.8.1 Internal slots

[...]

The value of the [[LocaleData]] internal slot is implementation-defined within the constraints described in 9.1 and the following additional constraints, for all locale values locale:

  • [[LocaleData]].[[<locale>]].[[nu]] must be a List that does not include the values "native", "traditio", or "finance".
  • [[LocaleData]].[[<locale>]].[[hc]] must be « null, "h11", "h12", "h23", "h24" ».
  • [[LocaleData]].[[<locale>]].[[hourCycle]] must be one of the String values "h11", "h12", "h23", or "h24".
  • [[LocaleData]].[[<locale>]].[[hourCycle12]] must be one of the String values "h11" or "h12".
  • [[LocaleData]].[[<locale>]].[[hourCycle24]] must be one of the String values "h23" or "h24".
  • [[LocaleData]].[[<locale>]] must have a [[formats]] field. The value of this [[formats]] field must be a Record with a [[<calendar>]] field for each calendar value calendar. The value of each [[<calendar>]] field must be a List of DateTime Format Records. Multiple Records in such a List may use the same subset of the fields as long as the corresponding values differ for at least one field. The following subsets must be available for each locale:
    • weekday, year, month, day, hour, minute, second, fractionalSecondDigits
    • weekday, year, month, day, hour, minute, second
    • weekday, year, month, day
    • year, month, day
    • year, month
    • month, day
    • month
    • hour, minute, second, fractionalSecondDigits
    • hour, minute, second
    • hour, minute
    • dayPeriod, hour
    • dayPeriod, hour, minute, second
    • dayPeriod, hour, minute
  • [[LocaleData]].[[<locale>]] must have a [[styles]] field. The value of this [[styles]] field must be a Record with a [[<calendar>]] field for each calendar value calendar. The value of each [[<calendar>]] field must be a DateTime Styles Record.

15.9 Abstract Operations for DateTimeFormat Objects

15.9.1 GetDateTimeFormat ( formats, matcher, options, required, defaults, inherit )

The abstract operation GetDateTimeFormat takes arguments formats (a List of DateTime Format Records), matcher ("basic" or "best fit"), options (a Record), required (date, time, year-month, month-day, or any), defaults (date, time, year-month, month-day, zoned-date-time, or all), and inherit (all or relevant) and returns a DateTime Format Record. It performs the following steps when called:

  1. If required is date, then
    1. Let requiredOptions be « "weekday", "year", "month", "day" ».
  2. Else if required is time, then
    1. Let requiredOptions be « "dayPeriod", "hour", "minute", "second", "fractionalSecondDigits" ».
  3. Else if required is year-month, then
    1. Let requiredOptions be « "year", "month" ».
  4. Else if required is month-day, then
    1. Let requiredOptions be « "month", "day" ».
  5. Else,
    1. Assert: required is any.
    2. Let requiredOptions be « "weekday", "year", "month", "day", "dayPeriod", "hour", "minute", "second", "fractionalSecondDigits" ».
  6. If defaults is date, then
    1. Let defaultOptions be « "year", "month", "day" ».
  7. Else if defaults is time, then
    1. Let defaultOptions be « "hour", "minute", "second" ».
  8. Else if defaults is year-month, then
    1. Let defaultOptions be « "year", "month" ».
  9. Else if defaults is month-day, then
    1. Let defaultOptions be « "month", "day" ».
  10. Else,
    1. Assert: defaults is zoned-date-time or all.
    2. Let defaultOptions be « "year", "month", "day", "hour", "minute", "second" ».
  11. If inherit is all, then
    1. Let formatOptions be a copy of options.
  12. Else,
    1. Let formatOptions be a new Record.
    2. If required is one of date, year-month, or any, then
      1. Set formatOptions.[[era]] to options.[[era]].
    3. If required is time or any, then
      1. Set formatOptions.[[hourCycle]] to options.[[hourCycle]].
  13. Let needDefaults be true.
  14. For each property name prop of requiredOptions, do
    1. Let value be options.[[<prop>]].
    2. If value is not undefined, then
      1. Set formatOptions.[[<prop>]] to value.
      2. Set needDefaults to false.
  15. If needDefaults is true, then
    1. For each property name prop of defaultOptions, do
      1. Set formatOptions.[[<prop>]] to "numeric".
    2. If defaults is zoned-date-time, then
      1. Set formatOptions.[[timeZoneName]] to "short".
  16. If matcher is "basic", then
    1. Let bestFormat be BasicFormatMatcher(formatOptions, formats).
  17. Else,
    1. Let bestFormat be BestFitFormatMatcher(formatOptions, formats).
  18. Return bestFormat.

15.9.2 DateTime Format Functions

A DateTime format function is an anonymous built-in function that has a [[DateTimeFormat]] internal slot.

When a DateTime format function F is called with optional argument date, the following steps are taken:

  1. Let dtf be F.[[DateTimeFormat]].
  2. Assert: dtf is an Object and dtf has an [[InitializedDateTimeFormat]] internal slot.
  3. If date is not provided or is undefined, then
    1. Let x be ! Call(%Date.now%, undefined).
  4. Else,
    1. Let x be ? ToNumberToDateTimeFormattable(date).
  5. Return ? FormatDateTime(dtf, x).

The "length" property of a DateTime format function is 1𝔽.

15.9.3 FormatDateTimePattern ( dateTimeFormat, format, pattern, x, epochNanoseconds )

The abstract operation FormatDateTimePattern takes arguments dateTimeFormat (an Intl.DateTimeFormat), format (a DateTime Format Record or a DateTime Range Pattern Format Record), pattern (a Pattern String), x (a Number), and epochNanoseconds (a BigInt) and returns either a normal completion containing a List of Records with fields [[Type]] (a String) and [[Value]] (a String), or a throw completion. It interprets x as a time value as specified in es2024, 21.4.1.1, and creates the corresponding parts for the epoch time epochNanoseconds according to pattern and to the effective locale and the formatting options of dateTimeFormat and format. It performs the following steps when called:

  1. Let x be TimeClip(x).
  2. If x is NaN, throw a RangeError exception.
  3. Let locale be dateTimeFormat.[[Locale]].
  4. Let nfOptions be OrdinaryObjectCreate(null).
  5. Perform ! CreateDataPropertyOrThrow(nfOptions, "useGrouping", false).
  6. Let nf be ! Construct(%Intl.NumberFormat%, « locale, nfOptions »).
  7. Let nf2Options be OrdinaryObjectCreate(null).
  8. Perform ! CreateDataPropertyOrThrow(nf2Options, "minimumIntegerDigits", 2𝔽).
  9. Perform ! CreateDataPropertyOrThrow(nf2Options, "useGrouping", false).
  10. Let nf2 be ! Construct(%Intl.NumberFormat%, « locale, nf2Options »).
  11. If format has a field [[fractionalSecondDigits]], then
    1. Let fractionalSecondDigits be format.[[fractionalSecondDigits]].
    2. Let nf3Options be OrdinaryObjectCreate(null).
    3. Perform ! CreateDataPropertyOrThrow(nf3Options, "minimumIntegerDigits", 𝔽(fractionalSecondDigits)).
    4. Perform ! CreateDataPropertyOrThrow(nf3Options, "useGrouping", false).
    5. Let nf3 be ! Construct(%Intl.NumberFormat%, « locale, nf3Options »).
  12. Let tm be ToLocalTime(((x) × 106)epochNanoseconds, dateTimeFormat.[[Calendar]], dateTimeFormat.[[TimeZone]]).
  13. Let patternParts be PartitionPattern(pattern).
  14. Let result be a new empty List.
  15. For each Record { [[Type]], [[Value]] } patternPart of patternParts, do
    1. Let p be patternPart.[[Type]].
    2. If p is "literal", then
      1. Append the Record { [[Type]]: "literal", [[Value]]: patternPart.[[Value]] } to result.
    3. Else if p is "fractionalSecondDigits", then
      1. Assert: format has a field [[fractionalSecondDigits]].
      2. Let v be tm.[[Millisecond]].
      3. Set v to floor(v × 10( fractionalSecondDigits - 3 )).
      4. Let fv be FormatNumeric(nf3, v).
      5. Append the Record { [[Type]]: "fractionalSecond", [[Value]]: fv } to result.
    4. Else if p is "dayPeriod", then
      1. Assert: format has a field [[dayPeriod]].
      2. Let f be format.[[dayPeriod]].
      3. Let fv be a String value representing the day period of tm in the form given by f; the String value depends upon the implementation and the effective locale of dateTimeFormat.
      4. Append the Record { [[Type]]: p, [[Value]]: fv } to result.
    5. Else if p is "timeZoneName", then
      1. Assert: format has a field [[timeZoneName]].
      2. Let f be format.[[timeZoneName]].
      3. Let v be dateTimeFormat.[[TimeZone]].
      4. Let fv be a String value representing v in the form given by f; the String value depends upon the implementation and the effective locale of dateTimeFormat. The String value may also depend on the value of the [[InDST]] field of tm if f is "short", "long", "shortOffset", or "longOffset". If the implementation does not have such a localized representation of f, then use the String value of v itself.
      5. Append the Record { [[Type]]: p, [[Value]]: fv } to result.
    6. Else if p matches a Property column of the row in Table 16, then
      1. Assert: format has a field [[<p>]].
      2. Let f be format.[[<p>]].
      3. Let v be the value of tm's field whose name is the Internal Slot column of the matching row.
      4. If p is "year" and v ≤ 0, set v to 1 - v.
      5. If p is "month", set v to v + 1.
      6. If p is "hour" and dateTimeFormat.[[HourCycle]] is "h11" or "h12", then
        1. Set v to v modulo 12.
        2. If v is 0 and dateTimeFormat.[[HourCycle]] is "h12", set v to 12.
      7. If p is "hour" and dateTimeFormat.[[HourCycle]] is "h24", then
        1. If v is 0, set v to 24.
      8. If f is "numeric", then
        1. Let fv be FormatNumeric(nf, v).
      9. Else if f is "2-digit", then
        1. Let fv be FormatNumeric(nf2, v).
        2. Let codePoints be StringToCodePoints(fv).
        3. Let count be the number of elements in codePoints.
        4. If count > 2, then
          1. Let tens be codePoints[count - 2].
          2. Let ones be codePoints[count - 1].
          3. Set fv to CodePointsToStringtens, ones »).
      10. Else if f is "narrow", "short", or "long", then
        1. Let fv be a String value representing v in the form given by f; the String value depends upon the implementation and the effective locale and calendar of dateTimeFormat. If p is "month", then the String value may also depend on whether format.[[day]] is present. If the implementation does not have a localized representation of f, then use the String value of v itself.
      11. Append the Record { [[Type]]: p, [[Value]]: fv } to result.
    7. Else if p is "ampm", then
      1. Let v be tm.[[Hour]].
      2. If v is greater than 11, then
        1. Let fv be an implementation and locale dependent String value representing "post meridiem".
      3. Else,
        1. Let fv be an implementation and locale dependent String value representing "ante meridiem".
      4. Append the Record { [[Type]]: "dayPeriod", [[Value]]: fv } to result.
    8. Else if p is "relatedYear", then
      1. Let v be tm.[[RelatedYear]].
      2. Let fv be FormatNumeric(nf, v).
      3. Append the Record { [[Type]]: "relatedYear", [[Value]]: fv } to result.
    9. Else if p is "yearName", then
      1. Let v be tm.[[YearName]].
      2. Let fv be an implementation and locale dependent String value representing v.
      3. Append the Record { [[Type]]: "yearName", [[Value]]: fv } to result.
    10. Else,
      1. Let unknown be an implementation-, locale-, and numbering system-dependent String based on xepochNanoseconds and p.
      2. Append the Record { [[Type]]: "unknown", [[Value]]: unknown } to result.
  16. Return result.
Note
It is recommended that implementations use the locale and calendar dependent strings provided by the Common Locale Data Repository (available at https://cldr.unicode.org/), and use CLDR "abbreviated" strings for DateTimeFormat "short" strings, and CLDR "wide" strings for DateTimeFormat "long" strings.

15.9.4 PartitionDateTimePattern ( dateTimeFormat, x )

The abstract operation PartitionDateTimePattern takes arguments dateTimeFormat (an Intl.DateTimeFormat) and x (a Number or an Object for which IsTemporalObject returns true) and returns either a normal completion containing a List of Records with fields [[Type]] (a String) and [[Value]] (a String), or a throw completion. It interprets x as a time value as specified in es2024, 21.4.1.1an epoch time, and creates the corresponding parts according to the type of x, effective locale, and the formatting options of dateTimeFormat. It performs the following steps when called:

  1. Let format be dateTimeFormat.[[DateTimeFormat]].
  2. Let xFormatRecord be ? HandleDateTimeValue(dateTimeFormat, x).
  3. Let format be xFormatRecord.[[Format]].
  4. If format has a field [[hour]] and dateTimeFormat.[[HourCycle]] is "h11" or "h12", then
    1. Let pattern be format.[[pattern12]].
  5. Else,
    1. Let pattern be format.[[pattern]].
  6. Let result be FormatDateTimePattern(dateTimeFormat, format, pattern, xxFormatRecord.[[EpochNanoseconds]]).
  7. Return result.

15.9.5 FormatDateTime ( dateTimeFormat, x )

The abstract operation FormatDateTime takes arguments dateTimeFormat (an Intl.DateTimeFormat) and x (a Number or an Object for which IsTemporalObject returns true) and returns either a normal completion containing a String or a throw completion. It performs the following steps when called:

  1. Let parts be ? PartitionDateTimePattern(dateTimeFormat, x).
  2. Let result be the empty String.
  3. For each Record { [[Type]], [[Value]] } part of parts, do
    1. Set result to the string-concatenation of result and part.[[Value]].
  4. Return result.

15.9.6 FormatDateTimeToParts ( dateTimeFormat, x )

The abstract operation FormatDateTimeToParts takes arguments dateTimeFormat (an Intl.DateTimeFormat) and x (a Number or an Object for which IsTemporalObject returns true) and returns either a normal completion containing an Array or a throw completion. It performs the following steps when called:

  1. Let parts be ? PartitionDateTimePattern(dateTimeFormat, x).
  2. Let result be ! ArrayCreate(0).
  3. Let n be 0.
  4. For each Record { [[Type]], [[Value]] } part of parts, do
    1. Let O be OrdinaryObjectCreate(%Object.prototype%).
    2. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
    3. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
    4. Perform ! CreateDataPropertyOrThrow(result, ! ToString(𝔽(n)), O).
    5. Increment n by 1.
  5. Return result.

15.9.7 PartitionDateTimeRangePattern ( dateTimeFormat, x, y )

The abstract operation PartitionDateTimeRangePattern takes arguments dateTimeFormat (an Intl.DateTimeFormat), x (a Number or an Object for which IsTemporalObject returns true), and y (a Number or an Object for which IsTemporalObject returns true) and returns either a normal completion containing a List of Records with fields [[Type]] (a String), [[Value]] (a String), and [[Source]] (a String), or a throw completion. It interprets x and y a time value as specified in es2024, 21.4.1.1epoch times, and creates the corresponding parts according to the types of x and y, effective locale, and the formatting options of dateTimeFormat. It performs the following steps when called:

  1. Let x be TimeClip(x).
  2. If x is NaN, throw a RangeError exception.
  3. Let y be TimeClip(y).
  4. If y is NaN, throw a RangeError exception.
  5. If IsTemporalObject(x) is true or IsTemporalObject(y) is true, then
    1. If SameTemporalType(x, y) is false, throw a TypeError exception.
  6. Let xFormatRecord be ? HandleDateTimeValue(dateTimeFormat, x).
  7. Let yFormatRecord be ? HandleDateTimeValue(dateTimeFormat, y).
  8. Let tm1 be ToLocalTime(((x) × 106)xFormatRecord.[[EpochNanoseconds]], dateTimeFormat.[[Calendar]], dateTimeFormat.[[TimeZone]]).
  9. Let tm2 be ToLocalTime(((y) × 106)yFormatRecord.[[EpochNanoseconds]], dateTimeFormat.[[Calendar]], dateTimeFormat.[[TimeZone]]).
  10. Let format be dateTimeFormat.[[DateTimeFormat]].
  11. Let format be xFormatRecord.[[Format]].
  12. Assert: format is equal to yFormatRecord.[[Format]].
  13. If format has a field [[hour]] and dateTimeFormat.[[HourCycle]] is "h11" or "h12", then
    1. Let pattern be format.[[pattern12]].
    2. Let rangePatterns be format.[[rangePatterns12]].
  14. Else,
    1. Let pattern be format.[[pattern]].
    2. Let rangePatterns be format.[[rangePatterns]].
  15. Let selectedRangePattern be undefined.
  16. Let relevantFieldsEqual be true.
  17. Let checkMoreFields be true.
  18. For each row of Table 6, except the header row, in table order, do
    1. Let fieldName be the name given in the Field Name column of the row.
    2. If rangePatterns has a field whose name is fieldName, let rangePattern be rangePatterns' field whose name is fieldName; else let rangePattern be undefined.
    3. If selectedRangePattern is not undefined and rangePattern is undefined, then
      1. NOTE: Because there is no range pattern for differences at or below this field, no further checks will be performed.
      2. Set checkMoreFields to false.
    4. If fieldName is not equal to [[Default]] and relevantFieldsEqual is true and checkMoreFields is true, then
      1. Set selectedRangePattern to rangePattern.
      2. If fieldName is [[AmPm]], then
        1. If tm1.[[Hour]] is less than 12, let v1 be "am"; else let v1 be "pm".
        2. If tm2.[[Hour]] is less than 12, let v2 be "am"; else let v2 be "pm".
      3. Else if fieldName is [[DayPeriod]], then
        1. Let v1 be a String value representing the day period of tm1; the String value depends upon the implementation and the effective locale of dateTimeFormat.
        2. Let v2 be a String value representing the day period of tm2; the String value depends upon the implementation and the effective locale of dateTimeFormat.
      4. Else if fieldName is [[FractionalSecondDigits]], then
        1. Let fractionalSecondDigits be dateTimeFormat.[[FractionalSecondDigits]].
        2. If fractionalSecondDigits is undefined, then
          1. Set fractionalSecondDigits to 3.
        3. Let exp be fractionalSecondDigits - 3.
        4. Let v1 be floor(tm1.[[Millisecond]] × 10exp).
        5. Let v2 be floor(tm2.[[Millisecond]] × 10exp).
      5. Else,
        1. Let v1 be tm1's field whose name is fieldName.
        2. Let v2 be tm2's field whose name is fieldName.
      6. If v1 is not equal to v2, then
        1. Set relevantFieldsEqual to false.
  19. If relevantFieldsEqual is true, then
    1. Let collapsedResult be a new empty List.
    2. Let resultParts be ! FormatDateTimePattern(dateTimeFormat, format, pattern, x).
    3. For each Record { [[Type]], [[Value]] } r of resultParts, do
      1. Append the Record { [[Type]]: r.[[Type]], [[Value]]: r.[[Value]], [[Source]]: "shared" } to collapsedResult.
    4. Return collapsedResult.
  20. Let rangeResult be a new empty List.
  21. If selectedRangePattern is undefined, then
    1. Set selectedRangePattern to rangePatterns.[[Default]].
  22. For each Record { [[Pattern]], [[Source]] } rangePatternPart of selectedRangePattern.[[PatternParts]], do
    1. Let pattern be rangePatternPart.[[Pattern]].
    2. Let source be rangePatternPart.[[Source]].
    3. If source is "startRange" or "shared", then
      1. Let z be x.
    4. Else,
      1. Let z be y.
    5. Let resultParts be ! FormatDateTimePattern(dateTimeFormat, selectedRangePattern, pattern, z).
    6. For each Record { [[Type]], [[Value]] } r of resultParts, do
      1. Append the Record { [[Type]]: r.[[Type]], [[Value]]: r.[[Value]], [[Source]]: source } to rangeResult.
  23. Return rangeResult.

15.9.8 FormatDateTimeRange ( dateTimeFormat, x, y )

The abstract operation FormatDateTimeRange takes arguments dateTimeFormat (an Intl.DateTimeFormat), x (a Number or an Object for which IsTemporalObject returns true), and y (a Number or an Object for which IsTemporalObject returns true) and returns either a normal completion containing a String or a throw completion. It performs the following steps when called:

  1. Let parts be ? PartitionDateTimeRangePattern(dateTimeFormat, x, y).
  2. Let result be the empty String.
  3. For each Record { [[Type]], [[Value]], [[Source]] } part of parts, do
    1. Set result to the string-concatenation of result and part.[[Value]].
  4. Return result.

15.9.9 FormatDateTimeRangeToParts ( dateTimeFormat, x, y )

The abstract operation FormatDateTimeRangeToParts takes arguments dateTimeFormat (an Intl.DateTimeFormat), x (a Number or an Object for which IsTemporalObject returns true), and y (a Number or an Object for which IsTemporalObject returns true) and returns either a normal completion containing an Array or a throw completion. It performs the following steps when called:

  1. Let parts be ? PartitionDateTimeRangePattern(dateTimeFormat, x, y).
  2. Let result be ! ArrayCreate(0).
  3. Let n be 0.
  4. For each Record { [[Type]], [[Value]], [[Source]] } part of parts, do
    1. Let O be OrdinaryObjectCreate(%Object.prototype%).
    2. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
    3. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
    4. Perform ! CreateDataPropertyOrThrow(O, "source", part.[[Source]]).
    5. Perform ! CreateDataPropertyOrThrow(result, ! ToString(𝔽(n)), O).
    6. Increment n by 1.
  5. Return result.

15.9.10 ToDateTimeFormattable ( value )

The abstract operation ToDateTimeFormattable takes argument value (an ECMAScript language value, but not undefined) and returns either a normal completion containing either a Number or an Object for which IsTemporalObject returns true, or a throw completion. It converts value to a value that can be formatted by an %Intl.DateTimeFormat% object. It performs the following steps when called:

  1. If IsTemporalObject(value) is true, return value.
  2. Return ? ToNumber(value).

15.9.11 IsTemporalObject ( value )

The abstract operation IsTemporalObject takes argument value (an ECMAScript language value) and returns a Boolean. It performs the following steps when called:

  1. If value is not an Object, then
    1. Return false.
  2. If value does not have an [[InitializedTemporalDate]], [[InitializedTemporalTime]], [[InitializedTemporalDateTime]], [[InitializedTemporalZonedDateTime]], [[InitializedTemporalYearMonth]], [[InitializedTemporalMonthDay]], or [[InitializedTemporalInstant]] internal slot, then
    1. Return false.
  3. Return true.

15.9.12 SameTemporalType ( x, y )

The abstract operation SameTemporalType takes arguments x (an ECMAScript language value) and y (an ECMAScript language value) and returns a Boolean. It determines whether x and y are both instances of the same Temporal type. It performs the following steps when called:

  1. If either of IsTemporalObject(x) or IsTemporalObject(y) is false, return false.
  2. If x has an [[InitializedTemporalDate]] internal slot and y does not, return false.
  3. If x has an [[InitializedTemporalTime]] internal slot and y does not, return false.
  4. If x has an [[InitializedTemporalDateTime]] internal slot and y does not, return false.
  5. If x has an [[InitializedTemporalZonedDateTime]] internal slot and y does not, return false.
  6. If x has an [[InitializedTemporalYearMonth]] internal slot and y does not, return false.
  7. If x has an [[InitializedTemporalMonthDay]] internal slot and y does not, return false.
  8. If x has an [[InitializedTemporalInstant]] internal slot and y does not, return false.
  9. Return true.

15.9.13 Value Format Records

Each Value Format Record has the fields defined in Table 30.

Table 30: Record returned by HandleDateTimeValue
Field Name Value Type
[[Format]] a DateTime Format Record
[[EpochNanoseconds]] a BigInt

15.9.14 HandleDateTimeTemporalDate ( dateTimeFormat, temporalDate )

The abstract operation HandleDateTimeTemporalDate takes arguments dateTimeFormat (an Intl.DateTimeFormat) and temporalDate (a Temporal.PlainDate) and returns either a normal completion containing a Value Format Record or a throw completion. It performs the following steps when called:

  1. If temporalDate.[[Calendar]] is not dateTimeFormat.[[Calendar]] or "iso8601", throw a RangeError exception.
  2. Let isoDateTime be ISO Date-Time Record { [[Year]]: temporalDate.[[ISOYear]], [[Month]]: temporalDate.[[ISOMonth]], [[Day]]: temporalDate.[[ISODay]], [[Hour]]: 12, [[Minute]]: 0, [[Second]]: 0, [[Millisecond]]: 0, [[Microsecond]]: 0, [[Nanosecond]]: 0 }.
  3. Let epochNs be ? GetEpochNanosecondsFor(dateTimeFormat.[[TimeZone]], isoDateTime, "compatible").
  4. Let format be dateTimeFormat.[[TemporalPlainDateFormat]].
  5. If format is null, throw a TypeError exception.
  6. Return Value Format Record { [[Format]]: format, [[EpochNanoseconds]]: epochNs  }.

15.9.15 HandleDateTimeTemporalYearMonth ( dateTimeFormat, temporalYearMonth )

The abstract operation HandleDateTimeTemporalYearMonth takes arguments dateTimeFormat (an Intl.DateTimeFormat) and temporalYearMonth (a Temporal.PlainYearMonth) and returns either a normal completion containing a Value Format Record or a throw completion. It performs the following steps when called:

  1. If temporalYearMonth.[[Calendar]] is not equal to dateTimeFormat.[[Calendar]], then
    1. Throw a RangeError exception.
  2. Let isoDateTime be ISO Date-Time Record { [[Year]]: temporalYearMonth.[[ISOYear]], [[Month]]: temporalYearMonth.[[ISOMonth]], [[Day]]: temporalYearMonth.[[ISODay]], [[Hour]]: 12, [[Minute]]: 0, [[Second]]: 0, [[Millisecond]]: 0, [[Microsecond]]: 0, [[Nanosecond]]: 0 }.
  3. Let epochNs be ? GetEpochNanosecondsFor(dateTimeFormat.[[TimeZone]], isoDateTime, "compatible").
  4. Let format be dateTimeFormat.[[TemporalPlainYearMonthFormat]].
  5. If format is null, throw a TypeError exception.
  6. Return Value Format Record { [[Format]]: format, [[EpochNanoseconds]]: epochNs  }.

15.9.16 HandleDateTimeTemporalMonthDay ( dateTimeFormat, temporalMonthDay )

The abstract operation HandleDateTimeTemporalMonthDay takes arguments dateTimeFormat (an Intl.DateTimeFormat) and temporalMonthDay (a Temporal.PlainMonthDay) and returns either a normal completion containing a Value Format Record or a throw completion. It performs the following steps when called:

  1. If temporalMonthDay.[[Calendar]] is not equal to dateTimeFormat.[[Calendar]], then
    1. Throw a RangeError exception.
  2. Let isoDateTime be ISO Date-Time Record { [[Year]]: temporalMonthDay.[[ISOYear]], [[Month]]: temporalMonthDay.[[ISOMonth]], [[Day]]: temporalMonthDay.[[ISODay]], [[Hour]]: 12, [[Minute]]: 0, [[Second]]: 0, [[Millisecond]]: 0, [[Microsecond]]: 0, [[Nanosecond]]: 0 }.
  3. Let epochNs be ? GetEpochNanosecondsFor(dateTimeFormat.[[TimeZone]], isoDateTime, "compatible").
  4. Let format be dateTimeFormat.[[TemporalPlainMonthDayFormat]].
  5. If format is null, throw a TypeError exception.
  6. Return Value Format Record { [[Format]]: format, [[EpochNanoseconds]]: epochNs  }.

15.9.17 HandleDateTimeTemporalTime ( dateTimeFormat, temporalTime )

The abstract operation HandleDateTimeTemporalTime takes arguments dateTimeFormat (an Intl.DateTimeFormat) and temporalTime (a Temporal.PlainTime) and returns either a normal completion containing a Value Format Record or a throw completion. It performs the following steps when called:

  1. Let isoDateTime be ISO Date-Time Record { [[Year]]: 1970, [[Month]]: 1, [[Day]]: 1, [[Hour]]: temporalTime.[[ISOHour]], [[Minute]]: temporalTime.[[ISOMinute]], [[Second]]: temporalTime.[[ISOSecond]], [[Millisecond]]: temporalTime.[[ISOMillisecond]], [[Microsecond]]: temporalTime.[[ISOMicrosecond]], [[Nanosecond]]: temporalTime.[[ISONanosecond]] }.
  2. Let epochNs be ? GetEpochNanosecondsFor(dateTimeFormat.[[TimeZone]], isoDateTime, "compatible").
  3. Let format be dateTimeFormat.[[TemporalPlainTimeFormat]].
  4. If format is null, throw a TypeError exception.
  5. Return Value Format Record { [[Format]]: format, [[EpochNanoseconds]]: epochNs  }.

15.9.18 HandleDateTimeTemporalDateTime ( dateTimeFormat, dateTime )

The abstract operation HandleDateTimeTemporalDateTime takes arguments dateTimeFormat (an Intl.DateTimeFormat) and dateTime (a Temporal.PlainDateTime) and returns either a normal completion containing a Value Format Record or a throw completion. It performs the following steps when called:

  1. If dateTime.[[Calendar]] is not "iso8601" and not equal to dateTimeFormat.[[Calendar]], then
    1. Throw a RangeError exception.
  2. Let isoDateTime be PlainDateTimeToISODateTimeRecord(dateTime).
  3. Let epochNs be ? GetEpochNanosecondsFor(dateTimeFormat.[[TimeZone]], isoDateTime, "compatible").
  4. Let format be dateTimeFormat.[[TemporalPlainDateTimeFormat]].
  5. Return Value Format Record { [[Format]]: format, [[EpochNanoseconds]]: epochNs  }.

15.9.19 HandleDateTimeTemporalInstant ( dateTimeFormat, instant )

The abstract operation HandleDateTimeTemporalInstant takes arguments dateTimeFormat (an Intl.DateTimeFormat) and instant (a Temporal.Instant) and returns a Value Format Record. It performs the following steps when called:

  1. Let format be dateTimeFormat.[[TemporalInstantFormat]].
  2. Return Value Format Record { [[Format]]: format, [[EpochNanoseconds]]: instant.[[Nanoseconds]]  }.

15.9.20 HandleDateTimeOthers ( dateTimeFormat, x )

The abstract operation HandleDateTimeOthers takes arguments dateTimeFormat (an Intl.DateTimeFormat) and x (a Number) and returns either a normal completion containing a Value Format Record or a throw completion. It performs the following steps when called:

  1. Set x to TimeClip(x).
  2. If x is NaN, throw a RangeError exception.
  3. Let epochNanoseconds be ((x) × 106).
  4. Let format be dateTimeFormat.[[DateTimeFormat]].
  5. Return Value Format Record { [[Format]]: format, [[EpochNanoseconds]]: epochNanoseconds  }.

15.9.21 HandleDateTimeValue ( dateTimeFormat, x )

The abstract operation HandleDateTimeValue takes arguments dateTimeFormat (an Intl.DateTimeFormat) and x (a Number, or an Object for which IsTemporalObject returns true) and returns either a normal completion containing a Value Format Record or a throw completion. It performs the following steps when called:

  1. If x is an Object, then
    1. If x has an [[InitializedTemporalDate]] internal slot, then
      1. Return ? HandleDateTimeTemporalDate(dateTimeFormat, x).
    2. If x has an [[InitializedTemporalYearMonth]] internal slot, then
      1. Return ? HandleDateTimeTemporalYearMonth(dateTimeFormat, x).
    3. If x has an [[InitializedTemporalMonthDay]] internal slot, then
      1. Return ? HandleDateTimeTemporalMonthDay(dateTimeFormat, x).
    4. If x has an [[InitializedTemporalTime]] internal slot, then
      1. Return ? HandleDateTimeTemporalTime(dateTimeFormat, x).
    5. If x has an [[InitializedTemporalDateTime]] internal slot, then
      1. Return ? HandleDateTimeTemporalDateTime(dateTimeFormat, x).
    6. If x has an [[InitializedTemporalInstant]] internal slot, then
      1. Return HandleDateTimeTemporalInstant(dateTimeFormat, x).
    7. Assert: x has an [[InitializedTemporalZonedDateTime]] internal slot.
    8. Throw a TypeError exception.
  2. Return ? HandleDateTimeOthers(dateTimeFormat, x).

15.9.22 ToLocalTime ( epochNs, calendar, timeZoneIdentifier )

The implementation-defined abstract operation ToLocalTime takes arguments epochNs (a BigInt), calendar (a String), and timeZoneIdentifier (a String) and returns a ToLocalTime Record. It performs the following steps when called:

  1. If IsTimeZoneOffsetString(timeZoneIdentifier) is true, then
    1. Let offsetNs be ParseTimeZoneOffsetString(timeZoneIdentifier).
  2. Else,
    1. Assert: IsValidTimeZoneName(timeZoneIdentifier) is true.
    2. Let offsetNs be GetNamedTimeZoneOffsetNanoseconds(timeZoneIdentifier, epochNs).
  3. Let tz be (epochNs) + offsetNs.
  4. If calendar is "gregory", then
    1. Return a ToLocalTime Record with fields calculated from tz according to Table 17.
  5. Else,
    1. Return a ToLocalTime Record with the fields calculated from tz for the given calendar. The calculations should use best available information about the specified calendar. Given the same values of epochNs, calendar, and timeZoneIdentifier, the result must be the same for the lifetime of the surrounding agent.
Note 1
A conforming implementation must recognize "UTC" and all Zone and Link names from the IANA Time Zone Database (and only such names), and use best available current and historical information about their offsets from UTC and their daylight saving time rules in calculations.
Note 2
Time zone information is subject to change, and host environments may update their time zone database at any time. At a minimum, implementations must ensure that the time zone information for each particular value of timeZone individually remains constant starting from the time it is first accessed, for the lifetime of the surrounding agent. Furthermore, it is recommended that the time zone information for all values of timeZone as a whole (i.e. the time zone database) remains the same for the lifetime of the surrounding agent.

15.10 Properties of the Intl.DateTimeFormat Prototype Object

15.10.1 Intl.DateTimeFormat.prototype.formatToParts ( date )

When the formatToParts method is called with an argument date, the following steps are taken:

  1. Let dtf be the this value.
  2. Perform ? RequireInternalSlot(dtf, [[InitializedDateTimeFormat]]).
  3. If date is undefined, then
    1. Let x be ! Call(%Date.now%, undefined).
  4. Else,
    1. Let x be ? ToNumberToDateTimeFormattable(date).
  5. Return ? FormatDateTimeToParts(dtf, x).

15.10.2 Intl.DateTimeFormat.prototype.formatRange ( startDate, endDate )

When the formatRange method is called with an arguments startDate and endDate, the following steps are taken:

  1. Let dtf be this value.
  2. Perform ? RequireInternalSlot(dtf, [[InitializedDateTimeFormat]]).
  3. If startDate is undefined or endDate is undefined, throw a TypeError exception.
  4. Let x be ? ToNumberToDateTimeFormattable(startDate).
  5. Let y be ? ToNumberToDateTimeFormattable(endDate).
  6. Return ? FormatDateTimeRange(dtf, x, y).

15.10.3 Intl.DateTimeFormat.prototype.formatRangeToParts ( startDate, endDate )

When the formatRangeToParts method is called with arguments startDate and endDate, the following steps are taken:

  1. Let dtf be this value.
  2. Perform ? RequireInternalSlot(dtf, [[InitializedDateTimeFormat]]).
  3. If startDate is undefined or endDate is undefined, throw a TypeError exception.
  4. Let x be ? ToNumberToDateTimeFormattable(startDate).
  5. Let y be ? ToNumberToDateTimeFormattable(endDate).
  6. Return ? FormatDateTimeRangeToParts(dtf, x, y).

15.10.4 Intl.DateTimeFormat.prototype.resolvedOptions ( )

This function provides access to the locale and options computed during initialization of the object.

  1. Let dtf be the this value.
  2. If the implementation supports the normative optional constructor mode of 4.3 Note 1, then
    1. Set dtf to ? UnwrapDateTimeFormat(dtf).
  3. Perform ? RequireInternalSlot(dtf, [[InitializedDateTimeFormat]]).
  4. Let format be dtf.[[DateTimeFormat]].
  5. Let options be OrdinaryObjectCreate(%Object.prototype%).
  6. For each row of Table 15, except the header row, in table order, do
    1. Let p be the Property value of the current row.
    2. If there is an Internal Slot value in the current row, then
      1. Let v be the value of dtf's internal slot whose name is the Internal Slot value of the current row.
      2. If p is neither "hourCycle" nor "hour12", or if format has a field [[hour]], then
        1. Let v be the value of dtf's internal slot whose name is the Internal Slot value of the current row.
      3. Else,
        1. Let v be undefined.
    3. Else,
      1. Let format be dtf.[[DateTimeFormat]].
      2. If format has a field [[<p>]] and dtf.[[DateStyle]] is undefined and dtf.[[TimeStyle]] is undefined, then
        1. Let v be format.[[<p>]].
      3. Else,
        1. Let v be undefined.
    4. If v is not undefined, then
      1. If there is a Conversion value in the current row, then
        1. Let conversion be the Conversion value of the current row.
        2. If conversion is hour12, then
          1. If v is "h11" or "h12", set v to true. Otherwise, set v to false.
        3. Else,
          1. Assert: conversion is number.
          2. Set v to 𝔽(v).
      2. Perform ! CreateDataPropertyOrThrow(options, p, v).
  7. Return options.

For web compatibility reasons, if the property "hourCycle" is set, the "hour12" property should be set to true when "hourCycle" is "h11" or "h12", or to false when "hourCycle" is "h23" or "h24".

Note 1
In this version of the API, the "timeZone" property will be the identifier of the host environment's time zone if no "timeZone" property was provided in the options object provided to the Intl.DateTimeFormat constructor. The first edition left the "timeZone" property undefined in this case.
Note 2
For compatibility with versions prior to the fifth edition, the "hour12" property is set in addition to the "hourCycle" property.

15.11 Properties of Intl.DateTimeFormat Instances

Intl.DateTimeFormat instances are ordinary objects that inherit properties from %Intl.DateTimeFormat.prototype%.

Intl.DateTimeFormat instances have an [[InitializedDateTimeFormat]] internal slot.

Intl.DateTimeFormat instances also have several internal slots that are computed by the constructor:

  • [[Locale]] is a String value with the language tag of the locale whose localization is used for formatting.
  • [[Calendar]] is a String value representing the Unicode Calendar Identifier used for formatting.
  • [[NumberingSystem]] is a String value representing the Unicode Number System Identifier used for formatting.
  • [[TimeZone]] is a String value used for formatting that is either a time zone identifier from the IANA Time Zone Database or a UTC offset in ISO 8601 extended format.
  • [[HourCycle]] is a String value indicating whether the 12-hour format ("h11", "h12") or the 24-hour format ("h23", "h24") should be used. "h11" and "h23" start with hour 0 and go up to 11 and 23 respectively. "h12" and "h24" start with hour 1 and go up to 12 and 24. [[HourCycle]] is only used when [[DateTimeFormat]] has an [[hour]] field.
  • [[DateStyle]], [[TimeStyle]] are each either undefined, or a String value with values "full", "long", "medium", or "short".
  • [[DateTimeFormat]] is a DateTime Format Record.
  • [[TemporalPlainDateFormat]] is a DateTime Format Record or null.
  • [[TemporalPlainYearMonthFormat]] is a DateTime Format Record or null.
  • [[TemporalPlainMonthDayFormat]] is a DateTime Format Record or null.
  • [[TemporalPlainTimeFormat]] is a DateTime Format Record or null.
  • [[TemporalPlainDateTimeFormat]] is a DateTime Format Record.
  • [[TemporalInstantFormat]] is a DateTime Format Records

Finally, Intl.DateTimeFormat instances have a [[BoundFormat]] internal slot that caches the function returned by the format accessor (11.3.3).

15.12 Locale Sensitive Functions of the ECMAScript Language Specification

15.12.1 Properties of the Temporal.Duration Prototype Object

15.12.1.1 Temporal.Duration.prototype.toLocaleString ( [ locales [ , options ] ] )

Editor's Note

This function is currently not specified. See the Intl.DurationFormat proposal.

15.12.2 Properties of the Temporal.Instant Prototype Object

15.12.2.1 Temporal.Instant.prototype.toLocaleString ( [ locales [ , options ] ] )

This definition supersedes the definition provided in 8.3.12.

This method performs the following steps when called:

  1. Let instant be the this value.
  2. Perform ? RequireInternalSlot(instant, [[InitializedTemporalInstant]]).
  3. Let dateFormat be ? CreateDateTimeFormat(%Intl.DateTimeFormat%, locales, options, any, all).
  4. Return ? FormatDateTime(dateFormat, instant).

15.12.3 Properties of the Temporal.PlainDate Prototype Object

15.12.3.1 Temporal.PlainDate.prototype.toLocaleString ( [ locales [ , options ] ] )

This definition supersedes the definition provided in 3.3.31.

This method performs the following steps when called:

  1. Let temporalDate be the this value.
  2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
  3. Let dateFormat be ? CreateDateTimeFormat(%Intl.DateTimeFormat%, locales, options, date, date).
  4. Return ? FormatDateTime(dateFormat, temporalDate).

15.12.4 Properties of the Temporal.PlainDateTime Prototype Object

15.12.4.1 Temporal.PlainDateTime.prototype.toLocaleString ( [ locales [ , options ] ] )

This definition supersedes the definition provided in 5.3.35.

This method performs the following steps when called:

  1. Let dateTime be the this value.
  2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
  3. Let dateFormat be ? CreateDateTimeFormat(%Intl.DateTimeFormat%, locales, options, any, all).
  4. Return ? FormatDateTime(dateFormat, dateTime).

15.12.5 Properties of the Temporal.PlainMonthDay Prototype Object

15.12.5.1 Temporal.PlainMonthDay.prototype.toLocaleString ( [ locales [ , options ] ] )

This definition supersedes the definition provided in 10.3.9.

This method performs the following steps when called:

  1. Let monthDay be the this value.
  2. Perform ? RequireInternalSlot(monthDay, [[InitializedTemporalMonthDay]]).
  3. Let dateFormat be ? CreateDateTimeFormat(%Intl.DateTimeFormat%, locales, options, date, date).
  4. Return ? FormatDateTime(dateFormat, monthDay).

15.12.6 Properties of the Temporal.PlainTime Prototype Object

15.12.6.1 Temporal.PlainTime.prototype.toLocaleString ( [ locales [ , options ] ] )

This definition supersedes the definition provided in 4.3.17.

This method performs the following steps when called:

  1. Let temporalTime be the this value.
  2. Perform ? RequireInternalSlot(temporalTime, [[InitializedTemporalTime]]).
  3. Let dateFormat be ? CreateDateTimeFormat(%Intl.DateTimeFormat%, locales, options, time, time).
  4. Return ? FormatDateTime(dateFormat, temporalTime).

15.12.7 Properties of the Temporal.PlainYearMonth Prototype Object

15.12.7.1 Temporal.PlainYearMonth.prototype.toLocaleString ( [ locales [ , options ] ] )

This definition supersedes the definition provided in 9.3.20.

This method performs the following steps when called:

  1. Let yearMonth be the this value.
  2. Perform ? RequireInternalSlot(yearMonth, [[InitializedTemporalYearMonth]]).
  3. Let dateFormat be ? CreateDateTimeFormat(%Intl.DateTimeFormat%, locales, options, date, date).
  4. Return ? FormatDateTime(dateFormat, yearMonth).

15.12.8 Properties of the Temporal.ZonedDateTime Prototype Object

15.12.8.1 Temporal.ZonedDateTime.prototype.toLocaleString ( [ locales [ , options ] ] )

This definition supersedes the definition provided in 6.3.42.

This method performs the following steps when called:

  1. Let zonedDateTime be the this value.
  2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
  3. Let timeZone be zonedDateTime.[[TimeZone]].
  4. Let timeZoneParseResult be ? ParseTimeZoneIdentifier(timeZone).
  5. If timeZoneParseResult.[[OffsetMinutes]] is empty, then
    1. Let timeZoneIdentifierRecord be GetAvailableNamedTimeZoneIdentifier(timeZone).
    2. If timeZoneIdentifierRecord is empty, throw a RangeError exception.
    3. Set timeZone to timeZoneIdentifierRecord.[[Identifier]].
  6. Else,
    1. Set timeZone to FormatOffsetTimeZoneIdentifier(timeZoneParseResult.[[OffsetMinutes]]).
  7. Let dateTimeFormat be ? CreateDateTimeFormat(%Intl.DateTimeFormat%, locales, options, any, all, timeZone).
  8. If zonedDateTime.[[Calendar]] is not "iso8601" and CalendarEquals(zonedDateTime.[[Calendar]], dateTimeFormat.[[Calendar]]) is false, then
    1. Throw a RangeError exception.
  9. Let instant be ! CreateTemporalInstant(zonedDateTime.[[Nanoseconds]]).
  10. Return ? FormatDateTime(dateTimeFormat, instant).

A Copyright & Software License

Copyright Notice

© 2024 Maggie Pint, Matt Johnson, Brian Terlson, Daniel Ehrenberg, Philipp Dunkel, Sasha Pierson, Ujjwal Sharma, Philip Chimento, Justin Grant

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.