Skip to content

Commit

Permalink
Implement Temporal.ZonedDateTime.getTimeZoneTransition
Browse files Browse the repository at this point in the history
  • Loading branch information
printfn committed Jan 22, 2025
1 parent c930e13 commit ee7293d
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 204 deletions.
321 changes: 133 additions & 188 deletions runtime/js/99_main.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const {
ObjectSetPrototypeOf,
PromisePrototypeThen,
PromiseResolve,
RangeError,
StringPrototypePadEnd,
Symbol,
SymbolIterator,
Expand Down Expand Up @@ -466,6 +467,136 @@ function exposeUnstableFeaturesForWindowOrWorkerGlobalScope(unstableFeatures) {
}
}

function updateTemporal() {
// Removes the obsoleted `Temporal` API.
// https://github.com/tc39/proposal-temporal/pull/2895
// https://github.com/tc39/proposal-temporal/pull/2914
// https://github.com/tc39/proposal-temporal/pull/2925
if (typeof globalThis.Temporal.Instant.fromEpochSeconds === "undefined") {
throw "V8 removes obsoleted Temporal API now, no need to delete them";
}
delete globalThis.Temporal.Instant.fromEpochSeconds;
delete globalThis.Temporal.Instant.fromEpochMicroseconds;
delete globalThis.Temporal.Instant.prototype.epochSeconds;
delete globalThis.Temporal.Instant.prototype.epochMicroseconds;
delete globalThis.Temporal.Instant.prototype.toZonedDateTime;
delete globalThis.Temporal.PlainDate.prototype.getISOFiels; // weird
delete globalThis.Temporal.PlainDate.prototype.getISOFields;
delete globalThis.Temporal.PlainDateTime.prototype.withPlainDate;
delete globalThis.Temporal.PlainDateTime.prototype.toPlainYearMonth;
delete globalThis.Temporal.PlainDateTime.prototype.toPlainMonthDay;
delete globalThis.Temporal.PlainDateTime.prototype.getISOFields;
delete globalThis.Temporal.PlainMonthDay.prototype.getISOFields;
delete globalThis.Temporal.PlainTime.prototype.calendar;
delete globalThis.Temporal.PlainTime.prototype.toPlainDateTime;
delete globalThis.Temporal.PlainTime.prototype.toZonedDateTime;
delete globalThis.Temporal.PlainTime.prototype.getISOFields;
delete globalThis.Temporal.PlainYearMonth.prototype.getISOFields;
delete globalThis.Temporal.ZonedDateTime.prototype.epochSeconds;
delete globalThis.Temporal.ZonedDateTime.prototype.epochMicroseconds;
delete globalThis.Temporal.ZonedDateTime.prototype.withPlainDate;
delete globalThis.Temporal.ZonedDateTime.prototype.toPlainYearMonth;
delete globalThis.Temporal.ZonedDateTime.prototype.toPlainMonthDay;
delete globalThis.Temporal.ZonedDateTime.prototype.getISOFields;
delete globalThis.Temporal.Now.zonedDateTime;
delete globalThis.Temporal.Now.plainDateTime;
delete globalThis.Temporal.Now.plainDate;
delete globalThis.Temporal.Calendar;
delete globalThis.Temporal.TimeZone;

// Modify `Temporal.Calendar` to calendarId string
ArrayPrototypeForEach([
globalThis.Temporal.PlainDate,
globalThis.Temporal.PlainDateTime,
globalThis.Temporal.PlainMonthDay,
globalThis.Temporal.PlainYearMonth,
globalThis.Temporal.ZonedDateTime,
], (target) => {
const getCalendar =
ObjectGetOwnPropertyDescriptor(target.prototype, "calendar").get;
ObjectDefineProperty(target.prototype, "calendarId", {
__proto__: null,
get: function calendarId() {
return FunctionPrototypeCall(getCalendar, this).id;
},
enumerable: false,
configurable: true,
});
delete target.prototype.calendar;
});

// Modify `Temporal.TimeZone` to timeZoneId string
{
const getTimeZone = ObjectGetOwnPropertyDescriptor(
globalThis.Temporal.ZonedDateTime.prototype,
"timeZone",
).get;
ObjectDefineProperty(
globalThis.Temporal.ZonedDateTime.prototype,
"timeZoneId",
{
__proto__: null,
get: function timeZoneId() {
return FunctionPrototypeCall(getTimeZone, this).id;
},
enumerable: false,
configurable: true,
},
);
ObjectAssign(globalThis.Temporal.ZonedDateTime.prototype, {
getTimeZoneTransition(options) {
if (options === undefined) {
throw new TypeError("options parameter is required");
}
if (typeof options === "string") {
options = {
direction: options,
};
}
const direction = options.direction;
if (direction === undefined) {
throw new TypeError("direction option is required");
}
const tz = FunctionPrototypeCall(getTimeZone, this);
let resultInstant;
switch (direction) {
case "next":
resultInstant = tz.getNextTransition(this.toInstant());
break;
case "previous":
resultInstant = tz.getPreviousTransition(this.toInstant());
break;
default:
throw new RangeError(
`direction must be one of next, previous, not ${options.direction}`,
);
}
return resultInstant?.toZonedDateTimeISO(tz.id) ?? null;
},
});
delete globalThis.Temporal.ZonedDateTime.prototype.timeZone;
}
{
const nowTimeZone = globalThis.Temporal.Now.timeZone;
ObjectDefineProperty(globalThis.Temporal.Now, "timeZoneId", {
__proto__: null,
value: function timeZoneId() {
return nowTimeZone().id;
},
writable: true,
enumerable: false,
configurable: true,
});
delete globalThis.Temporal.Now.timeZone;
}

// deno-lint-ignore prefer-primordials
if (new Temporal.Duration().toLocaleString("en-US") !== "PT0S") {
throw "V8 supports Temporal.Duration.prototype.toLocaleString now, no need to shim it";
}
shimTemporalDurationToLocaleString();
}

function shimTemporalDurationToLocaleString() {
const DurationFormat = Intl.DurationFormat;
if (!DurationFormat) {
Expand Down Expand Up @@ -786,102 +917,7 @@ function bootstrapMainRuntime(runtimeOptions, warmup = false) {
delete globalThis.Temporal;
delete globalThis.Date.prototype.toTemporalInstant;
} else {
// Removes the obsoleted `Temporal` API.
// https://github.com/tc39/proposal-temporal/pull/2895
// https://github.com/tc39/proposal-temporal/pull/2914
// https://github.com/tc39/proposal-temporal/pull/2925
if (typeof globalThis.Temporal.Instant.fromEpochSeconds === "undefined") {
throw "V8 removes obsoleted Temporal API now, no need to delete them";
}
delete globalThis.Temporal.Instant.fromEpochSeconds;
delete globalThis.Temporal.Instant.fromEpochMicroseconds;
delete globalThis.Temporal.Instant.prototype.epochSeconds;
delete globalThis.Temporal.Instant.prototype.epochMicroseconds;
delete globalThis.Temporal.Instant.prototype.toZonedDateTime;
delete globalThis.Temporal.PlainDate.prototype.getISOFiels; // weird
delete globalThis.Temporal.PlainDate.prototype.getISOFields;
delete globalThis.Temporal.PlainDateTime.prototype.withPlainDate;
delete globalThis.Temporal.PlainDateTime.prototype.toPlainYearMonth;
delete globalThis.Temporal.PlainDateTime.prototype.toPlainMonthDay;
delete globalThis.Temporal.PlainDateTime.prototype.getISOFields;
delete globalThis.Temporal.PlainMonthDay.prototype.getISOFields;
delete globalThis.Temporal.PlainTime.prototype.calendar;
delete globalThis.Temporal.PlainTime.prototype.toPlainDateTime;
delete globalThis.Temporal.PlainTime.prototype.toZonedDateTime;
delete globalThis.Temporal.PlainTime.prototype.getISOFields;
delete globalThis.Temporal.PlainYearMonth.prototype.getISOFields;
delete globalThis.Temporal.ZonedDateTime.prototype.epochSeconds;
delete globalThis.Temporal.ZonedDateTime.prototype.epochMicroseconds;
delete globalThis.Temporal.ZonedDateTime.prototype.withPlainDate;
delete globalThis.Temporal.ZonedDateTime.prototype.toPlainYearMonth;
delete globalThis.Temporal.ZonedDateTime.prototype.toPlainMonthDay;
delete globalThis.Temporal.ZonedDateTime.prototype.getISOFields;
delete globalThis.Temporal.Now.zonedDateTime;
delete globalThis.Temporal.Now.plainDateTime;
delete globalThis.Temporal.Now.plainDate;
delete globalThis.Temporal.Calendar;
delete globalThis.Temporal.TimeZone;

// Modify `Temporal.Calendar` to calendarId string
ArrayPrototypeForEach([
globalThis.Temporal.PlainDate,
globalThis.Temporal.PlainDateTime,
globalThis.Temporal.PlainMonthDay,
globalThis.Temporal.PlainYearMonth,
globalThis.Temporal.ZonedDateTime,
], (target) => {
const getCalendar =
ObjectGetOwnPropertyDescriptor(target.prototype, "calendar").get;
ObjectDefineProperty(target.prototype, "calendarId", {
__proto__: null,
get: function calendarId() {
return FunctionPrototypeCall(getCalendar, this).id;
},
enumerable: false,
configurable: true,
});
delete target.prototype.calendar;
});

// Modify `Temporal.TimeZone` to timeZoneId string
{
const getTimeZone = ObjectGetOwnPropertyDescriptor(
globalThis.Temporal.ZonedDateTime.prototype,
"timeZone",
).get;
ObjectDefineProperty(
globalThis.Temporal.ZonedDateTime.prototype,
"timeZoneId",
{
__proto__: null,
get: function timeZoneId() {
return FunctionPrototypeCall(getTimeZone, this).id;
},
enumerable: false,
configurable: true,
},
);
delete globalThis.Temporal.ZonedDateTime.prototype.timeZone;
}
{
const nowTimeZone = globalThis.Temporal.Now.timeZone;
ObjectDefineProperty(globalThis.Temporal.Now, "timeZoneId", {
__proto__: null,
value: function timeZoneId() {
return nowTimeZone().id;
},
writable: true,
enumerable: false,
configurable: true,
});
delete globalThis.Temporal.Now.timeZone;
}

// deno-lint-ignore prefer-primordials
if (new Temporal.Duration().toLocaleString("en-US") !== "PT0S") {
throw "V8 supports Temporal.Duration.prototype.toLocaleString now, no need to shim it";
}
shimTemporalDurationToLocaleString();
updateTemporal();
}

// Setup `Deno` global - we're actually overriding already existing global
Expand Down Expand Up @@ -997,98 +1033,7 @@ function bootstrapWorkerRuntime(
delete globalThis.Temporal;
delete globalThis.Date.prototype.toTemporalInstant;
} else {
// Removes the obsoleted `Temporal` API.
// https://github.com/tc39/proposal-temporal/pull/2895
// https://github.com/tc39/proposal-temporal/pull/2914
// https://github.com/tc39/proposal-temporal/pull/2925
if (typeof globalThis.Temporal.Instant.fromEpochSeconds === "undefined") {
throw "V8 removes obsoleted Temporal API now, no need to delete them";
}
delete globalThis.Temporal.Instant.fromEpochSeconds;
delete globalThis.Temporal.Instant.fromEpochMicroseconds;
delete globalThis.Temporal.Instant.prototype.epochSeconds;
delete globalThis.Temporal.Instant.prototype.epochMicroseconds;
delete globalThis.Temporal.Instant.prototype.toZonedDateTime;
delete globalThis.Temporal.PlainDate.prototype.getISOFiels; // weird
delete globalThis.Temporal.PlainDate.prototype.getISOFields;
delete globalThis.Temporal.PlainDateTime.prototype.withPlainDate;
delete globalThis.Temporal.PlainDateTime.prototype.toPlainYearMonth;
delete globalThis.Temporal.PlainDateTime.prototype.toPlainMonthDay;
delete globalThis.Temporal.PlainDateTime.prototype.getISOFields;
delete globalThis.Temporal.PlainMonthDay.prototype.getISOFields;
delete globalThis.Temporal.PlainTime.prototype.calendar;
delete globalThis.Temporal.PlainTime.prototype.toPlainDateTime;
delete globalThis.Temporal.PlainTime.prototype.toZonedDateTime;
delete globalThis.Temporal.PlainTime.prototype.getISOFields;
delete globalThis.Temporal.PlainYearMonth.prototype.getISOFields;
delete globalThis.Temporal.ZonedDateTime.prototype.epochSeconds;
delete globalThis.Temporal.ZonedDateTime.prototype.epochMicroseconds;
delete globalThis.Temporal.ZonedDateTime.prototype.withPlainDate;
delete globalThis.Temporal.ZonedDateTime.prototype.toPlainYearMonth;
delete globalThis.Temporal.ZonedDateTime.prototype.toPlainMonthDay;
delete globalThis.Temporal.ZonedDateTime.prototype.getISOFields;
delete globalThis.Temporal.Now.zonedDateTime;
delete globalThis.Temporal.Now.plainDateTime;
delete globalThis.Temporal.Now.plainDate;
delete globalThis.Temporal.Calendar;
delete globalThis.Temporal.TimeZone;

// Modify `Temporal.Calendar` to calendarId string
ArrayPrototypeForEach([
globalThis.Temporal.PlainDate,
globalThis.Temporal.PlainDateTime,
globalThis.Temporal.PlainMonthDay,
globalThis.Temporal.PlainYearMonth,
globalThis.Temporal.ZonedDateTime,
], (target) => {
const getCalendar =
ObjectGetOwnPropertyDescriptor(target.prototype, "calendar").get;
ObjectDefineProperty(target.prototype, "calendarId", {
__proto__: null,
get: function calendarId() {
return FunctionPrototypeCall(getCalendar, this).id;
},
enumerable: false,
configurable: true,
});
delete target.prototype.calendar;
});

// Modify `Temporal.TimeZone` to timeZoneId string
{
const getTimeZone = ObjectGetOwnPropertyDescriptor(
globalThis.Temporal.ZonedDateTime.prototype,
"timeZone",
).get;
ObjectDefineProperty(
globalThis.Temporal.ZonedDateTime.prototype,
"timeZoneId",
{
__proto__: null,
get: function timeZoneId() {
return FunctionPrototypeCall(getTimeZone, this).id;
},
enumerable: false,
configurable: true,
},
);
delete globalThis.Temporal.ZonedDateTime.prototype.timeZone;
}
{
const nowTimeZone = globalThis.Temporal.Now.timeZone;
ObjectDefineProperty(globalThis.Temporal.Now, "timeZoneId", {
__proto__: null,
value: function timeZoneId() {
return nowTimeZone().id;
},
writable: true,
enumerable: false,
configurable: true,
});
delete globalThis.Temporal.Now.timeZone;
}

shimTemporalDurationToLocaleString();
updateTemporal();
}

// Setup `Deno` global - we're actually overriding already existing global
Expand Down
32 changes: 16 additions & 16 deletions tests/specs/run/unstable_temporal_api_list/main.out
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,22 @@ Temporal.Instant.prototype
]
Temporal.ZonedDateTime.prototype
[
"add", "calendarId", "constructor",
"day", "dayOfWeek", "dayOfYear",
"daysInMonth", "daysInWeek", "daysInYear",
"epochMilliseconds", "epochNanoseconds", "equals",
"era", "eraYear", "hour",
"hoursInDay", "inLeapYear", "microsecond",
"millisecond", "minute", "month",
"monthCode", "monthsInYear", "nanosecond",
"offset", "offsetNanoseconds", "round",
"second", "since", "startOfDay",
"subtract", "timeZoneId", "toInstant",
"toJSON", "toLocaleString", "toPlainDate",
"toPlainDateTime", "toPlainTime", "toString",
"until", "valueOf", "weekOfYear",
"with", "withCalendar", "withPlainTime",
"withTimeZone", "year"
"add", "calendarId", "constructor",
"day", "dayOfWeek", "dayOfYear",
"daysInMonth", "daysInWeek", "daysInYear",
"epochMilliseconds", "epochNanoseconds", "equals",
"era", "eraYear", "getTimeZoneTransition",
"hour", "hoursInDay", "inLeapYear",
"microsecond", "millisecond", "minute",
"month", "monthCode", "monthsInYear",
"nanosecond", "offset", "offsetNanoseconds",
"round", "second", "since",
"startOfDay", "subtract", "timeZoneId",
"toInstant", "toJSON", "toLocaleString",
"toPlainDate", "toPlainDateTime", "toPlainTime",
"toString", "until", "valueOf",
"weekOfYear", "with", "withCalendar",
"withPlainTime", "withTimeZone", "year"
]
Temporal.PlainDate.prototype
[
Expand Down
1 change: 1 addition & 0 deletions tests/specs/run/unstable_temporal_api_patch/main.out
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ UTC
undefined
undefined
1 day, 6 hr, 30 min
2020-03-08T03:00:00-04:00[America/New_York]
Loading

0 comments on commit ee7293d

Please sign in to comment.