From e4e240e053ba3c7d07f318b4933b9a1371fb23e3 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Sun, 15 Nov 2020 15:01:46 -0800 Subject: [PATCH] Refactor calendars to eliminate multiple parent classes We had originally decided to go with a scheme where the value of the [[Identifier]] internal slot determines the behaviour of the calendar methods, and there are not individual parent classes for each built-in calendar. This implements that scheme. Merges most of the spec text of ISO8601Calendar into Calendar. Closes: #847 See: #300 --- polyfill/lib/calendar.mjs | 442 ++++++++++++++------------------ polyfill/lib/ecmascript.mjs | 35 +-- polyfill/lib/instant.mjs | 3 +- polyfill/lib/now.mjs | 5 +- polyfill/lib/plaindate.mjs | 3 +- polyfill/lib/plaindatetime.mjs | 3 +- polyfill/lib/plainmonthday.mjs | 3 +- polyfill/lib/plaintime.mjs | 3 +- polyfill/lib/plainyearmonth.mjs | 3 +- polyfill/lib/timezone.mjs | 3 +- polyfill/lib/zoneddatetime.mjs | 3 +- polyfill/test/regex.mjs | 27 +- polyfill/test/usercalendar.mjs | 16 +- spec.html | 1 - spec/calendar.html | 286 ++++++++++++++++++--- spec/isocalendar.html | 363 -------------------------- 16 files changed, 487 insertions(+), 712 deletions(-) delete mode 100644 spec/isocalendar.html diff --git a/polyfill/lib/calendar.mjs b/polyfill/lib/calendar.mjs index a7f8d3ba67..9c55cdf6a7 100644 --- a/polyfill/lib/calendar.mjs +++ b/polyfill/lib/calendar.mjs @@ -2,7 +2,6 @@ import { ES } from './ecmascript.mjs'; import { GetIntrinsic, MakeIntrinsicClass, DefineIntrinsic } from './intrinsicclass.mjs'; -import * as REGEX from './regex.mjs'; import { CALENDAR_ID, ISO_YEAR, @@ -20,13 +19,17 @@ import { SetSlot } from './slots.mjs'; -const ID_REGEX = new RegExp(`^${REGEX.calendarID.source}$`); +const ArrayIncludes = Array.prototype.includes; +const ObjectAssign = Object.assign; + +const BUILTIN_CALENDAR_IDS = ['gregory', 'iso8601', 'japanese']; +const impl = {}; export class Calendar { constructor(id) { - if (!ID_REGEX.exec(id)) throw new RangeError(`invalid calendar identifier ${id}`); - CreateSlots(this); id = ES.ToString(id); + if (!IsBuiltinCalendar(id)) throw new RangeError(`invalid calendar identifier ${id}`); + CreateSlots(this); SetSlot(this, CALENDAR_ID, id); if (typeof __debug__ !== 'undefined' && __debug__) { @@ -42,130 +45,162 @@ export class Calendar { return ES.CalendarToString(this); } dateFromFields(fields, options, constructor) { - void fields; - void options; - void constructor; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + options = ES.NormalizeOptionsObject(options); + const overflow = ES.ToTemporalOverflow(options); + const { year, month, day } = impl[GetSlot(this, CALENDAR_ID)].dateFromFields(fields, overflow); + return new constructor(year, month, day, this); } timeFromFields(fields, options, constructor) { - void fields; - void options; - void constructor; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + options = ES.NormalizeOptionsObject(options); + const overflow = ES.ToTemporalOverflow(options); + const { hour, minute, second, millisecond, microsecond, nanosecond } = impl[ + GetSlot(this, CALENDAR_ID) + ].timeFromFields(fields, overflow); + return new constructor(hour, minute, second, millisecond, microsecond, nanosecond, this); } yearMonthFromFields(fields, options, constructor) { - void fields; - void options; - void constructor; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + options = ES.NormalizeOptionsObject(options); + const overflow = ES.ToTemporalOverflow(options); + const { year, month } = impl[GetSlot(this, CALENDAR_ID)].yearMonthFromFields(fields, overflow); + return new constructor(year, month, this, /* referenceISODay = */ 1); } monthDayFromFields(fields, options, constructor) { - void fields; - void options; - void constructor; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + options = ES.NormalizeOptionsObject(options); + const overflow = ES.ToTemporalOverflow(options); + const { month, day } = impl[GetSlot(this, CALENDAR_ID)].monthDayFromFields(fields, overflow); + return new constructor(month, day, this, /* referenceISOYear = */ 1972); } fields(fields) { if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); - return ES.CreateListFromArrayLike(fields, ['String']); + fields = ES.CreateListFromArrayLike(fields, ['String']); + return impl[GetSlot(this, CALENDAR_ID)].fields(fields); } dateAdd(date, duration, options, constructor) { - void date; - void duration; - void options; - void constructor; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); + duration = ES.ToTemporalDuration(duration, GetIntrinsic('%Temporal.Duration%')); + options = ES.NormalizeOptionsObject(options); + const overflow = ES.ToTemporalOverflow(options); + const { year, month, day } = impl[GetSlot(this, CALENDAR_ID)].dateAdd(date, duration, overflow); + return new constructor(year, month, day, this); } dateUntil(one, two, options) { - void one; - void two; - void options; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + one = ES.ToTemporalDate(one, GetIntrinsic('%Temporal.PlainDate%')); + two = ES.ToTemporalDate(two, GetIntrinsic('%Temporal.PlainDate%')); + options = ES.NormalizeOptionsObject(options); + const largestUnit = ES.ToLargestTemporalUnit(options, 'days', [ + 'hours', + 'minutes', + 'seconds', + 'milliseconds', + 'microseconds', + 'nanoseconds' + ]); + const { years, months, weeks, days } = impl[GetSlot(this, CALENDAR_ID)].dateUntil(one, two, largestUnit); + const Duration = GetIntrinsic('%Temporal.Duration%'); + return new Duration(years, months, weeks, days, 0, 0, 0, 0, 0, 0); } timeAdd(time, duration, options, constructor) { - void time; - void duration; - void options; - void constructor; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + time = ES.ToTemporalTime(time, GetIntrinsic('%Temporal.PlainTime%')); + duration = ES.ToTemporalDuration(duration, GetIntrinsic('%Temporal.Duration%')); + options = ES.NormalizeOptionsObject(options); + const overflow = ES.ToTemporalOverflow(options); + const { hour, minute, second, millisecond, microsecond, nanosecond } = impl[GetSlot(this, CALENDAR_ID)].timeAdd( + time, + duration, + overflow + ); + return new constructor(hour, minute, second, millisecond, microsecond, nanosecond, this); } timeUntil(one, two, options) { - void one; - void two; - void options; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + one = ES.ToTemporalTime(one, GetIntrinsic('%Temporal.PlainTime%')); + two = ES.ToTemporalTime(two, GetIntrinsic('%Temporal.PlainTime%')); + options = ES.NormalizeOptionsObject(options); + const largestUnit = ES.ToLargestTemporalUnit(options, 'hours', ['years', 'months', 'days']); + const { days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = impl[ + GetSlot(this, CALENDAR_ID) + ].timeUntil(one, two, largestUnit); + const Duration = GetIntrinsic('%Temporal.Duration%'); + return new Duration(0, 0, 0, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); } year(date) { - void date; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].year(date); } month(date) { - void date; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].month(date); } day(date) { - void date; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].day(date); } era(date) { - void date; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].era(date); } dayOfWeek(date) { - void date; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].dayOfWeek(date); } dayOfYear(date) { - void date; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].dayOfYear(date); } weekOfYear(date) { - void date; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].weekOfYear(date); } daysInWeek(date) { - void date; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].daysInWeek(date); } daysInMonth(date) { - void date; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].daysInMonth(date); } daysInYear(date) { - void date; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].daysInYear(date); } monthsInYear(date) { - void date; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].monthsInYear(date); } inLeapYear(date) { - void date; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].inLeapYear(date); } hour(time) { - void time; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].hour(time); } minute(time) { - void time; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].minute(time); } second(time) { - void time; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].second(time); } millisecond(time) { - void time; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].millisecond(time); } microsecond(time) { - void time; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].microsecond(time); } nanosecond(time) { - void time; - throw new Error('not implemented'); + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return impl[GetSlot(this, CALENDAR_ID)].nanosecond(time); } toString() { if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); @@ -178,7 +213,7 @@ export class Calendar { if (ES.Type(item) === 'Object' && !('calendar' in item)) return item; } const stringIdent = ES.ToString(item); - if (IsBuiltinCalendar(stringIdent)) return GetBuiltinCalendar(stringIdent); + if (IsBuiltinCalendar(stringIdent)) return new Calendar(stringIdent); let calendar; try { ({ calendar } = ES.ParseISODateTime(stringIdent, { zoneRequired: false })); @@ -186,7 +221,7 @@ export class Calendar { throw new RangeError(`Invalid calendar: ${stringIdent}`); } if (!calendar) calendar = 'iso8601'; - return GetBuiltinCalendar(calendar); + return new Calendar(calendar); } } @@ -195,25 +230,13 @@ DefineIntrinsic('Temporal.Calendar.from', Calendar.from); DefineIntrinsic('Temporal.Calendar.prototype.fields', Calendar.prototype.fields); DefineIntrinsic('Temporal.Calendar.prototype.toString', Calendar.prototype.toString); -class ISO8601Calendar extends Calendar { - constructor(id = 'iso8601') { - // Needs to be subclassable, that's why the ID is a default argument - id = ES.ToString(id); - super(id); - } - dateFromFields(fields, options, constructor) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); - options = ES.NormalizeOptionsObject(options); - const overflow = ES.ToTemporalOverflow(options); - let { year, month, day } = ES.ToRecord(fields, [['day'], ['month'], ['year']]); - ({ year, month, day } = ES.RegulateDate(year, month, day, overflow)); - return new constructor(year, month, day, this); - } - timeFromFields(fields, options, constructor) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); - options = ES.NormalizeOptionsObject(options); - const overflow = ES.ToTemporalOverflow(options); - let { hour, minute, second, millisecond, microsecond, nanosecond } = ES.ToRecord(fields, [ +impl['iso8601'] = { + dateFromFields(fields, overflow) { + const { year, month, day } = ES.ToRecord(fields, [['day'], ['month'], ['year']]); + return ES.RegulateDate(year, month, day, overflow); + }, + timeFromFields(fields, overflow) { + const { hour, minute, second, millisecond, microsecond, nanosecond } = ES.ToRecord(fields, [ ['hour', 0], ['microsecond', 0], ['millisecond', 0], @@ -221,61 +244,29 @@ class ISO8601Calendar extends Calendar { ['nanosecond', 0], ['second', 0] ]); - ({ hour, minute, second, millisecond, microsecond, nanosecond } = ES.RegulateTime( - hour, - minute, - second, - millisecond, - microsecond, - nanosecond, - overflow - )); - return new constructor(hour, minute, second, millisecond, microsecond, nanosecond, this); - } - yearMonthFromFields(fields, options, constructor) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); - options = ES.NormalizeOptionsObject(options); - const overflow = ES.ToTemporalOverflow(options); - let { year, month } = ES.ToRecord(fields, [['month'], ['year']]); - ({ year, month } = ES.RegulateYearMonth(year, month, overflow)); - return new constructor(year, month, this, /* referenceISODay = */ 1); - } - monthDayFromFields(fields, options, constructor) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); - options = ES.NormalizeOptionsObject(options); - const overflow = ES.ToTemporalOverflow(options); - let { month, day } = ES.ToRecord(fields, [['day'], ['month']]); - ({ month, day } = ES.RegulateMonthDay(month, day, overflow)); - return new constructor(month, day, this, /* referenceISOYear = */ 1972); - } - dateAdd(date, duration, options, constructor) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); - date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); - duration = ES.ToTemporalDuration(duration, GetIntrinsic('%Temporal.Duration%')); - options = ES.NormalizeOptionsObject(options); - const overflow = ES.ToTemporalOverflow(options); + return ES.RegulateTime(hour, minute, second, millisecond, microsecond, nanosecond, overflow); + }, + yearMonthFromFields(fields, overflow) { + const { year, month } = ES.ToRecord(fields, [['month'], ['year']]); + return ES.RegulateYearMonth(year, month, overflow); + }, + monthDayFromFields(fields, overflow) { + const { month, day } = ES.ToRecord(fields, [['day'], ['month']]); + return ES.RegulateMonthDay(month, day, overflow); + }, + fields(fields) { + return fields; + }, + dateAdd(date, duration, overflow) { const { years, months, weeks, days } = duration; ES.RejectDurationSign(years, months, weeks, days, 0, 0, 0, 0, 0, 0); - let year = GetSlot(date, ISO_YEAR); - let month = GetSlot(date, ISO_MONTH); - let day = GetSlot(date, ISO_DAY); - ({ year, month, day } = ES.AddDate(year, month, day, years, months, weeks, days, overflow)); - return new constructor(year, month, day, this); - } - dateUntil(one, two, options) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); - one = ES.ToTemporalDate(one, GetIntrinsic('%Temporal.PlainDate%')); - two = ES.ToTemporalDate(two, GetIntrinsic('%Temporal.PlainDate%')); - options = ES.NormalizeOptionsObject(options); - const largestUnit = ES.ToLargestTemporalUnit(options, 'days', [ - 'hours', - 'minutes', - 'seconds', - 'milliseconds', - 'microseconds', - 'nanoseconds' - ]); - const { years, months, weeks, days } = ES.DifferenceDate( + const year = GetSlot(date, ISO_YEAR); + const month = GetSlot(date, ISO_MONTH); + const day = GetSlot(date, ISO_DAY); + return ES.AddDate(year, month, day, years, months, weeks, days, overflow); + }, + dateUntil(one, two, largestUnit) { + return ES.DifferenceDate( GetSlot(one, ISO_YEAR), GetSlot(one, ISO_MONTH), GetSlot(one, ISO_DAY), @@ -284,15 +275,8 @@ class ISO8601Calendar extends Calendar { GetSlot(two, ISO_DAY), largestUnit ); - const Duration = GetIntrinsic('%Temporal.Duration%'); - return new Duration(years, months, weeks, days, 0, 0, 0, 0, 0, 0); - } - timeAdd(time, duration, options, constructor) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); - time = ES.ToTemporalTime(time, GetIntrinsic('%Temporal.PlainTime%')); - duration = ES.ToTemporalDuration(duration, GetIntrinsic('%Temporal.Duration%')); - options = ES.NormalizeOptionsObject(options); - const overflow = ES.ToTemporalOverflow(options); + }, + timeAdd(time, duration, overflow) { const { years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = duration; ES.RejectDurationSign(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); let hour = GetSlot(time, ISO_HOUR); @@ -315,22 +299,10 @@ class ISO8601Calendar extends Calendar { microseconds, nanoseconds )); - ({ hour, minute, second, millisecond, microsecond, nanosecond } = ES.RegulateTime( - hour, - minute, - second, - millisecond, - microsecond, - nanosecond, - overflow - )); - return new constructor(hour, minute, second, millisecond, microsecond, nanosecond, this); - } + return ES.RegulateTime(hour, minute, second, millisecond, microsecond, nanosecond, overflow); + }, timeUntil(one, two) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); - one = ES.ToTemporalTime(one, GetIntrinsic('%Temporal.PlainTime%')); - two = ES.ToTemporalTime(two, GetIntrinsic('%Temporal.PlainTime%')); - let { deltaDays, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.DifferenceTime( + const { deltaDays: days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds } = ES.DifferenceTime( GetSlot(one, ISO_HOUR), GetSlot(one, ISO_MINUTE), GetSlot(one, ISO_SECOND), @@ -344,95 +316,77 @@ class ISO8601Calendar extends Calendar { GetSlot(two, ISO_MICROSECOND), GetSlot(two, ISO_NANOSECOND) ); - const Duration = GetIntrinsic('%Temporal.Duration%'); - return new Duration(0, 0, 0, deltaDays, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); - } + return { days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds }; + }, year(date) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); if (!HasSlot(date, ISO_YEAR)) date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); return GetSlot(date, ISO_YEAR); - } + }, month(date) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); if (!HasSlot(date, ISO_MONTH)) date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); return GetSlot(date, ISO_MONTH); - } + }, day(date) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); if (!HasSlot(date, ISO_DAY)) date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); return GetSlot(date, ISO_DAY); - } + }, era(date) { if (!HasSlot(date, ISO_YEAR)) date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.Date%')); return undefined; - } + }, hour(time) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); return GetSlot(time, ISO_HOUR); - } + }, minute(time) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); return GetSlot(time, ISO_MINUTE); - } + }, second(time) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); return GetSlot(time, ISO_SECOND); - } + }, millisecond(time) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); return GetSlot(time, ISO_MILLISECOND); - } + }, microsecond(time) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); return GetSlot(time, ISO_MICROSECOND); - } + }, nanosecond(time) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); return GetSlot(time, ISO_NANOSECOND); - } + }, dayOfWeek(date) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); return ES.DayOfWeek(GetSlot(date, ISO_YEAR), GetSlot(date, ISO_MONTH), GetSlot(date, ISO_DAY)); - } + }, dayOfYear(date) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); return ES.DayOfYear(GetSlot(date, ISO_YEAR), GetSlot(date, ISO_MONTH), GetSlot(date, ISO_DAY)); - } + }, weekOfYear(date) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); return ES.WeekOfYear(GetSlot(date, ISO_YEAR), GetSlot(date, ISO_MONTH), GetSlot(date, ISO_DAY)); - } + }, daysInWeek(date) { ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); return 7; - } + }, daysInMonth(date) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); if (!HasSlot(date, ISO_YEAR) || !HasSlot(date, ISO_MONTH)) { date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); } return ES.DaysInMonth(GetSlot(date, ISO_YEAR), GetSlot(date, ISO_MONTH)); - } + }, daysInYear(date) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); if (!HasSlot(date, ISO_YEAR)) date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); return ES.LeapYear(GetSlot(date, ISO_YEAR)) ? 366 : 365; - } + }, monthsInYear(date) { if (!HasSlot(date, ISO_YEAR)) ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); return 12; - } + }, inLeapYear(date) { - if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); if (!HasSlot(date, ISO_YEAR)) date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); return ES.LeapYear(GetSlot(date, ISO_YEAR)); } -} - -MakeIntrinsicClass(ISO8601Calendar, 'Temporal.ISO8601Calendar'); +}; // Note: other built-in calendars than iso8601 are not part of the Temporal // proposal for ECMA-262. These calendars will be standardized as part of @@ -448,40 +402,35 @@ const gre = { // 'iso8601' calendar is equivalent to 'gregory' except for ISO 8601 week // numbering rules, which we do not currently use in Temporal, and the addition // of BC/AD eras which means no negative years or year 0. -class Gregorian extends ISO8601Calendar { - constructor() { - super('gregory'); - } - +impl['gregory'] = ObjectAssign({}, impl['iso8601'], { era(date) { if (!HasSlot(date, ISO_YEAR)) date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); return GetSlot(date, ISO_YEAR) < 1 ? 'bc' : 'ad'; - } + }, year(date) { if (!HasSlot(date, ISO_YEAR)) date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); const isoYear = GetSlot(date, ISO_YEAR); return isoYear < 1 ? -isoYear + 1 : isoYear; - } + }, fields(fields) { - fields = super.fields(fields); if (fields.includes('year')) fields.push('era'); return fields; - } + }, - dateFromFields(fields, options, constructor) { + dateFromFields(fields, overflow) { // Intentionally alphabetical fields = ES.ToRecord(fields, [['day'], ['era', 'ad'], ['month'], ['year']]); const isoYear = gre.isoYear(fields.year, fields.era); - return super.dateFromFields({ ...fields, year: isoYear }, options, constructor); - } - yearMonthFromFields(fields, options, constructor) { + return impl['iso8601'].dateFromFields({ ...fields, year: isoYear }, overflow); + }, + yearMonthFromFields(fields, overflow) { // Intentionally alphabetical fields = ES.ToRecord(fields, [['era', 'ad'], ['month'], ['year']]); const isoYear = gre.isoYear(fields.year, fields.era); - return super.yearMonthFromFields({ ...fields, year: isoYear }, options, constructor); + return impl['iso8601'].yearMonthFromFields({ ...fields, year: isoYear }, overflow); } -} +}); // Implementation details for Japanese calendar // @@ -545,59 +494,40 @@ const jpn = { } }; -class Japanese extends ISO8601Calendar { - constructor() { - super('japanese'); - } - +impl['japanese'] = ObjectAssign({}, impl['iso8601'], { era(date) { if (!HasSlot(date, ISO_YEAR) || !HasSlot(date, ISO_MONTH) || !HasSlot(date, ISO_DAY)) { date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); } return jpn.eraNames[jpn.findEra(date)]; - } + }, year(date) { if (!HasSlot(date, ISO_YEAR) || !HasSlot(date, ISO_MONTH) || !HasSlot(date, ISO_DAY)) { date = ES.ToTemporalDate(date, GetIntrinsic('%Temporal.PlainDate%')); } const eraIdx = jpn.findEra(date); return GetSlot(date, ISO_YEAR) - jpn.eraAddends[eraIdx]; - } + }, fields(fields) { - fields = super.fields(fields); if (fields.includes('year')) fields.push('era'); return fields; - } + }, - dateFromFields(fields, options, constructor) { + dateFromFields(fields, overflow) { // Intentionally alphabetical fields = ES.ToRecord(fields, [['day'], ['era'], ['month'], ['year']]); const isoYear = jpn.isoYear(fields.year, fields.era); - return super.dateFromFields({ ...fields, year: isoYear }, options, constructor); - } - yearMonthFromFields(fields, options, constructor) { + return impl['iso8601'].dateFromFields({ ...fields, year: isoYear }, overflow); + }, + yearMonthFromFields(fields, overflow) { // Intentionally alphabetical fields = ES.ToRecord(fields, [['era'], ['month'], ['year']]); const isoYear = jpn.isoYear(fields.year, fields.era); - return super.yearMonthFromFields({ ...fields, year: isoYear }, options, constructor); + return impl['iso8601'].yearMonthFromFields({ ...fields, year: isoYear }, overflow); } -} - -const BUILTIN_CALENDARS = { - gregory: Gregorian, - iso8601: ISO8601Calendar, - japanese: Japanese - // To be filled in as builtin calendars are implemented -}; +}); function IsBuiltinCalendar(id) { - return id in BUILTIN_CALENDARS; -} -function GetBuiltinCalendar(id) { - if (!(id in BUILTIN_CALENDARS)) throw new RangeError(`unknown calendar ${id}`); - return new BUILTIN_CALENDARS[id](); -} -export function GetISO8601Calendar() { - return GetBuiltinCalendar('iso8601'); + return ArrayIncludes.call(BUILTIN_CALENDAR_IDS, id); } diff --git a/polyfill/lib/ecmascript.mjs b/polyfill/lib/ecmascript.mjs index 0e19560559..3e3b72bb3f 100644 --- a/polyfill/lib/ecmascript.mjs +++ b/polyfill/lib/ecmascript.mjs @@ -21,7 +21,6 @@ import ToPrimitive from 'es-abstract/2020/ToPrimitive.js'; import ToString from 'es-abstract/2020/ToString.js'; import Type from 'es-abstract/2020/Type.js'; -import { GetISO8601Calendar } from './calendar.mjs'; import { GetIntrinsic } from './intrinsicclass.mjs'; import { GetSlot, @@ -677,7 +676,7 @@ export const ES = ObjectAssign({}, ES2020, { if (ES.Type(relativeTo) === 'Object') { if (ES.IsTemporalZonedDateTime(relativeTo) || ES.IsTemporalDateTime(relativeTo)) return relativeTo; calendar = relativeTo.calendar; - if (calendar === undefined) calendar = GetISO8601Calendar(); + if (calendar === undefined) calendar = ES.GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); const fieldNames = ES.CalendarFields(calendar, [ 'day', @@ -721,7 +720,7 @@ export const ES = ObjectAssign({}, ES2020, { offset } = ES.ParseISODateTime(ES.ToString(relativeTo), { zoneRequired: false })); if (ianaName) timeZone = ianaName; - if (!calendar) calendar = GetISO8601Calendar(); + if (!calendar) calendar = ES.GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); } if (timeZone) { @@ -764,7 +763,7 @@ export const ES = ObjectAssign({}, ES2020, { return new TemporalTime(hour, minute, second, millisecond, microsecond, nanosecond); } let { year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, calendar } = props; - if (!calendar) calendar = new (GetIntrinsic('%Temporal.ISO8601Calendar%'))(); + if (!calendar) calendar = ES.GetISO8601Calendar(); const DATE_ONLY = new RegExp(`^${PARSE.datesplit.source}$`); const match = DATE_ONLY.exec(str); if (match) { @@ -972,7 +971,7 @@ export const ES = ObjectAssign({}, ES2020, { if (ES.Type(item) === 'Object') { if (ES.IsTemporalDate(item)) return item; let calendar = item.calendar; - if (calendar === undefined) calendar = new (GetIntrinsic('%Temporal.ISO8601Calendar%'))(); + if (calendar === undefined) calendar = ES.GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); const fieldNames = ES.CalendarFields(calendar, ['day', 'month', 'year']); const fields = ES.ToTemporalDateFields(item, fieldNames); @@ -980,7 +979,7 @@ export const ES = ObjectAssign({}, ES2020, { } let { year, month, day, calendar } = ES.ParseTemporalDateString(ES.ToString(item)); ({ year, month, day } = ES.RegulateDate(year, month, day, overflow)); - if (calendar === undefined) calendar = new (GetIntrinsic('%Temporal.ISO8601Calendar%'))(); + if (calendar === undefined) calendar = ES.GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); let result = new constructor(year, month, day, calendar); if (!ES.IsTemporalDate(result)) throw new TypeError('invalid result'); @@ -1010,7 +1009,7 @@ export const ES = ObjectAssign({}, ES2020, { if (ES.IsTemporalDateTime(item)) return item; calendar = item.calendar; - if (calendar === undefined) calendar = new (GetIntrinsic('%Temporal.ISO8601Calendar%'))(); + if (calendar === undefined) calendar = ES.GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); const fieldNames = ES.CalendarFields(calendar, ['day', 'month', 'year']); @@ -1039,7 +1038,7 @@ export const ES = ObjectAssign({}, ES2020, { nanosecond, calendar } = ES.ParseTemporalDateTimeString(ES.ToString(item))); - if (calendar === undefined) calendar = new (GetIntrinsic('%Temporal.ISO8601Calendar%'))(); + if (calendar === undefined) calendar = ES.GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); } const result = new constructor( @@ -1113,7 +1112,7 @@ export const ES = ObjectAssign({}, ES2020, { if (ES.Type(item) === 'Object') { if (ES.IsTemporalMonthDay(item)) return item; let calendar = item.calendar; - if (calendar === undefined) calendar = new (GetIntrinsic('%Temporal.ISO8601Calendar%'))(); + if (calendar === undefined) calendar = ES.GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); const fieldNames = ES.CalendarFields(calendar, ['day', 'month']); const fields = ES.ToTemporalMonthDayFields(item, fieldNames); @@ -1122,7 +1121,7 @@ export const ES = ObjectAssign({}, ES2020, { let { month, day, referenceISOYear, calendar } = ES.ParseTemporalMonthDayString(ES.ToString(item)); ({ month, day } = ES.RegulateMonthDay(month, day, overflow)); - if (calendar === undefined) calendar = new (GetIntrinsic('%Temporal.ISO8601Calendar%'))(); + if (calendar === undefined) calendar = ES.GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); if (referenceISOYear === undefined) referenceISOYear = 1972; let result = new constructor(month, day, calendar, referenceISOYear); @@ -1133,7 +1132,7 @@ export const ES = ObjectAssign({}, ES2020, { if (ES.Type(item) === 'Object') { if (ES.IsTemporalTime(item)) return item; let calendar = item.calendar; - if (calendar === undefined) calendar = new (GetIntrinsic('%Temporal.ISO8601Calendar%'))(); + if (calendar === undefined) calendar = ES.GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); const fieldNames = ES.CalendarFields(calendar, [ 'hour', @@ -1159,7 +1158,7 @@ export const ES = ObjectAssign({}, ES2020, { nanosecond, overflow )); - if (calendar === undefined) calendar = new (GetIntrinsic('%Temporal.ISO8601Calendar%'))(); + if (calendar === undefined) calendar = ES.GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); let result = new constructor(hour, minute, second, millisecond, microsecond, nanosecond, calendar); if (!ES.IsTemporalTime(result)) throw new TypeError('invalid result'); @@ -1169,7 +1168,7 @@ export const ES = ObjectAssign({}, ES2020, { if (ES.Type(item) === 'Object') { if (ES.IsTemporalYearMonth(item)) return item; let calendar = item.calendar; - if (calendar === undefined) calendar = new (GetIntrinsic('%Temporal.ISO8601Calendar%'))(); + if (calendar === undefined) calendar = ES.GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); const fieldNames = ES.CalendarFields(calendar, ['month', 'year']); const fields = ES.ToTemporalYearMonthFields(item, fieldNames); @@ -1178,7 +1177,7 @@ export const ES = ObjectAssign({}, ES2020, { let { year, month, referenceISODay = 1, calendar } = ES.ParseTemporalYearMonthString(ES.ToString(item)); ({ year, month } = ES.RegulateYearMonth(year, month, overflow)); - if (calendar === undefined) calendar = new (GetIntrinsic('%Temporal.ISO8601Calendar%'))(); + if (calendar === undefined) calendar = ES.GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); let result = new constructor(year, month, calendar, referenceISODay); if (!ES.IsTemporalYearMonth(result)) throw new TypeError('invalid result'); @@ -1258,7 +1257,7 @@ export const ES = ObjectAssign({}, ES2020, { if (ES.Type(item) === 'Object') { if (ES.IsTemporalZonedDateTime(item)) return item; calendar = item.calendar; - if (calendar === undefined) calendar = new (GetIntrinsic('%Temporal.ISO8601Calendar%'))(); + if (calendar === undefined) calendar = ES.GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); const fieldNames = ES.CalendarFields(calendar, ['day', 'month', 'year']); const fields = ES.ToTemporalZonedDateTimeFields(item, fieldNames); @@ -1294,7 +1293,7 @@ export const ES = ObjectAssign({}, ES2020, { } = ES.ParseTemporalZonedDateTimeString(ES.ToString(item))); if (!ianaName) throw new RangeError('time zone ID required in brackets'); timeZone = ES.TimeZoneFrom(ianaName); - if (!calendar) calendar = new (GetIntrinsic('%Temporal.ISO8601Calendar%'))(); + if (!calendar) calendar = ES.GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); } let offsetNs = null; @@ -1319,6 +1318,10 @@ export const ES = ObjectAssign({}, ES2020, { return result; }, + GetISO8601Calendar: () => { + const TemporalCalendar = GetIntrinsic('%Temporal.Calendar%'); + return new TemporalCalendar('iso8601'); + }, CalendarFrom: (calendarLike) => { const TemporalCalendar = GetIntrinsic('%Temporal.Calendar%'); let from = TemporalCalendar.from; diff --git a/polyfill/lib/instant.mjs b/polyfill/lib/instant.mjs index d05a6161ea..b790ff5524 100644 --- a/polyfill/lib/instant.mjs +++ b/polyfill/lib/instant.mjs @@ -1,6 +1,5 @@ /* global __debug__ */ -import { GetISO8601Calendar } from './calendar.mjs'; import { ES } from './ecmascript.mjs'; import { DateTimeFormat } from './intl.mjs'; import { GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass.mjs'; @@ -259,7 +258,7 @@ export class Instant { } } const timeZone = ES.ToTemporalTimeZone(item); - const calendar = GetISO8601Calendar(); + const calendar = ES.GetISO8601Calendar(); const TemporalZonedDateTime = GetIntrinsic('%Temporal.ZonedDateTime%'); return new TemporalZonedDateTime(GetSlot(this, EPOCHNANOSECONDS), timeZone, calendar); } diff --git a/polyfill/lib/now.mjs b/polyfill/lib/now.mjs index 8a14981cd1..d3e21b9fbe 100644 --- a/polyfill/lib/now.mjs +++ b/polyfill/lib/now.mjs @@ -1,4 +1,3 @@ -import { GetISO8601Calendar } from './calendar.mjs'; import { ES } from './ecmascript.mjs'; import { GetIntrinsic } from './intrinsicclass.mjs'; @@ -27,7 +26,7 @@ function plainDateTime(calendarLike, temporalTimeZoneLike = timeZone()) { } function plainDateTimeISO(temporalTimeZoneLike = timeZone()) { const timeZone = ES.ToTemporalTimeZone(temporalTimeZoneLike); - const calendar = GetISO8601Calendar(); + const calendar = ES.GetISO8601Calendar(); const inst = instant(); return ES.GetTemporalDateTimeFor(timeZone, inst, calendar); } @@ -39,7 +38,7 @@ function zonedDateTime(calendarLike, temporalTimeZoneLike = timeZone()) { } function zonedDateTimeISO(temporalTimeZoneLike = timeZone()) { const timeZone = ES.ToTemporalTimeZone(temporalTimeZoneLike); - const calendar = GetISO8601Calendar(); + const calendar = ES.GetISO8601Calendar(); const ZonedDateTime = GetIntrinsic('%Temporal.ZonedDateTime%'); return new ZonedDateTime(ES.SystemUTCEpochNanoSeconds(), timeZone, calendar); } diff --git a/polyfill/lib/plaindate.mjs b/polyfill/lib/plaindate.mjs index 1a11477eda..4f8e098741 100644 --- a/polyfill/lib/plaindate.mjs +++ b/polyfill/lib/plaindate.mjs @@ -1,6 +1,5 @@ /* global __debug__ */ -import { GetISO8601Calendar } from './calendar.mjs'; import { ES } from './ecmascript.mjs'; import { DateTimeFormat } from './intl.mjs'; import { GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass.mjs'; @@ -34,7 +33,7 @@ function TemporalDateToString(date, showCalendar = 'auto') { } export class PlainDate { - constructor(isoYear, isoMonth, isoDay, calendar = GetISO8601Calendar()) { + constructor(isoYear, isoMonth, isoDay, calendar = ES.GetISO8601Calendar()) { isoYear = ES.ToInteger(isoYear); isoMonth = ES.ToInteger(isoMonth); isoDay = ES.ToInteger(isoDay); diff --git a/polyfill/lib/plaindatetime.mjs b/polyfill/lib/plaindatetime.mjs index e56e42b324..513745d3eb 100644 --- a/polyfill/lib/plaindatetime.mjs +++ b/polyfill/lib/plaindatetime.mjs @@ -1,6 +1,5 @@ /* global __debug__ */ -import { GetISO8601Calendar } from './calendar.mjs'; import { ES } from './ecmascript.mjs'; import { DateTimeFormat } from './intl.mjs'; import { GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass.mjs'; @@ -75,7 +74,7 @@ export class PlainDateTime { millisecond = 0, microsecond = 0, nanosecond = 0, - calendar = GetISO8601Calendar() + calendar = ES.GetISO8601Calendar() ) { isoYear = ES.ToInteger(isoYear); isoMonth = ES.ToInteger(isoMonth); diff --git a/polyfill/lib/plainmonthday.mjs b/polyfill/lib/plainmonthday.mjs index d8e2bda39b..7f9790652e 100644 --- a/polyfill/lib/plainmonthday.mjs +++ b/polyfill/lib/plainmonthday.mjs @@ -1,6 +1,5 @@ /* global __debug__ */ -import { GetISO8601Calendar } from './calendar.mjs'; import { ES } from './ecmascript.mjs'; import { DateTimeFormat } from './intl.mjs'; import { GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass.mjs'; @@ -24,7 +23,7 @@ function MonthDayToString(monthDay, showCalendar = 'auto') { } export class PlainMonthDay { - constructor(isoMonth, isoDay, calendar = GetISO8601Calendar(), referenceISOYear = 1972) { + constructor(isoMonth, isoDay, calendar = ES.GetISO8601Calendar(), referenceISOYear = 1972) { isoMonth = ES.ToInteger(isoMonth); isoDay = ES.ToInteger(isoDay); calendar = ES.ToTemporalCalendar(calendar); diff --git a/polyfill/lib/plaintime.mjs b/polyfill/lib/plaintime.mjs index 2e647fc6d4..ba7b0ce2bc 100644 --- a/polyfill/lib/plaintime.mjs +++ b/polyfill/lib/plaintime.mjs @@ -1,6 +1,5 @@ /* global __debug__ */ -import { GetISO8601Calendar } from './calendar.mjs'; import { ES } from './ecmascript.mjs'; import { DateTimeFormat } from './intl.mjs'; import { GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass.mjs'; @@ -63,7 +62,7 @@ export class PlainTime { isoMillisecond = 0, isoMicrosecond = 0, isoNanosecond = 0, - calendar = GetISO8601Calendar() + calendar = ES.GetISO8601Calendar() ) { isoHour = ES.ToInteger(isoHour); isoMinute = ES.ToInteger(isoMinute); diff --git a/polyfill/lib/plainyearmonth.mjs b/polyfill/lib/plainyearmonth.mjs index 07037ed5e5..1f3e1bdebb 100644 --- a/polyfill/lib/plainyearmonth.mjs +++ b/polyfill/lib/plainyearmonth.mjs @@ -1,6 +1,5 @@ /* global __debug__ */ -import { GetISO8601Calendar } from './calendar.mjs'; import { ES } from './ecmascript.mjs'; import { DateTimeFormat } from './intl.mjs'; import { GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass.mjs'; @@ -24,7 +23,7 @@ function YearMonthToString(yearMonth, showCalendar = 'auto') { } export class PlainYearMonth { - constructor(isoYear, isoMonth, calendar = GetISO8601Calendar(), referenceISODay = 1) { + constructor(isoYear, isoMonth, calendar = ES.GetISO8601Calendar(), referenceISODay = 1) { isoYear = ES.ToInteger(isoYear); isoMonth = ES.ToInteger(isoMonth); calendar = ES.ToTemporalCalendar(calendar); diff --git a/polyfill/lib/timezone.mjs b/polyfill/lib/timezone.mjs index ece97d7e47..30176ed03b 100644 --- a/polyfill/lib/timezone.mjs +++ b/polyfill/lib/timezone.mjs @@ -1,6 +1,5 @@ /* global __debug__ */ -import { GetISO8601Calendar } from './calendar.mjs'; import { ES } from './ecmascript.mjs'; import { GetIntrinsic, MakeIntrinsicClass, DefineIntrinsic } from './intrinsicclass.mjs'; import { @@ -62,7 +61,7 @@ export class TimeZone { const offsetNs = ES.GetOffsetNanosecondsFor(this, instant); return ES.FormatTimeZoneOffsetString(offsetNs); } - getPlainDateTimeFor(instant, calendar = GetISO8601Calendar()) { + getPlainDateTimeFor(instant, calendar = ES.GetISO8601Calendar()) { instant = ES.ToTemporalInstant(instant, GetIntrinsic('%Temporal.Instant%')); calendar = ES.ToTemporalCalendar(calendar); diff --git a/polyfill/lib/zoneddatetime.mjs b/polyfill/lib/zoneddatetime.mjs index 41f7965cac..aa3787d438 100644 --- a/polyfill/lib/zoneddatetime.mjs +++ b/polyfill/lib/zoneddatetime.mjs @@ -1,6 +1,5 @@ /* global __debug__ */ -import { GetISO8601Calendar } from './calendar.mjs'; import { ES } from './ecmascript.mjs'; import { DateTimeFormat } from './intl.mjs'; import { GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass.mjs'; @@ -29,7 +28,7 @@ const ArrayPrototypePush = Array.prototype.push; const ObjectAssign = Object.assign; export class ZonedDateTime { - constructor(epochNanoseconds, timeZone, calendar = GetISO8601Calendar()) { + constructor(epochNanoseconds, timeZone, calendar = ES.GetISO8601Calendar()) { epochNanoseconds = ES.ToBigInt(epochNanoseconds); timeZone = ES.ToTemporalTimeZone(timeZone); calendar = ES.ToTemporalCalendar(calendar); diff --git a/polyfill/test/regex.mjs b/polyfill/test/regex.mjs index 6539b6684f..b2a13cd79c 100644 --- a/polyfill/test/regex.mjs +++ b/polyfill/test/regex.mjs @@ -1,5 +1,5 @@ import Demitasse from '@pipobscure/demitasse'; -const { describe, it, report } = Demitasse; +const { after, before, describe, it, report } = Demitasse; import Pretty from '@pipobscure/demitasse-pretty'; const { reporter } = Pretty; @@ -649,30 +649,35 @@ describe('fromString regex', () => { }); describe('calendar ID', () => { - function makeCustomCalendar(id) { - return class extends Temporal.Calendar { - constructor() { - super(id); - } + let oldTemporalCalendarFrom = Temporal.Calendar.from; + let fromCalledWith; + before(() => { + Temporal.Calendar.from = function (item) { + fromCalledWith = item; + return new Temporal.Calendar('iso8601'); }; + }); + function testCalendarID(id) { + return Temporal.PlainDateTime.from(`1970-01-01T00:00[c=${id}]`); } describe('valid', () => { ['aaa', 'aaa-aaa', 'eightZZZ', 'eightZZZ-eightZZZ'].forEach((id) => { it(id, () => { - const Custom = makeCustomCalendar(id); - const calendar = new Custom(); - equal(calendar.id, id); + testCalendarID(id); + equal(fromCalledWith, id); }); }); }); describe('not valid', () => { ['a', 'a-a', 'aa', 'aa-aa', 'foo_', 'foo.', 'ninechars', 'ninechars-ninechars'].forEach((id) => { it(id, () => { - const Custom = makeCustomCalendar(id); - throws(() => new Custom(), RangeError); + throws(() => testCalendarID(id), RangeError); }); }); }); + after(() => { + Temporal.Calendar.from = oldTemporalCalendarFrom; + }); }); }); diff --git a/polyfill/test/usercalendar.mjs b/polyfill/test/usercalendar.mjs index c1ffbfdac2..de4da2497f 100644 --- a/polyfill/test/usercalendar.mjs +++ b/polyfill/test/usercalendar.mjs @@ -18,10 +18,12 @@ describe('Userland calendar', () => { describe('Trivial subclass', () => { // For the purposes of testing, a nonsensical calendar that uses 0-based // month numbers, like legacy Date - const ISO8601Calendar = Temporal.Calendar.from('iso8601').constructor; - class ZeroBasedCalendar extends ISO8601Calendar { + class ZeroBasedCalendar extends Temporal.Calendar { constructor() { - super('zero-based'); + super('iso8601'); + } + toString() { + return 'zero-based'; } dateFromFields(fields, options, constructor) { fields.month++; @@ -503,10 +505,9 @@ describe('Userland calendar', () => { // Contrived example of a calendar identical to the ISO calendar except that // months are numbered 1, 2, 3, and each year has four seasons of 3 months // numbered 1, 2, 3, 4. - const ISO8601Calendar = Temporal.Calendar.from('iso8601').constructor; - class SeasonCalendar extends ISO8601Calendar { + class SeasonCalendar extends Temporal.Calendar { constructor() { - super('season'); + super('iso8601'); Object.defineProperty(Temporal.PlainDateTime.prototype, 'season', { get() { return this.calendar.season(this); @@ -532,6 +533,9 @@ describe('Userland calendar', () => { configurable: true }); } + toString() { + return 'season'; + } month(date) { const { isoMonth } = date.getISOFields(); return ((isoMonth - 1) % 3) + 1; diff --git a/spec.html b/spec.html index 5577d42bf8..79bb39640a 100644 --- a/spec.html +++ b/spec.html @@ -38,7 +38,6 @@

