mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-23 09:46:04 -05:00
LibJS: Implement Temporal.ZonedDateTime.prototype.with*
Includes: Temporal.ZonedDateTime.prototype.with Temporal.ZonedDateTime.prototype.withPlainTime Temporal.ZonedDateTime.prototype.withCalendar Temporal.ZonedDateTime.prototype.withTimeZone
This commit is contained in:
parent
f2ab9e1aa9
commit
3d0f384e01
Notes:
github-actions[bot]
2024-11-26 10:03:27 +00:00
Author: https://github.com/trflynn89 Commit: https://github.com/LadybirdBrowser/ladybird/commit/3d0f384e011 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2577 Reviewed-by: https://github.com/shannonbooth ✅
6 changed files with 427 additions and 0 deletions
|
@ -6,11 +6,13 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/Date.h>
|
||||
#include <LibJS/Runtime/Temporal/Calendar.h>
|
||||
#include <LibJS/Runtime/Temporal/Duration.h>
|
||||
#include <LibJS/Runtime/Temporal/Instant.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDate.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainDateTime.h>
|
||||
#include <LibJS/Runtime/Temporal/PlainTime.h>
|
||||
#include <LibJS/Runtime/Temporal/TimeZone.h>
|
||||
#include <LibJS/Runtime/Temporal/ZonedDateTimePrototype.h>
|
||||
|
||||
|
@ -63,6 +65,10 @@ void ZonedDateTimePrototype::initialize(Realm& realm)
|
|||
define_native_accessor(realm, vm.names.offset, offset_getter, {}, Attribute::Configurable);
|
||||
|
||||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||||
define_native_function(realm, vm.names.with, with, 1, attr);
|
||||
define_native_function(realm, vm.names.withPlainTime, with_plain_time, 0, attr);
|
||||
define_native_function(realm, vm.names.withTimeZone, with_time_zone, 1, attr);
|
||||
define_native_function(realm, vm.names.withCalendar, with_calendar, 1, attr);
|
||||
define_native_function(realm, vm.names.add, add, 1, attr);
|
||||
define_native_function(realm, vm.names.subtract, subtract, 1, attr);
|
||||
define_native_function(realm, vm.names.until, until, 1, attr);
|
||||
|
@ -349,6 +355,165 @@ JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::offset_getter)
|
|||
return PrimitiveString::create(vm, format_utc_offset_nanoseconds(offset_nanoseconds));
|
||||
}
|
||||
|
||||
// 6.3.31 Temporal.ZonedDateTime.prototype.with ( temporalZonedDateTimeLike [ , options ] ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.with
|
||||
JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::with)
|
||||
{
|
||||
auto temporal_zoned_date_time_like = vm.argument(0);
|
||||
auto options = vm.argument(1);
|
||||
|
||||
// 1. Let zonedDateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
|
||||
auto zoned_date_time = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. If ? IsPartialTemporalObject(temporalZonedDateTimeLike) is false, throw a TypeError exception.
|
||||
if (!TRY(is_partial_temporal_object(vm, temporal_zoned_date_time_like)))
|
||||
return vm.throw_completion<TypeError>(ErrorType::TemporalObjectMustBePartialTemporalObject);
|
||||
|
||||
// 4. Let epochNs be zonedDateTime.[[EpochNanoseconds]].
|
||||
auto const& epoch_nanoseconds = zoned_date_time->epoch_nanoseconds()->big_integer();
|
||||
|
||||
// 5. Let timeZone be zonedDateTime.[[TimeZone]].
|
||||
auto const& time_zone = zoned_date_time->time_zone();
|
||||
|
||||
// 6. Let calendar be zonedDateTime.[[Calendar]].
|
||||
auto const& calendar = zoned_date_time->calendar();
|
||||
|
||||
// 7. Let offsetNanoseconds be GetOffsetNanosecondsFor(timeZone, epochNs).
|
||||
auto offset_nanoseconds = get_offset_nanoseconds_for(time_zone, epoch_nanoseconds);
|
||||
|
||||
// 8. Let isoDateTime be GetISODateTimeFor(timeZone, epochNs).
|
||||
auto iso_date_time = get_iso_date_time_for(time_zone, epoch_nanoseconds);
|
||||
|
||||
// 9. Let fields be ISODateToFields(calendar, isoDateTime.[[ISODate]], DATE).
|
||||
auto fields = iso_date_to_fields(calendar, iso_date_time.iso_date, DateType::Date);
|
||||
|
||||
// 10. Set fields.[[Hour]] to isoDateTime.[[Time]].[[Hour]].
|
||||
fields.hour = iso_date_time.time.hour;
|
||||
|
||||
// 11. Set fields.[[Minute]] to isoDateTime.[[Time]].[[Minute]].
|
||||
fields.minute = iso_date_time.time.minute;
|
||||
|
||||
// 12. Set fields.[[Second]] to isoDateTime.[[Time]].[[Second]].
|
||||
fields.second = iso_date_time.time.second;
|
||||
|
||||
// 13. Set fields.[[Millisecond]] to isoDateTime.[[Time]].[[Millisecond]].
|
||||
fields.millisecond = iso_date_time.time.millisecond;
|
||||
|
||||
// 14. Set fields.[[Microsecond]] to isoDateTime.[[Time]].[[Microsecond]].
|
||||
fields.microsecond = iso_date_time.time.microsecond;
|
||||
|
||||
// 15. Set fields.[[Nanosecond]] to isoDateTime.[[Time]].[[Nanosecond]].
|
||||
fields.nanosecond = iso_date_time.time.nanosecond;
|
||||
|
||||
// 16. Set fields.[[OffsetString]] to FormatUTCOffsetNanoseconds(offsetNanoseconds).
|
||||
fields.offset = format_utc_offset_nanoseconds(offset_nanoseconds);
|
||||
|
||||
// 17. Let partialZonedDateTime be ? PrepareCalendarFields(calendar, temporalZonedDateTimeLike, « YEAR, MONTH, MONTH-CODE, DAY », « HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND, NANOSECOND, OFFSET », PARTIAL).
|
||||
static constexpr auto calendar_field_names = to_array({ CalendarField::Year, CalendarField::Month, CalendarField::MonthCode, CalendarField::Day });
|
||||
static constexpr auto non_calendar_field_names = to_array({ CalendarField::Hour, CalendarField::Minute, CalendarField::Second, CalendarField::Millisecond, CalendarField::Microsecond, CalendarField::Nanosecond, CalendarField::Offset });
|
||||
auto partial_zoned_date_time = TRY(prepare_calendar_fields(vm, calendar, temporal_zoned_date_time_like.as_object(), calendar_field_names, non_calendar_field_names, Partial {}));
|
||||
|
||||
// 18. Set fields to CalendarMergeFields(calendar, fields, partialZonedDateTime).
|
||||
fields = calendar_merge_fields(calendar, fields, partial_zoned_date_time);
|
||||
|
||||
// 19. Let resolvedOptions be ? GetOptionsObject(options).
|
||||
auto resolved_options = TRY(get_options_object(vm, options));
|
||||
|
||||
// 20. Let disambiguation be ? GetTemporalDisambiguationOption(resolvedOptions).
|
||||
auto disambiguation = TRY(get_temporal_disambiguation_option(vm, resolved_options));
|
||||
|
||||
// 21. Let offset be ? GetTemporalOffsetOption(resolvedOptions, PREFER).
|
||||
auto offset = TRY(get_temporal_offset_option(vm, resolved_options, OffsetOption::Prefer));
|
||||
|
||||
// 22. Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
|
||||
auto overflow = TRY(get_temporal_overflow_option(vm, resolved_options));
|
||||
|
||||
// 23. Let dateTimeResult be ? InterpretTemporalDateTimeFields(calendar, fields, overflow).
|
||||
auto date_time_result = TRY(interpret_temporal_date_time_fields(vm, calendar, fields, overflow));
|
||||
|
||||
// 24. Let newOffsetNanoseconds be ! ParseDateTimeUTCOffset(fields.[[OffsetString]]).
|
||||
auto new_offset_nanoseconds = parse_date_time_utc_offset(*fields.offset);
|
||||
|
||||
// 25. Let epochNanoseconds be ? InterpretISODateTimeOffset(dateTimeResult.[[ISODate]], dateTimeResult.[[Time]], OPTION, newOffsetNanoseconds, timeZone, disambiguation, offset, MATCH-EXACTLY).
|
||||
auto new_epoch_nanoseconds = TRY(interpret_iso_date_time_offset(vm, date_time_result.iso_date, date_time_result.time, OffsetBehavior::Option, new_offset_nanoseconds, time_zone, disambiguation, offset, MatchBehavior::MatchExactly));
|
||||
|
||||
// 26. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).
|
||||
return MUST(create_temporal_zoned_date_time(vm, BigInt::create(vm, move(new_epoch_nanoseconds)), time_zone, calendar));
|
||||
}
|
||||
|
||||
// 6.3.32 Temporal.ZonedDateTime.prototype.withPlainTime ( [ plainTimeLike ] ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.withplaintime
|
||||
JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::with_plain_time)
|
||||
{
|
||||
auto plain_time_like = vm.argument(0);
|
||||
|
||||
// 1. Let zonedDateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
|
||||
auto zoned_date_time = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Let timeZone be zonedDateTime.[[TimeZone]].
|
||||
auto const& time_zone = zoned_date_time->time_zone();
|
||||
|
||||
// 4. Let calendar be zonedDateTime.[[Calendar]].
|
||||
auto const& calendar = zoned_date_time->calendar();
|
||||
|
||||
// 5. Let isoDateTime be GetISODateTimeFor(timeZone, zonedDateTime.[[EpochNanoseconds]]).
|
||||
auto iso_date_time = get_iso_date_time_for(time_zone, zoned_date_time->epoch_nanoseconds()->big_integer());
|
||||
|
||||
Crypto::SignedBigInteger epoch_nanoseconds;
|
||||
|
||||
// 6. If plainTimeLike is undefined, then
|
||||
if (plain_time_like.is_undefined()) {
|
||||
// a. Let epochNs be ? GetStartOfDay(timeZone, isoDateTime.[[ISODate]]).
|
||||
epoch_nanoseconds = TRY(get_start_of_day(vm, time_zone, iso_date_time.iso_date));
|
||||
}
|
||||
// 7. Else,
|
||||
else {
|
||||
// a. Let plainTime be ? ToTemporalTime(plainTimeLike).
|
||||
auto plain_time = TRY(to_temporal_time(vm, plain_time_like));
|
||||
|
||||
// b. Let resultISODateTime be CombineISODateAndTimeRecord(isoDateTime.[[ISODate]], plainTime.[[Time]]).
|
||||
auto result_iso_date_time = combine_iso_date_and_time_record(iso_date_time.iso_date, plain_time->time());
|
||||
|
||||
// c. Let epochNs be ? GetEpochNanosecondsFor(timeZone, resultISODateTime, COMPATIBLE).
|
||||
epoch_nanoseconds = TRY(get_epoch_nanoseconds_for(vm, time_zone, result_iso_date_time, Disambiguation::Compatible));
|
||||
}
|
||||
|
||||
// 8. Return ! CreateTemporalZonedDateTime(epochNs, timeZone, calendar).
|
||||
return MUST(create_temporal_zoned_date_time(vm, BigInt::create(vm, move(epoch_nanoseconds)), time_zone, calendar));
|
||||
}
|
||||
|
||||
// 6.3.33 Temporal.ZonedDateTime.prototype.withTimeZone ( timeZoneLike ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.withtimezone
|
||||
JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::with_time_zone)
|
||||
{
|
||||
auto time_zone_like = vm.argument(0);
|
||||
|
||||
// 1. Let zonedDateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
|
||||
auto zoned_date_time = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Let timeZone be ? ToTemporalTimeZoneIdentifier(timeZoneLike).
|
||||
auto time_zone = TRY(to_temporal_time_zone_identifier(vm, time_zone_like));
|
||||
|
||||
// 4. Return ! CreateTemporalZonedDateTime(zonedDateTime.[[EpochNanoseconds]], timeZone, zonedDateTime.[[Calendar]]).
|
||||
return MUST(create_temporal_zoned_date_time(vm, zoned_date_time->epoch_nanoseconds(), move(time_zone), zoned_date_time->calendar()));
|
||||
}
|
||||
|
||||
// 6.3.34 Temporal.ZonedDateTime.prototype.withCalendar ( calendarLike ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.withcalendar
|
||||
JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::with_calendar)
|
||||
{
|
||||
auto calendar_like = vm.argument(0);
|
||||
|
||||
// 1. Let zonedDateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
|
||||
auto zoned_date_time = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Let calendar be ? ToTemporalCalendarIdentifier(calendarLike).
|
||||
auto calendar = TRY(to_temporal_calendar_identifier(vm, calendar_like));
|
||||
|
||||
// 4. Return ! CreateTemporalZonedDateTime(zonedDateTime.[[EpochNanoseconds]], zonedDateTime.[[TimeZone]], calendar).
|
||||
return MUST(create_temporal_zoned_date_time(vm, zoned_date_time->epoch_nanoseconds(), zoned_date_time->time_zone(), move(calendar)));
|
||||
}
|
||||
|
||||
// 6.3.35 Temporal.ZonedDateTime.prototype.add ( temporalDurationLike [ , options ] ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.add
|
||||
JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::add)
|
||||
{
|
||||
|
|
|
@ -51,6 +51,10 @@ private:
|
|||
JS_DECLARE_NATIVE_FUNCTION(in_leap_year_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(offset_nanoseconds_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(offset_getter);
|
||||
JS_DECLARE_NATIVE_FUNCTION(with);
|
||||
JS_DECLARE_NATIVE_FUNCTION(with_plain_time);
|
||||
JS_DECLARE_NATIVE_FUNCTION(with_time_zone);
|
||||
JS_DECLARE_NATIVE_FUNCTION(with_calendar);
|
||||
JS_DECLARE_NATIVE_FUNCTION(add);
|
||||
JS_DECLARE_NATIVE_FUNCTION(subtract);
|
||||
JS_DECLARE_NATIVE_FUNCTION(until);
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
describe("correct behavior", () => {
|
||||
test("length is 1", () => {
|
||||
expect(Temporal.ZonedDateTime.prototype.with).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const zonedDateTime = new Temporal.ZonedDateTime(0n, "UTC");
|
||||
const values = [
|
||||
[{ year: 2021 }, 1609459200000000000n],
|
||||
[{ year: 2021, month: 7 }, 1625097600000000000n],
|
||||
[{ year: 2021, month: 7, day: 6 }, 1625529600000000000n],
|
||||
[{ year: 2021, monthCode: "M07", day: 6 }, 1625529600000000000n],
|
||||
[{ hour: 18, minute: 14, second: 47 }, 65687000000000n],
|
||||
[
|
||||
{
|
||||
year: 2021,
|
||||
month: 7,
|
||||
day: 6,
|
||||
hour: 18,
|
||||
minute: 14,
|
||||
second: 47,
|
||||
millisecond: 123,
|
||||
microsecond: 456,
|
||||
nanosecond: 789,
|
||||
},
|
||||
1625595287123456789n,
|
||||
],
|
||||
];
|
||||
for (const [arg, epochNanoseconds] of values) {
|
||||
const expected = new Temporal.ZonedDateTime(epochNanoseconds, "UTC");
|
||||
expect(zonedDateTime.with(arg).equals(expected)).toBeTrue();
|
||||
}
|
||||
|
||||
// Supplying the same values doesn't change the date/time, but still creates a new object
|
||||
const zonedDateTimeLike = {
|
||||
year: zonedDateTime.year,
|
||||
month: zonedDateTime.month,
|
||||
day: zonedDateTime.day,
|
||||
hour: zonedDateTime.hour,
|
||||
minute: zonedDateTime.minute,
|
||||
second: zonedDateTime.second,
|
||||
millisecond: zonedDateTime.millisecond,
|
||||
microsecond: zonedDateTime.microsecond,
|
||||
nanosecond: zonedDateTime.nanosecond,
|
||||
};
|
||||
expect(zonedDateTime.with(zonedDateTimeLike)).not.toBe(zonedDateTime);
|
||||
expect(zonedDateTime.with(zonedDateTimeLike).equals(zonedDateTime)).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.ZonedDateTime object", () => {
|
||||
expect(() => {
|
||||
Temporal.ZonedDateTime.prototype.with.call("foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.ZonedDateTime");
|
||||
});
|
||||
|
||||
test("argument must be an object", () => {
|
||||
expect(() => {
|
||||
new Temporal.ZonedDateTime(0n, "UTC").with("foo");
|
||||
}).toThrowWithMessage(TypeError, "Object must be a partial Temporal object");
|
||||
expect(() => {
|
||||
new Temporal.ZonedDateTime(0n, "UTC").with(42);
|
||||
}).toThrowWithMessage(TypeError, "Object must be a partial Temporal object");
|
||||
});
|
||||
|
||||
test("argument must have one of 'day', 'hour', 'microsecond', 'millisecond', 'minute', 'month', 'monthCode', 'nanosecond', 'second', 'year'", () => {
|
||||
expect(() => {
|
||||
new Temporal.ZonedDateTime(0n, "UTC").with({});
|
||||
}).toThrowWithMessage(TypeError, "Object must be a partial Temporal object");
|
||||
});
|
||||
|
||||
test("argument must not have 'calendar' or 'timeZone'", () => {
|
||||
expect(() => {
|
||||
new Temporal.ZonedDateTime(0n, "UTC").with({ calendar: {} });
|
||||
}).toThrowWithMessage(TypeError, "Object must be a partial Temporal object");
|
||||
expect(() => {
|
||||
new Temporal.ZonedDateTime(0n, "UTC").with({ timeZone: {} });
|
||||
}).toThrowWithMessage(TypeError, "Object must be a partial Temporal object");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
describe("correct behavior", () => {
|
||||
test("length is 1", () => {
|
||||
expect(Temporal.ZonedDateTime.prototype.withCalendar).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const object = {};
|
||||
const zonedDateTime = new Temporal.ZonedDateTime(1n, "UTC", "gregory");
|
||||
expect(zonedDateTime.calendarId).toBe("gregory");
|
||||
|
||||
const withCalendarZonedDateTime = zonedDateTime.withCalendar("iso8601");
|
||||
expect(withCalendarZonedDateTime.calendarId).toBe("iso8601");
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.ZonedDateTime object", () => {
|
||||
expect(() => {
|
||||
Temporal.ZonedDateTime.prototype.withCalendar.call("foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.ZonedDateTime");
|
||||
});
|
||||
|
||||
test("from invalid calendar identifier", () => {
|
||||
const zonedDateTime = new Temporal.ZonedDateTime(1n, "UTC", "iso8601");
|
||||
|
||||
expect(() => {
|
||||
zonedDateTime.withCalendar("iso8602foobar");
|
||||
}).toThrowWithMessage(RangeError, "Invalid calendar identifier 'iso8602foobar'");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,118 @@
|
|||
describe("correct behavior", () => {
|
||||
test("length is 0", () => {
|
||||
expect(Temporal.ZonedDateTime.prototype.withPlainTime).toHaveLength(0);
|
||||
});
|
||||
|
||||
function checkCommonExpectedResults(withPlainTimeZonedDateTime) {
|
||||
expect(withPlainTimeZonedDateTime.epochNanoseconds).toBe(1636064604200300400n);
|
||||
expect(withPlainTimeZonedDateTime.epochMilliseconds).toBe(1636064604200);
|
||||
expect(withPlainTimeZonedDateTime.year).toBe(2021);
|
||||
expect(withPlainTimeZonedDateTime.month).toBe(11);
|
||||
expect(withPlainTimeZonedDateTime.monthCode).toBe("M11");
|
||||
expect(withPlainTimeZonedDateTime.day).toBe(4);
|
||||
expect(withPlainTimeZonedDateTime.hour).toBe(22);
|
||||
expect(withPlainTimeZonedDateTime.minute).toBe(23);
|
||||
expect(withPlainTimeZonedDateTime.second).toBe(24);
|
||||
expect(withPlainTimeZonedDateTime.millisecond).toBe(200);
|
||||
expect(withPlainTimeZonedDateTime.microsecond).toBe(300);
|
||||
expect(withPlainTimeZonedDateTime.nanosecond).toBe(400);
|
||||
expect(withPlainTimeZonedDateTime.dayOfWeek).toBe(4);
|
||||
expect(withPlainTimeZonedDateTime.dayOfYear).toBe(308);
|
||||
expect(withPlainTimeZonedDateTime.weekOfYear).toBe(44);
|
||||
expect(withPlainTimeZonedDateTime.hoursInDay).toBe(24);
|
||||
expect(withPlainTimeZonedDateTime.daysInWeek).toBe(7);
|
||||
expect(withPlainTimeZonedDateTime.daysInYear).toBe(365);
|
||||
expect(withPlainTimeZonedDateTime.monthsInYear).toBe(12);
|
||||
expect(withPlainTimeZonedDateTime.inLeapYear).toBeFalse();
|
||||
expect(withPlainTimeZonedDateTime.offset).toBe("+00:00");
|
||||
expect(withPlainTimeZonedDateTime.offsetNanoseconds).toBe(0);
|
||||
}
|
||||
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 11, 4, 21, 16, 56, 100, 200, 300);
|
||||
const zonedDateTime = plainDateTime.toZonedDateTime("UTC");
|
||||
const plainTime = new Temporal.PlainTime(22, 23, 24, 200, 300, 400);
|
||||
const withPlainTimeZonedDateTime = zonedDateTime.withPlainTime(plainTime);
|
||||
|
||||
checkCommonExpectedResults(withPlainTimeZonedDateTime);
|
||||
});
|
||||
|
||||
test("plain time-like object", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 11, 4, 21, 16, 56, 100, 200, 300);
|
||||
const zonedDateTime = plainDateTime.toZonedDateTime("UTC");
|
||||
const plainTimeLike = {
|
||||
hour: 22,
|
||||
minute: 23,
|
||||
second: 24,
|
||||
millisecond: 200,
|
||||
microsecond: 300,
|
||||
nanosecond: 400,
|
||||
};
|
||||
const withPlainTimeZonedDateTime = zonedDateTime.withPlainTime(plainTimeLike);
|
||||
|
||||
checkCommonExpectedResults(withPlainTimeZonedDateTime);
|
||||
});
|
||||
|
||||
// FIXME: Enable this test when we have ZonedDateTime.prototype.startOfDay
|
||||
// test("passing no parameters is the equivalent of using startOfDay", () => {
|
||||
// const plainDateTime = new Temporal.PlainDateTime(2021, 11, 4, 21, 16, 56, 100, 200, 300);
|
||||
// const zonedDateTime = plainDateTime.toZonedDateTime("UTC");
|
||||
// const startOfDayZonedDateTime = zonedDateTime.startOfDay();
|
||||
// const withPlainTimeZonedDateTime = zonedDateTime.withPlainTime();
|
||||
|
||||
// expect(startOfDayZonedDateTime.epochNanoseconds).toBe(
|
||||
// withPlainTimeZonedDateTime.epochNanoseconds
|
||||
// );
|
||||
// expect(startOfDayZonedDateTime.epochMilliseconds).toBe(
|
||||
// withPlainTimeZonedDateTime.epochMilliseconds
|
||||
// );
|
||||
// expect(startOfDayZonedDateTime.year).toBe(withPlainTimeZonedDateTime.year);
|
||||
// expect(startOfDayZonedDateTime.month).toBe(withPlainTimeZonedDateTime.month);
|
||||
// expect(startOfDayZonedDateTime.monthCode).toBe(withPlainTimeZonedDateTime.monthCode);
|
||||
// expect(startOfDayZonedDateTime.day).toBe(withPlainTimeZonedDateTime.day);
|
||||
// expect(startOfDayZonedDateTime.hour).toBe(withPlainTimeZonedDateTime.hour);
|
||||
// expect(startOfDayZonedDateTime.minute).toBe(withPlainTimeZonedDateTime.minute);
|
||||
// expect(startOfDayZonedDateTime.second).toBe(withPlainTimeZonedDateTime.second);
|
||||
// expect(startOfDayZonedDateTime.millisecond).toBe(withPlainTimeZonedDateTime.millisecond);
|
||||
// expect(startOfDayZonedDateTime.microsecond).toBe(withPlainTimeZonedDateTime.microsecond);
|
||||
// expect(startOfDayZonedDateTime.nanosecond).toBe(withPlainTimeZonedDateTime.nanosecond);
|
||||
// expect(startOfDayZonedDateTime.dayOfWeek).toBe(withPlainTimeZonedDateTime.dayOfWeek);
|
||||
// expect(startOfDayZonedDateTime.dayOfYear).toBe(withPlainTimeZonedDateTime.dayOfYear);
|
||||
// expect(startOfDayZonedDateTime.weekOfYear).toBe(withPlainTimeZonedDateTime.weekOfYear);
|
||||
// expect(startOfDayZonedDateTime.hoursInDay).toBe(withPlainTimeZonedDateTime.hoursInDay);
|
||||
// expect(startOfDayZonedDateTime.daysInWeek).toBe(withPlainTimeZonedDateTime.daysInWeek);
|
||||
// expect(startOfDayZonedDateTime.daysInYear).toBe(withPlainTimeZonedDateTime.daysInYear);
|
||||
// expect(startOfDayZonedDateTime.monthsInYear).toBe(withPlainTimeZonedDateTime.monthsInYear);
|
||||
// expect(startOfDayZonedDateTime.inLeapYear).toBe(withPlainTimeZonedDateTime.inLeapYear);
|
||||
// expect(startOfDayZonedDateTime.offset).toBe(withPlainTimeZonedDateTime.offset);
|
||||
// expect(startOfDayZonedDateTime.offsetNanoseconds).toBe(
|
||||
// withPlainTimeZonedDateTime.offsetNanoseconds
|
||||
// );
|
||||
// });
|
||||
|
||||
test("from plain time string", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 11, 4, 21, 16, 56, 100, 200, 300);
|
||||
const zonedDateTime = plainDateTime.toZonedDateTime("UTC");
|
||||
const withPlainTimeZonedDateTime = zonedDateTime.withPlainTime("22:23:24.200300400");
|
||||
|
||||
checkCommonExpectedResults(withPlainTimeZonedDateTime);
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.ZonedDateTime object", () => {
|
||||
expect(() => {
|
||||
Temporal.ZonedDateTime.prototype.withPlainTime.call("foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.ZonedDateTime");
|
||||
});
|
||||
|
||||
test("invalid plain time-like object", () => {
|
||||
expect(() => {
|
||||
new Temporal.ZonedDateTime(1n, "UTC").withPlainTime({});
|
||||
}).toThrowWithMessage(TypeError, "Invalid time");
|
||||
|
||||
expect(() => {
|
||||
new Temporal.ZonedDateTime(1n, "UTC").withPlainTime({ foo: 1, bar: 2 });
|
||||
}).toThrowWithMessage(TypeError, "Invalid time");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,29 @@
|
|||
describe("correct behavior", () => {
|
||||
test("length is 1", () => {
|
||||
expect(Temporal.ZonedDateTime.prototype.withTimeZone).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const zonedDateTime = new Temporal.ZonedDateTime(1n, "America/New_York");
|
||||
expect(zonedDateTime.timeZoneId).toBe("America/New_York");
|
||||
|
||||
const withTimeZoneZonedDateTime = zonedDateTime.withTimeZone("UTC");
|
||||
expect(withTimeZoneZonedDateTime.timeZoneId).toBe("UTC");
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.ZonedDateTime object", () => {
|
||||
expect(() => {
|
||||
Temporal.ZonedDateTime.prototype.withTimeZone.call("foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.ZonedDateTime");
|
||||
});
|
||||
|
||||
test("from invalid time zone string", () => {
|
||||
const zonedDateTime = new Temporal.ZonedDateTime(1n, "UTC");
|
||||
|
||||
expect(() => {
|
||||
zonedDateTime.withTimeZone("UTCfoobar");
|
||||
}).toThrowWithMessage(RangeError, "Invalid time zone name 'UTCfoobar'");
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue