Skip to content

Commit

Permalink
Normative: Remove calendar property from PlainTime
Browse files Browse the repository at this point in the history
PlainTime now has no calendar. Removes the getter and the internal slot.
Calendar annotations are now ignored in ParseTemporalTimeString.

RejectObjectWithCalendarOrTimeZone still rejects PlainTime, so it is
renamed to RejectTemporalObject.

ToTemporalCalendar rejects PlainTime explicitly instead of looking for its
`calendar` property or treating it as a plain object calendar.

See: #1808
Closes: #1588
  • Loading branch information
ptomato committed Feb 16, 2023
1 parent 90cc40c commit ce4de05
Show file tree
Hide file tree
Showing 17 changed files with 47 additions and 80 deletions.
37 changes: 17 additions & 20 deletions polyfill/lib/ecmascript.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -317,10 +317,13 @@ export const ES = ObjectAssign({}, ES2022, {
IsTemporalYearMonth: (item) => HasSlot(item, YEAR_MONTH_BRAND),
IsTemporalMonthDay: (item) => HasSlot(item, MONTH_DAY_BRAND),
IsTemporalZonedDateTime: (item) => HasSlot(item, EPOCHNANOSECONDS, TIME_ZONE, CALENDAR),
RejectObjectWithCalendarOrTimeZone: (item) => {
RejectTemporalObject: (item) => {
if (HasSlot(item, CALENDAR) || HasSlot(item, TIME_ZONE)) {
throw new TypeError('with() does not support a calendar or timeZone property');
}
if (ES.IsTemporalTime(item)) {
throw new TypeError('with() does not accept Temporal.PlainTime, use withPlainTime() instead');
}
if (item.calendar !== undefined) {
throw new TypeError('with() does not support a calendar property');
}
Expand Down Expand Up @@ -430,7 +433,7 @@ export const ES = ObjectAssign({}, ES2022, {
},
ParseTemporalTimeString: (isoString) => {
const match = PARSE.time.exec(isoString);
let hour, minute, second, millisecond, microsecond, nanosecond, annotations, calendar;
let hour, minute, second, millisecond, microsecond, nanosecond, annotations;
if (match) {
hour = ES.ToIntegerOrInfinity(match[1]);
minute = ES.ToIntegerOrInfinity(match[2] || match[5]);
Expand All @@ -442,23 +445,20 @@ export const ES = ObjectAssign({}, ES2022, {
nanosecond = ES.ToIntegerOrInfinity(fraction.slice(6, 9));
annotations = match[14];
for (const [, critical, key, value] of annotations.matchAll(PARSE.annotation)) {
if (key === 'u-ca') {
if (calendar === undefined) calendar = value;
} else if (critical === '!') {
if (key !== 'u-ca' && critical === '!') {
throw new RangeError(`Unrecognized annotation: !${key}=${value}`);
}
}
if (match[8]) throw new RangeError('Z designator not supported for PlainTime');
} else {
let z, hasTime;
({ hasTime, hour, minute, second, millisecond, microsecond, nanosecond, calendar, z } =
ES.ParseISODateTime(isoString));
({ hasTime, hour, minute, second, millisecond, microsecond, nanosecond, z } = ES.ParseISODateTime(isoString));
if (!hasTime) throw new RangeError(`time is missing in string: ${isoString}`);
if (z) throw new RangeError('Z designator not supported for PlainTime');
}
// if it's a date-time string, OK
if (/[tT ][0-9][0-9]/.test(isoString)) {
return { hour, minute, second, millisecond, microsecond, nanosecond, calendar };
return { hour, minute, second, millisecond, microsecond, nanosecond };
}
// Reject strings that are ambiguous with PlainMonthDay or PlainYearMonth.
try {
Expand All @@ -469,7 +469,7 @@ export const ES = ObjectAssign({}, ES2022, {
const { year, month } = ES.ParseTemporalYearMonthString(isoString);
ES.RejectISODate(year, month, 1);
} catch {
return { hour, minute, second, millisecond, microsecond, nanosecond, calendar };
return { hour, minute, second, millisecond, microsecond, nanosecond };
}
}
throw new RangeError(`invalid ISO 8601 time-only string ${isoString}; may need a T prefix`);
Expand Down Expand Up @@ -1222,7 +1222,7 @@ export const ES = ObjectAssign({}, ES2022, {
return ES.CalendarMonthDayFromFields(calendar, result);
},
ToTemporalTime: (item, overflow = 'constrain') => {
let hour, minute, second, millisecond, microsecond, nanosecond, calendar;
let hour, minute, second, millisecond, microsecond, nanosecond;
if (ES.Type(item) === 'Object') {
if (ES.IsTemporalTime(item)) return item;
if (ES.IsTemporalZonedDateTime(item)) {
Expand All @@ -1239,10 +1239,6 @@ export const ES = ObjectAssign({}, ES2022, {
GetSlot(item, ISO_NANOSECOND)
);
}
calendar = ES.GetTemporalCalendarWithISODefault(item);
if (ES.ToString(calendar) !== 'iso8601') {
throw new RangeError('PlainTime can only have iso8601 calendar');
}
({ hour, minute, second, millisecond, microsecond, nanosecond } = ES.ToTemporalTimeRecord(item));
({ hour, minute, second, millisecond, microsecond, nanosecond } = ES.RegulateTime(
hour,
Expand All @@ -1254,13 +1250,8 @@ export const ES = ObjectAssign({}, ES2022, {
overflow
));
} else {
({ hour, minute, second, millisecond, microsecond, nanosecond, calendar } = ES.ParseTemporalTimeString(
ES.ToString(item)
));
({ hour, minute, second, millisecond, microsecond, nanosecond } = ES.ParseTemporalTimeString(ES.ToString(item)));
ES.RejectTime(hour, minute, second, millisecond, microsecond, nanosecond);
if (calendar !== undefined && calendar !== 'iso8601') {
throw new RangeError('PlainTime can only have iso8601 calendar');
}
}
const TemporalPlainTime = GetIntrinsic('%Temporal.PlainTime%');
return new TemporalPlainTime(hour, minute, second, millisecond, microsecond, nanosecond);
Expand Down Expand Up @@ -1771,12 +1762,18 @@ export const ES = ObjectAssign({}, ES2022, {
if (ES.Type(calendarLike) === 'Object') {
if (ES.IsTemporalCalendar(calendarLike)) return calendarLike;
if (HasSlot(calendarLike, CALENDAR)) return GetSlot(calendarLike, CALENDAR);
if (ES.IsTemporalTime(calendarLike)) {
throw new RangeError('Expected a calendar object but received a Temporal.PlainTime');
}
if (ES.IsTemporalTimeZone(calendarLike)) {
throw new RangeError('Expected a calendar object but received a Temporal.TimeZone');
}
if (!('calendar' in calendarLike)) return calendarLike;
calendarLike = calendarLike.calendar;
if (ES.Type(calendarLike) === 'Object') {
if (ES.IsTemporalTime(calendarLike)) {
throw new RangeError('Expected a calendar object as the calendar property but received a Temporal.PlainTime');
}
if (ES.IsTemporalTimeZone(calendarLike)) {
throw new RangeError('Expected a calendar object as the calendar property but received a Temporal.TimeZone');
}
Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/plaindate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export class PlainDate {
if (ES.Type(temporalDateLike) !== 'Object') {
throw new TypeError('invalid argument');
}
ES.RejectObjectWithCalendarOrTimeZone(temporalDateLike);
ES.RejectTemporalObject(temporalDateLike);
options = ES.GetOptionsObject(options);

const calendar = GetSlot(this, CALENDAR);
Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/plaindatetime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ export class PlainDateTime {
if (ES.Type(temporalDateTimeLike) !== 'Object') {
throw new TypeError('invalid argument');
}
ES.RejectObjectWithCalendarOrTimeZone(temporalDateTimeLike);
ES.RejectTemporalObject(temporalDateTimeLike);

options = ES.GetOptionsObject(options);
const calendar = GetSlot(this, CALENDAR);
Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/plainmonthday.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class PlainMonthDay {
if (ES.Type(temporalMonthDayLike) !== 'Object') {
throw new TypeError('invalid argument');
}
ES.RejectObjectWithCalendarOrTimeZone(temporalMonthDayLike);
ES.RejectTemporalObject(temporalMonthDayLike);
options = ES.GetOptionsObject(options);

const calendar = GetSlot(this, CALENDAR);
Expand Down
8 changes: 1 addition & 7 deletions polyfill/lib/plaintime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ export class PlainTime {
SetSlot(this, ISO_MILLISECOND, isoMillisecond);
SetSlot(this, ISO_MICROSECOND, isoMicrosecond);
SetSlot(this, ISO_NANOSECOND, isoNanosecond);
SetSlot(this, CALENDAR, ES.GetISO8601Calendar());

if (typeof __debug__ !== 'undefined' && __debug__) {
Object.defineProperty(this, '_repr_', {
Expand All @@ -82,10 +81,6 @@ export class PlainTime {
}
}

get calendar() {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return GetSlot(this, CALENDAR);
}
get hour() {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return GetSlot(this, ISO_HOUR);
Expand Down Expand Up @@ -116,7 +111,7 @@ export class PlainTime {
if (ES.Type(temporalTimeLike) !== 'Object') {
throw new TypeError('invalid argument');
}
ES.RejectObjectWithCalendarOrTimeZone(temporalTimeLike);
ES.RejectTemporalObject(temporalTimeLike);
options = ES.GetOptionsObject(options);
const overflow = ES.ToTemporalOverflow(options);

Expand Down Expand Up @@ -305,7 +300,6 @@ export class PlainTime {
getISOFields() {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
return {
calendar: GetSlot(this, CALENDAR),
isoHour: GetSlot(this, ISO_HOUR),
isoMicrosecond: GetSlot(this, ISO_MICROSECOND),
isoMillisecond: GetSlot(this, ISO_MILLISECOND),
Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/plainyearmonth.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export class PlainYearMonth {
if (ES.Type(temporalYearMonthLike) !== 'Object') {
throw new TypeError('invalid argument');
}
ES.RejectObjectWithCalendarOrTimeZone(temporalYearMonthLike);
ES.RejectTemporalObject(temporalYearMonthLike);
options = ES.GetOptionsObject(options);

const calendar = GetSlot(this, CALENDAR);
Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/zoneddatetime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export class ZonedDateTime {
if (ES.Type(temporalZonedDateTimeLike) !== 'Object') {
throw new TypeError('invalid zoned-date-time-like');
}
ES.RejectObjectWithCalendarOrTimeZone(temporalZonedDateTimeLike);
ES.RejectTemporalObject(temporalZonedDateTimeLike);
options = ES.GetOptionsObject(options);

const calendar = GetSlot(this, CALENDAR);
Expand Down
2 changes: 1 addition & 1 deletion polyfill/test/validStrings.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ const comparisonItems = {
'nanoseconds'
],
MonthDay: ['month', 'day', 'calendar'],
Time: [...timeItems, 'calendar'],
Time: [...timeItems],
TimeZone: ['offset', 'ianaName'],
YearMonth: ['year', 'month', 'calendar'],
ZonedDateTime: [...dateItems, ...timeItems, 'offset', 'ianaName', 'calendar']
Expand Down
18 changes: 11 additions & 7 deletions spec/abstractops.html
Original file line number Diff line number Diff line change
Expand Up @@ -554,13 +554,17 @@ <h1>MaximumTemporalDurationRoundingIncrement ( _unit_ )</h1>
</emu-alg>
</emu-clause>

<emu-clause id="sec-temporal-rejectobjectwithcalendarortimezone" aoid="RejectObjectWithCalendarOrTimeZone">
<h1>RejectObjectWithCalendarOrTimeZone ( _object_ )</h1>
<p>
The abstract operation RejectObjectWithCalendarOrTimeZone throws an exception if its argument _object_ is an instance of one of the Temporal types that carries a calendar or time zone, or is an object that has a `calendar` or `timeZone` property.
</p>
<emu-clause id="sec-temporal-rejecttemporalobject" type="abstract operation">
<h1>
RejectTemporalObject (
_object_: an Object,
): either a normal completion containing ~unused~, or an abrupt completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>It throws an exception if its argument _object_ is an instance of one of the time-related or date-related Temporal types, or is an object that has a `calendar` or `timeZone` property.</dd>
</dl>
<emu-alg>
1. Assert: Type(_object_) is Object.
1. If _object_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
1. Throw a *TypeError* exception.
1. Let _calendarProperty_ be ? Get(_object_, *"calendar"*).
Expand All @@ -569,6 +573,7 @@ <h1>RejectObjectWithCalendarOrTimeZone ( _object_ )</h1>
1. Let _timeZoneProperty_ be ? Get(_object_, *"timeZone"*).
1. If _timeZoneProperty_ is not *undefined*, then
1. Throw a *TypeError* exception.
1. Return ~unused~.
</emu-alg>
</emu-clause>

Expand Down Expand Up @@ -1551,7 +1556,6 @@ <h1>
[[Millisecond]]: _result_.[[Millisecond]],
[[Microsecond]]: _result_.[[Microsecond]],
[[Nanosecond]]: _result_.[[Nanosecond]],
[[Calendar]]: _result_.[[Calendar]]
}.
</emu-alg>
<emu-note>
Expand Down
8 changes: 4 additions & 4 deletions spec/calendar.html
Original file line number Diff line number Diff line change
Expand Up @@ -448,13 +448,13 @@ <h1>ToTemporalCalendar ( _temporalCalendarLike_ )</h1>
1. If Type(_temporalCalendarLike_) is Object, then
1. If _temporalCalendarLike_ has an [[InitializedTemporalCalendar]] internal slot, then
1. Return _temporalCalendarLike_.
1. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
1. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
1. Return _temporalCalendarLike_.[[Calendar]].
1. If _temporalCalendarLike_ has an [[InitializedTemporalTimeZone]] internal slot, throw a *RangeError* exception.
1. If _temporalCalendarLike_ has an [[InitializedTemporalTime]] or [[InitializedTemporalTimeZone]] internal slot, throw a *RangeError* exception.
1. If ? HasProperty(_temporalCalendarLike_, *"calendar"*) is *false*, return _temporalCalendarLike_.
1. Set _temporalCalendarLike_ to ? Get(_temporalCalendarLike_, *"calendar"*).
1. If Type(_temporalCalendarLike_) is Object, then
1. If _temporalCalendarLike_ has an [[InitializedTemporalTimeZone]] internal slot, throw a *RangeError* exception.
1. If _temporalCalendarLike_ has an [[InitializedTemporalTime]] or [[InitializedTemporalTimeZone]] internal slot, throw a *RangeError* exception.
1. If ? HasProperty(_temporalCalendarLike_, *"calendar"*) is *false*, return _temporalCalendarLike_.
1. Let _identifier_ be ? ToString(_temporalCalendarLike_).
1. Set _identifier_ to ? ParseTemporalCalendarString(_identifier_).
Expand Down Expand Up @@ -483,7 +483,7 @@ <h1>GetTemporalCalendarWithISODefault ( _item_ )</h1>
If no such property is present, the ISO 8601 calendar is returned.
</p>
<emu-alg>
1. If _item_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalTime]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
1. If _item_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
1. Return _item_.[[Calendar]].
1. Let _calendarLike_ be ? Get(_item_, *"calendar"*).
1. Return ? ToTemporalCalendarWithISODefault(_calendarLike_).
Expand Down
2 changes: 1 addition & 1 deletion spec/plaindate.html
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ <h1>Temporal.PlainDate.prototype.with ( _temporalDateLike_ [ , _options_ ] )</h1
1. Perform ? RequireInternalSlot(_temporalDate_, [[InitializedTemporalDate]]).
1. If Type(_temporalDateLike_) is not Object, then
1. Throw a *TypeError* exception.
1. Perform ? RejectObjectWithCalendarOrTimeZone(_temporalDateLike_).
1. Perform ? RejectTemporalObject(_temporalDateLike_).
1. Set _options_ to ? GetOptionsObject(_options_).
1. Let _calendar_ be _temporalDate_.[[Calendar]].
1. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
Expand Down
2 changes: 1 addition & 1 deletion spec/plaindatetime.html
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ <h1>Temporal.PlainDateTime.prototype.with ( _temporalDateTimeLike_ [ , _options_
1. Perform ? RequireInternalSlot(_dateTime_, [[InitializedTemporalDateTime]]).
1. If Type(_temporalDateTimeLike_) is not Object, then
1. Throw a *TypeError* exception.
1. Perform ? RejectObjectWithCalendarOrTimeZone(_temporalDateTimeLike_).
1. Perform ? RejectTemporalObject(_temporalDateTimeLike_).
1. Set _options_ to ? GetOptionsObject(_options_).
1. Let _calendar_ be _dateTime_.[[Calendar]].
1. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"hour"*, *"microsecond"*, *"millisecond"*, *"minute"*, *"month"*, *"monthCode"*, *"nanosecond"*, *"second"*, *"year"* »).
Expand Down
2 changes: 1 addition & 1 deletion spec/plainmonthday.html
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ <h1>Temporal.PlainMonthDay.prototype.with ( _temporalMonthDayLike_ [ , _options_
1. Perform ? RequireInternalSlot(_monthDay_, [[InitializedTemporalMonthDay]]).
1. If Type(_temporalMonthDayLike_) is not Object, then
1. Throw a *TypeError* exception.
1. Perform ? RejectObjectWithCalendarOrTimeZone(_temporalMonthDayLike_).
1. Perform ? RejectTemporalObject(_temporalMonthDayLike_).
1. Set _options_ to ? GetOptionsObject(_options_).
1. Let _calendar_ be _monthDay_.[[Calendar]].
1. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
Expand Down
Loading

0 comments on commit ce4de05

Please sign in to comment.