Introduction

- diff --git a/spec/calendar.html b/spec/calendar.html index 71614ef5bc..73c1dd6ea5 100644 --- a/spec/calendar.html +++ b/spec/calendar.html @@ -25,7 +25,7 @@

GetBuiltinCalendar ( _id_ )

An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the *GetBuiltinCalendar* abstract operation as specified in the ECMA-402 specification. If an ECMAScript implementation does not include the ECMA-402 API the following specification of the *GetBuiltinCalendar* abstract operation is used.

1. If _id_ is not *"iso8601"*, throw a *RangeError* exception. - 1. Return ? Construct(%Temporal.ISO8601Calendar%, « »). + 1. Return ? Construct(%Temporal.Calendar%, « _id_ »). @@ -200,6 +200,74 @@

CalendarEquals ( _one_, _two_ )

1. Return *false*. + + +

IsLeapYear ( _year_ )

+ + 1. Assert: _year_ is an integer. + 1. If _year_ modulo 4 ≠ 0, return *false*. + 1. If _year_ modulo 400 = 0, return *true*. + 1. If _year_ modulo 100 = 0, return *false*. + 1. Return *true*. + +
+ + +

DaysInYear ( _year_ )

+ + 1. Assert: _year_ is an integer. + 1. If ! IsLeapYear(_year_) is *true*, then + 1. Return 366. + 1. Return 365. + +
+ + +

