Skip to content

Commit

Permalink
Allow ISO strings in Temporal.Calendar.from()
Browse files Browse the repository at this point in the history
This brings the behaviour in line with Temporal.TimeZone. If a calendar
annotation is not given in the ISO string, then the ISO calendar is
assumed.

Closes: #862
  • Loading branch information
ptomato committed Oct 19, 2020
1 parent 6e36d93 commit b0ac231
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 4 deletions.
13 changes: 12 additions & 1 deletion polyfill/lib/calendar.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,15 @@ export class Calendar {
static from(item) {
if (ES.Type(item) === 'Object') return item;
const stringIdent = ES.ToString(item);
return GetBuiltinCalendar(stringIdent);
if (IsBuiltinCalendar(stringIdent)) return GetBuiltinCalendar(stringIdent);
let calendar;
try {
({ calendar } = ES.ParseISODateTime(stringIdent, { zoneRequired: false }));
} catch {
throw new RangeError(`Invalid calendar: ${stringIdent}`);
}
if (!calendar) calendar = 'iso8601';
return GetBuiltinCalendar(calendar);
}
}

Expand Down Expand Up @@ -371,6 +379,9 @@ const BUILTIN_CALENDARS = {
// To be filled in as builtin calendars are implemented
};

function IsBuiltinCalendar(id) {
return id in BUILTIN_CALENDARS;
}
function GetBuiltinCalendar(id) {
if (!(id in BUILTIN_CALENDARS)) throw new RangeError(`unknown calendar ${id}`);
return new BUILTIN_CALENDARS[id]();
Expand Down
29 changes: 28 additions & 1 deletion polyfill/test/calendar.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Pretty from '@pipobscure/demitasse-pretty';
const { reporter } = Pretty;

import { strict as assert } from 'assert';
const { equal } = assert;
const { equal, throws } = assert;

import * as Temporal from 'proposal-temporal';
const { Calendar } = Temporal;
Expand Down Expand Up @@ -90,6 +90,33 @@ describe('Calendar', () => {
equal(typeof Calendar.from, 'function');
});
});
describe('Calendar.from()', () => {
describe('from identifier', () => {
test('iso8601');
test('gregory');
test('japanese');
function test(id) {
const calendar = Calendar.from(id);
it(`Calendar.from(${id}) is a calendar`, () => assert(calendar instanceof Calendar));
it(`Calendar.from(${id}) has the correct ID`, () => equal(calendar.id, id));
}
it('Calendar.from throws with bad identifier', () => {
throws(() => Calendar.from('local'));
throws(() => Calendar.from('iso-8601'));
throws(() => Calendar.from('[c=iso8601]'));
});
});
describe('Calendar.from(ISO string)', () => {
test('1994-11-05T08:15:30-05:00', 'iso8601');
test('1994-11-05T08:15:30-05:00[c=gregory]', 'gregory');
test('1994-11-05T13:15:30Z[c=japanese]', 'japanese');
function test(isoString, id) {
const calendar = Calendar.from(isoString);
it(`Calendar.from(${isoString}) is a calendar`, () => assert(calendar instanceof Calendar));
it(`Calendar.from(${isoString}) has ID ${id}`, () => equal(calendar.id, id));
}
});
});
});

import { normalize } from 'path';
Expand Down
24 changes: 24 additions & 0 deletions spec/abstractops.html
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,14 @@ <h1>ISO 8601 grammar</h1>
TemporalYearMonthString :
DateSpecYearMonth
DateTime

TemporalCalendarString :
CalendarName
TemporalInstantString
CalendarDateTime
Time
DateSpecYearMonth
DateSpecMonthDay
</emu-grammar>
</emu-clause>

Expand Down Expand Up @@ -828,6 +836,22 @@ <h1>ParseTemporalInstantString ( _isoString_ )</h1>
</emu-alg>
</emu-clause>

<emu-clause id="sec-temporal-parsetemporalcalendarstring" aoid="ParseTemporalCalendarString">
<h1>ParseTemporalCalendarString ( _isoString_ )</h1>
<p>
The ParseTemporalCalendarString abstract operation interprets an ISO 8601 string and retrieves the calendar identifier from it.
</p>
<emu-alg>
1. Assert: Type(_isoString_) is String.
1. If _isoString_ does not satisfy the syntax of a |TemporalCalendarString| (see <emu-xref href="#sec-temporal-iso8601grammar"></emu-xref>), then
1. Throw a *RangeError* exception.
1. Let _id_ be the part of _isoString_ produced by the |CalendarName| production, or *undefined* if not present.
1. If _id_ is *undefined*, then
1. Return *"iso8601"*.
1. Return _id_.
</emu-alg>
</emu-clause>

<emu-clause id="sec-temporal-parsetemporaldatestring" aoid="ParseTemporalDateString">
<h1>ParseTemporalDateString ( _isoString_ )</h1>
<p>
Expand Down
18 changes: 16 additions & 2 deletions spec/calendar.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@ <h1>Temporal.Calendar Objects</h1>
<emu-clause id="sec-temporal-calendar-abstract-ops">
<h1>Abstract Operations for Temporal.Calendar Objects</h1>

<emu-clause id="sec-temporal-isbuiltincalendar" aoid="IsBuiltinCalendar">
<h1>IsBuiltinCalendar ( _id_ )</h1>
<p>
An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the *IsBuiltinCalendar* abstract operation as specified in the ECMA-402 specification.
If an ECMAScript implementation does not include the ECMA-402 API the following specification of the *IsBuiltinCalendar* abstract operation is used.
</p>
<emu-alg>
1. If _id_ is not *"iso8601"*, return *false*.
1. Return *true*.
</emu-alg>
</emu-clause>

<emu-clause id="sec-temporal-getbuiltincalendar" aoid="GetBuiltinCalendar">
<h1>GetBuiltinCalendar ( _id_ )</h1>
<p>An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the *GetBuiltinCalendar* abstract operation as specified in the ECMA-402 specification. If an ECMAScript implementation does not include the ECMA-402 API the following specification of the *GetBuiltinCalendar* abstract operation is used.</p>
Expand Down Expand Up @@ -160,8 +172,10 @@ <h1>Temporal.Calendar.from ( _item_ )</h1>
<emu-alg>
1. If Type(_item_) is Object, then
1. Return _item_.
1. Let _stringIdent_ be ? ToString(_item_).
1. Return ? GetBuiltinCalendar(_stringIdent_).
1. Let _string_ be ? ToString(_item_).
1. If ! IsBuiltinCalendar(_string_) is *false*, then
1. Let _string_ be ? ParseTemporalCalendarString(_string_).
1. Return ? GetBuiltinCalendar(_string_).
</emu-alg>
<p>
This function is the <dfn>%Temporal.Calendar.from%</dfn> intrinsic object.
Expand Down

0 comments on commit b0ac231

Please sign in to comment.