mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-20 19:45:12 +00:00
LibJS: Implement stringification Temporal.ZonedDateTime prototypes
This commit is contained in:
parent
c0150acc5e
commit
4ef21614e9
Notes:
github-actions[bot]
2024-11-26 10:03:54 +00:00
Author: https://github.com/trflynn89 Commit: https://github.com/LadybirdBrowser/ladybird/commit/4ef21614e9b Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2577 Reviewed-by: https://github.com/shannonbooth ✅
9 changed files with 339 additions and 1 deletions
|
@ -211,6 +211,40 @@ ThrowCompletionOr<ShowCalendar> get_temporal_show_calendar_name_option(VM& vm, O
|
|||
return ShowCalendar::Auto;
|
||||
}
|
||||
|
||||
// 13.11 GetTemporalShowTimeZoneNameOption ( options ), https://tc39.es/proposal-temporal/#sec-temporal-gettemporalshowtimezonenameoption
|
||||
ThrowCompletionOr<ShowTimeZoneName> get_temporal_show_time_zone_name_option(VM& vm, Object const& options)
|
||||
{
|
||||
// 1. Let stringValue be ? GetOption(options, "timeZoneName", STRING, « "auto", "never", "critical" », "auto").
|
||||
auto string_value = TRY(get_option(vm, options, vm.names.timeZoneName, OptionType::String, { "auto"sv, "never"sv, "critical"sv }, "auto"sv));
|
||||
auto string_view = string_value.as_string().utf8_string_view();
|
||||
|
||||
// 2. If stringValue is "never", return NEVER.
|
||||
if (string_view == "never"sv)
|
||||
return ShowTimeZoneName::Never;
|
||||
|
||||
// 3. If stringValue is "critical", return CRITICAL.
|
||||
if (string_view == "critical"sv)
|
||||
return ShowTimeZoneName::Critical;
|
||||
|
||||
// 4. Return AUTO.
|
||||
return ShowTimeZoneName::Auto;
|
||||
}
|
||||
|
||||
// 13.12 GetTemporalShowOffsetOption ( options ), https://tc39.es/proposal-temporal/#sec-temporal-gettemporalshowoffsetoption
|
||||
ThrowCompletionOr<ShowOffset> get_temporal_show_offset_option(VM& vm, Object const& options)
|
||||
{
|
||||
// 1. Let stringValue be ? GetOption(options, "offset", STRING, « "auto", "never" », "auto").
|
||||
auto string_value = TRY(get_option(vm, options, vm.names.offset, OptionType::String, { "auto"sv, "never"sv }, "auto"sv));
|
||||
auto string_view = string_value.as_string().utf8_string_view();
|
||||
|
||||
// 2. If stringValue is "never", return never.
|
||||
if (string_view == "never"sv)
|
||||
return ShowOffset::Never;
|
||||
|
||||
// 3. Return auto.
|
||||
return ShowOffset::Auto;
|
||||
}
|
||||
|
||||
// 13.14 ValidateTemporalRoundingIncrement ( increment, dividend, inclusive ), https://tc39.es/proposal-temporal/#sec-validatetemporalroundingincrement
|
||||
ThrowCompletionOr<void> validate_temporal_rounding_increment(VM& vm, u64 increment, u64 dividend, bool inclusive)
|
||||
{
|
||||
|
|
|
@ -64,6 +64,17 @@ enum class ShowCalendar {
|
|||
Critical,
|
||||
};
|
||||
|
||||
enum class ShowOffset {
|
||||
Auto,
|
||||
Never,
|
||||
};
|
||||
|
||||
enum class ShowTimeZoneName {
|
||||
Auto,
|
||||
Never,
|
||||
Critical,
|
||||
};
|
||||
|
||||
enum class TimeStyle {
|
||||
Separated,
|
||||
Unseparated,
|
||||
|
@ -161,6 +172,8 @@ ThrowCompletionOr<Overflow> get_temporal_overflow_option(VM&, Object const& opti
|
|||
ThrowCompletionOr<Disambiguation> get_temporal_disambiguation_option(VM&, Object const& options);
|
||||
RoundingMode negate_rounding_mode(RoundingMode);
|
||||
ThrowCompletionOr<OffsetOption> get_temporal_offset_option(VM&, Object const& options, OffsetOption fallback);
|
||||
ThrowCompletionOr<ShowTimeZoneName> get_temporal_show_time_zone_name_option(VM&, Object const& options);
|
||||
ThrowCompletionOr<ShowOffset> get_temporal_show_offset_option(VM&, Object const& options);
|
||||
ThrowCompletionOr<ShowCalendar> get_temporal_show_calendar_name_option(VM&, Object const& options);
|
||||
ThrowCompletionOr<void> validate_temporal_rounding_increment(VM&, u64 increment, u64 dividend, bool inclusive);
|
||||
ThrowCompletionOr<Precision> get_temporal_fractional_second_digits_option(VM&, Object const& options);
|
||||
|
@ -184,7 +197,7 @@ Crypto::SignedBigInteger round_number_to_increment_as_if_positive(Crypto::Signed
|
|||
ThrowCompletionOr<ParsedISODateTime> parse_iso_date_time(VM&, StringView iso_string, ReadonlySpan<Production> allowed_formats);
|
||||
ThrowCompletionOr<String> parse_temporal_calendar_string(VM&, String const&);
|
||||
ThrowCompletionOr<GC::Ref<Duration>> parse_temporal_duration_string(VM&, StringView iso_string);
|
||||
ThrowCompletionOr<TimeZone> parse_temporal_time_zone_string(VM& vm, StringView time_zone_string);
|
||||
ThrowCompletionOr<TimeZone> parse_temporal_time_zone_string(VM&, StringView time_zone_string);
|
||||
ThrowCompletionOr<String> to_month_code(VM&, Value argument);
|
||||
ThrowCompletionOr<String> to_offset_string(VM&, Value argument);
|
||||
CalendarFields iso_date_to_fields(StringView calendar, ISODate const&, DateType);
|
||||
|
|
|
@ -319,6 +319,63 @@ ThrowCompletionOr<GC::Ref<ZonedDateTime>> create_temporal_zoned_date_time(VM& vm
|
|||
return object;
|
||||
}
|
||||
|
||||
// 6.5.4 TemporalZonedDateTimeToString ( zonedDateTime, precision, showCalendar, showTimeZone, showOffset [ , increment [ , unit [ , roundingMode ] ] ] ), https://tc39.es/proposal-temporal/#sec-temporal-temporalzoneddatetimetostring
|
||||
String temporal_zoned_date_time_to_string(ZonedDateTime const& zoned_date_time, SecondsStringPrecision::Precision precision, ShowCalendar show_calendar, ShowTimeZoneName show_time_zone, ShowOffset show_offset, u64 increment, Unit unit, RoundingMode rounding_mode)
|
||||
{
|
||||
// 1. If increment is not present, set increment to 1.
|
||||
// 2. If unit is not present, set unit to NANOSECOND.
|
||||
// 3. If roundingMode is not present, set roundingMode to TRUNC.
|
||||
|
||||
// 4. Let epochNs be zonedDateTime.[[EpochNanoseconds]].
|
||||
// 5. Set epochNs to RoundTemporalInstant(epochNs, increment, unit, roundingMode).
|
||||
auto epoch_nanoseconds = round_temporal_instant(zoned_date_time.epoch_nanoseconds()->big_integer(), increment, unit, rounding_mode);
|
||||
|
||||
// 6. Let timeZone be zonedDateTime.[[TimeZone]].
|
||||
auto const& time_zone = zoned_date_time.time_zone();
|
||||
|
||||
// 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 dateTimeString be ISODateTimeToString(isoDateTime, "iso8601", precision, NEVER).
|
||||
auto date_time_string = iso_date_time_to_string(iso_date_time, "iso8601"sv, precision, ShowCalendar::Never);
|
||||
|
||||
String offset_string;
|
||||
String time_zone_string;
|
||||
|
||||
// 10. If showOffset is NEVER, then
|
||||
if (show_offset == ShowOffset::Never) {
|
||||
// a. Let offsetString be the empty String.
|
||||
}
|
||||
// 11. Else,
|
||||
else {
|
||||
// a. Let offsetString be FormatDateTimeUTCOffsetRounded(offsetNanoseconds).
|
||||
offset_string = format_date_time_utc_offset_rounded(offset_nanoseconds);
|
||||
}
|
||||
|
||||
// 12. If showTimeZone is NEVER, then
|
||||
if (show_time_zone == ShowTimeZoneName::Never) {
|
||||
// a. Let timeZoneString be the empty String.
|
||||
}
|
||||
// 13. Else,
|
||||
else {
|
||||
// a. If showTimeZone is critical, let flag be "!"; else let flag be the empty String.
|
||||
auto flag = show_time_zone == ShowTimeZoneName::Critical ? "!"sv : ""sv;
|
||||
|
||||
// b. Let timeZoneString be the string-concatenation of the code unit 0x005B (LEFT SQUARE BRACKET), flag,
|
||||
// timeZone, and the code unit 0x005D (RIGHT SQUARE BRACKET).
|
||||
time_zone_string = MUST(String::formatted("[{}{}]", flag, time_zone));
|
||||
}
|
||||
|
||||
// 14. Let calendarString be FormatCalendarAnnotation(zonedDateTime.[[Calendar]], showCalendar).
|
||||
auto calendar_string = format_calendar_annotation(zoned_date_time.calendar(), show_calendar);
|
||||
|
||||
// 15. Return the string-concatenation of dateTimeString, offsetString, timeZoneString, and calendarString.
|
||||
return MUST(String::formatted("{}{}{}{}", date_time_string, offset_string, time_zone_string, calendar_string));
|
||||
}
|
||||
|
||||
// 6.5.5 AddZonedDateTime ( epochNanoseconds, timeZone, calendar, duration, overflow ), https://tc39.es/proposal-temporal/#sec-temporal-addzoneddatetime
|
||||
ThrowCompletionOr<Crypto::SignedBigInteger> add_zoned_date_time(VM& vm, Crypto::SignedBigInteger const& epoch_nanoseconds, StringView time_zone, StringView calendar, InternalDuration const& duration, Overflow overflow)
|
||||
{
|
||||
|
|
|
@ -51,6 +51,7 @@ enum class MatchBehavior {
|
|||
ThrowCompletionOr<Crypto::SignedBigInteger> interpret_iso_date_time_offset(VM&, ISODate, Variant<ParsedISODateTime::StartOfDay, Time> const&, OffsetBehavior, double offset_nanoseconds, StringView time_zone, Disambiguation, OffsetOption, MatchBehavior);
|
||||
ThrowCompletionOr<GC::Ref<ZonedDateTime>> to_temporal_zoned_date_time(VM&, Value item, Value options = js_undefined());
|
||||
ThrowCompletionOr<GC::Ref<ZonedDateTime>> create_temporal_zoned_date_time(VM&, BigInt const& epoch_nanoseconds, String time_zone, String calendar, GC::Ptr<FunctionObject> new_target = {});
|
||||
String temporal_zoned_date_time_to_string(ZonedDateTime const&, SecondsStringPrecision::Precision, ShowCalendar, ShowTimeZoneName, ShowOffset, u64 increment = 1, Unit = Unit::Nanosecond, RoundingMode = RoundingMode::Trunc);
|
||||
ThrowCompletionOr<Crypto::SignedBigInteger> add_zoned_date_time(VM&, Crypto::SignedBigInteger const& epoch_nanoseconds, StringView time_zone, StringView calendar, InternalDuration const&, Overflow);
|
||||
ThrowCompletionOr<InternalDuration> difference_zoned_date_time(VM&, Crypto::SignedBigInteger const& nanoseconds1, Crypto::SignedBigInteger const& nanoseconds2, StringView time_zone, StringView calendar, Unit largest_unit);
|
||||
ThrowCompletionOr<InternalDuration> difference_zoned_date_time_with_rounding(VM&, Crypto::SignedBigInteger const& nanoseconds1, Crypto::SignedBigInteger const& nanoseconds2, StringView time_zone, StringView calendar, Unit largest_unit, u64 rounding_increment, Unit smallest_unit, RoundingMode);
|
||||
|
|
|
@ -62,6 +62,9 @@ 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.toString, to_string, 0, attr);
|
||||
define_native_function(realm, vm.names.toLocaleString, to_locale_string, 0, attr);
|
||||
define_native_function(realm, vm.names.toJSON, to_json, 0, attr);
|
||||
define_native_function(realm, vm.names.valueOf, value_of, 0, attr);
|
||||
}
|
||||
|
||||
|
@ -339,6 +342,72 @@ JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::offset_getter)
|
|||
return PrimitiveString::create(vm, format_utc_offset_nanoseconds(offset_nanoseconds));
|
||||
}
|
||||
|
||||
// 6.3.41 Temporal.ZonedDateTime.prototype.toString ( [ options ] ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.tostring
|
||||
JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::to_string)
|
||||
{
|
||||
// 1. Let zonedDateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
|
||||
auto zoned_date_time = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Let resolvedOptions be ? GetOptionsObject(options).
|
||||
auto resolved_options = TRY(get_options_object(vm, vm.argument(0)));
|
||||
|
||||
// 4. NOTE: The following steps read options and perform independent validation in alphabetical order
|
||||
// (GetTemporalShowCalendarNameOption reads "calendarName", GetTemporalFractionalSecondDigitsOption reads
|
||||
// "fractionalSecondDigits", GetTemporalShowOffsetOption reads "offset", and GetRoundingModeOption reads "roundingMode").
|
||||
|
||||
// 5. Let showCalendar be ? GetTemporalShowCalendarNameOption(resolvedOptions).
|
||||
auto show_calendar = TRY(get_temporal_show_calendar_name_option(vm, resolved_options));
|
||||
|
||||
// 6. Let digits be ? GetTemporalFractionalSecondDigitsOption(resolvedOptions).
|
||||
auto digits = TRY(get_temporal_fractional_second_digits_option(vm, resolved_options));
|
||||
|
||||
// 7. Let showOffset be ? GetTemporalShowOffsetOption(resolvedOptions).
|
||||
auto show_offset = TRY(get_temporal_show_offset_option(vm, resolved_options));
|
||||
|
||||
// 8. Let roundingMode be ? GetRoundingModeOption(resolvedOptions, TRUNC).
|
||||
auto rounding_mode = TRY(get_rounding_mode_option(vm, resolved_options, RoundingMode::Trunc));
|
||||
|
||||
// 9. Let smallestUnit be ? GetTemporalUnitValuedOption(resolvedOptions, "smallestUnit", TIME, UNSET).
|
||||
auto smallest_unit = TRY(get_temporal_unit_valued_option(vm, resolved_options, vm.names.smallestUnit, UnitGroup::Time, Unset {}));
|
||||
|
||||
// 10. If smallestUnit is hour, throw a RangeError exception.
|
||||
if (auto const* unit = smallest_unit.get_pointer<Unit>(); unit && *unit == Unit::Hour)
|
||||
return vm.throw_completion<RangeError>(ErrorType::OptionIsNotValidValue, temporal_unit_to_string(*unit), vm.names.smallestUnit);
|
||||
|
||||
// 11. Let showTimeZone be ? GetTemporalShowTimeZoneNameOption(resolvedOptions).
|
||||
auto show_time_zone = TRY(get_temporal_show_time_zone_name_option(vm, resolved_options));
|
||||
|
||||
// 12. Let precision be ToSecondsStringPrecisionRecord(smallestUnit, digits).
|
||||
auto precision = to_seconds_string_precision_record(smallest_unit, digits);
|
||||
|
||||
// 13. Return TemporalZonedDateTimeToString(zonedDateTime, precision.[[Precision]], showCalendar, showTimeZone, showOffset, precision.[[Increment]], precision.[[Unit]], roundingMode).
|
||||
return PrimitiveString::create(vm, temporal_zoned_date_time_to_string(zoned_date_time, precision.precision, show_calendar, show_time_zone, show_offset, precision.increment, precision.unit, rounding_mode));
|
||||
}
|
||||
|
||||
// 6.3.42 Temporal.ZonedDateTime.prototype.toLocaleString ( [ locales [ , options ] ] ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.tolocalestring
|
||||
// NOTE: This is the minimum toLocaleString implementation for engines without ECMA-402.
|
||||
JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::to_locale_string)
|
||||
{
|
||||
// 1. Let zonedDateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
|
||||
auto zoned_date_time = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Return TemporalZonedDateTimeToString(zonedDateTime, AUTO, AUTO, AUTO, AUTO).
|
||||
return PrimitiveString::create(vm, temporal_zoned_date_time_to_string(zoned_date_time, Auto {}, ShowCalendar::Auto, ShowTimeZoneName::Auto, ShowOffset::Auto));
|
||||
}
|
||||
|
||||
// 6.3.43 Temporal.ZonedDateTime.prototype.toJSON ( ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.tojson
|
||||
JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::to_json)
|
||||
{
|
||||
// 1. Let zonedDateTime be the this value.
|
||||
// 2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
|
||||
auto zoned_date_time = TRY(typed_this_object(vm));
|
||||
|
||||
// 3. Return TemporalZonedDateTimeToString(zonedDateTime, AUTO, AUTO, AUTO, AUTO).
|
||||
return PrimitiveString::create(vm, temporal_zoned_date_time_to_string(zoned_date_time, Auto {}, ShowCalendar::Auto, ShowTimeZoneName::Auto, ShowOffset::Auto));
|
||||
}
|
||||
|
||||
// 6.3.44 Temporal.ZonedDateTime.prototype.valueOf ( ), https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.valueof
|
||||
JS_DEFINE_NATIVE_FUNCTION(ZonedDateTimePrototype::value_of)
|
||||
{
|
||||
|
|
|
@ -51,6 +51,9 @@ 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(to_string);
|
||||
JS_DECLARE_NATIVE_FUNCTION(to_locale_string);
|
||||
JS_DECLARE_NATIVE_FUNCTION(to_json);
|
||||
JS_DECLARE_NATIVE_FUNCTION(value_of);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
describe("correct behavior", () => {
|
||||
test("length is 0", () => {
|
||||
expect(Temporal.ZonedDateTime.prototype.toJSON).toHaveLength(0);
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 11, 3, 1, 33, 5, 100, 200, 300);
|
||||
const zonedDateTime = plainDateTime.toZonedDateTime("UTC");
|
||||
expect(zonedDateTime.toJSON()).toBe("2021-11-03T01:33:05.1002003+00:00[UTC]");
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.ZonedDateTime object", () => {
|
||||
expect(() => {
|
||||
Temporal.ZonedDateTime.prototype.toJSON.call("foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.ZonedDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
describe("correct behavior", () => {
|
||||
test("length is 0", () => {
|
||||
expect(Temporal.ZonedDateTime.prototype.toLocaleString).toHaveLength(0);
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 11, 3, 1, 33, 5, 100, 200, 300);
|
||||
const zonedDateTime = plainDateTime.toZonedDateTime("UTC");
|
||||
expect(zonedDateTime.toLocaleString()).toBe("2021-11-03T01:33:05.1002003+00:00[UTC]");
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.ZonedDateTime object", () => {
|
||||
expect(() => {
|
||||
Temporal.ZonedDateTime.prototype.toLocaleString.call("foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.ZonedDateTime");
|
||||
});
|
||||
});
|
|
@ -0,0 +1,123 @@
|
|||
describe("correct behavior", () => {
|
||||
test("length is 0", () => {
|
||||
expect(Temporal.ZonedDateTime.prototype.toString).toHaveLength(0);
|
||||
});
|
||||
|
||||
test("basic functionality", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 11, 3, 1, 33, 5, 100, 200, 300);
|
||||
const zonedDateTime = plainDateTime.toZonedDateTime("UTC");
|
||||
expect(zonedDateTime.toString()).toBe("2021-11-03T01:33:05.1002003+00:00[UTC]");
|
||||
});
|
||||
|
||||
test("negative epoch nanoseconds", () => {
|
||||
const zonedDateTime = new Temporal.ZonedDateTime(-999_999_999n, "UTC");
|
||||
expect(zonedDateTime.toString()).toBe("1969-12-31T23:59:59.000000001+00:00[UTC]");
|
||||
});
|
||||
|
||||
test("fractionalSecondDigits option", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 11, 3, 1, 33, 5, 100, 200, 300);
|
||||
const zonedDateTime = plainDateTime.toZonedDateTime("UTC");
|
||||
const values = [
|
||||
["auto", "2021-11-03T01:33:05.1002003+00:00[UTC]"],
|
||||
[0, "2021-11-03T01:33:05+00:00[UTC]"],
|
||||
[1, "2021-11-03T01:33:05.1+00:00[UTC]"],
|
||||
[2, "2021-11-03T01:33:05.10+00:00[UTC]"],
|
||||
[3, "2021-11-03T01:33:05.100+00:00[UTC]"],
|
||||
[4, "2021-11-03T01:33:05.1002+00:00[UTC]"],
|
||||
[5, "2021-11-03T01:33:05.10020+00:00[UTC]"],
|
||||
[6, "2021-11-03T01:33:05.100200+00:00[UTC]"],
|
||||
[7, "2021-11-03T01:33:05.1002003+00:00[UTC]"],
|
||||
[8, "2021-11-03T01:33:05.10020030+00:00[UTC]"],
|
||||
[9, "2021-11-03T01:33:05.100200300+00:00[UTC]"],
|
||||
];
|
||||
|
||||
for (const [fractionalSecondDigits, expected] of values) {
|
||||
const options = { fractionalSecondDigits };
|
||||
expect(zonedDateTime.toString(options)).toBe(expected);
|
||||
}
|
||||
|
||||
// Ignored when smallestUnit is given
|
||||
expect(zonedDateTime.toString({ smallestUnit: "minute", fractionalSecondDigits: 9 })).toBe(
|
||||
"2021-11-03T01:33+00:00[UTC]"
|
||||
);
|
||||
});
|
||||
|
||||
test("smallestUnit option", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 11, 3, 1, 33, 5, 100, 200, 300);
|
||||
const zonedDateTime = plainDateTime.toZonedDateTime("UTC");
|
||||
const values = [
|
||||
["minute", "2021-11-03T01:33+00:00[UTC]"],
|
||||
["second", "2021-11-03T01:33:05+00:00[UTC]"],
|
||||
["millisecond", "2021-11-03T01:33:05.100+00:00[UTC]"],
|
||||
["microsecond", "2021-11-03T01:33:05.100200+00:00[UTC]"],
|
||||
["nanosecond", "2021-11-03T01:33:05.100200300+00:00[UTC]"],
|
||||
];
|
||||
|
||||
for (const [smallestUnit, expected] of values) {
|
||||
const singularOptions = { smallestUnit };
|
||||
const pluralOptions = { smallestUnit: `${smallestUnit}s` };
|
||||
expect(zonedDateTime.toString(singularOptions)).toBe(expected);
|
||||
expect(zonedDateTime.toString(pluralOptions)).toBe(expected);
|
||||
}
|
||||
});
|
||||
|
||||
test("timeZoneName option", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 11, 3, 1, 33, 5, 100, 200, 300);
|
||||
const zonedDateTime = plainDateTime.toZonedDateTime("UTC");
|
||||
const values = [
|
||||
["auto", "2021-11-03T01:33:05.1002003+00:00[UTC]"],
|
||||
["never", "2021-11-03T01:33:05.1002003+00:00"],
|
||||
["critical", "2021-11-03T01:33:05.1002003+00:00[!UTC]"],
|
||||
];
|
||||
|
||||
for (const [timeZoneName, expected] of values) {
|
||||
const options = { timeZoneName };
|
||||
expect(zonedDateTime.toString(options)).toBe(expected);
|
||||
}
|
||||
});
|
||||
|
||||
test("offset option", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2021, 11, 3, 1, 33, 5, 100, 200, 300);
|
||||
const zonedDateTime = plainDateTime.toZonedDateTime("UTC");
|
||||
const values = [
|
||||
["auto", "2021-11-03T01:33:05.1002003+00:00[UTC]"],
|
||||
["never", "2021-11-03T01:33:05.1002003[UTC]"],
|
||||
];
|
||||
|
||||
for (const [offset, expected] of values) {
|
||||
const options = { offset };
|
||||
expect(zonedDateTime.toString(options)).toBe(expected);
|
||||
}
|
||||
});
|
||||
|
||||
test("calendarName option", () => {
|
||||
const plainDateTime = new Temporal.PlainDateTime(2022, 11, 2, 19, 4, 35, 100, 200, 300);
|
||||
const zonedDateTime = plainDateTime.toZonedDateTime("UTC");
|
||||
const values = [
|
||||
["auto", "2022-11-02T19:04:35.1002003+00:00[UTC]"],
|
||||
["always", "2022-11-02T19:04:35.1002003+00:00[UTC][u-ca=iso8601]"],
|
||||
["never", "2022-11-02T19:04:35.1002003+00:00[UTC]"],
|
||||
["critical", "2022-11-02T19:04:35.1002003+00:00[UTC][!u-ca=iso8601]"],
|
||||
];
|
||||
|
||||
for (const [calendarName, expected] of values) {
|
||||
const options = { calendarName };
|
||||
expect(zonedDateTime.toString(options)).toBe(expected);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors", () => {
|
||||
test("this value must be a Temporal.ZonedDateTime object", () => {
|
||||
expect(() => {
|
||||
Temporal.ZonedDateTime.prototype.toString.call("foo");
|
||||
}).toThrowWithMessage(TypeError, "Not an object of type Temporal.ZonedDateTime");
|
||||
});
|
||||
|
||||
test("calendarName option must be one of 'auto', 'always', 'never', 'critical'", () => {
|
||||
const zonedDateTime = new Temporal.ZonedDateTime(0n, "UTC");
|
||||
expect(() => {
|
||||
zonedDateTime.toString({ calendarName: "foo" });
|
||||
}).toThrowWithMessage(RangeError, "foo is not a valid value for option calendarName");
|
||||
});
|
||||
});
|
Loading…
Add table
Reference in a new issue