DaysInMonth ( _year_, _month_ )

+ + 1. Assert: _year_ is an integer. + 1. Assert: _month_ is an integer, _month_ ≥ 1, and _month_ ≤ 12. + 1. If _month_ is 1, 3, 5, 7, 8, 10, or 12, return 31. + 1. If _month_ is 4, 6, 9, or 11, return 30. + 1. If ! IsLeapYear(_year_) is *true*, return 29. + 1. Return 28. + +
+ + +

ToDayOfWeek ( _year_, _month_, _day_ )

+ + 1. Assert: _year_ is an integer. + 1. Assert: _month_ is an integer. + 1. Assert: _day_ is an integer. + 1. Let _date_ be the date given by _year_, _month_, and _day_. + 1. Return _date_'s day of the week according to ISO-8601. + + Monday is 1 and Sunday is 7. +
+ + +

ToDayOfYear ( _year_, _month_, _day_ )

+ + 1. Assert: _year_ is an integer. + 1. Assert: _month_ is an integer. + 1. Assert: _day_ is an integer. + 1. Let _date_ be the date given by _year_, _month_, and _day_. + 1. Return _date_'s ordinal date in the year according to ISO-8601. + +
+ + +

ToWeekOfYear ( _year_, _month_, _day_ )

+ + 1. Assert: _year_ is an integer. + 1. Assert: _month_ is an integer. + 1. Assert: _day_ is an integer. + 1. Let _date_ be the date given by _year_, _month_, and _day_. + 1. Return _date_'s week number according to ISO-8601. + + Beware that dates at the beginning of a year may be part of a week from the preceding year, and dates at the end of a year may be part of a week at the beginning of the next year, as the first week of any year is defined as the week that contains the first Thursday of the year. +
@@ -221,7 +289,7 @@

Temporal.Calendar ( _id_ )

1. If NewTarget is *undefined*, then 1. Throw a *TypeError* exception. 1. Set _id_ to ? ToString(_id_). - 1. If ! IsValidCalendarID(_id_) is *false*, then + 1. If ! IsBuiltinCalendar(_id_) is *false*, then 1. Throw a *RangeError* exception. 1. Let _calendar_ be ? OrdinaryCreateFromConstructor(NewTarget, *"%Temporal.Calendar.prototype%"*, « [[InitializedTemporalCalendar]], [[Identifier]] »). 1. Set _calendar_.[[Identifier]] to _id_. @@ -319,182 +387,319 @@

get Temporal.Calendar.prototype.id

Temporal.Calendar.prototype.dateFromFields ( _fields_, _options_, _constructor_ )

+

+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `dateFromFields` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `dateFromFields` method is used. +

The `dateFromFields` method takes three arguments, _fields_, _options_, and _constructor_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. TODO.

Temporal.Calendar.prototype.yearMonthFromFields ( _fields_, _options_, _constructor_ )

+

+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `yearMonthFromFields` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `yearMonthFromFields` method is used. +

The `yearMonthFromFields` method takes three arguments, _fields_, _options_, and _constructor_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. TODO.

Temporal.Calendar.prototype.monthDayFromFields ( _fields_, _options_, _constructor_ )

