Skip to content

Commit

Permalink
Bring custom time zones in line with custom calendars
Browse files Browse the repository at this point in the history
This makes a small change to the constructor of Temporal.TimeZone so that
it doesn't accept any arbitrary ID, only a recognized built-in one, to
bring it in line with calendars.

See: #847
See: #300
  • Loading branch information
ptomato committed Nov 16, 2020
1 parent dc8b3a1 commit ecaec95
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 37 deletions.
11 changes: 1 addition & 10 deletions polyfill/lib/timezone.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,9 @@ import {
SetSlot
} from './slots.mjs';

import * as REGEX from './regex.mjs';
const OFFSET = new RegExp(`^${REGEX.offset.source}$`);
const IANA_NAME = new RegExp(`^${REGEX.timeZoneID.source}$`);

export class TimeZone {
constructor(timeZoneIdentifier) {
if (new.target === TimeZone) {
timeZoneIdentifier = ES.GetCanonicalTimeZoneIdentifier(timeZoneIdentifier);
}
if (!OFFSET.exec(timeZoneIdentifier) && !IANA_NAME.exec(timeZoneIdentifier)) {
throw new RangeError(`invalid time zone identifier ${timeZoneIdentifier}`);
}
timeZoneIdentifier = ES.GetCanonicalTimeZoneIdentifier(timeZoneIdentifier);
CreateSlots(this);
SetSlot(this, TIMEZONE_ID, timeZoneIdentifier);

Expand Down
25 changes: 15 additions & 10 deletions polyfill/test/regex.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -589,12 +589,16 @@ describe('fromString regex', () => {
});

describe('time zone ID', () => {
function makeCustomTimeZone(id) {
return class extends Temporal.TimeZone {
constructor() {
super(id);
}
let oldTemporalTimeZoneFrom = Temporal.TimeZone.from;
let fromCalledWith;
before(() => {
Temporal.TimeZone.from = function (item) {
fromCalledWith = item;
return new Temporal.TimeZone('UTC');
};
});
function testTimeZoneID(id) {
return Temporal.ZonedDateTime.from(`1970-01-01T00:00[${id}]`);
}
describe('valid', () => {
[
Expand All @@ -616,9 +620,8 @@ describe('fromString regex', () => {
'Etc/GMT+12'
].forEach((id) => {
it(id, () => {
const Custom = makeCustomTimeZone(id);
const tz = new Custom();
equal(tz.id, id);
testTimeZoneID(id);
equal(fromCalledWith, id);
});
});
});
Expand All @@ -641,11 +644,13 @@ describe('fromString regex', () => {
'Foo/Etc/GMT-8'
].forEach((id) => {
it(id, () => {
const Custom = makeCustomTimeZone(id);
throws(() => new Custom(), RangeError);
throws(() => testTimeZoneID(id), RangeError);
});
});
});
after(() => {
Temporal.TimeZone.from = oldTemporalTimeZoneFrom;
});
});

describe('calendar ID', () => {
Expand Down
10 changes: 8 additions & 2 deletions polyfill/test/usertimezone.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ describe('Userland time zone', () => {
describe('Trivial subclass', () => {
class CustomUTCSubclass extends Temporal.TimeZone {
constructor() {
super('Etc/Custom/UTC_Subclass');
super('UTC');
}
toString() {
return 'Etc/Custom/UTC_Subclass';
}
getOffsetNanosecondsFor(/* instant */) {
return 0;
Expand Down Expand Up @@ -205,7 +208,10 @@ describe('Userland time zone', () => {
describe('sub-minute offset', () => {
class SubminuteTimeZone extends Temporal.TimeZone {
constructor() {
super('Custom/Subminute');
super('-00:00:01.111111111');
}
toString() {
return 'Custom/Subminute';
}
getOffsetNanosecondsFor() {
return -1111111111;
Expand Down
23 changes: 8 additions & 15 deletions spec/timezone.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,14 @@ <h1>Temporal.TimeZone ( _identifier_ )</h1>
<emu-alg>
1. If NewTarget is *undefined*, then
1. Throw a *TypeError* exception.
1. Let _identifier_ be ? ToString(_identifier_).
1. If _identifier_ does not satisfy the syntax of a |TemporalTimeZoneIdentifier| (see <emu-xref href="#sec-temporal-iso8601grammar"></emu-xref>), then
1. Throw a *RangeError* exception.
1. Let _sign_, _hour_, _minute_, and _id_ be the parts of _identifier_ produced respectively by the |TimeZoneUTCOffsetSign|, |TimeZoneUTCOffsetHour|, |TimeZoneUTCOffsetMinute| and |TimeZoneIANAName| productions, or *undefined* if not present.
1. If _hour_ is not *undefined*, then
1. Assert: _sign_ is not *undefined*.
1. Set _hour_ to ! ToInteger(_hour_).
1. If _sign_ = *"-"*, then
1. Set _hour_ to −1 × _hour_.
1. If _minute_ is not *undefined*, then
1. Set _minute_ to ! ToInteger(_minute_).
1. <mark>Do something with the offset.</mark>
1. If ! IsValidTimeZoneName(_id_) is *false*, then
1. Throw a *TypeError* exception.
1. Let _canonical_ be ! CanonicalizeTimeZoneName(_identifier_).
1. Set _identifier_ to ? ToString(_identifier_).
1. If _identifier_ satisfies the syntax of a |TimeZoneNumericUTCOffset| (see <emu-xref href="#sec-temporal-iso8601grammar"></emu-xref>), then
1. Let _offsetNanoseconds_ be ? ParseTimeZoneOffsetString(_identifier_).
1. Let _canonical_ be ? FormatTimeZoneOffsetString(_offsetNanoseconds_).
1. Else,
1. If ! IsValidTimeZoneName(_id_) is *false*, then
1. Throw a *RangeError* exception.
1. Let _canonical_ be ! CanonicalizeTimeZoneName(_identifier_).
1. Return ? CreateTemporalTimeZone(_canonical_, NewTarget).
</emu-alg>
</emu-clause>
Expand Down

0 comments on commit ecaec95

Please sign in to comment.