Skip to content

Commit

Permalink
RefIsoYear and RefIsoDay internal slots
Browse files Browse the repository at this point in the history
Temporal.YearMonth gets a RefIsoDay internal slot and Temporal.MonthDay
gets a RefIsoYear internal slot, as discussed in #391. This will be
required for calendar support.
  • Loading branch information
ptomato committed May 25, 2020
1 parent af94b7a commit 672b6b5
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 27 deletions.
10 changes: 6 additions & 4 deletions docs/monthday.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,22 @@ A `Temporal.MonthDay` can be converted into a `Temporal.Date` by combining it wi

## Constructor

### **new Temporal.MonthDay**(_isoMonth_: number, _isoDay_: number) : Temporal.MonthDay
### **new Temporal.MonthDay**(_isoMonth_: number, _isoDay_: number, _refIsoYear_: number = 1972) : Temporal.MonthDay

**Parameters:**
- `isoMonth` (number): A month, ranging between 1 and 12 inclusive.
- `isoDay` (number): A day of the month, ranging between 1 and 31 inclusive.
- `refIsoYear` (optional number): A reference year, used for disambiguation when implementing other calendar systems.
This parameter can usually be omitted.

**Returns:** a new `Temporal.MonthDay` object.

Use this constructor if you have the correct parameters for the date already as individual number values.
Use this constructor if you have the correct parameters for the date already as individual number values, or you are implementing a custom calendar.
Otherwise, `Temporal.MonthDay.from()`, which accepts more kinds of input and allows disambiguation behaviour, is probably more convenient.