+

+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `monthDayFromFields` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `monthDayFromFields` method is used. +

The `monthDayFromFields` method takes three arguments, _fields_, _options_, and _constructor_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. TODO.

Temporal.Calendar.prototype.dateAdd ( _date_, _duration_, _options_, _constructor_ )

+

+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `dateAdd` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `dateAdd` method is used. +

The `dateAdd` method takes four arguments, _date_, _duration_, _options_, and _constructor_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. Set _date_ to ? ToTemporalDate(_date_). + 1. Set _duration_ to ? ToTemporalDuration(_duration_). + 1. TODO.

Temporal.Calendar.prototype.dateUntil ( _one_, _two_, _options_ )

+

+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `dateUntil` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `dateUntil` method is used. +

The `dateUntil` method takes three arguments, _one_, _two_, and _options_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. Set _one_ to ? ToTemporalDate(_one_). + 1. Set _two_ to ? ToTemporalDate(_two_). + 1. TODO.
-

Temporal.Calendar.prototype.year ( _date_ )

+

Temporal.Calendar.prototype.year ( _dateOrDateTime_ )

- The `year` method takes one argument _date_. + An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `year` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `year` method is used. +

+

+ The `year` method takes one argument _dateOrDateTime_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. If _dateOrDateTime_ does not have an [[ISOYear]] internal slot, then + 1. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_). + 1. Return 𝔽(_dateOrDateTime_.[[ISOYear]]).
-

