Skip to content

Commit

Permalink
Add eras to Gregorian calendar
Browse files Browse the repository at this point in the history
As part of this issue we decided that another difference between the ISO
and Gregorian calendars is that the latter has BC/AD eras. It's
indeterminate how this will exactly be standardized, as that's up to
ECMA-402, but we add it to the experimental Gregorian calendar in the
polyfill.

See: #901
  • Loading branch information
ptomato committed Oct 23, 2020
1 parent 2282eb4 commit 7881996
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 2 deletions.
42 changes: 40 additions & 2 deletions polyfill/lib/calendar.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 26 additions & 0 deletions polyfill/test/calendar.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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])) {
Expand Down

0 comments on commit 7881996

Please sign in to comment.