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 Slot |
- Property |
-
-
-
-
- [[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 Slot |
- Property |
- Optional |
-
-
-
-
- [[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 Slot |
- Property |
-
-
-
-
- [[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 Slot |
- Property |
-
-
-
-
- [[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_.