Temporal.Calendar.prototype.month ( _date_ )

+

Temporal.Calendar.prototype.month ( _dateOrDateTime_ )

- The `month` method takes one argument _date_. + An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `month` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `month` method is used. +

+

+ The `month` method takes one argument _dateOrDateTime_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. If _dateOrDateTime_ does not have an [[ISOMonth]] internal slot, then + 1. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_). + 1. Return 𝔽(_dateOrDateTime_.[[ISOMonth]]).
-

Temporal.Calendar.prototype.day ( _date_ )

+

Temporal.Calendar.prototype.day ( _dateOrDateTime_ )

+

+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `day` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `day` method is used. +

- The `day` method takes one argument _date_. + The `day` method takes one argument _dateOrDateTime_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. If _dateOrDateTime_ does not have an [[ISODay]] internal slot, then + 1. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_). + 1. Return 𝔽(_dateOrDateTime_.[[ISODay]]).
-

Temporal.Calendar.prototype.dayOfWeek ( _date_ )

+

Temporal.Calendar.prototype.dayOfWeek ( _dateOrDateTime_ )

- The `dayOfWeek` method takes one argument _date_. + An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `dayOfWeek` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `dayOfWeek` method is used. +

+

+ The `dayOfWeek` method takes one argument _dateOrDateTime_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. Set _date_ to ? ToTemporalDate(_dateOrDateTime_). + 1. Return 𝔽(! ToDayOfWeek(_dateOrDateTime_.[[ISOYear]], _dateOrDateTime_.[[ISOMonth]], _dateOrDateTime_.[[ISODay]])).
-

