diff --git a/docs/calendar-draft.md b/docs/calendar-draft.md index 977a1a42c9..e1b48871a0 100644 --- a/docs/calendar-draft.md +++ b/docs/calendar-draft.md @@ -74,6 +74,10 @@ class Temporal.Calendar { /** A string identifier for this calendar */ id : string; + fields( + fields: array + ) : array; + ////////////////// // Arithmetic // ////////////////// @@ -151,6 +155,9 @@ get foo(...args) { Calendars can add additional *calendar-specific accessors*, such as the year type ("kesidran", "chaser", "maleh") in the Hebrew calendar, and may add conforming accessor methods to Temporal.Date.prototype. +If any of these accessors are needed for constructing a Temporal.Date from fields, then the calendar should implement `fields()` which, given an array of field names in the ISO calendar, returns an array of equivalent field names in the calendar. +We are not aware of this being necessary for any built-in calendars. + An instance of `MyCalendar` is *expected* to have stateless behavior; i.e., calling a method with the same arguments should return the same result each time. There would be no mechanism for enforcing that user-land calendars are stateless; the calendar author should test this expectation on their own in order to prevent unexpected behavior such as the lack of round-tripping. ### Enumerable Properties diff --git a/docs/calendar.md b/docs/calendar.md index 77e894da5b..1bb00d27d3 100644 --- a/docs/calendar.md +++ b/docs/calendar.md @@ -291,6 +291,28 @@ Temporal.Calendar.from('chinese').dateDifference( ) // => P1M2D ``` +### calendar.**fields**(fields: array) : array + +**Parameters:** + +- `fields` (array of strings): A list of field names. + +**Returns:** a new list of field names. + +This method does not need to be called directly except in specialized code. +It is called indirectly when using the `from()` static methods and `with()` methods of `Temporal.DateTime`, `Temporal.Date`, and `Temporal.YearMonth`. + +Custom calendars should override this method if they require more fields with which to denote the date than the standard `era`, `year`, `month`, and `day`. +The input array contains the field names that are necessary for a particular operation (for example, `'month'` and `'day'` for `Temporal.MonthDay.prototype.with()`), and the method should make a copy of the array and add whichever extra fields are necessary. + +Usage example: + +```js +// In built-in calendars, this method just makes a copy of the input array +Temporal.Calendar.from('iso8601').fields(['month', 'day']); + // => ['month', 'day'] +``` + ### calendar.**toString**() : string **Returns:** The string given by `calendar.id`. diff --git a/polyfill/index.d.ts b/polyfill/index.d.ts index 46f6489dac..535923ace4 100644 --- a/polyfill/index.d.ts +++ b/polyfill/index.d.ts @@ -399,6 +399,7 @@ export namespace Temporal { | /** @deprecated */ 'day' > ): Temporal.Duration; + fields?(fields: Array): Array; } /** @@ -465,6 +466,7 @@ export namespace Temporal { | /** @deprecated */ 'day' > ): Temporal.Duration; + fields(fields: Array): Array; toString(): string; } diff --git a/polyfill/lib/calendar.mjs b/polyfill/lib/calendar.mjs index c11596baf0..9788d49bb8 100644 --- a/polyfill/lib/calendar.mjs +++ b/polyfill/lib/calendar.mjs @@ -44,6 +44,10 @@ export class Calendar { void constructor; throw new Error('not implemented'); } + fields(fields) { + if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); + return ES.CreateListFromArrayLike(fields, ['String']); + } dateAdd(date, duration, options, constructor) { void date; void duration; @@ -137,7 +141,7 @@ class ISO8601Calendar extends Calendar { if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); options = ES.NormalizeOptionsObject(options); const overflow = ES.ToTemporalOverflow(options); - let { year, month, day } = ES.ToTemporalDateRecord(fields); + 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); } @@ -145,7 +149,7 @@ class ISO8601Calendar extends Calendar { if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); options = ES.NormalizeOptionsObject(options); const overflow = ES.ToTemporalOverflow(options); - let { year, month } = ES.ToTemporalYearMonthRecord(fields); + let { year, month } = ES.ToRecord(fields, [['month'], ['year']]); ({ year, month } = ES.RegulateYearMonth(year, month, overflow)); return new constructor(year, month, this, /* referenceISODay = */ 1); } @@ -153,7 +157,7 @@ class ISO8601Calendar extends Calendar { if (!ES.IsTemporalCalendar(this)) throw new TypeError('invalid receiver'); options = ES.NormalizeOptionsObject(options); const overflow = ES.ToTemporalOverflow(options); - let { month, day } = ES.ToTemporalMonthDayRecord(fields); + let { month, day } = ES.ToRecord(fields, [['day'], ['month']]); ({ month, day } = ES.RegulateMonthDay(month, day, overflow)); return new constructor(month, day, this, /* referenceISOYear = */ 1972); } diff --git a/polyfill/lib/date.mjs b/polyfill/lib/date.mjs index 61c3f0bbb9..385ae43e51 100644 --- a/polyfill/lib/date.mjs +++ b/polyfill/lib/date.mjs @@ -120,11 +120,12 @@ export class Date { calendar = GetSlot(this, CALENDAR); source = this; } - const props = ES.ToPartialRecord(temporalDateLike, ['day', 'era', 'month', 'year']); + const fieldNames = calendar.fields(['day', 'era', 'month', 'year']); + const props = ES.ToPartialRecord(temporalDateLike, fieldNames); if (!props) { throw new TypeError('invalid date-like'); } - const fields = ES.ToTemporalDateRecord(source); + const fields = ES.ToTemporalDateFields(source, calendar); ObjectAssign(fields, props); const Construct = ES.SpeciesConstructor(this, Date); const result = calendar.dateFromFields(fields, options, Construct); @@ -269,20 +270,21 @@ export class Date { if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver'); const YearMonth = GetIntrinsic('%Temporal.YearMonth%'); const calendar = GetSlot(this, CALENDAR); - const fields = ES.ToTemporalDateRecord(this); + const fields = ES.ToTemporalDateFields(this, calendar); return calendar.yearMonthFromFields(fields, {}, YearMonth); } toMonthDay() { if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver'); const MonthDay = GetIntrinsic('%Temporal.MonthDay%'); const calendar = GetSlot(this, CALENDAR); - const fields = ES.ToTemporalDateRecord(this); + const fields = ES.ToTemporalDateFields(this, calendar); return calendar.monthDayFromFields(fields, {}, MonthDay); } getFields() { - const fields = ES.ToTemporalDateRecord(this); - if (!fields) throw new TypeError('invalid receiver'); - fields.calendar = GetSlot(this, CALENDAR); + if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver'); + const calendar = GetSlot(this, CALENDAR); + const fields = ES.ToTemporalDateFields(this, calendar); + fields.calendar = calendar; return fields; } getISOFields() { @@ -310,7 +312,7 @@ export class Date { let calendar = item.calendar; if (calendar === undefined) calendar = GetISO8601Calendar(); calendar = TemporalCalendar.from(calendar); - const fields = ES.ToTemporalDateRecord(item); + const fields = ES.ToTemporalDateFields(item, calendar); result = calendar.dateFromFields(fields, options, this); } } else { diff --git a/polyfill/lib/datetime.mjs b/polyfill/lib/datetime.mjs index 088c99f3f6..9d2206fe84 100644 --- a/polyfill/lib/datetime.mjs +++ b/polyfill/lib/datetime.mjs @@ -188,7 +188,7 @@ export class DateTime { calendar = GetSlot(this, CALENDAR); source = this; } - const props = ES.ToPartialRecord(temporalDateTimeLike, [ + const fieldNames = calendar.fields([ 'day', 'era', 'hour', @@ -200,10 +200,11 @@ export class DateTime { 'second', 'year' ]); + const props = ES.ToPartialRecord(temporalDateTimeLike, fieldNames); if (!props) { throw new TypeError('invalid date-time-like'); } - const fields = ES.ToTemporalDateTimeRecord(source); + const fields = ES.ToTemporalDateTimeFields(source, calendar); ObjectAssign(fields, props); const date = calendar.dateFromFields(fields, options, GetIntrinsic('%Temporal.Date%')); let year = GetSlot(date, ISO_YEAR); @@ -591,14 +592,14 @@ export class DateTime { if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver'); const YearMonth = GetIntrinsic('%Temporal.YearMonth%'); const calendar = GetSlot(this, CALENDAR); - const fields = ES.ToTemporalDateTimeRecord(this); + const fields = ES.ToTemporalDateTimeFields(this, calendar); return calendar.yearMonthFromFields(fields, {}, YearMonth); } toMonthDay() { if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver'); const MonthDay = GetIntrinsic('%Temporal.MonthDay%'); const calendar = GetSlot(this, CALENDAR); - const fields = ES.ToTemporalDateTimeRecord(this); + const fields = ES.ToTemporalDateTimeFields(this, calendar); return calendar.monthDayFromFields(fields, {}, MonthDay); } toTime() { @@ -606,9 +607,10 @@ export class DateTime { return ES.TemporalDateTimeToTime(this); } getFields() { - const fields = ES.ToTemporalDateTimeRecord(this); - if (!fields) throw new TypeError('invalid receiver'); - fields.calendar = GetSlot(this, CALENDAR); + if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver'); + const calendar = GetSlot(this, CALENDAR); + const fields = ES.ToTemporalDateTimeFields(this, calendar); + fields.calendar = calendar; return fields; } getISOFields() { @@ -649,7 +651,7 @@ export class DateTime { let calendar = item.calendar; if (calendar === undefined) calendar = GetISO8601Calendar(); calendar = TemporalCalendar.from(calendar); - const fields = ES.ToTemporalDateTimeRecord(item); + const fields = ES.ToTemporalDateTimeFields(item, calendar); const TemporalDate = GetIntrinsic('%Temporal.Date%'); const date = calendar.dateFromFields(fields, options, TemporalDate); const year = GetSlot(date, ISO_YEAR); diff --git a/polyfill/lib/ecmascript.mjs b/polyfill/lib/ecmascript.mjs index d8b25b4064..6822d736ee 100644 --- a/polyfill/lib/ecmascript.mjs +++ b/polyfill/lib/ecmascript.mjs @@ -1,3 +1,6 @@ +const ArrayIsArray = Array.isArray; +const ArrayPrototypeIndexOf = Array.prototype.indexOf; +const ArrayPrototypePush = Array.prototype.push; const IntlDateTimeFormat = globalThis.Intl.DateTimeFormat; const MathAbs = Math.abs; const MathCeil = Math.ceil; @@ -10,8 +13,10 @@ const ObjectCreate = Object.create; import bigInt from 'big-integer'; import Call from 'es-abstract/2020/Call.js'; +import IsPropertyKey from 'es-abstract/2020/IsPropertyKey.js'; import SpeciesConstructor from 'es-abstract/2020/SpeciesConstructor.js'; import ToInteger from 'es-abstract/2020/ToInteger.js'; +import ToLength from 'es-abstract/2020/ToLength.js'; import ToNumber from 'es-abstract/2020/ToNumber.js'; import ToPrimitive from 'es-abstract/2020/ToPrimitive.js'; import ToString from 'es-abstract/2020/ToString.js'; @@ -61,8 +66,10 @@ import * as PARSE from './regex.mjs'; const ES2020 = { Call, + IsPropertyKey, SpeciesConstructor, ToInteger, + ToLength, ToNumber, ToPrimitive, ToString, @@ -581,7 +588,7 @@ export const ES = ObjectAssign({}, ES2020, { calendar = relativeTo.calendar; if (calendar === undefined) calendar = GetISO8601Calendar(); calendar = ES.ToTemporalCalendar(calendar); - const fields = ES.ToTemporalDateTimeRecord(relativeTo); + const fields = ES.ToTemporalDateTimeFields(relativeTo, calendar); const TemporalDate = GetIntrinsic('%Temporal.Date%'); const date = calendar.dateFromFields(fields, {}, TemporalDate); year = GetSlot(date, ISO_YEAR); @@ -679,11 +686,20 @@ export const ES = ObjectAssign({}, ES2020, { return result; }, // field access in the following operations is intentionally alphabetical - ToTemporalDateRecord: (bag) => { - return ES.ToRecord(bag, [['day'], ['era', undefined], ['month'], ['year']]); + ToTemporalDateFields: (bag, calendar) => { + const fieldNames = calendar.fields(['day', 'era', 'month', 'year']); + const entries = [['day'], ['era', undefined], ['month'], ['year']]; + // Add extra fields from the calendar at the end + fieldNames.forEach((fieldName) => { + if (!entries.some(([name]) => name === fieldName)) { + entries.push([fieldName, undefined]); + } + }); + return ES.ToRecord(bag, entries); }, - ToTemporalDateTimeRecord: (bag) => { - return ES.ToRecord(bag, [ + ToTemporalDateTimeFields: (bag, calendar) => { + const fieldNames = calendar.fields(['day', 'era', 'month', 'year']); + const entries = [ ['day'], ['era', undefined], ['hour', 0], @@ -694,10 +710,25 @@ export const ES = ObjectAssign({}, ES2020, { ['nanosecond', 0], ['second', 0], ['year'] - ]); - }, - ToTemporalMonthDayRecord: (bag) => { - return ES.ToRecord(bag, [['day'], ['month']]); + ]; + // Add extra fields from the calendar at the end + fieldNames.forEach((fieldName) => { + if (!entries.some(([name]) => name === fieldName)) { + entries.push([fieldName, undefined]); + } + }); + return ES.ToRecord(bag, entries); + }, + ToTemporalMonthDayFields: (bag, calendar) => { + const fieldNames = calendar.fields(['day', 'month']); + const entries = [['day'], ['month']]; + // Add extra fields from the calendar at the end + fieldNames.forEach((fieldName) => { + if (!entries.some(([name]) => name === fieldName)) { + entries.push([fieldName, undefined]); + } + }); + return ES.ToRecord(bag, entries); }, ToTemporalTimeRecord: (bag) => { const props = ES.ToPartialRecord(bag, ['hour', 'microsecond', 'millisecond', 'minute', 'nanosecond', 'second']); @@ -705,8 +736,16 @@ export const ES = ObjectAssign({}, ES2020, { const { hour = 0, minute = 0, second = 0, millisecond = 0, microsecond = 0, nanosecond = 0 } = props; return { hour, minute, second, millisecond, microsecond, nanosecond }; }, - ToTemporalYearMonthRecord: (bag) => { - return ES.ToRecord(bag, [['era', undefined], ['month'], ['year']]); + ToTemporalYearMonthFields: (bag, calendar) => { + const fieldNames = calendar.fields(['era', 'month', 'year']); + const entries = [['era', undefined], ['month'], ['year']]; + // Add extra fields from the calendar at the end + fieldNames.forEach((fieldName) => { + if (!entries.some(([name]) => name === fieldName)) { + entries.push([fieldName, undefined]); + } + }); + return ES.ToRecord(bag, entries); }, CalendarFrom: (calendarLike) => { const TemporalCalendar = GetIntrinsic('%Temporal.Calendar%'); @@ -2237,6 +2276,47 @@ export const ES = ObjectAssign({}, ES2020, { throw new RangeError(`${property} must be between ${minimum} and ${maximum}, not ${value}`); } return MathFloor(value); + }, + // Overridden because the es-abstract version unconditionally uses util.inspect + Get: (O, P) => { + if (Type(O) !== 'Object') { + throw new TypeError('Assertion failed: Type(O) is not Object'); + } + if (!ES.IsPropertyKey(P)) { + throw new TypeError(`Assertion failed: IsPropertyKey(P) is not true, got ${P}`); + } + return O[P]; + }, + LengthOfArrayLike: (obj) => { + if (Type(obj) !== 'Object') { + throw new TypeError('Assertion failed: `obj` must be an Object'); + } + return ES.ToLength(ES.Get(obj, 'length')); + }, + CreateListFromArrayLike: ( + obj, + elementTypes = ['Undefined', 'Null', 'Boolean', 'String', 'Symbol', 'Number', 'Object'] + ) => { + if (ES.Type(obj) !== 'Object') { + throw new TypeError('Assertion failed: `obj` must be an Object'); + } + if (!ArrayIsArray(elementTypes)) { + throw new TypeError('Assertion failed: `elementTypes`, if provided, must be an array'); + } + var len = ES.LengthOfArrayLike(obj); + var list = []; + var index = 0; + while (index < len) { + var indexName = ToString(index); + var next = ES.Get(obj, indexName); + var nextType = Type(next); + if (ArrayPrototypeIndexOf.call(elementTypes, nextType) < 0) { + throw new TypeError(`item type ${nextType} is not a valid elementType`); + } + ArrayPrototypePush.call(list, next); + index += 1; + } + return list; } }); diff --git a/polyfill/lib/monthday.mjs b/polyfill/lib/monthday.mjs index f24746e2a6..ff48be3c94 100644 --- a/polyfill/lib/monthday.mjs +++ b/polyfill/lib/monthday.mjs @@ -64,14 +64,16 @@ export class MonthDay { if ('calendar' in temporalMonthDayLike) { throw new RangeError('invalid calendar property in month-day-like'); } - const props = ES.ToPartialRecord(temporalMonthDayLike, ['day', 'month']); + const calendar = GetSlot(this, CALENDAR); + const propsFields = calendar.fields(['day', 'month']); + const props = ES.ToPartialRecord(temporalMonthDayLike, propsFields); if (!props) { throw new TypeError('invalid month-day-like'); } - const fields = ES.ToTemporalMonthDayRecord(this); + const fields = ES.ToTemporalMonthDayFields(this, calendar); ObjectAssign(fields, props); const Construct = ES.SpeciesConstructor(this, MonthDay); - const result = GetSlot(this, CALENDAR).monthDayFromFields(fields, options, Construct); + const result = calendar.monthDayFromFields(fields, options, Construct); if (!ES.IsTemporalMonthDay(result)) throw new TypeError('invalid result'); return result; } @@ -109,14 +111,15 @@ export class MonthDay { year = ES.ToInteger(item); } const calendar = GetSlot(this, CALENDAR); - const fields = ES.ToTemporalMonthDayRecord(this); + const fields = ES.ToTemporalMonthDayFields(this, calendar); const Date = GetIntrinsic('%Temporal.Date%'); return calendar.dateFromFields({ ...fields, era, year }, options, Date); } getFields() { - const fields = ES.ToTemporalMonthDayRecord(this); - if (!fields) throw new TypeError('invalid receiver'); - fields.calendar = GetSlot(this, CALENDAR); + if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver'); + const calendar = GetSlot(this, CALENDAR); + const fields = ES.ToTemporalMonthDayFields(this, calendar); + fields.calendar = calendar; return fields; } getISOFields() { @@ -144,7 +147,7 @@ export class MonthDay { let calendar = item.calendar; if (calendar === undefined) calendar = GetISO8601Calendar(); calendar = TemporalCalendar.from(calendar); - const fields = ES.ToTemporalMonthDayRecord(item); + const fields = ES.ToTemporalMonthDayFields(item, calendar); result = calendar.monthDayFromFields(fields, options, this); } } else { diff --git a/polyfill/lib/yearmonth.mjs b/polyfill/lib/yearmonth.mjs index 8120d79d11..a9099ef50f 100644 --- a/polyfill/lib/yearmonth.mjs +++ b/polyfill/lib/yearmonth.mjs @@ -81,14 +81,16 @@ export class YearMonth { if ('calendar' in temporalYearMonthLike) { throw new RangeError('invalid calendar property in year-month-like'); } - const props = ES.ToPartialRecord(temporalYearMonthLike, ['era', 'month', 'year']); + const calendar = GetSlot(this, CALENDAR); + const propsFields = calendar.fields(['era', 'month', 'year']); + const props = ES.ToPartialRecord(temporalYearMonthLike, propsFields); if (!props) { throw new TypeError('invalid year-month-like'); } - const fields = ES.ToTemporalYearMonthRecord(this); + const fields = ES.ToTemporalYearMonthFields(this, calendar); ObjectAssign(fields, props); const Construct = ES.SpeciesConstructor(this, YearMonth); - const result = GetSlot(this, CALENDAR).yearMonthFromFields(fields, options, Construct); + const result = calendar.yearMonthFromFields(fields, options, Construct); if (!ES.IsTemporalYearMonth(result)) throw new TypeError('invalid result'); return result; } @@ -101,7 +103,7 @@ export class YearMonth { const TemporalDate = GetIntrinsic('%Temporal.Date%'); const calendar = GetSlot(this, CALENDAR); - const fields = ES.ToTemporalYearMonthRecord(this); + const fields = ES.ToTemporalYearMonthFields(this, calendar); const sign = ES.DurationSign(years, months, weeks, days, 0, 0, 0, 0, 0, 0); const day = sign < 0 ? calendar.daysInMonth(this) : 1; const startDate = calendar.dateFromFields({ ...fields, day }, {}, TemporalDate); @@ -121,7 +123,7 @@ export class YearMonth { const TemporalDate = GetIntrinsic('%Temporal.Date%'); const calendar = GetSlot(this, CALENDAR); - const fields = ES.ToTemporalYearMonthRecord(this); + const fields = ES.ToTemporalYearMonthFields(this, calendar); const sign = ES.DurationSign(years, months, weeks, days, 0, 0, 0, 0, 0, 0); const day = sign < 0 ? 1 : calendar.daysInMonth(this); const startDate = calendar.dateFromFields({ ...fields, day }, {}, TemporalDate); @@ -159,8 +161,8 @@ export class YearMonth { const roundingMode = ES.ToTemporalRoundingMode(options); const roundingIncrement = ES.ToTemporalRoundingIncrement(options, undefined, false); - const otherFields = ES.ToTemporalYearMonthRecord(other); - const thisFields = ES.ToTemporalYearMonthRecord(this); + const otherFields = ES.ToTemporalYearMonthFields(other, calendar); + const thisFields = ES.ToTemporalYearMonthFields(this, calendar); const TemporalDate = GetIntrinsic('%Temporal.Date%'); const otherDate = calendar.dateFromFields({ ...otherFields, day: 1 }, {}, TemporalDate); const thisDate = calendar.dateFromFields({ ...thisFields, day: 1 }, {}, TemporalDate); @@ -230,14 +232,15 @@ export class YearMonth { toDateOnDay(day) { if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver'); const calendar = GetSlot(this, CALENDAR); - const fields = ES.ToTemporalYearMonthRecord(this); + const fields = ES.ToTemporalYearMonthFields(this, calendar); const Date = GetIntrinsic('%Temporal.Date%'); return calendar.dateFromFields({ ...fields, day }, { overflow: 'reject' }, Date); } getFields() { - const fields = ES.ToTemporalYearMonthRecord(this); - if (!fields) throw new TypeError('invalid receiver'); - fields.calendar = GetSlot(this, CALENDAR); + if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver'); + const calendar = GetSlot(this, CALENDAR); + const fields = ES.ToTemporalYearMonthFields(this, calendar); + fields.calendar = calendar; return fields; } getISOFields() { @@ -265,7 +268,7 @@ export class YearMonth { let calendar = item.calendar; if (calendar === undefined) calendar = GetISO8601Calendar(); calendar = TemporalCalendar.from(calendar); - const fields = ES.ToTemporalYearMonthRecord(item); + const fields = ES.ToTemporalYearMonthFields(item, calendar); result = calendar.yearMonthFromFields(fields, options, this); } } else { diff --git a/polyfill/test/usercalendar.mjs b/polyfill/test/usercalendar.mjs index d105185d61..f97c015b59 100644 --- a/polyfill/test/usercalendar.mjs +++ b/polyfill/test/usercalendar.mjs @@ -283,6 +283,9 @@ describe('Userland calendar', () => { }, era() { return undefined; + }, + fields(fields) { + return fields.slice(); } }; @@ -467,6 +470,104 @@ describe('Userland calendar', () => { }); }); }); + describe('calendar with extra fields', () => { + // 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 { + constructor() { + super('season'); + Object.defineProperty(Temporal.DateTime.prototype, 'season', { + get() { + return this.calendar.season(this); + } + }); + Object.defineProperty(Temporal.Date.prototype, 'season', { + get() { + return this.calendar.season(this); + } + }); + Object.defineProperty(Temporal.YearMonth.prototype, 'season', { + get() { + return this.calendar.season(this); + } + }); + Object.defineProperty(Temporal.MonthDay.prototype, 'season', { + get() { + return this.calendar.season(this); + } + }); + } + month(date) { + const { isoMonth } = date.getISOFields(); + return ((isoMonth - 1) % 3) + 1; + } + season(date) { + const { isoMonth } = date.getISOFields(); + return Math.floor((isoMonth - 1) / 3) + 1; + } + dateFromFields(fields, options, constructor) { + const isoMonth = (fields.season - 1) * 3 + fields.month; + return super.dateFromFields({ ...fields, month: isoMonth }, options, constructor); + } + yearMonthFromFields(fields, options, constructor) { + const isoMonth = (fields.season - 1) * 3 + fields.month; + return super.yearMonthFromFields({ ...fields, month: isoMonth }, options, constructor); + } + monthDayFromFields(fields, options, constructor) { + const isoMonth = (fields.season - 1) * 3 + fields.month; + return super.monthDayFromFields({ ...fields, month: isoMonth }, options, constructor); + } + fields(fields) { + fields = fields.slice(); + if (fields.includes('month')) fields.push('season'); + return fields; + } + } + const calendar = new SeasonCalendar(); + const datetime = new Temporal.DateTime(2019, 9, 15, 0, 0, 0, 0, 0, 0, calendar); + const date = new Temporal.Date(2019, 9, 15, calendar); + const yearmonth = new Temporal.YearMonth(2019, 9, calendar); + const monthday = new Temporal.MonthDay(9, 15, calendar); + it('property getter works', () => { + equal(datetime.season, 3); + equal(datetime.month, 3); + equal(date.season, 3); + equal(date.month, 3); + equal(yearmonth.season, 3); + equal(yearmonth.month, 3); + equal(monthday.season, 3); + equal(monthday.month, 3); + }); + it('accepts season in from()', () => { + equal( + `${Temporal.DateTime.from({ year: 2019, season: 3, month: 3, day: 15, calendar })}`, + '2019-09-15T00:00[c=season]' + ); + equal(`${Temporal.Date.from({ year: 2019, season: 3, month: 3, day: 15, calendar })}`, '2019-09-15[c=season]'); + equal(`${Temporal.YearMonth.from({ year: 2019, season: 3, month: 3, calendar })}`, '2019-09-01[c=season]'); + equal(`${Temporal.MonthDay.from({ season: 3, month: 3, day: 15, calendar })}`, '1972-09-15[c=season]'); + }); + it('accepts season in with()', () => { + equal(`${datetime.with({ season: 2 })}`, '2019-06-15T00:00[c=season]'); + equal(`${date.with({ season: 2 })}`, '2019-06-15[c=season]'); + equal(`${yearmonth.with({ season: 2 })}`, '2019-06-01[c=season]'); + equal(`${monthday.with({ season: 2 })}`, '1972-06-15[c=season]'); + }); + it('translates month correctly in with()', () => { + equal(`${datetime.with({ month: 2 })}`, '2019-08-15T00:00[c=season]'); + equal(`${date.with({ month: 2 })}`, '2019-08-15[c=season]'); + equal(`${yearmonth.with({ month: 2 })}`, '2019-08-01[c=season]'); + equal(`${monthday.with({ month: 2 })}`, '1972-08-15[c=season]'); + }); + after(() => { + delete Temporal.DateTime.prototype.season; + delete Temporal.Date.prototype.season; + delete Temporal.YearMonth.prototype.season; + delete Temporal.MonthDay.prototype.season; + }); + }); }); import { normalize } from 'path'; diff --git a/spec/calendar.html b/spec/calendar.html index e073d5903d..da73ffd362 100644 --- a/spec/calendar.html +++ b/spec/calendar.html @@ -405,6 +405,21 @@

Temporal.Calendar.prototype.isLeapYear ( _date_ )

+ +

Temporal.Calendar.prototype.fields ( _fields_ )

+

+ The `fields` method takes one argument _fields_. + The following steps are taken: +

+ + 1. Let _calendar_ be the *this* value. + 1. Perform ? RequireInternalSlot(_calendar_, [[InitializedTemporalCalendar]]). + 1. Set _fields_ to ? ToObject(_fields_). + 1. Let _fieldNames_ be ? CreateListFromArrayLike(_fields_, « String »). + 1. Return ? CreateArrayFromList(_fieldNames_). + +
+

Temporal.Calendar.prototype.toString ( )

diff --git a/spec/date.html b/spec/date.html index 5d3dc8b577..be27219dd8 100644 --- a/spec/date.html +++ b/spec/date.html @@ -75,7 +75,10 @@

Temporal.Date.from ( _item_ [ , _options_ ] )

1. If Type(_item_) is Object, then 1. If _item_ has an [[InitializedTemporalDate]] internal slot, then 1. Return ? CreateTemporalDateFromStatic(_constructor_, _item_.[[ISOYear]], _item_.[[ISOMonth]], _item_.[[ISODay]], _item_.[[Calendar]]). - 1. Let _result_ be ? ToTemporalDateRecord(_item_). + 1. Let _calendar_ be ? Get(_item_, *"calendar"*). + 1. If _calendar_ is *undefined*, set _calendar_ to ! GetISO8601Calendar(). + 1. Set _calendar_ to ? ToTemporalCalendar(_calendar_). + 1. Let _result_ be ? ToTemporalDateFields(_item_, _calendar_). 1. Return TODO: create via calendar.dateFromFields. 1. Let _string_ be ? ToString(_item_). 1. Let _result_ be ? ParseTemporalDateString(_string_). @@ -315,6 +318,7 @@

Temporal.Date.prototype.toYearMonth ( )

1. Let _temporalDate_ be the *this* value. 1. Perform ? RequireInternalSlot(_temporalDate_, [[InitializedTemporalDate]]). 1. Let _calendar_ be _temporalDate_.[[Calendar]]. + 1. Let _fields_ be ? ToTemporalDateFields(_temporalDate_, _calendar_). 1. Create via calendar.yearMonthFromFields. Return ? CreateTemporalYearMonth(_temporalDate_.[[ISOYear]], _temporalDate_.[[ISOMonth]]). @@ -329,6 +333,7 @@

Temporal.Date.prototype.toMonthDay ( )

1. Let _temporalDate_ be the *this* value. 1. Perform ? RequireInternalSlot(_temporalDate_, [[InitializedTemporalDate]]). 1. Let _calendar_ be _temporalDate_.[[Calendar]]. + 1. Let _fields_ be ? ToTemporalDateFields(_temporalDate_, _calendar_). 1. Create via calendar.monthDayFromFields. Return ? CreateTemporalMonthDay(_temporalDate_.[[ISOMonth]], _temporalDate_.[[ISODay]]). @@ -341,12 +346,10 @@

Temporal.Date.prototype.getFields ( )

1. Let _temporalDate_ be the *this* value. - 1. Let _record_ be ? ToPartialDate(_temporalDate_). - 1. Let _fields_ be ? ObjectCreate(%ObjectPrototype%). - 1. For each row of , except the header row, in table order, do - 1. Let _p_ be the Property value of the current row. - 1. Let _v_ be the value of _record_'s field whose name is the Internal Slot value of the current row. - 1. Perform ! CreateDataPropertyOrThrow(_fields_, _p_, _v_). + 1. Perform ? RequireInternalSlot(_temporalDate_, [[InitializedTemporalDate]]). + 1. Let _calendar_ be _temporalDate_.[[Calendar]]. + 1. Let _fields_ be ? ToTemporalDateFields(_temporalDate_, _calendar_). + 1. Perform ! CreateDataPropertyOrThrow(_fields_, *"calendar"*, _calendar_). 1. Return _fields_.
@@ -417,7 +420,8 @@

Temporal.Date.prototype.with ( _temporalDateLike_ [ , _options_ ] )

1. Let _temporalDate_ be the *this* value. 1. Perform ? RequireInternalSlot(_temporalDate_, [[InitializedTemporalDate]]). - 1. Let _partialDate_ be ? ToPartialDate(_temporalDateLike_). + 1. Let _calendar_ be _temporalDate_.[[Calendar]]. + 1. Let _partialDate_ be ? ToPartialDate(_temporalDateLike_, _calendar_). 1. Set _options_ to ? NormalizeOptionsObject(_options_). 1. Let _overflow_ be ? ToTemporalOverflow(_options_). 1. TODO: Create via calendar.dateFromFields. @@ -708,76 +712,46 @@

DifferenceDate ( _y1_, _m1_, _d1_, _y2_, _m2_, _d2_, _largestUnit_ )

- -

ToTemporalDateRecord ( _temporalDateLike_ )

+ +

ToTemporalDateFields ( _temporalDateLike_, _calendar_ )

1. Assert: Type(_temporalDateLike_) is Object. - 1. If _temporalDateLike_ has an [[InitializedTemporalDate]] internal slot, then - 1. Return the Record { - [[Year]]: _temporalDateLike_.[[Year]], - [[Month]]: _temporalDateLike_.[[Month]], - [[Day]]: _temporalDateLike_.[[Day]], - }. - 1. Let _result_ be a new Record with all the internal slots given in the Internal Slot column in . - 1. For each row of , except the header row, in table order, do - 1. Let _property_ be the Property value of the current row. + 1. Let _fieldsMethod_ be ? Get(_calendar_, *fields*). + 1. Let _fields_ be ? CreateArrayFromList(« *"day"*, *"era"*, *"month"*, *"year"* »). + 1. Set _fields_ to ? Call(_fieldsMethod_, _calendar_, « _fields_ »). + 1. Let _result_ be ? OrdinaryObjectCreate(%Object.prototype%). + 1. For each value _property_ of _fields_, do 1. Let _value_ be ? Get(_temporalDateLike_, _property_). - 1. If _value_ is *undefined*, then + 1. If _property_ is one of *"day"*, *"month"*, or *"year"*, and _value_ is *undefined*, then 1. Throw a *TypeError* exception. - 1. Let _value_ be ? ToInteger(_value_). - 1. Set _result_'s internal slot whose name is the Internal Slot value of the current row to _value_. + 1. If _property_ is not *"era"*, then + 1. Let _value_ be ? ToInteger(_value_). + 1. Perform ! CreateDataPropertyOrThrow(_result_, _property_, _value_). 1. Return _result_.
-

ToPartialDate ( _temporalDateLike_ )

+

ToPartialDate ( _temporalDateLike_, _calendar_ )

1. If Type(_temporalDateLike_) is not Object, then 1. Throw a *TypeError* exception. - 1. Let _result_ be a new Record with all the internal slots given in the Internal Slot column in , all set to *undefined*. + 1. Let _fieldsMethod_ be ? Get(_calendar_, *fields*). + 1. Let _fields_ be ? CreateArrayFromList(« *"day"*, *"era"*, *"month"*, *"year"* »). + 1. Set _fields_ to ? Call(_fieldsMethod_, _calendar_, « _fields_ »). + 1. Let _result_ be ? OrdinaryObjectCreate(%Object.prototype%). 1. Let _any_ be *false*. - 1. For each row of , except the header row, in table order, do - 1. Let _property_ be the Property value of the current row. + 1. For each value _property_ of _fields_, do 1. Let _value_ be ? Get(_temporalDateLike_, _property_). 1. If _value_ is not *undefined*, then 1. Set _any_ to *true*. - 1. Set _value_ to ? ToInteger(_value_). - 1. Set _result_'s internal slot whose name is the Internal Slot value of the current row to _value_. + 1. If _property_ is not *"era"*, then + 1. Set _value_ to ? ToInteger(_value_). + 1. Perform ! CreateDataPropertyOrThrow(_result_, _property_, _value_). 1. If _any_ is *false*, then 1. Throw a *TypeError* exception. 1. Return _result_. - - - Properties of a TemporalDateLike - - - - - - - - - - - - - - - - - - - - - - - - - -
Internal SlotProperty
[[Day]]`"day"`
[[Month]]`"month"`
[[Year]]`"year"`
[[Calendar]]`"calendar"`
-
diff --git a/spec/datetime.html b/spec/datetime.html index a7bca0cd71..a97ba72f26 100644 --- a/spec/datetime.html +++ b/spec/datetime.html @@ -78,7 +78,10 @@

Temporal.DateTime.from ( _item_ [ , _options_ ] )

1. If Type(_item_) is Object, then 1. If _item_ has an [[InitializedTemporalDateTime]] internal slot, then 1. Return ? CreateTemporalDateTimeFromStatic(_constructor_, _item_.[[ISOYear]], _item_.[[ISOMonth]], _item_.[[ISODay]], _item_.[[Hour]], _item_.[[Minute]], _item_.[[Second]], _item_.[[Millisecond]], _item_.[[Microsecond]], _item_.[[Nanosecond]], _item_.[[Calendar]]). - 1. Let _result_ be ? ToTemporalDateTimeRecord(_item_). + 1. Let _calendar_ be ? Get(_item_, *"calendar"*). + 1. If _calendar_ is *undefined*, set _calendar_ to ! GetISO8601Calendar(). + 1. Set _calendar_ to ? ToTemporalCalendar(_calendar_). + 1. Let _result_ be ? ToTemporalDateTimeFields(_item_, calendar). 1. Let _temporalDate_ be TODO: create via calendar.dateFromFields. 1. Return ? CreateTemporalDateFromStatic(_constructor_, _temporalDate_.[[ISOYear]], _temporalDate_.[[ISOMonth]], _temporalDate_.[[ISODay]], _result_.[[Hour]], _result_.[[Minute]], _result_.[[Second]], _result_.[[Millisecond]], _result_.[[Microsecond]], _result_.[[Nanosecond]], _calendar_). 1. Let _string_ be ? ToString(_item_). @@ -399,9 +402,11 @@

Temporal.DateTime.prototype.with ( _temporalDateTimeLike_ [ , _options_ ] )< 1. Let _dateTime_ be the *this* value. 1. Perform ? RequireInternalSlot(_dateTime_, [[InitializedTemporalDateTime]]). - 1. Let _partialDateTime_ be ? ToPartialDateTime(_temporalDateTimeLike_). + 1. Let _calendar_ be _dateTime_.[[Calendar]]. + 1. Let _partialDateTime_ be ? ToPartialDateTime(_temporalDateTimeLike_, _calendar_). 1. Set _options_ to ? NormalizeOptionsObject(_options_). 1. Let _overflow_ be ? ToTemporalOverflow(_options_). + 1. Let _fields_ be ? ToTemporalDateTimeFields(_datetime_, _calendar_). 1. Let _temporalDate_ be TODO: create via calendar.dateFromFields. 1. Let _year_ be _temporalDate_.[[ISOYear]]. 1. Let _month_ be _temporalDate_.[[ISOMonth]]. @@ -650,6 +655,7 @@

Temporal.DateTime.prototype.toYearMonth ( )

1. Let _dateTime_ be the *this* value. 1. Perform ? RequireInternalSlot(_dateTime_, [[InitializedTemporalDateTime]]). 1. Let _calendar_ be _dateTime_.[[Calendar]]. + 1. Let _fields_ be ? ToTemporalDateTimeFields(_dateTime_, _calendar_). 1. Create via calendar.yearMonthFromFields. Return ? CreateTemporalYearMonth(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]]).
@@ -664,6 +670,7 @@

Temporal.DateTime.prototype.toMonthDay ( )

1. Let _dateTime_ be the *this* value. 1. Perform ? RequireInternalSlot(_dateTime_, [[InitializedTemporalDateTime]]). 1. Let _calendar_ be _dateTime_.[[Calendar]]. + 1. Let _fields_ be ? ToTemporalDateFields(_dateTime_, _calendar_). 1. Create via calendar.monthDayFromFields. Return ? CreateTemporalMonthDay(_dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]]). @@ -688,12 +695,10 @@

Temporal.DateTime.prototype.getFields ( )

1. Let _dateTime_ be the *this* value. - 1. Let _record_ be ? ToPartialDateTime(_dateTime_). - 1. Let _fields_ be ? ObjectCreate(%ObjectPrototype%). - 1. For each row of , except the header row, in table order, do - 1. Let _p_ be the Property value of the current row. - 1. Let _v_ be the value of _record_'s field whose name is the Internal Slot value of the current row. - 1. Perform ! CreateDataPropertyOrThrow(_fields_, _p_, _v_). + 1. Perform ? RequireInternalSlot(_dateTime_, [[InitializedTemporalDateTime]]). + 1. Let _calendar_ be _dateTime_.[[Calendar]]. + 1. Let _fields_ be ? ToTemporalDateTimeFields(_dateTime_, _calendar_). + 1. Perform ! CreateDataPropertyOrThrow(_fields_, *"calendar"*, _calendar_). 1. Return _fields_.
@@ -869,101 +874,33 @@