All values are given as reckoned in the [ISO 8601 calendar](https://en.wikipedia.org/wiki/ISO_8601#Dates).
Together, `isoMonth` and `isoDay` must represent a valid date in at least one year of that calendar.
For example, February 29 (Leap day in the ISO 8601 calendar) is a valid value for `Temporal.MonthDay`, even though that date does not occur every year.
Together, `refIsoYear`, `isoMonth` and `isoDay` must represent a valid date in that calendar.
For example, February 29 (Leap day in the ISO 8601 calendar) is a valid value for `Temporal.MonthDay`, even though that date does not occur every year, because the default value of `refIsoYear` is 1972 which is a leap year.

> **NOTE**: The `isoMonth` argument ranges from 1 to 12, which is different from legacy `Date` where months are represented by zero-based indices (0 to 11).
Expand Down
8 changes: 5 additions & 3 deletions docs/yearmonth.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,21 @@ A `Temporal.YearMonth` can be converted into a `Temporal.Date` by combining it w

## Constructor

### **new Temporal.YearMonth**(_isoYear_: number, _isoMonth_: number) : Temporal.YearMonth
### **new Temporal.YearMonth**(_isoYear_: number, _isoMonth_: number, _refIsoDay_: number = 1) : Temporal.YearMonth

**Parameters:**
- `isoYear` (number): A year.
- `isoMonth` (number): A month, ranging between 1 and 12 inclusive.
- `refIsoDay` (optional number): A reference day, used for disambiguation when implementing other calendar systems.
This parameter can usually be omitted.

**Returns:** a new `Temporal.YearMonth` object.

Use this constructor if you have the correct parameters already as individual number values.
Use this constructor if you have the correct parameters already as individual number values, or you are implementing a custom calendar.
Otherwise, `Temporal.YearMonth.from()`, which accepts more kinds of input and allows disambiguation behaviour, is probably more convenient.

All values are given as reckoned in the [ISO 8601 calendar](https://en.wikipedia.org/wiki/ISO_8601#Dates).
Together, `isoYear` and `isoMonth` must represent a valid month in that calendar.
Together, `isoYear`, `isoMonth`, and `refIsoDay` must represent a valid date in that calendar.

The range of allowed values for this type is exactly enough that calling [`getYearMonth()`](./date.html#getYearMonth) on any valid `Temporal.Date` will succeed.
If `isoYear` and `isoMonth` are outside of this range, then `constrain` mode will clamp the date to the limit of the allowed range.
Expand Down
22 changes: 13 additions & 9 deletions polyfill/lib/ecmascript.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import {
MILLISECOND,
MICROSECOND,
NANOSECOND,
REF_ISO_YEAR,
REF_ISO_DAY,
YEARS,
MONTHS,
DAYS,
Expand Down Expand Up @@ -52,8 +54,8 @@ export const ES = ObjectAssign({}, ES2019, {
!HasSlot(item, ISO_YEAR, ISO_MONTH, ISO_DAY),
IsTemporalDateTime: (item) =>
HasSlot(item, ISO_YEAR, ISO_MONTH, ISO_DAY, HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND, NANOSECOND),
IsTemporalYearMonth: (item) => HasSlot(item, ISO_YEAR, ISO_MONTH) && !HasSlot(item, ISO_DAY),
IsTemporalMonthDay: (item) => HasSlot(item, ISO_MONTH, ISO_DAY) && !HasSlot(item, ISO_YEAR),
IsTemporalYearMonth: (item) => HasSlot(item, ISO_YEAR, ISO_MONTH, REF_ISO_DAY),
IsTemporalMonthDay: (item) => HasSlot(item, ISO_MONTH, ISO_DAY, REF_ISO_YEAR),
ToTemporalTimeZone: (item) => {
if (ES.IsTemporalTimeZone(item)) return item;
const TimeZone = GetIntrinsic('%Temporal.TimeZone%');
Expand Down Expand Up @@ -281,32 +283,33 @@ export const ES = ObjectAssign({}, ES2019, {
return { hour, minute, second, millisecond, microsecond, nanosecond };
},
RegulateYearMonth: (year, month, disambiguation) => {
const refIsoDay = 1;
switch (disambiguation) {
case 'reject':
ES.RejectYearMonth(year, month);
ES.RejectYearMonth(year, month, refIsoDay);
break;
case 'constrain':
({ year, month } = ES.ConstrainYearMonth(year, month));
break;
case 'balance':
({ year, month } = ES.BalanceYearMonth(year, month));
// Still rejected if balanced YearMonth is outside valid range
ES.RejectYearMonth(year, month);
ES.RejectYearMonth(year, month, refIsoDay);
break;
}
return { year, month };
},
RegulateMonthDay: (month, day, disambiguation) => {
const leapYear = 1972;
const refIsoYear = 1972;
switch (disambiguation) {
case 'reject':
ES.RejectDate(leapYear, month, day);
ES.RejectDate(refIsoYear, month, day);
break;
case 'constrain':
({ month, day } = ES.ConstrainDate(leapYear, month, day));
({ month, day } = ES.ConstrainDate(refIsoYear, month, day));
break;
case 'balance':
({ month, day } = ES.BalanceDate(leapYear, month, day));
({ month, day } = ES.BalanceDate(refIsoYear, month, day));
break;
}
return { month, day };
Expand Down Expand Up @@ -1053,7 +1056,7 @@ export const ES = ObjectAssign({}, ES2019, {
throw new RangeError('Absolute outside of supported range');
}
},
RejectYearMonth: (year, month) => {
RejectYearMonth: (year, month, refIsoDay) => {
ES.RejectToRange(year, YEAR_MIN, YEAR_MAX);
if (year === YEAR_MIN) {
ES.RejectToRange(month, 4, 12);
Expand All @@ -1062,6 +1065,7 @@ export const ES = ObjectAssign({}, ES2019, {
} else {
ES.RejectToRange(month, 1, 12);
}
ES.RejectToRange(refIsoDay, 1, ES.DaysInMonth(year, month));
},

DifferenceDate: (smaller, larger, largestUnit = 'days') => {
Expand Down
16 changes: 10 additions & 6 deletions polyfill/lib/monthday.mjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { ES } from './ecmascript.mjs';
import { GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass.mjs';
import { ISO_MONTH, ISO_DAY, CreateSlots, GetSlot, SetSlot } from './slots.mjs';
import { ISO_MONTH, ISO_DAY, REF_ISO_YEAR, CreateSlots, GetSlot, SetSlot } from './slots.mjs';

export class MonthDay {
constructor(isoMonth, isoDay) {
constructor(isoMonth, isoDay, refIsoYear = 1972) {
isoMonth = ES.ToInteger(isoMonth);
isoDay = ES.ToInteger(isoDay);
const leapYear = 1972; // XXX #261 leap year
ES.RejectDate(leapYear, isoMonth, isoDay);
refIsoYear = ES.ToInteger(refIsoYear);
ES.RejectDate(refIsoYear, isoMonth, isoDay);

CreateSlots(this);
SetSlot(this, ISO_MONTH, isoMonth);
SetSlot(this, ISO_DAY, isoDay);
SetSlot(this, REF_ISO_YEAR, refIsoYear);
}

get month() {
Expand Down Expand Up @@ -85,20 +86,23 @@ export class MonthDay {
}
static from(item, options = undefined) {
const disambiguation = ES.ToTemporalDisambiguation(options);
let month, day;
let month, day, refIsoYear;
if (typeof item === 'object' && item) {
if (ES.IsTemporalMonthDay(item)) {
month = GetSlot(item, ISO_MONTH);
day = GetSlot(item, ISO_DAY);
refIsoYear = GetSlot(item, REF_ISO_YEAR);
} else {
// Intentionally alphabetical
({ month, day } = ES.ToRecord(item, [['day'], ['month']]));
refIsoYear = 1972;
}
} else {
({ month, day } = ES.ParseTemporalMonthDayString(ES.ToString(item)));
refIsoYear = 1972;
}
({ month, day } = ES.RegulateMonthDay(month, day, disambiguation));
const result = new this(month, day);
const result = new this(month, day, refIsoYear);
if (!ES.IsTemporalMonthDay(result)) throw new TypeError('invalid result');
return result;
}
Expand Down
2 changes: 2 additions & 0 deletions polyfill/lib/slots.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export const SECOND = 'slot-second';
export const MILLISECOND = 'slot-millisecond';
export const MICROSECOND = 'slot-microsecond';
export const NANOSECOND = 'slot-nanosecond';
export const REF_ISO_YEAR = 'slot-ref-iso-year';
export const REF_ISO_DAY = 'slot-ref-iso-day';

// Duration
export const YEARS = 'slot-years';
Expand Down
15 changes: 10 additions & 5 deletions polyfill/lib/yearmonth.mjs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { ES } from './ecmascript.mjs';
import { GetIntrinsic, MakeIntrinsicClass } from './intrinsicclass.mjs';
import { ISO_YEAR, ISO_MONTH, CreateSlots, GetSlot, SetSlot } from './slots.mjs';
import { ISO_YEAR, ISO_MONTH, REF_ISO_DAY, CreateSlots, GetSlot, SetSlot } from './slots.mjs';

export class YearMonth {
constructor(isoYear, isoMonth) {
constructor(isoYear, isoMonth, refIsoDay = 1) {
isoYear = ES.ToInteger(isoYear);
isoMonth = ES.ToInteger(isoMonth);
ES.RejectYearMonth(isoYear, isoMonth);
refIsoDay = ES.ToInteger(refIsoDay);
ES.RejectYearMonth(isoYear, isoMonth, refIsoDay);
CreateSlots(this);
SetSlot(this, ISO_YEAR, isoYear);
SetSlot(this, ISO_MONTH, isoMonth);
SetSlot(this, REF_ISO_DAY, refIsoDay);
}
get year() {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
Expand Down Expand Up @@ -154,20 +156,23 @@ export class YearMonth {
}
static from(item, options = undefined) {
const disambiguation = ES.ToTemporalDisambiguation(options);
let year, month;
let year, month, refIsoDay;
if (typeof item === 'object' && item) {
if (ES.IsTemporalYearMonth(item)) {
year = GetSlot(item, ISO_YEAR);
month = GetSlot(item, ISO_MONTH);
refIsoDay = GetSlot(item, REF_ISO_DAY);
} else {
// Intentionally alphabetical
({ year, month } = ES.ToRecord(item, [['month'], ['year']]));
refIsoDay = 1;
}
} else {
({ year, month } = ES.ParseTemporalYearMonthString(ES.ToString(item)));
refIsoDay = 1;
}
({ year, month } = ES.RegulateYearMonth(year, month, disambiguation));
const result = new this(year, month);
const result = new this(year, month, refIsoDay);
if (!ES.IsTemporalYearMonth(result)) throw new TypeError('invalid result');
return result;
}
Expand Down

0 comments on commit 672b6b5

Please sign in to comment.