Temporal.Calendar.prototype.dayOfYear ( _date_ )

+

Temporal.Calendar.prototype.dayOfYear ( _dateOrDateTime_ )

- The `dayOfYear` method takes one argument _date_. + An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `dayOfYear` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `dayOfYear` method is used. +

+

+ The `dayOfYear` method takes one argument _dateOrDateTime_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. Set _date_ to ? ToTemporalDate(_dateOrDateTime_). + 1. Return 𝔽(! ToDayOfYear(_dateOrDateTime_.[[ISOYear]], _dateOrDateTime_.[[ISOMonth]], _dateOrDateTime_.[[ISODay]])).
-

Temporal.Calendar.prototype.weekOfYear ( _date_ )

+

Temporal.Calendar.prototype.weekOfYear ( _dateOrDateTime_ )

+

+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `weekOfYear` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `weekOfYear` method is used. +

- The `weekOfYear` method takes one argument _date_. + The `weekOfYear` method takes one argument _dateOrDateTime_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. Set _date_ to ? ToTemporalDate(_dateOrDateTime_). + 1. Return 𝔽(! ToWeekOfYear(_dateOrDateTime_.[[ISOYear]], _dateOrDateTime_.[[ISOMonth]], _dateOrDateTime_.[[ISODay]])).
-

Temporal.Calendar.prototype.daysInWeek ( _date_ )

+

Temporal.Calendar.prototype.daysInWeek ( _dateOrDateTime_ )

- The `daysInWeek` method takes one argument _date_. + An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `daysInWeek` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `daysInWeek` method is used. +

+

+ The `daysInWeek` method takes one argument _dateOrDateTime_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. Perform ? ToTemporalDate(_dateOrDateTime_). + 1. Return *7*𝔽.
-

Temporal.Calendar.prototype.daysInMonth ( _date_ )

+

Temporal.Calendar.prototype.daysInMonth ( _dateOrDateTime_ )

+

+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `daysInMonth` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `daysInMonth` method is used. +

- The `daysInMonth` method takes one argument _date_. + The `daysInMonth` method takes one argument _dateOrDateTime_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. If _dateOrDateTime_ does not have [[ISOYear]] and [[ISOMonth]] internal slots, then + 1. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_). + 1. Return 𝔽(! DaysInMonth(_dateOrDateTime_.[[ISOYear]], _dateOrDateTime_.[[ISOMonth]])).
-

Temporal.Calendar.prototype.daysInYear ( _date_ )

+

Temporal.Calendar.prototype.daysInYear ( _dateOrDateTime_ )

- The `daysInYear` method takes one argument _date_. + An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `daysInYear` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `daysInYear` method is used. +

+

+ The `daysInYear` method takes one argument _dateOrDateTime_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. If _dateOrDateTime_ does not have an [[ISOYear]] internal slot, then + 1. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_). + 1. Return 𝔽(! DaysInYear(_dateOrDateTime_.[[ISOYear]])).
-

Temporal.Calendar.prototype.monthsInYear ( _date_ )

+

Temporal.Calendar.prototype.monthsInYear ( _dateOrDateTime_ )

+

+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `monthsInYear` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `monthsInYear` method is used. +

- The `monthsInYear` method takes one argument _date_. + The `monthsInYear` method takes one argument _dateOrDateTime_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. Perform ? ToTemporalDateTime(_dateOrDateTime_). + 1. Return *12*𝔽.
-

Temporal.Calendar.prototype.inLeapYear ( _date_ )

+

Temporal.Calendar.prototype.inLeapYear ( _dateOrDateTime_ )

- The `inLeapYear` method takes one argument _date_. + An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `inLeapYear` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `inLeapYear` method is used. +

+

+ The `inLeapYear` method takes one argument _dateOrDateTime_. The following steps are taken:

- 1. Throw an *Error* exception. + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. + 1. If _dateOrDateTime_ does not have an [[ISOYear]] internal slot, then + 1. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_). + 1. Return ! IsLeapYear(_dateOrDateTime_.[[ISOYear]]).

Temporal.Calendar.prototype.fields ( _fields_ )

+

+ An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the `fields` method as specified in the ECMA-402 specification. + If an ECMAScript implementation does not include the ECMA-402 API the following specification of the `fields` method is used. +

The `fields` method takes one argument _fields_. The following steps are taken: @@ -502,6 +707,7 @@

Temporal.Calendar.prototype.fields ( _fields_ )

1. Let _calendar_ be the *this* value. 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. If _calendar_.[[Identifier]] is not *"iso8601"*, throw an *Error* exception. 1. Set _fields_ to ? ToObject(_fields_). 1. Let _fieldNames_ be ? CreateListFromArrayLike(_fields_, « String »). 1. Return ? CreateArrayFromList(_fieldNames_). diff --git a/spec/isocalendar.html b/spec/isocalendar.html deleted file mode 100644 index 18cf1e5254..0000000000 --- a/spec/isocalendar.html +++ /dev/null @@ -1,363 +0,0 @@ - - - - -

Temporal.ISO8601Calendar Objects

-

A Temporal.ISO8601Calendar object is an immutable Object representing an ISO 8601 calendar.

- - -

The Temporal.ISO8601Calendar Constructor

-

The Temporal.ISO8601Calendar constructor:

-
    -
  • is the intrinsic object %Temporal.ISO8601Calendar%.
  • -
  • creates and initializes a new Temporal.ISO8601Calendar object when called as a constructor.
  • -
  • is designed to be subclassable. It may be used as the value of an `extends` clause of a class definition. Subclass constructors that intend to inherit the specified Temporal.ISO8601Calendar behaviour must include a super call to the %Temporal.ISO8601Calendar% constructor to create and initialize subclass instances with the necessary internal slots.
  • -
  • has a *"length"* property whose value is 1.
  • -
- - -

Temporal.ISO8601Calendar ( _id_ )

-

- When the `Temporal.ISO8601Calendar` function is called, the following steps are taken: -

- - 1. If NewTarget is *undefined*, then - 1. Throw a *TypeError* exception. - 1. Set _id_ to ? ToString(_id_). - 1. Let _calendar_ be ? OrdinaryCreateFromConstructor(NewTarget, *"%Temporal.ISO8601Calendar.prototype%"*, « [[InitializedTemporalISO8601Calendar]], [[InitializedTemporalCalendar]], [[Identifier]] »). - 1. Set _calendar_.[[Identifier]] to _id_. - 1. Return _calendar_. - -
-
- - -

Properties of the Temporal.ISO8601Calendar Constructor

-

The Temporal.ISO8601Calendar prototype:

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

Temporal.ISO8601Calendar.prototype

-

The initial value of Temporal.ISO8601Calendar.prototype is %Temporal.ISO8601Calendar.prototype%.

-

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

-
- - -

get Temporal.ISO8601Calendar [ @@species ]

-

- `Temporal.ISO8601Calendar[@@species]` is an accessor property whose set accessor function is *undefined*. - Its get accessor function performs the following steps: -

- - 1. Return the *this* value. - - -

The value of the *"name"* property of this function is *"get [Symbol.species]"*.

-
-
- - -

Properties of the Temporal.ISO8601Calendar Prototype Object

- -

The Temporal.ISO8601Calendar prototype object

-
    -
  • is the intrinsic object %Temporal.ISO8601Calendar.prototype%. -
  • is itself an ordinary object. -
  • is not a Temporal.ISO8601Calendar instance and does not have a [[InitializedTemporalCalendar]] internal slot. -
  • has a [[Prototype]] internal slot whose value is %Temporal.Calendar.prototype%. -
- - -

Temporal.ISO8601Calendar.prototype.constructor

-

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

-
- - -

Temporal.ISO8601Calendar.prototype[ @@toStringTag ]

-

- The initial value of the @@toStringTag property is the string value *"Temporal.ISO8601Calendar"*. -

-

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

-
- - -

Temporal.ISO8601Calendar.prototype.dateFromFields ( _fields_, _options_, _constructor_ )

-

- The `dateFromFields` method takes three arguments, _fields_, _options_, and _constructor_. - The following steps are taken: -

- - 1. TODO. - -
- - -

