Skip to content

Commit

Permalink
Add getISOCalendarFields() method to calendar-dependent types
Browse files Browse the repository at this point in the history
This is in order to be able to get the underlying fields from the data
model, which are stored in the ISO 8601 calendar.

It's not expected to be used in normal Temporal usage, it really exists
only for calendar implementors.

Closes: #354
  • Loading branch information
ptomato committed May 28, 2020
1 parent 6353cb0 commit 831b7a1
Show file tree
Hide file tree
Showing 29 changed files with 568 additions and 4 deletions.
15 changes: 14 additions & 1 deletion docs/date.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,6 @@ This method can be used to convert a `Temporal.Date` into a record-like data str
It returns a new plain JavaScript object, with all the fields as enumerable, writable, own data properties.

Note that if using a different calendar from ISO 8601, these will be the calendar-specific values.
To get the ISO 8601 values, use `date.getISOFields()`.

> **NOTE**: The possible values for the `month` property of the returned object start at 1, which is different from legacy `Date` where months are represented by zero-based indices (0 to 11).
Expand All @@ -519,3 +518,17 @@ date = Temporal.Date.from('2006-08-24');
Object.assign({}, date).day // => undefined
Object.assign({}, date.getFields()).day // => 24
```

### date.**getISOCalendarFields**(): { year: number, month: number, day: number }

**Returns:** a plain object with properties expressing `date` in the ISO 8601 calendar.

This method is mainly useful if you are implementing a custom calendar.
Most code will not need to use it.
Use `date.getFields()` instead.

Usage example:
```javascript
date = Temporal.Date.from('2006-08-24');
date.getISOCalendarFields().day // => 24
```
15 changes: 14 additions & 1 deletion docs/datetime.md
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,6 @@ This method can be used to convert a `Temporal.DateTime` into a record-like data
It returns a new plain JavaScript object, with all the fields as enumerable, writable, own data properties.

Note that if using a different calendar from ISO 8601, these will be the calendar-specific values.
To get the ISO 8601 values, use `datetime.getISOFields()`.

> **NOTE**: The possible values for the `month` property of the returned object start at 1, which is different from legacy `Date` where months are represented by zero-based indices (0 to 11).
Expand All @@ -596,3 +595,17 @@ dt = Temporal.DateTime.from('1995-12-07T03:24:30.000003500');
Object.assign({}, dt).day // => undefined
Object.assign({}, dt.getFields()).day // => 7
```

### datetime.**getISOCalendarFields**(): { year: number, month: number, day: number, hour: number, minute: number, second: number, millisecond: number, microsecond: number, nanosecond: number }

**Returns:** a plain object with properties expressing `datetime` in the ISO 8601 calendar.

This method is mainly useful if you are implementing a custom calendar.
Most code will not need to use it.
Use `datetime.getFields()` instead.

Usage example:
```javascript
dt = Temporal.Date.from('1995-12-07T03:24:30.000003500');
date.getISOCalendarFields().day // => 7
```
15 changes: 14 additions & 1 deletion docs/monthday.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,6 @@ This method can be used to convert a `Temporal.MonthDay` into a record-like data
It returns a new plain JavaScript object, with all the fields as enumerable, writable, own data properties.

Note that if using a different calendar from ISO 8601, these will be the calendar-specific values.
To get the ISO 8601 values, use `datetime.getISOFields()`.

