Skip to content

Commit

Permalink
Sync calendar annotation format with the IETF draft
Browse files Browse the repository at this point in the history
IETF is moving forward with [n-kk=vvvvv] (n=namespace, k=key, v=value)
rather than [n-kk-vvvvv]. By definition, Temporal uses the format that is
being standardized within IETF.

Update the note in the spec text as well to remove the text saying that
the format is tentative. This is the format that IETF is moving forward
with.

Closes: #1409
Closes: #1412
  • Loading branch information
ptomato committed May 6, 2021
1 parent 42a10ba commit 29f7bc3
Show file tree
Hide file tree
Showing 14 changed files with 119 additions and 142 deletions.
2 changes: 1 addition & 1 deletion lib/ecmascript.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export const ES = ObjectAssign({}, ES2020, {
FormatCalendarAnnotation: (id, showCalendar) => {
if (showCalendar === 'never') return '';
if (showCalendar === 'auto' && id === 'iso8601') return '';
return `[u-ca-${id}]`;
return `[u-ca=${id}]`;
},
ParseISODateTime: (isoString, { zoneRequired }) => {
const regex = zoneRequired ? PARSE.instant : PARSE.datetime;
Expand Down
27 changes: 2 additions & 25 deletions lib/regex.mjs
Original file line number Diff line number Diff line change
@@ -1,30 +1,7 @@
// Per specification,
// TZLeadingChar TZChar? TZChar? TZChar? TZChar? TZChar? TZChar? TZChar?
// TZChar? TZChar? TZChar? TZChar? TZChar? TZChar?
// but not one of `.` or `..` or
// CalChar `-` CalChar CalChar `-` CalendarNameComponent
// In plain words, 1 to 14 letters, periods, underscores, or dashes, but not
// starting with a dash, and not consisting only of one or two periods, and not
// of the form (letter)-(2 letters)-(3 or more letters) which conflicts with
// calComponent
const tzComponentNotBCP47 = new RegExp(
[
'\\.\\.[-A-Za-z._]{1,12}',
'\\.[-A-Za-z_][-A-Za-z._]{0,12}',
'_[-A-Za-z._]{0,13}',
'[a-zA-Z](?:[A-Za-z._][-A-Za-z._]{0,12})?',
'[a-zA-Z]-(?:[-._][-A-Za-z._]{0,11})?',
'[a-zA-Z]-[a-zA-Z](?:[-._][-A-Za-z._]{0,10})?',
'[a-zA-Z]-[a-zA-Z][a-zA-Z](?:[A-Za-z._][-A-Za-z._]{0,9})?',
'[a-zA-Z]-[a-zA-Z][a-zA-Z]-(?:[-._][-A-Za-z._]{0,8})?',
'[a-zA-Z]-[a-zA-Z][a-zA-Z]-[a-zA-Z](?:[-._][-A-Za-z._]{0,7})?',
'[a-zA-Z]-[a-zA-Z][a-zA-Z]-[a-zA-Z][a-zA-Z](?:[-._][-A-Za-z._]{0,6})?'
].join('|')
);
const tzComponent = /\.[-A-Za-z_]|\.\.[-A-Za-z._]{1,12}|\.[-A-Za-z_][-A-Za-z._]{0,12}|[A-Za-z_][-A-Za-z._]{0,13}/;
const offsetNoCapture = /(?:[+\u2212-][0-2][0-9](?::?[0-5][0-9](?::?[0-5][0-9](?:[.,]\d{1,9})?)?)?)/;
export const timeZoneID = new RegExp(
`(?:(?:${tzComponentNotBCP47.source})(?:\\/(?:${tzComponent.source}))*|Etc/GMT[-+]\\d{1,2}|${offsetNoCapture.source})`
`(?:(?:${tzComponent.source})(?:\\/(?:${tzComponent.source}))*|Etc/GMT[-+]\\d{1,2}|${offsetNoCapture.source})`
);

const calComponent = /[A-Za-z0-9]{3,8}/;
Expand All @@ -35,7 +12,7 @@ export const datesplit = new RegExp(`(${yearpart.source})(?:-(\\d{2})-(\\d{2})|(
const timesplit = /(\d{2})(?::(\d{2})(?::(\d{2})(?:[.,](\d{1,9}))?)?|(\d{2})(?:(\d{2})(?:[.,](\d{1,9}))?)?)?/;
export const offset = /([+\u2212-])([01][0-9]|2[0-3])(?::?([0-5][0-9])(?::?([0-5][0-9])(?:[.,](\d{1,9}))?)?)?/;
const zonesplit = new RegExp(`(?:([zZ])|(?:${offset.source})?)(?:\\[(${timeZoneID.source})\\])?`);
const calendar = new RegExp(`\\[u-ca-(${calendarID.source})\\]`);
const calendar = new RegExp(`\\[u-ca=(${calendarID.source})\\]`);

export const instant = new RegExp(
`^${datesplit.source}(?:(?:T|\\s+)${timesplit.source})?${zonesplit.source}(?:${calendar.source})?$`,
Expand Down
24 changes: 12 additions & 12 deletions test/calendar.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,10 @@ describe('Calendar', () => {
}
it('other types with a calendar are accepted', () => {
[
Temporal.PlainDate.from('1976-11-18[u-ca-gregory]'),
Temporal.PlainDateTime.from('1976-11-18[u-ca-gregory]'),
Temporal.PlainMonthDay.from('1972-11-18[u-ca-gregory]'),
Temporal.PlainYearMonth.from('1976-11-01[u-ca-gregory]')
Temporal.PlainDate.from('1976-11-18[u-ca=gregory]'),
Temporal.PlainDateTime.from('1976-11-18[u-ca=gregory]'),
Temporal.PlainMonthDay.from('1972-11-18[u-ca=gregory]'),
Temporal.PlainYearMonth.from('1976-11-01[u-ca=gregory]')
].forEach((obj) => {
const calFrom = Calendar.from(obj);
assert(calFrom instanceof Calendar);
Expand All @@ -132,7 +132,7 @@ describe('Calendar', () => {
it('throws with bad identifier', () => {
throws(() => Calendar.from('local'), RangeError);
throws(() => Calendar.from('iso-8601'), RangeError);
throws(() => Calendar.from('[u-ca-iso8601]'), RangeError);
throws(() => Calendar.from('[u-ca=iso8601]'), RangeError);
});
it('throws with bad value in property bag', () => {
throws(() => Calendar.from({ calendar: 'local' }), RangeError);
Expand All @@ -141,8 +141,8 @@ describe('Calendar', () => {
});
describe('Calendar.from(ISO string)', () => {
test('1994-11-05T08:15:30-05:00', 'iso8601');
test('1994-11-05T08:15:30-05:00[u-ca-gregory]', 'gregory');
test('1994-11-05T13:15:30Z[u-ca-japanese]', 'japanese');
test('1994-11-05T08:15:30-05:00[u-ca=gregory]', 'gregory');
test('1994-11-05T13:15:30Z[u-ca=japanese]', 'japanese');
function test(isoString, id) {
const calendar = Calendar.from(isoString);
it(`Calendar.from(${isoString}) is a calendar`, () => assert(calendar instanceof Calendar));
Expand Down Expand Up @@ -384,28 +384,28 @@ describe('Calendar', () => {
describe('Built-in calendars (not standardized yet)', () => {
describe('gregory', () => {
it('era CE', () => {
const date = Temporal.PlainDate.from('1999-12-31[u-ca-gregory]');
const date = Temporal.PlainDate.from('1999-12-31[u-ca=gregory]');
equal(date.era, 'ce');
equal(date.eraYear, 1999);
equal(date.year, 1999);
});
it('era BCE', () => {
const date = Temporal.PlainDate.from('-000001-12-31[u-ca-gregory]');
const date = Temporal.PlainDate.from('-000001-12-31[u-ca=gregory]');
equal(date.era, 'bce');
equal(date.eraYear, 2);
equal(date.year, -1);
});
it('can create from fields with era CE', () => {
const date = Temporal.PlainDate.from({ era: 'ce', eraYear: 1999, month: 12, day: 31, calendar: 'gregory' });
equal(`${date}`, '1999-12-31[u-ca-gregory]');
equal(`${date}`, '1999-12-31[u-ca=gregory]');
});
it('era CE is the default', () => {
const date = Temporal.PlainDate.from({ year: 1999, month: 12, day: 31, calendar: 'gregory' });
equal(`${date}`, '1999-12-31[u-ca-gregory]');
equal(`${date}`, '1999-12-31[u-ca=gregory]');
});
it('can create from fields with era BCE', () => {
const date = Temporal.PlainDate.from({ era: 'bce', eraYear: 2, month: 12, day: 31, calendar: 'gregory' });
equal(`${date}`, '-000001-12-31[u-ca-gregory]');
equal(`${date}`, '-000001-12-31[u-ca=gregory]');
});
});
});
Expand Down
6 changes: 3 additions & 3 deletions test/instant.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ describe('Instant', () => {
equal(`${Instant.from('1976-11-18T15Z')}`, '1976-11-18T15:00:00Z');
});
it('ignores any specified calendar', () =>
equal(`${Instant.from('1976-11-18T15:23:30.123456789Z[u-ca-discord]')}`, '1976-11-18T15:23:30.123456789Z'));
equal(`${Instant.from('1976-11-18T15:23:30.123456789Z[u-ca=discord]')}`, '1976-11-18T15:23:30.123456789Z'));
it('no junk at end of string', () => throws(() => Instant.from('1976-11-18T15:23:30.123456789Zjunk'), RangeError));
});
describe('Instant.add works', () => {
Expand Down Expand Up @@ -1392,13 +1392,13 @@ describe('Instant', () => {
const timeZone = Temporal.TimeZone.from('UTC');
const zdt = inst.toZonedDateTime({ timeZone, calendar: 'gregory' });
equal(inst.epochNanoseconds, zdt.epochNanoseconds);
equal(`${zdt}`, '1976-11-18T14:23:30.123456789+00:00[UTC][u-ca-gregory]');
equal(`${zdt}`, '1976-11-18T14:23:30.123456789+00:00[UTC][u-ca=gregory]');
});
it('time zone parameter non-UTC', () => {
const timeZone = Temporal.TimeZone.from('America/New_York');
const zdt = inst.toZonedDateTime({ timeZone, calendar: 'gregory' });
equal(inst.epochNanoseconds, zdt.epochNanoseconds);
equal(`${zdt}`, '1976-11-18T09:23:30.123456789-05:00[America/New_York][u-ca-gregory]');
equal(`${zdt}`, '1976-11-18T09:23:30.123456789-05:00[America/New_York][u-ca=gregory]');
});
});
});
Expand Down
26 changes: 13 additions & 13 deletions test/intl.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,7 @@ describe('Intl', () => {
}
});
it('handles leap days', () => {
const leapYearFirstDay = Temporal.PlainDate.from('2004-03-21[u-ca-indian]');
const leapYearFirstDay = Temporal.PlainDate.from('2004-03-21[u-ca=indian]');
equal(leapYearFirstDay.year, 2004 - 78);
equal(leapYearFirstDay.month, 1);
equal(leapYearFirstDay.day, 1);
Expand All @@ -936,7 +936,7 @@ describe('Intl', () => {
equal(leapYearLastDay.day, 31);
});
it('handles non-leap years', () => {
const nonLeapYearFirstDay = Temporal.PlainDate.from('2005-03-22[u-ca-indian]');
const nonLeapYearFirstDay = Temporal.PlainDate.from('2005-03-22[u-ca=indian]');
equal(nonLeapYearFirstDay.year, 2005 - 78);
equal(nonLeapYearFirstDay.month, 1);
equal(nonLeapYearFirstDay.day, 1);
Expand All @@ -953,51 +953,51 @@ describe('Intl', () => {
describe('Japanese eras', () => {
it('Reiwa (2019-)', () => {
let date = Temporal.PlainDate.from({ era: 'reiwa', eraYear: 2, month: 1, day: 1, calendar: 'japanese' });
equal(`${date}`, '2020-01-01[u-ca-japanese]');
equal(`${date}`, '2020-01-01[u-ca=japanese]');
});
it('Heisei (1989-2019)', () => {
let date = Temporal.PlainDate.from({ era: 'heisei', eraYear: 2, month: 1, day: 1, calendar: 'japanese' });
equal(`${date}`, '1990-01-01[u-ca-japanese]');
equal(`${date}`, '1990-01-01[u-ca=japanese]');
});
it('Showa (1926-1989)', () => {
let date = Temporal.PlainDate.from({ era: 'showa', eraYear: 2, month: 1, day: 1, calendar: 'japanese' });
equal(`${date}`, '1927-01-01[u-ca-japanese]');
equal(`${date}`, '1927-01-01[u-ca=japanese]');
});
it('Taisho (1912-1926)', () => {
let date = Temporal.PlainDate.from({ era: 'taisho', eraYear: 2, month: 1, day: 1, calendar: 'japanese' });
equal(`${date}`, '1913-01-01[u-ca-japanese]');
equal(`${date}`, '1913-01-01[u-ca=japanese]');
});
it('Meiji (1868-1912)', () => {
let date = Temporal.PlainDate.from({ era: 'meiji', eraYear: 2, month: 1, day: 1, calendar: 'japanese' });
equal(`${date}`, '1869-01-01[u-ca-japanese]');
equal(`${date}`, '1869-01-01[u-ca=japanese]');
});
it('Dates in same year before Japanese era starts will resolve to previous era', () => {
let date = Temporal.PlainDate.from({ era: 'reiwa', eraYear: 1, month: 1, day: 1, calendar: 'japanese' });
equal(`${date}`, '2019-01-01[u-ca-japanese]');
equal(`${date}`, '2019-01-01[u-ca=japanese]');
equal(date.era, 'heisei');
equal(date.eraYear, 31);
date = Temporal.PlainDate.from({ era: 'heisei', eraYear: 1, month: 1, day: 1, calendar: 'japanese' });
equal(`${date}`, '1989-01-01[u-ca-japanese]');
equal(`${date}`, '1989-01-01[u-ca=japanese]');
equal(date.era, 'showa');
equal(date.eraYear, 64);
date = Temporal.PlainDate.from({ era: 'showa', eraYear: 1, month: 1, day: 1, calendar: 'japanese' });
equal(`${date}`, '1926-01-01[u-ca-japanese]');
equal(`${date}`, '1926-01-01[u-ca=japanese]');
equal(date.era, 'taisho');
equal(date.eraYear, 15);
date = Temporal.PlainDate.from({ era: 'taisho', eraYear: 1, month: 1, day: 1, calendar: 'japanese' });
equal(`${date}`, '1912-01-01[u-ca-japanese]');
equal(`${date}`, '1912-01-01[u-ca=japanese]');
equal(date.era, 'meiji');
equal(date.eraYear, 45);
date = Temporal.PlainDate.from({ era: 'meiji', eraYear: 1, month: 1, day: 1, calendar: 'japanese' });
equal(`${date}`, '1868-01-01[u-ca-japanese]');
equal(`${date}`, '1868-01-01[u-ca=japanese]');
equal(date.era, 'ce');
equal(date.eraYear, 1868);
throws(
() => Temporal.PlainDate.from({ era: 'bce', eraYear: 1, month: 1, day: 1, calendar: 'japanese' }),
RangeError
);
// uncomment & revise `throws` above if https://bugs.chromium.org/p/chromium/issues/detail?id=1173158 is resolved
// equal(`${date}`, '+000000-01-01[u-ca-japanese]');
// equal(`${date}`, '+000000-01-01[u-ca=japanese]');
// equal(date.era, 'bce');
// equal(date.eraYear, 1);
});
Expand Down
6 changes: 3 additions & 3 deletions test/plaindate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -879,17 +879,17 @@ describe('Date', () => {
const d = new PlainDate(1976, 11, 18);
it('shows only non-ISO calendar if calendarName = auto', () => {
equal(d.toString({ calendarName: 'auto' }), '1976-11-18');
equal(d.withCalendar('gregory').toString({ calendarName: 'auto' }), '1976-11-18[u-ca-gregory]');
equal(d.withCalendar('gregory').toString({ calendarName: 'auto' }), '1976-11-18[u-ca=gregory]');
});
it('shows ISO calendar if calendarName = always', () => {
equal(d.toString({ calendarName: 'always' }), '1976-11-18[u-ca-iso8601]');
equal(d.toString({ calendarName: 'always' }), '1976-11-18[u-ca=iso8601]');
});
it('omits non-ISO calendar if calendarName = never', () => {
equal(d.withCalendar('gregory').toString({ calendarName: 'never' }), '1976-11-18');
});
it('default is calendar = auto', () => {
equal(d.toString(), '1976-11-18');
equal(d.withCalendar('gregory').toString(), '1976-11-18[u-ca-gregory]');
equal(d.withCalendar('gregory').toString(), '1976-11-18[u-ca=gregory]');
});
it('throws on invalid calendar', () => {
['ALWAYS', 'sometimes', false, 3, null].forEach((calendarName) => {
Expand Down
12 changes: 6 additions & 6 deletions test/plaindatetime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -370,13 +370,13 @@ describe('DateTime', () => {
equal(`${dt.withPlainDate('2018-09-15')}`, '2018-09-15T03:24:30');
});
it('result contains a non-ISO calendar if present in the input', () => {
equal(`${dt.withCalendar('japanese').withPlainDate('2008-09-06')}`, '2008-09-06T03:24:30[u-ca-japanese]');
equal(`${dt.withCalendar('japanese').withPlainDate('2008-09-06')}`, '2008-09-06T03:24:30[u-ca=japanese]');
});
it('calendar is unchanged if input has ISO calendar', () => {
equal(`${dt.withPlainDate('2008-09-06[u-ca-japanese]')}`, '2008-09-06T03:24:30[u-ca-japanese]');
equal(`${dt.withPlainDate('2008-09-06[u-ca=japanese]')}`, '2008-09-06T03:24:30[u-ca=japanese]');
});
it('throws if both `this` and `other` have a non-ISO calendar', () => {
throws(() => dt.withCalendar('gregory').withPlainDate('2008-09-06[u-ca-japanese]'), RangeError);
throws(() => dt.withCalendar('gregory').withPlainDate('2008-09-06[u-ca=japanese]'), RangeError);
});
it('object must contain at least one correctly-spelled property', () => {
throws(() => dt.withPlainDate({}), TypeError);
Expand Down Expand Up @@ -1674,17 +1674,17 @@ describe('DateTime', () => {
});
it('shows only non-ISO calendar if calendarName = auto', () => {
equal(dt1.toString({ calendarName: 'auto' }), '1976-11-18T15:23:00');
equal(dt1.withCalendar('gregory').toString({ calendarName: 'auto' }), '1976-11-18T15:23:00[u-ca-gregory]');
equal(dt1.withCalendar('gregory').toString({ calendarName: 'auto' }), '1976-11-18T15:23:00[u-ca=gregory]');
});
it('shows ISO calendar if calendarName = always', () => {
equal(dt1.toString({ calendarName: 'always' }), '1976-11-18T15:23:00[u-ca-iso8601]');
equal(dt1.toString({ calendarName: 'always' }), '1976-11-18T15:23:00[u-ca=iso8601]');
});
it('omits non-ISO calendar if calendarName = never', () => {
equal(dt1.withCalendar('gregory').toString({ calendarName: 'never' }), '1976-11-18T15:23:00');
});
it('default is calendar = auto', () => {
equal(dt1.toString(), '1976-11-18T15:23:00');
equal(dt1.withCalendar('gregory').toString(), '1976-11-18T15:23:00[u-ca-gregory]');
equal(dt1.withCalendar('gregory').toString(), '1976-11-18T15:23:00[u-ca=gregory]');
});
it('throws on invalid calendar', () => {
['ALWAYS', 'sometimes', false, 3, null].forEach((calendarName) => {
Expand Down
10 changes: 5 additions & 5 deletions test/plainmonthday.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ describe('MonthDay', () => {
it('MonthDay.from({year, month, day}) allowed in other calendar', () => {
equal(
`${PlainMonthDay.from({ year: 1970, month: 11, day: 18, calendar: 'gregory' })}`,
'1972-11-18[u-ca-gregory]'
'1972-11-18[u-ca=gregory]'
);
});
it('MonthDay.from({era, eraYear, month, day}) allowed in other calendar', () => {
equal(
`${PlainMonthDay.from({ era: 'ce', eraYear: 1970, month: 11, day: 18, calendar: 'gregory' })}`,
'1972-11-18[u-ca-gregory]'
'1972-11-18[u-ca=gregory]'
);
});
it('MonthDay.from({ day: 15 }) throws', () => throws(() => PlainMonthDay.from({ day: 15 }), TypeError));
Expand Down Expand Up @@ -310,18 +310,18 @@ describe('MonthDay', () => {
const md2 = PlainMonthDay.from({ monthCode: 'M11', day: 18, calendar: 'gregory' });
it('shows only non-ISO calendar if calendarName = auto', () => {
equal(md1.toString({ calendarName: 'auto' }), '11-18');
equal(md2.toString({ calendarName: 'auto' }), '1972-11-18[u-ca-gregory]');
equal(md2.toString({ calendarName: 'auto' }), '1972-11-18[u-ca=gregory]');
});
it('shows ISO calendar if calendarName = always', () => {
equal(md1.toString({ calendarName: 'always' }), '11-18[u-ca-iso8601]');
equal(md1.toString({ calendarName: 'always' }), '11-18[u-ca=iso8601]');
});
it('omits non-ISO calendar, but not year, if calendarName = never', () => {
equal(md1.toString({ calendarName: 'never' }), '11-18');
equal(md2.toString({ calendarName: 'never' }), '1972-11-18');
});
it('default is calendar = auto', () => {
equal(md1.toString(), '11-18');
equal(md2.toString(), '1972-11-18[u-ca-gregory]');
equal(md2.toString(), '1972-11-18[u-ca=gregory]');
});
it('throws on invalid calendar', () => {
['ALWAYS', 'sometimes', false, 3, null].forEach((calendarName) => {
Expand Down
6 changes: 3 additions & 3 deletions test/plainyearmonth.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -778,18 +778,18 @@ describe('YearMonth', () => {
const ym2 = PlainYearMonth.from({ year: 1976, month: 11, calendar: 'gregory' });
it('shows only non-ISO calendar if calendarName = auto', () => {
equal(ym1.toString({ calendarName: 'auto' }), '1976-11');
equal(ym2.toString({ calendarName: 'auto' }), '1976-11-01[u-ca-gregory]');
equal(ym2.toString({ calendarName: 'auto' }), '1976-11-01[u-ca=gregory]');
});
it('shows ISO calendar if calendarName = always', () => {
equal(ym1.toString({ calendarName: 'always' }), '1976-11[u-ca-iso8601]');
equal(ym1.toString({ calendarName: 'always' }), '1976-11[u-ca=iso8601]');
});
it('omits non-ISO calendar, but not day, if calendarName = never', () => {
equal(ym1.toString({ calendarName: 'never' }), '1976-11');
equal(ym2.toString({ calendarName: 'never' }), '1976-11-01');
});
it('default is calendar = auto', () => {
equal(ym1.toString(), '1976-11');
equal(ym2.toString(), '1976-11-01[u-ca-gregory]');
equal(ym2.toString(), '1976-11-01[u-ca=gregory]');
});
it('throws on invalid calendar', () => {
['ALWAYS', 'sometimes', false, 3, null].forEach((calendarName) => {
Expand Down
Loading

0 comments on commit 29f7bc3

Please sign in to comment.