Temporal.ISO8601Calendar.prototype.yearMonthFromFields ( _fields_, _options_, _constructor_ )

-

- The `yearMonthFromFields` method takes three arguments, _fields_, _options_, and _constructor_. - The following steps are taken: -

- - 1. TODO. - -
- - -

Temporal.ISO8601Calendar.prototype.monthDayFromFields ( _fields_, _options_, _constructor_ )

-

- The `monthDayFromFields` method takes three arguments, _fields_, _options_, and _constructor_. - The following steps are taken: -

- - 1. TODO. - -
- - -

Temporal.ISO8601Calendar.prototype.dateAdd ( _date_, _duration_, _options_, _constructor_ )

-

- The `dateAdd` method takes four arguments, _date_, _duration_, _options_, and _constructor_. - The following steps are taken: -

- - 1. Set _date_ to ? ToTemporalDate(_date_). - 1. Set _duration_ to ? ToTemporalDuration(_duration_). - 1. TODO. - -
- - -

Temporal.ISO8601Calendar.prototype.dateUntil ( _one_, _two_, _options_ )

-

- The `dateUntil` method takes three arguments, _one_, _two_, and _options_. - The following steps are taken: -

- - 1. Set _one_ to ? ToTemporalDate(_one_). - 1. Set _two_ to ? ToTemporalDate(_two_). - 1. TODO. - -
- - -

Temporal.ISO8601Calendar.prototype.year ( _dateOrDateTime_ )

-

- The `year` method takes one argument _dateOrDateTime_. - The following steps are taken: -

- - 1. If _dateOrDateTime_ does not have an [[ISOYear]] internal slot, then - 1. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_). - 1. Return 𝔽(_dateOrDateTime_.[[ISOYear]]). - -
- - -

Temporal.ISO8601Calendar.prototype.month ( _dateOrDateTime_ )

-

- The `month` method takes one argument _dateOrDateTime_. - The following steps are taken: -

- - 1. If _dateOrDateTime_ does not have an [[ISOMonth]] internal slot, then - 1. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_). - 1. Return 𝔽(_dateOrDateTime_.[[ISOMonth]]). - -
- - -

Temporal.ISO8601Calendar.prototype.day ( _dateOrDateTime_ )

-

- The `day` method takes one argument _dateOrDateTime_. - The following steps are taken: -

- - 1. If _dateOrDateTime_ does not have an [[ISODay]] internal slot, then - 1. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_). - 1. Return 𝔽(_dateOrDateTime_.[[ISODay]]). - -
- - -

Temporal.ISO8601Calendar.prototype.dayOfWeek ( _dateOrDateTime_ )

-

- The `dayOfWeek` method takes one argument _dateOrDateTime_. - The following steps are taken: -

- - 1. Set _date_ to ? ToTemporalDate(_dateOrDateTime_). - 1. Return 𝔽(! ToDayOfWeek(_dateOrDateTime_.[[ISOYear]], _dateOrDateTime_.[[ISOMonth]], _dateOrDateTime_.[[ISODay]])). - -
- - -

Temporal.ISO8601Calendar.prototype.dayOfYear ( _dateOrDateTime_ )

-

- The `dayOfYear` method takes one argument _dateOrDateTime_. - The following steps are taken: -

- - 1. Set _date_ to ? ToTemporalDate(_dateOrDateTime_). - 1. Return 𝔽(! ToDayOfYear(_dateOrDateTime_.[[ISOYear]], _dateOrDateTime_.[[ISOMonth]], _dateOrDateTime_.[[ISODay]])). - -
- - -

Temporal.ISO8601Calendar.prototype.weekOfYear ( _dateOrDateTime_ )

-

- The `weekOfYear` method takes one argument _dateOrDateTime_. - The following steps are taken: -

- - 1. Set _date_ to ? ToTemporalDate(_dateOrDateTime_). - 1. Return 𝔽(! ToWeekOfYear(_dateOrDateTime_.[[ISOYear]], _dateOrDateTime_.[[ISOMonth]], _dateOrDateTime_.[[ISODay]])). - -
- - -

Temporal.ISO8601Calendar.prototype.daysInWeek ( _dateOrDateTime_ )

-

- The `daysInWeek` method takes one argument _dateOrDateTime_. - The following steps are taken: -

- - 1. Perform ? ToTemporalDate(_dateOrDateTime_). - 1. Return *7*𝔽. - -
- - -

Temporal.ISO8601Calendar.prototype.daysInMonth ( _dateOrDateTime_ )

-

- The `daysInMonth` method takes one argument _dateOrDateTime_. - The following steps are taken: -

- - 1. If _dateOrDateTime_ does not have [[ISOYear]] and [[ISOMonth]] internal slots, then - 1. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_). - 1. Return 𝔽(! DaysInMonth(_dateOrDateTime_.[[ISOYear]], _dateOrDateTime_.[[ISOMonth]])). - -
- - -

Temporal.ISO8601Calendar.prototype.daysInYear ( _dateOrDateTime_ )

-

- The `daysInYear` method takes one argument _dateOrDateTime_. - The following steps are taken: -

- - 1. If _dateOrDateTime_ does not have an [[ISOYear]] internal slot, then - 1. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_). - 1. Return 𝔽(! DaysInYear(_dateOrDateTime_.[[ISOYear]])). - -
- - -

Temporal.ISO8601Calendar.prototype.monthsInYear ( _dateOrDateTime_ )

-

- The `monthsInYear` method takes one argument _dateOrDateTime_. - The following steps are taken: -

- - 1. Perform ? ToTemporalDateTime(_dateOrDateTime_). - 1. Return *12*𝔽. - -
- - -

Temporal.ISO8601Calendar.prototype.inLeapYear ( _dateOrDateTime_ )

-

- The `inLeapYear` method takes one argument _dateOrDateTime_. - The following steps are taken: -

- - 1. If _dateOrDateTime_ does not have an [[ISOYear]] internal slot, then - 1. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_). - 1. Return ! IsLeapYear(_dateOrDateTime_.[[ISOYear]]). - -
-
- - -

Properties of Temporal.ISO8601Calendar Instances

- -

Temporal.ISO8601Calendar instances are ordinary objects that inherit properties from the %Temporal.ISO8601Calendar.prototype%. Temporal.ISO8601Calendar instances also have a [[Identifier]] internal slot. The value of this internal slot is a string.

-
- - -

Abstract Operations for Temporal.ISO8601Calendar Objects

- - -

IsLeapYear ( _year_ )

- - 1. Assert: _year_ is an integer. - 1. If _year_ modulo 4 ≠ 0, return *false*. - 1. If _year_ modulo 400 = 0, return *true*. - 1. If _year_ modulo 100 = 0, return *false*. - 1. Return *true*. - -
- - -

DaysInYear ( _year_ )

- - 1. Assert: _year_ is an integer. - 1. If ! IsLeapYear(_year_) is *true*, then - 1. Return 366. - 1. Return 365. - -
- - -

DaysInMonth ( _year_, _month_ )

- - 1. Assert: _year_ is an integer. - 1. Assert: _month_ is an integer, _month_ ≥ 1, and _month_ ≤ 12. - 1. If _month_ is 1, 3, 5, 7, 8, 10, or 12, return 31. - 1. If _month_ is 4, 6, 9, or 11, return 30. - 1. If ! IsLeapYear(_year_) is *true*, return 29. - 1. Return 28. - -
- - -

ToDayOfWeek ( _year_, _month_, _day_ )

- - 1. Assert: _year_ is an integer. - 1. Assert: _month_ is an integer. - 1. Assert: _day_ is an integer. - 1. Let _date_ be the date given by _year_, _month_, and _day_. - 1. Return _date_'s day of the week according to ISO-8601. - - Monday is 1 and Sunday is 7. -
- - -

ToDayOfYear ( _year_, _month_, _day_ )

- - 1. Assert: _year_ is an integer. - 1. Assert: _month_ is an integer. - 1. Assert: _day_ is an integer. - 1. Let _date_ be the date given by _year_, _month_, and _day_. - 1. Return _date_'s ordinal date in the year according to ISO-8601. - -
- - -

ToWeekOfYear ( _year_, _month_, _day_ )

- - 1. Assert: _year_ is an integer. - 1. Assert: _month_ is an integer. - 1. Assert: _day_ is an integer. - 1. Let _date_ be the date given by _year_, _month_, and _day_. - 1. Return _date_'s week number according to ISO-8601. - - Beware that dates at the beginning of a year may be part of a week from the preceding year, and dates at the end of a year may be part of a week at the beginning of the next year, as the first week of any year is defined as the week that contains the first Thursday of the year. -
-
-