> **NOTE**: The possible values for the `month` property of the returned object start at 1, which is different from legacy `Date` where months are represented by zero-based indices (0 to 11).
Expand All @@ -280,3 +279,17 @@ md = Temporal.MonthDay.from('08-24');
Object.assign({}, md).day // => undefined
Object.assign({}, md.getFields()).day // => 24
```

### monthDay.**getISOCalendarFields**(): { month: number, day: number }

**Returns:** a plain object with properties expressing `monthDay` in the ISO 8601 calendar.

This method is mainly useful if you are implementing a custom calendar.
Most code will not need to use it.
Use `monthDay.getFields()` instead.

Usage example:
```javascript
md = Temporal.MonthDay.from('08-24');
md.getISOCalendarFields().day // => 24
```
15 changes: 14 additions & 1 deletion docs/yearmonth.md
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,6 @@ This method can be used to convert a `Temporal.YearMonth` into a record-like dat
It returns a new plain JavaScript object, with all the fields as enumerable, writable, own data properties.

Note that if using a different calendar from ISO 8601, these will be the calendar-specific values.
To get the ISO 8601 values, use `yearMonth.getISOFields()`.

> **NOTE**: The possible values for the `month` property of the returned object start at 1, which is different from legacy `Date` where months are represented by zero-based indices (0 to 11).
Expand All @@ -446,3 +445,17 @@ ym = Temporal.DateTime.from('2019-06');
Object.assign({}, ym).year // => undefined
Object.assign({}, ym.getFields()).year // => 2019
```

### yearMonth.**getISOCalendarFields**(): { year: number, month: number }

**Returns:** a plain object with properties expressing `yearMonth` in the ISO 8601 calendar.

This method is mainly useful if you are implementing a custom calendar.
Most code will not need to use it.
Use `yearMonth.getFields()` instead.

Usage example:
```javascript
ym = Temporal.YearMonth.from('2019-06');
ym.getISOCalendarFields().year // => 2019
```
32 changes: 32 additions & 0 deletions polyfill/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,12 @@ export namespace Temporal {
day?: number;
};

export type DateISOCalendarFields = {
year: number;
month: number;
day: number;
};