DateTimeWithinLimits ( _year_, _month_, _day_, _hour_, _minute_, _second_, _ -

ToPartialDateTime ( _temporalDateTimeLike_ )

+

ToPartialDateTime ( _temporalDateTimeLike_, _calendar_ )

1. If Type(_temporalDateTimeLike_) is not Object, then 1. Throw a *TypeError* exception. - 1. Let _result_ be the new Record { - [[Year]]: *undefined*, - [[Month]]: *undefined*, - [[Day]]: *undefined*, - [[Hour]]: *undefined*, - [[Minute]]: *undefined*, - [[Second]]: *undefined*, - [[Millisecond]]: *undefined*, - [[Microsecond]]: *undefined*, - [[Nanosecond]]: *undefined* - }. + 1. Let _fieldsMethod_ be ? Get(_calendar_, *fields*). + 1. Let _fields_ be ? CreateArrayFromList(« *"day"*, *"era"*, *"month"*, *"year"* »). + 1. Set _fields_ to ? Call(_fieldsMethod_, _calendar_, « _fields_ »). + 1. Let _result_ be ? OrdinaryObjectCreate(%Object.prototype%). 1. Let _any_ be *false*. - 1. For each row of , except the header row, in table order, do + 1. For each value _property_ of _fields_, do + 1. Let _value_ be ? Get(_temporalDateTimeLike_, _property_). + 1. If _value_ is not *undefined*, then + 1. Set _any_ to *true*. + 1. If _property_ is not *"era"*, then + 1. Set _value_ to ? ToInteger(_value_). + 1. Perform ! CreateDataPropertyOrThrow(_result_, _property_, _value_). + 1. For each row of , except the header row, in table order, do 1. Let _property_ be the Property value of the current row. 1. Let _value_ be ? Get(_temporalDateTimeLike_, _property_). 1. If _value_ is not *undefined*, then 1. Set _any_ to *true*. 1. Set _value_ to ? ToInteger(_value_). - 1. Set _result_'s internal slot whose name is the Internal Slot value of the current row to _value_. + 1. Perform ! CreateDataPropertyOrThrow(_result_, _property_, _value_). 1. If _any_ is *false*, then 1. Throw a *TypeError* exception. 1. Return _result_. - - - Internal slots and properties for Temporal.DateTime argument objects - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Internal SlotPropertyOptional
[[Day]]`"day"`*false*
[[Hour]]`"hour"`*true*
[[Microsecond]]`"microsecond"`*true*
[[Millisecond]]`"millisecond"`*true*
[[Minute]]`"minute"`*true*
[[Month]]`"month"`*false*
[[Nanosecond]]`"nanosecond"`*true*
[[Second]]`"second"`*true*
[[Year]]`"year"`*false*
-
@@ -1091,31 +1028,29 @@

CreateTemporalDateTimeFromStatic ( _constructor_, _year_, _month_, _day_, _h - -

ToTemporalDateTimeRecord ( _temporalDateTimeLike_ )

+ +

ToTemporalDateTimeFields ( _temporalDateTimeLike_, _calendar_ )

The value of ? ToInteger(*undefined*) is 0. 1. Assert: Type(_temporalDateTimeLike_) is Object. - 1. If _temporalDateTimeLike_ has an [[InitializedTemporalDateTime]] internal slot, then - 1. Return the Record { - [[Year]]: _temporalDateTimeLike_.[[Year]], - [[Month]]: _temporalDateTimeLike_.[[Month]], - [[Day]]: _temporalDateTimeLike_.[[Day]], - [[Hour]]: _temporalDateTimeLike_.[[Hour]], - [[Minute]]: _temporalDateTimeLike_.[[Minute]], - [[Second]]: _temporalDateTimeLike_.[[Second]], - [[Millisecond]]: _temporalDateTimeLike_.[[Millisecond]], - [[Microsecond]]: _temporalDateTimeLike_.[[Microsecond]], - [[Nanosecond]]: _temporalDateTimeLike_.[[Nanosecond]] - }. - 1. Let _result_ be a new Record with all the internal slots given in the Internal Slot column in . - 1. For each row of , except the header row, in table order, do + 1. Let _fieldsMethod_ be ? Get(_calendar_, *fields*). + 1. Let _fields_ be ? CreateArrayFromList(« *"day"*, *"era"*, *"month"*, *"year"* »). + 1. Set _fields_ to ? Call(_fieldsMethod_, _calendar_, « _fields_ »). + 1. Let _result_ be ? OrdinaryObjectCreate(%Object.prototype%). + 1. For each value _property_ of _fields_, do + 1. Let _value_ be ? Get(_temporalDateLike_, _property_). + 1. If _property_ is one of *"day"*, *"month"*, or *"year"*, and _value_ is *undefined*, then + 1. Throw a *TypeError* exception. + 1. If _property_ is not *"era"*, then + 1. Let _value_ be ? ToInteger(_value_). + 1. Perform ! CreateDataPropertyOrThrow(_result_, _property_, _value_). + 1. For each row of , except the header row, in table order, do 1. Let _property_ be the Property value of the current row. 1. Let _value_ be ? Get(_temporalDateTimeLike_, _property_). 1. If _value_ is *undefined* and the Optional value of the current row is *false*, then 1. Throw a *TypeError* exception. 1. Let _value_ be ? ToInteger(_value_). - 1. Set _result_'s internal slot whose name is the Internal Slot value of the current row to _value_. + 1. Perform ! CreateDataPropertyOrThrow(_result_, _property_, _value_). 1. Return _result_.
diff --git a/spec/monthday.html b/spec/monthday.html index 2730554f67..57c2488a42 100644 --- a/spec/monthday.html +++ b/spec/monthday.html @@ -77,7 +77,10 @@

Temporal.MonthDay.from ( _item_ [ , _options_ ] )

1. If Type(_item_) is Object, then 1. If _item_ has an [[InitializedTemporalMonthDay]] internal slot, then 1. Return ? CreateTemporalMonthDayFromStatic(_constructor_, _item_.[[ISOMonth]], _item_.[[ISODay]], _item_.[[ISOYear]], _item_.[[Calendar]]). - 1. Let _result_ be ? ToTemporalMonthDayRecord(_item_). + 1. Let _calendar_ be ? Get(_item_, *"calendar"*). + 1. If _calendar_ is *undefined*, set _calendar_ to ! GetISO8601Calendar(). + 1. Set _calendar_ to ? ToTemporalCalendar(_calendar_). + 1. Let _result_ be ? ToTemporalMonthDayFields(_item_, _calendar_). 1. Return TODO: create via calendar.monthDayFromFields. 1. Let _string_ be ? ToString(_item_). 1. Let _result_ be ? ParseTemporalMonthDayString(_string_). @@ -152,7 +155,8 @@

Temporal.MonthDay.prototype.with ( _temporalMonthDayLike_ [ , _options_ ] )< 1. Let _monthDay_ be the *this* value. 1. Perform ? RequireInternalSlot(_monthDay_, [[InitializedTemporalMonthDay]]). - 1. Let _partialMonthDay_ be ? ToPartialMonthDay(_temporalMonthDayLike_). + 1. Let _calendar_ be _monthDay_.[[Calendar]]. + 1. Let _partialMonthDay_ be ? ToPartialMonthDay(_temporalMonthDayLike_, _calendar_). 1. Set _options_ to ? NormalizeOptionsObject(_options_). 1. Let _overflow_ be ? ToTemporalOverflow(_options_). 1. TODO: create via calendar.monthDayFromFields. @@ -243,8 +247,13 @@

Temporal.MonthDay.prototype.toDateInYear ( _item_ [ , _options_ ] )

1. If _y_ is *undefined*, then 1. Throw a *TypeError* exception. 1. Let _y_ be ? ToInteger(_y_). + 1. Let _era_ be ? Get(_item_, *"era"*). 1. Else, 1. Let _y_ be ? ToInteger(_item_). + 1. Let _fields_ be ? ToTemporalMonthDayFields(_monthDay_, _calendar_). + 1. Perform ! Set(_fields_, *"year"*, _y_, *false*). + 1. If _era_ is not *undefined*, then + 1. Perform ! Set(_fields_, *"era"*, _era_, *false*). 1. TODO: create via calendar.dateFromFields. Return ? CreateTemporalDate(_date_.[[Year]], _date_.[[Month]], _date_.[[Day]]).
@@ -257,12 +266,10 @@

Temporal.MonthDay.prototype.getFields ( )

1. Let _monthDay_ be the *this* value. - 1. Let _record_ be ? ToPartialMonthDay(_monthDay_). - 1. Let _fields_ be ? ObjectCreate(%ObjectPrototype%). - 1. For each row of , except the header row, in table order, do - 1. Let _p_ be the Property value of the current row. - 1. Let _v_ be the value of _record_'s field whose name is the Internal Slot value of the current row. - 1. Perform ! CreateDataPropertyOrThrow(_fields_, _p_, _v_). + 1. Perform ? RequireInternalSlot(_monthDay_, [[InitializedTemporalMonthDay]]). + 1. Let _calendar_ be _monthDay_.[[Calendar]]. + 1. Let _fields_ be ? ToTemporalMonthDayFields(_monthDay_, _calendar_). + 1. Perform ! CreateDataPropertyOrThrow(_fields_, *"calendar"*, _calendar_). 1. Return _fields_.
@@ -352,48 +359,25 @@

Properties of Temporal.MonthDay Instances

Abstract operations

-

ToPartialMonthDay ( _temporalMonthDayLike_ )

+

ToPartialMonthDay ( _temporalMonthDayLike_, _calendar_ )

1. If Type(_temporalMonthDayLike_) is not Object, then 1. Throw a *TypeError* exception. - 1. Let _result_ be the new Record { - [[Month]]: *undefined*, - [[Day]]: *undefined* - }. + 1. Let _fieldsMethod_ be ? Get(_calendar_, *fields*). + 1. Let _fields_ be ? CreateArrayFromList(« *"day"*, *"month"* »). + 1. Set _fields_ to ? Call(_fieldsMethod_, _calendar_, « _fields_ »). + 1. Let _result_ be ? OrdinaryObjectCreate(%Object.prototype%). 1. Let _any_ be *false*. - 1. For each row of , except the header row, in table order, do - 1. Let _property_ be the Property value of the current row. + 1. For each value _property_ of _fields_, do 1. Let _value_ be ? Get(_temporalMonthDayLike_, _property_). 1. If _value_ is not *undefined*, then 1. Set _any_ to *true*. 1. Set _value_ to ? ToInteger(_value_). - 1. Set _result_'s internal slot whose name is the Internal Slot value of the current row to _value_. + 1. Perform ! CreateDataPropertyOrThrow(_result_, _property_, _value_). 1. If _any_ is *false*, then 1. Throw a *TypeError* exception. 1. Return _result_. - - - Properties of a TemporalMonthDayLike - - - - - - - - - - - - - - - - - -
Internal SlotProperty
[[Day]]`"day"`
[[Month]]`"month"`
-
@@ -486,25 +470,22 @@

CreateTemporalMonthDayFromStatic ( _constructor_, _month_, _day_, _reference - -

ToTemporalMonthDayRecord ( _temporalMonthDayLike_ )

+ +

ToTemporalMonthDayFields ( _temporalMonthDayLike_, _calendar_ )

1. Assert: Type(_temporalMonthDayLike_) is Object. - 1. If _temporalMonthDayLike_ has an [[InitializedTemporalMonthDay]] internal slot, then - 1. Return the Record { - [[Month]]: _temporalMonthDayLike_.[[ISOMonth]], - [[Day]]: _temporalMonthDayLike_.[[ISODay]], - [[Year]]: _temporalMonthDayLike_.[[ISOYear]] - }. - 1. Let _result_ be a new Record with all the internal slots given in the Internal Slot column in , as well as a [[Year]] slot. - 1. For each row of , except the header row, in table order, do - 1. Let _property_ be the Property value of the current row. - 1. Let _value_ be ? Get(_temporalMonthDayLike_, _property_). - 1. If _value_ is *undefined*, then + 1. Let _fieldsMethod_ be ? Get(_calendar_, *fields*). + 1. Let _fields_ be ? CreateArrayFromList(« *"day"*, *"month"* »). + 1. Set _fields_ to ? Call(_fieldsMethod_, _calendar_, « _fields_ »). + 1. Let _result_ be ? OrdinaryObjectCreate(%Object.prototype%). + 1. For each value _property_ of _fields_, do + 1. Let _value_ be ? Get(_temporalDateLike_, _property_). + 1. If _property_ is one of *"month"* or *"year"*, and _value_ is *undefined*, then 1. Throw a *TypeError* exception. 1. Let _value_ be ? ToInteger(_value_). - 1. Set _result_'s internal slot whose name is the Internal Slot value of the current row to _value_. - 1. Set _result_.[[Year]] to the first leap year after the Unix epoch (1972). + 1. Perform ! CreateDataPropertyOrThrow(_result_, _property_, _value_). + 1. Let _year_ be the first leap year after the Unix epoch (1972). + 1. Perform ! CreateDataPropertyOrThrow(_result_, *"year"*, _year_). 1. Return _result_.
diff --git a/spec/yearmonth.html b/spec/yearmonth.html index bcd2c76e54..84f5c0fa27 100644 --- a/spec/yearmonth.html +++ b/spec/yearmonth.html @@ -76,7 +76,10 @@

Temporal.YearMonth.from ( _item_ [ , _options_ ] )

1. If Type(_item_) is Object, then 1. If _item_ has an [[InitializedTemporalYearMonth]] internal slot, then 1. Return ? CreateTemporalYearMonthFromStatic(_constructor_, _item_.[[ISOYear]], _item_.[[ISOMonth]], _item_.[[ISODay]], _item_.[[Calendar]]). - 1. Let _result_ be ? ToTemporalYearMonthRecord(_item_). + 1. Let _calendar_ be ? Get(_item_, *"calendar"*). + 1. If _calendar_ is *undefined*, set _calendar_ to ! GetISO8601Calendar(). + 1. Set _calendar_ to ? ToTemporalCalendar(_calendar_). + 1. Let _result_ be ? ToTemporalYearMonthFields(_item_, _calendar_). 1. Return TODO: create via calendar.yearMonthFromFields. 1. Let _string_ be ? ToString(_item_). 1. Let _result_ be ? ParseTemporalYearMonthString(_string_). @@ -218,7 +221,8 @@

Temporal.YearMonth.prototype.with ( _temporalYearMonthLike_ [ , _options_ ] 1. Let _yearMonth_ be the *this* value. 1. Perform ? RequireInternalSlot(_yearMonth_, [[InitializedTemporalYearMonth]]). - 1. Let _partialYearMonth_ be ? ToPartialYearMonth(_temporalYearMonthLike_). + 1. Let _calendar_ be _yearMonth_.[[Calendar]]. + 1. Let _partialYearMonth_ be ? ToPartialYearMonth(_temporalYearMonthLike_, _calendar_). 1. Set _options_ to ? NormalizeOptionsObject(_options_). 1. Let _overflow_ be ? ToTemporalOverflow(_options_). 1. TODO: Create via calendar.dateFromFields. @@ -387,7 +391,10 @@

Temporal.YearMonth.prototype.toDateOnDay ( _day_ )

1. Let _yearMonth_ be the *this* value. 1. Perform ? RequireInternalSlot(_yearMonth_, [[InitializedTemporalYearMonth]]). + 1. Let _calendar_ be _yearMonth_.[[Calendar]]. + 1. Let _fields_ be ? ToTemporalYearMonthFields(_yearMonth_, _calendar_). 1. Let _d_ be ? ToInteger(_day_). + 1. Perform ! Set(_fields_, *"day"*, _d_, *false*). 1. TODO: create via calendar.dateFromFields. Return ? CreateTemporalDate(_yearMonth_.[[ISOYear]], _yearMonth_.[[ISOMonth]], _d_). @@ -400,12 +407,10 @@

Temporal.YearMonth.prototype.getFields ( )

1. Let _yearMonth_ be the *this* value. - 1. Let _record_ be ? ToPartialYearMonth(_yearMonth_). - 1. Let _fields_ be ? ObjectCreate(%ObjectPrototype%). - 1. For each row of , except the header row, in table order, do - 1. Let _p_ be the Property value of the current row. - 1. Let _v_ be the value of _record_'s field whose name is the Internal Slot value of the current row. - 1. Perform ! CreateDataPropertyOrThrow(_fields_, _p_, _v_). + 1. Perform ? RequireInternalSlot(_yearMonth_, [[InitializedTemporalYearMonth]]). + 1. Let _calendar_ be _yearMonth_.[[Calendar]]. + 1. Let _fields_ be ? ToTemporalYearMonthFields(_yearMonth_, _calendar_). + 1. Perform ! CreateDataPropertyOrThrow(_fields_, *"calendar"*, _calendar_). 1. Return _fields_. @@ -495,49 +500,28 @@

Properties of Temporal.YearMonth Instances

Abstract operations

-

ToPartialYearMonth ( _temporalYearMonthLike_ )

+

ToPartialYearMonth ( _temporalYearMonthLike_, _calendar_ )

1. If Type(_temporalYearMonthLike_) is not Object, then 1. Throw a *TypeError* exception. - 1. Let _result_ be the new Record { - [[Year]]: *undefined*, - [[Month]]: *undefined* - }. + 1. Let _fieldsMethod_ be ? Get(_calendar_, *fields*). + 1. Let _fields_ be ? CreateArrayFromList(« *"era"*, *"month"*, *"year"* »). + 1. Set _fields_ to ? Call(_fieldsMethod_, _calendar_, « _fields_ »). + 1. Let _result_ be ? OrdinaryObjectCreate(%Object.prototype%). 1. Let _any_ be *false*. - 1. For each row of , except the header row, in table order, do - 1. Let _property_ be the Property value of the current row. + 1. For each value _property_ of _fields_, do 1. Let _value_ be ? Get(_temporalYearMonthLike_, _property_). 1. If _value_ is not *undefined*, then 1. Set _any_ to *true*. - 1. Set _value_ to ? ToInteger(_value_). - 1. Set _result_'s internal slot whose name is the Internal Slot value of the current row to _value_. + 1. If _property_ is not *"era"*, then + 1. Set _value_ to ? ToInteger(_value_). + 1. Perform ! CreateDataPropertyOrThrow(_result_, _property_, _value_). 1. If _any_ is *false*, then 1. Throw a *TypeError* exception. 1. Return _result_. - - - Properties of a TemporalYearMonthLike - - - - - - - - - - - - - - - - - -
Internal SlotProperty
[[Month]]`"month"`
[[Year]]`"year"`
-
+

RegulateYearMonth ( _year_, _month_, _overflow_ )

@@ -647,25 +631,22 @@

CreateTemporalYearMonthFromStatic ( _constructor_, _year_, _month_, _referen - -

ToTemporalYearMonthRecord ( _temporalYearMonthLike_ )

+ +

ToTemporalYearMonthFields ( _temporalYearMonthLike_, _calendar_ )

1. Assert: Type(_temporalYearMonthLike_) is Object. - 1. If _temporalYearMonthLike_ has an [[InitializedTemporalYearMonth]] internal slot, then - 1. Return the Record { - [[Year]]: _temporalYearMonthLike_.[[ISOYear]], - [[Month]]: _temporalYearMonthLike_.[[ISOMonth]], - [[Day]]: _temporalYearMonthLike_.[[ISODay]] - }. - 1. Let _result_ be a new Record with all the internal slots given in the Internal Slot column in , as well as a [[Day]] slot. - 1. For each row of , except the header row, in table order, do - 1. Let _property_ be the Property value of the current row. - 1. Let _value_ be ? Get(_temporalYearMonthLike_, _property_). - 1. If _value_ is *undefined*, then + 1. Let _fieldsMethod_ be ? Get(_calendar_, *fields*). + 1. Let _fields_ be ? CreateArrayFromList(« *"era"*, *"month"*, *"year"* »). + 1. Set _fields_ to ? Call(_fieldsMethod_, _calendar_, « _fields_ »). + 1. Let _result_ be ? OrdinaryObjectCreate(%Object.prototype%). + 1. For each value _property_ of _fields_, do + 1. Let _value_ be ? Get(_temporalDateLike_, _property_). + 1. If _property_ is one of *"day"*, *"month"*, or *"year"*, and _value_ is *undefined*, then 1. Throw a *TypeError* exception. - 1. Let _value_ be ? ToInteger(_value_). - 1. Set _result_'s internal slot whose name is the Internal Slot value of the current row to _value_. - 1. Set _result_.[[Day]] to 1. + 1. If _property_ is not *"era"*, then + 1. Let _value_ be ? ToInteger(_value_). + 1. Perform ! CreateDataPropertyOrThrow(_result_, _property_, _value_). + 1. Perform ! CreateDataPropertyOrThrow(_result_, *"day"*, 1). 1. Return _result_.