Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,8 +603,9 @@ export namespace Temporal {
readonly [Symbol.toStringTag]: 'Temporal.Instant';
}

type EitherYearOrEraAndEraYear = { era: string; eraYear: number } | { year: number };
type EitherMonthCodeOrMonthAndYear = (EitherYearOrEraAndEraYear & { month: number }) | { monthCode: string };
type YearOrEraAndEraYear = { era: string; eraYear: number } | { year: number };
type MonthCodeOrMonthAndYear = (YearOrEraAndEraYear & { month: number }) | { monthCode: string };
type MonthOrMonthCode = { month: number } | { monthCode: string };

export interface CalendarProtocol {
id?: string;
Expand Down Expand Up @@ -648,15 +649,15 @@ export namespace Temporal {
date: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainYearMonth | PlainDateLike | string
): boolean;
dateFromFields(
fields: EitherMonthCodeOrMonthAndYear & { day: number },
fields: YearOrEraAndEraYear & MonthOrMonthCode & { day: number },
options?: AssignmentOptions
): Temporal.PlainDate;
yearMonthFromFields(
fields: EitherYearOrEraAndEraYear & ({ month: number } | { monthCode: string }),
fields: YearOrEraAndEraYear & MonthOrMonthCode,
options?: AssignmentOptions
): Temporal.PlainYearMonth;
monthDayFromFields(
fields: EitherMonthCodeOrMonthAndYear & { day: number },
fields: MonthCodeOrMonthAndYear & { day: number },
options?: AssignmentOptions
): Temporal.PlainMonthDay;
dateAdd(
Expand Down Expand Up @@ -726,15 +727,15 @@ export namespace Temporal {
date: Temporal.PlainDate | Temporal.PlainDateTime | Temporal.PlainYearMonth | PlainDateLike | string
): boolean;
dateFromFields(
fields: EitherMonthCodeOrMonthAndYear & { day: number },
fields: YearOrEraAndEraYear & MonthOrMonthCode & { day: number },
options?: AssignmentOptions
): Temporal.PlainDate;
yearMonthFromFields(
fields: EitherYearOrEraAndEraYear & ({ month: number } | { monthCode: string }),
fields: YearOrEraAndEraYear & MonthOrMonthCode,
options?: AssignmentOptions
): Temporal.PlainYearMonth;
monthDayFromFields(
fields: EitherMonthCodeOrMonthAndYear & { day: number },
fields: MonthCodeOrMonthAndYear & { day: number },
options?: AssignmentOptions
): Temporal.PlainMonthDay;
dateAdd(
Expand Down
42 changes: 24 additions & 18 deletions lib/calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import type {
const ArrayIncludes = Array.prototype.includes;
const ArrayPrototypePush = Array.prototype.push;
const IntlDateTimeFormat = globalThis.Intl.DateTimeFormat;
const ArraySort = Array.prototype.sort;
const MathAbs = Math.abs;
const MathFloor = Math.floor;
const ObjectAssign = Object.assign;
Expand Down Expand Up @@ -529,7 +530,7 @@ class OneObjectCache {
constructor(cacheToClone: OneObjectCache = undefined) {
this.now = globalThis.performance ? globalThis.performance.now() : Date.now();
if (cacheToClone !== undefined) {
let i = 0; // TODO why was this originally cacheToClone.length ?
let i = 0;
for (const entry of cacheToClone.map.entries()) {
if (++i > OneObjectCache.MAX_CACHE_ENTRIES) break;
this.map.set(...entry);
Expand Down Expand Up @@ -643,7 +644,7 @@ interface NonIsoHelperBase {
reviseIntlEra?(calendarDate: any, isoDate?: any): { era: number; eraYear: number };
hasEra?: boolean;
constantEra?: string;
checkIcuBugs?(calendarDate: any, isoDate: any): void;
checkIcuBugs?(isoDate: any): void;
calendarType?: string;
monthsInYear?(calendarDate: any, cache?: any): number;
maximumMonthLength?(calendarDate?: any): number;
Expand Down Expand Up @@ -761,7 +762,7 @@ const nonIsoHelperBase: NonIsoHelperBase = {
result.era = era;
result.eraYear = eraYear;
}
if (this.checkIcuBugs) this.checkIcuBugs(result, isoDate);
if (this.checkIcuBugs) this.checkIcuBugs(isoDate);

const calendarDate = this.adjustCalendarDate(result, cache, 'constrain', true);
if (calendarDate.year === undefined) throw new RangeError(`Missing year converting ${JSON.stringify(isoDate)}`);
Expand Down Expand Up @@ -820,18 +821,22 @@ const nonIsoHelperBase: NonIsoHelperBase = {
if (this.calendarType === 'lunisolar') throw new RangeError('Override required for lunisolar calendars');
let calendarDate = calendarDateParam;
this.validateCalendarDate(calendarDate);
const largestMonth = this.monthsInYear(calendarDate, cache);
let { month, year, eraYear, monthCode } = calendarDate;

// For calendars that always use the same era, set it here so that derived
// calendars won't need to implement this method simply to set the era.
if (this.constantEra) {
// year and eraYear always match when there's only one possible era
if (year === undefined) year = eraYear;
if (eraYear === undefined) eraYear = year;
calendarDate = { ...calendarDate, era: this.constantEra, year, eraYear };
const { year, eraYear } = calendarDate;
calendarDate = {
...calendarDate,
era: this.constantEra,
year: year !== undefined ? year : eraYear,
eraYear: eraYear !== undefined ? eraYear : year
};
}

const largestMonth = this.monthsInYear(calendarDate, cache);
let { month, monthCode } = calendarDate;

({ month, monthCode } = resolveNonLunisolarMonth(calendarDate, overflow, largestMonth));
return { ...calendarDate, month, monthCode };
},
Expand Down Expand Up @@ -1300,8 +1305,8 @@ const helperHebrew: NonIsoHelperBase = ObjectAssign({}, nonIsoHelperBase, {
fromLegacyDate = false
) {
let { year, eraYear, month, monthCode, day, monthExtra } = calendarDate;
if (year === undefined) year = eraYear;
if (eraYear === undefined) eraYear = year;
if (year === undefined && eraYear !== undefined) year = eraYear;
if (eraYear === undefined && year !== undefined) eraYear = year;
if (fromLegacyDate) {
// In Pre Node-14 V8, DateTimeFormat.formatToParts `month: 'numeric'`
// output returns the numeric equivalent of `month` as a string, meaning
Expand Down Expand Up @@ -1348,10 +1353,10 @@ const helperHebrew: NonIsoHelperBase = ObjectAssign({}, nonIsoHelperBase, {
} else {
if (overflow === 'reject') {
ES.RejectToRange(month, 1, this.monthsInYear({ year }));
ES.RejectToRange(day, 1, this.maximumMonthLength(calendarDate));
ES.RejectToRange(day, 1, this.maximumMonthLength({ year, month }));
} else {
month = ES.ConstrainToRange(month, 1, this.monthsInYear({ year }));
day = ES.ConstrainToRange(day, 1, this.maximumMonthLength({ ...calendarDate, month }));
day = ES.ConstrainToRange(day, 1, this.maximumMonthLength({ year, month }));
}
if (monthCode === undefined) {
monthCode = this.getMonthCode(year, month);
Expand Down Expand Up @@ -1485,7 +1490,7 @@ const helperIndian: NonIsoHelperBase = ObjectAssign({}, nonIsoHelperBase, {
// expected.
vulnerableToBceBug:
new Date('0000-01-01T00:00Z').toLocaleDateString('en-US-u-ca-indian', { timeZone: 'UTC' }) !== '10/11/-79 Saka',
checkIcuBugs(calendarDate, isoDate) {
checkIcuBugs(isoDate) {
if (this.vulnerableToBceBug && isoDate.year < 1) {
throw new RangeError(
`calendar '${this.id}' is broken for ISO dates before 0001-01-01` +
Expand Down Expand Up @@ -1650,9 +1655,10 @@ function adjustEras(erasParam: InputEra[]): { eras: Era[]; anchorEra: Era } {
// Ensure that the latest epoch is first in the array. This lets us try to
// match eras in index order, with the last era getting the remaining older
// years. Any reverse-signed era must be at the end.
eras.sort((e1, e2) => {
ArraySort.call(eras, (e1, e2) => {
if (e1.reverseOf) return 1;
if (e2.reverseOf) return -1;
if (!e1.isoEpoch || !e2.isoEpoch) throw new RangeError('Invalid era data: missing ISO epoch');
return e2.isoEpoch.year - e1.isoEpoch.year;
});

Expand Down Expand Up @@ -1794,7 +1800,7 @@ const makeHelperGregorian = (id: BuiltinCalendarId, originalEras: InputEra[]) =>
.toLocaleDateString('en-US-u-ca-japanese', { timeZone: 'UTC' })
.startsWith('12'),
calendarIsVulnerableToJulianBug: false,
checkIcuBugs(calendarDate, isoDate) {
checkIcuBugs(isoDate) {
if (this.calendarIsVulnerableToJulianBug && this.v8IsVulnerableToJulianBug) {
const beforeJulianSwitch = ES.CompareISODate(isoDate.year, isoDate.month, isoDate.day, 1582, 10, 15) < 0;
if (beforeJulianSwitch) {
Expand Down Expand Up @@ -2079,7 +2085,7 @@ const helperChinese: NonIsoHelperBase = ObjectAssign({}, nonIsoHelperBase, {
if (
month === undefined &&
monthCode.endsWith('L') &&
!['M01L', 'M12L', 'M13L'].includes(monthCode) &&
!ArrayIncludes.call(['M01L', 'M12L', 'M13L'], monthCode) &&
overflow === 'constrain'
) {
let withoutML = monthCode.slice(1, -1);
Expand Down Expand Up @@ -2262,7 +2268,7 @@ const nonIsoGeneralImpl: NonIsoGeneralImpl = {
},
fields(fieldsParam) {
let fields = fieldsParam;
if (fields.includes('year')) fields = [...fields, 'era', 'eraYear'];
if (ArrayIncludes.call(fields, 'year')) fields = [...fields, 'era', 'eraYear'];
return fields;
},
mergeFields(fields, additionalFields) {
Expand Down