/**
* A `Temporal.Date` represents a calendar date. "Calendar date" refers to the
* concept of a date as expressed in everyday usage, independent of any time
Expand Down Expand Up @@ -222,6 +228,7 @@ export namespace Temporal {
getYearMonth(): Temporal.YearMonth;
getMonthDay(): Temporal.MonthDay;
getFields(): Required<DateLike>;
getISOCalendarFields(): DateISOCalendarFields;
toLocaleString(locales?: string | string[], options?: Intl.DateTimeFormatOptions): string;
toJSON(): string;
toString(): string;
Expand All @@ -239,6 +246,18 @@ export namespace Temporal {
nanosecond?: number;
};

export type DateTimeISOCalendarFields = {
year: number;
month: number;
day: number;
hour: number;
minute: number;
second: number;
millisecond: number;
microsecond: number;
nanosecond: number;
};

/**
* A `Temporal.DateTime` represents a calendar date and wall-clock time, with
* a precision in nanoseconds, and without any time zone. Of the Temporal
Expand Down Expand Up @@ -292,6 +311,7 @@ export namespace Temporal {
getMonthDay(): Temporal.MonthDay;
getTime(): Temporal.Time;
getFields(): Required<DateTimeLike>;
getISOCalendarFields(): DateTimeISOCalendarFields;
toLocaleString(locales?: string | string[], options?: Intl.DateTimeFormatOptions): string;
toJSON(): string;
toString(): string;
Expand All @@ -302,6 +322,11 @@ export namespace Temporal {
day?: number;
};

export type MonthDayISOCalendarFields = {
month: number;
day: number;
};

/**
* A `Temporal.MonthDay` represents a particular day on the calendar, but
* without a year. For example, it could be used to represent a yearly
Expand All @@ -318,6 +343,7 @@ export namespace Temporal {
with(monthDayLike: MonthDayLike, options?: AssignmentOptions): Temporal.MonthDay;
withYear(year: number | { year: number }): Temporal.Date;
getFields(): Required<MonthDayLike>;
getISOCalendarFields(): MonthDayISOCalendarFields;
toLocaleString(locales?: string | string[], options?: Intl.DateTimeFormatOptions): string;
toJSON(): string;
toString(): string;
Expand Down Expand Up @@ -408,6 +434,11 @@ export namespace Temporal {
month?: number;
};

export type YearMonthISOCalendarFields = {
year: number;
month: number;
};

/**
* A `Temporal.YearMonth` represents a particular month on the calendar. For
* example, it could be used to represent a particular instance of a monthly
Expand All @@ -431,6 +462,7 @@ export namespace Temporal {
difference(other: Temporal.YearMonth, options: DifferenceOptions<'years' | 'months'>): Temporal.Duration;
withDay(day: number): Temporal.Date;
getFields(): Required<YearMonthLike>;
getISOCalendarFields(): YearMonthISOCalendarFields;
toLocaleString(locales?: string | string[], options?: Intl.DateTimeFormatOptions): string;
toJSON(): string;
toString(): string;
Expand Down
8 changes: 8 additions & 0 deletions polyfill/lib/date.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,14 @@ export class Date {
if (!fields) throw new TypeError('invalid receiver');
return fields;
}
getISOCalendarFields() {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
return {
year: GetSlot(this, ISO_YEAR),
month: GetSlot(this, ISO_MONTH),
day: GetSlot(this, ISO_DAY)
};
}
static from(item, options = undefined) {
const disambiguation = ES.ToTemporalDisambiguation(options);
let year, month, day;
Expand Down
14 changes: 14 additions & 0 deletions polyfill/lib/datetime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,20 @@ export class DateTime {
if (!fields) throw new TypeError('invalid receiver');
return fields;
}
getISOCalendarFields() {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
return {
year: GetSlot(this, ISO_YEAR),
month: GetSlot(this, ISO_MONTH),
day: GetSlot(this, ISO_DAY),
hour: GetSlot(this, HOUR),
minute: GetSlot(this, MINUTE),
second: GetSlot(this, SECOND),
millisecond: GetSlot(this, MILLISECOND),
microsecond: GetSlot(this, MICROSECOND),
nanosecond: GetSlot(this, NANOSECOND)
};
}

static from(item, options = undefined) {
const disambiguation = ES.ToTemporalDisambiguation(options);
Expand Down
7 changes: 7 additions & 0 deletions polyfill/lib/monthday.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ export class MonthDay {
if (!fields) throw new TypeError('invalid receiver');
return fields;
}
getISOCalendarFields() {
if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver');
return {
month: GetSlot(this, ISO_MONTH),
day: GetSlot(this, ISO_DAY)
};
}
static from(item, options = undefined) {
const disambiguation = ES.ToTemporalDisambiguation(options);
let month, day;
Expand Down
7 changes: 7 additions & 0 deletions polyfill/lib/yearmonth.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ export class YearMonth {
if (!fields) throw new TypeError('invalid receiver');
return fields;
}
getISOCalendarFields() {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
return {
year: GetSlot(this, ISO_YEAR),
month: GetSlot(this, ISO_MONTH)
};
}
static from(item, options = undefined) {
const disambiguation = ES.ToTemporalDisambiguation(options);
let year, month;
Expand Down
16 changes: 16 additions & 0 deletions polyfill/test/Date/prototype/getISOCalendarFields/branding.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (C) 2020 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

const getISOCalendarFields = Temporal.Date.prototype.getISOCalendarFields;

assert.sameValue(typeof getISOCalendarFields, "function");

assert.throws(TypeError, () => getISOCalendarFields.call(undefined), "undefined");
assert.throws(TypeError, () => getISOCalendarFields.call(null), "null");
assert.throws(TypeError, () => getISOCalendarFields.call(true), "true");
assert.throws(TypeError, () => getISOCalendarFields.call(""), "empty string");
assert.throws(TypeError, () => getISOCalendarFields.call(Symbol()), "symbol");
assert.throws(TypeError, () => getISOCalendarFields.call(1), "1");
assert.throws(TypeError, () => getISOCalendarFields.call({}), "plain object");
assert.throws(TypeError, () => getISOCalendarFields.call(Temporal.Date), "Temporal.Date");
assert.throws(TypeError, () => getISOCalendarFields.call(Temporal.Date.prototype), "Temporal.Date.prototype");
18 changes: 18 additions & 0 deletions polyfill/test/Date/prototype/getISOCalendarFields/prop-desc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (C) 2020 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
includes: [propertyHelper.js]
---*/

assert.sameValue(
typeof Temporal.Date.prototype.getISOCalendarFields,
"function",
"`typeof Date.prototype.getISOCalendarFields` is `function`"
);

