diff --git a/polyfill/lib/calendar.mjs b/polyfill/lib/calendar.mjs index 52ef4437f8..f6a04510ff 100644 --- a/polyfill/lib/calendar.mjs +++ b/polyfill/lib/calendar.mjs @@ -283,13 +283,51 @@ class ISO8601Calendar extends Calendar { MakeIntrinsicClass(ISO8601Calendar, 'Temporal.ISO8601Calendar'); -// According to documentation for Intl.Locale.prototype.calendar on MDN, +// Note: other built-in calendars than iso8601 are not part of the Temporal +// proposal for ECMA-262. These calendars will be standardized as part of +// ECMA-402. + +// Implementation details for Gregorian calendar +const gre = { + isoYear(year, era) { + return era === 'bc' ? -(year - 1) : year; + } +}; + // 'iso8601' calendar is equivalent to 'gregory' except for ISO 8601 week -// numbering rules, which we do not currently use in Temporal. +// numbering rules, which we do not currently use in Temporal, and the addition +// of BC/AD eras which means no negative years or year 0. class Gregorian extends ISO8601Calendar { constructor() { super('gregory'); } + + era(date) { + return GetSlot(date, ISO_YEAR) < 1 ? 'bc' : 'ad'; + } + year(date) { + const isoYear = GetSlot(date, ISO_YEAR); + return isoYear < 1 ? -isoYear + 1 : isoYear; + } + + fields(fields) { + fields = super.fields(fields); + if (fields.includes('year')) fields.push('era'); + return fields; + } + + dateFromFields(fields, options, constructor) { + // Intentionally alphabetical + fields = ES.ToRecord(fields, [['day'], ['era', 'ad'], ['month'], ['year']]); + const isoYear = gre.isoYear(fields.year, fields.era); + return super.dateFromFields({ ...fields, year: isoYear }, options, constructor); + } + yearMonthFromFields(fields, options, constructor) { + // Intentionally alphabetical + fields = ES.ToRecord(fields, [['era', 'ad'], ['month'], ['year']]); + const isoYear = gre.isoYear(fields.year, fields.era); + return super.yearMonthFromFields({ ...fields, year: isoYear }, options, constructor); + } } // Implementation details for Japanese calendar diff --git a/polyfill/test/calendar.mjs b/polyfill/test/calendar.mjs index 6feae35aa4..bf7a4988fb 100644 --- a/polyfill/test/calendar.mjs +++ b/polyfill/test/calendar.mjs @@ -150,6 +150,32 @@ describe('Calendar', () => { }); }); }); +describe('Built-in calendars (not standardized yet)', () => { + describe('gregory', () => { + it('era AD', () => { + const date = Temporal.Date.from('1999-12-31[c=gregory]'); + equal(date.era, 'ad'); + equal(date.year, 1999); + }); + it('era BC', () => { + const date = Temporal.Date.from('-000001-12-31[c=gregory]'); + equal(date.era, 'bc'); + equal(date.year, 2); + }); + it('can create from fields with era AD', () => { + const date = Temporal.Date.from({ era: 'ad', year: 1999, month: 12, day: 31, calendar: 'gregory' }); + equal(`${date}`, '1999-12-31[c=gregory]'); + }); + it('era AD is the default', () => { + const date = Temporal.Date.from({ year: 1999, month: 12, day: 31, calendar: 'gregory' }); + equal(`${date}`, '1999-12-31[c=gregory]'); + }); + it('can create from fields with era BC', () => { + const date = Temporal.Date.from({ era: 'bc', year: 2, month: 12, day: 31, calendar: 'gregory' }); + equal(`${date}`, '-000001-12-31[c=gregory]'); + }); + }); +}); import { normalize } from 'path'; if (normalize(import.meta.url.slice(8)) === normalize(process.argv[1])) {