verifyProperty(Temporal.Date.prototype, "getISOCalendarFields", {
writable: true,
enumerable: false,
configurable: true,
});
31 changes: 31 additions & 0 deletions polyfill/test/Date/prototype/getISOCalendarFields/subclass.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (C) 2020 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.date.prototype.getisocalendarfields
includes: [compareArray.js]
---*/

let called = 0;

const constructorArguments = [
[2000, 5, 2]
];

class MyDate extends Temporal.Date {
constructor(year, month, day) {
assert.compareArray([year, month, day], constructorArguments.shift(), "constructor arguments");
++called;
super(year, month, day);
}
}

const instance = MyDate.from("2000-05-02");
assert.sameValue(called, 1);

const result = instance.getISOCalendarFields();
assert.sameValue(result.year, 2000, "year result");
assert.sameValue(result.month, 5, "month result");
assert.sameValue(result.day, 2, "day result");
assert.sameValue(called, 1);
assert.sameValue(Object.getPrototypeOf(result), Object.prototype);
16 changes: 16 additions & 0 deletions polyfill/test/DateTime/prototype/getISOCalendarFields/branding.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (C) 2020 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

const getISOCalendarFields = Temporal.DateTime.prototype.getISOCalendarFields;

assert.sameValue(typeof getISOCalendarFields, "function");

assert.throws(TypeError, () => getISOCalendarFields.call(undefined), "undefined");
assert.throws(TypeError, () => getISOCalendarFields.call(null), "null");
assert.throws(TypeError, () => getISOCalendarFields.call(true), "true");
assert.throws(TypeError, () => getISOCalendarFields.call(""), "empty string");
assert.throws(TypeError, () => getISOCalendarFields.call(Symbol()), "symbol");
assert.throws(TypeError, () => getISOCalendarFields.call(1), "1");
assert.throws(TypeError, () => getISOCalendarFields.call({}), "plain object");
assert.throws(TypeError, () => getISOCalendarFields.call(Temporal.DateTime), "Temporal.DateTime");
assert.throws(TypeError, () => getISOCalendarFields.call(Temporal.DateTime.prototype), "Temporal.DateTime.prototype");
18 changes: 18 additions & 0 deletions polyfill/test/DateTime/prototype/getISOCalendarFields/prop-desc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (C) 2020 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
includes: [propertyHelper.js]
---*/

assert.sameValue(
typeof Temporal.DateTime.prototype.getISOCalendarFields,
"function",
"`typeof DateTime.prototype.getISOCalendarFields` is `function`"
);

verifyProperty(Temporal.DateTime.prototype, "getISOCalendarFields", {
writable: true,
enumerable: false,
configurable: true,
});
37 changes: 37 additions & 0 deletions polyfill/test/DateTime/prototype/getISOCalendarFields/subclass.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (C) 2020 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-temporal.datetime.prototype.getisocalendarfields
includes: [compareArray.js]
---*/

let called = 0;

const constructorArguments = [
[2000, 5, 2, 12, 34, 56, 987, 654, 321]
];

class MyDateTime extends Temporal.DateTime {
constructor(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond) {
assert.compareArray([year, month, day, hour, minute, second, millisecond, microsecond, nanosecond], constructorArguments.shift(), "constructor arguments");
++called;
super(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond);
}
}

const instance = MyDateTime.from("2000-05-02T12:34:56.987654321");
assert.sameValue(called, 1);

const result = instance.getISOCalendarFields();
assert.sameValue(result.year, 2000, "year result");
assert.sameValue(result.month, 5, "month result");
assert.sameValue(result.day, 2, "day result");
assert.sameValue(result.hour, 12, "hour result");
assert.sameValue(result.minute, 34, "minute result");
assert.sameValue(result.second, 56, "second result");
assert.sameValue(result.millisecond, 987, "millisecond result");
assert.sameValue(result.microsecond, 654, "microsecond result");
assert.sameValue(result.nanosecond, 321, "nanosecond result");
assert.sameValue(called, 1);
assert.sameValue(Object.getPrototypeOf(result), Object.prototype);
Loading

0 comments on commit 831b7a1

Please sign in to comment.