/* * Copyright (c) 2021, Idan Horowitz * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include namespace JS::Temporal { // 5 Temporal.PlainDateTime Objects, https://tc39.es/proposal-temporal/#sec-temporal-plaindatetime-objects PlainDateTime::PlainDateTime(i32 iso_year, u8 iso_month, u8 iso_day, u8 iso_hour, u8 iso_minute, u8 iso_second, u8 iso_millisecond, u8 iso_microsecond, u8 iso_nanosecond, Object& calendar, Object& prototype) : Object(prototype) , m_iso_year(iso_year) , m_iso_month(iso_month) , m_iso_day(iso_day) , m_iso_hour(iso_hour) , m_iso_minute(iso_minute) , m_iso_second(iso_second) , m_iso_millisecond(iso_millisecond) , m_iso_microsecond(iso_microsecond) , m_iso_nanosecond(iso_nanosecond) , m_calendar(calendar) { } void PlainDateTime::visit_edges(Visitor& visitor) { visitor.visit(&m_calendar); } // 5.5.1 GetEpochFromISOParts ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond ), https://tc39.es/proposal-temporal/#sec-temporal-getepochfromisoparts BigInt* get_epoch_from_iso_parts(GlobalObject& global_object, i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond) { auto& vm = global_object.vm(); // 1. Assert: year, month, day, hour, minute, second, millisecond, microsecond, and nanosecond are integers. // 2. Assert: ! IsValidISODate(year, month, day) is true. VERIFY(is_valid_iso_date(year, month, day)); // 3. Assert: ! IsValidTime(hour, minute, second, millisecond, microsecond, nanosecond) is true. VERIFY(is_valid_time(hour, minute, second, millisecond, microsecond, nanosecond)); // 4. Let date be ! MakeDay(๐”ฝ(year), ๐”ฝ(month โˆ’ 1), ๐”ฝ(day)). auto date = make_day(global_object, Value(year), Value(month - 1), Value(day)); // 5. Let time be ! MakeTime(๐”ฝ(hour), ๐”ฝ(minute), ๐”ฝ(second), ๐”ฝ(millisecond)). auto time = make_time(global_object, Value(hour), Value(minute), Value(second), Value(millisecond)); // 6. Let ms be ! MakeDate(date, time). auto ms = make_date(date, time); // 7. Assert: ms is finite. VERIFY(ms.is_finite_number()); // 8. Return โ„(ms) ร— 10^6 + microsecond ร— 10^3 + nanosecond. return js_bigint(vm.heap(), Crypto::SignedBigInteger::create_from(static_cast(ms.as_double())).multiplied_by(Crypto::UnsignedBigInteger { 1'000'000 }).plus(Crypto::SignedBigInteger::create_from((i64)microsecond * 1000)).plus(Crypto::SignedBigInteger(nanosecond))); } // -864 * 10^19 - 864 * 10^14 const auto DATETIME_NANOSECONDS_MIN = "-8640086400000000000000"_sbigint; // +864 * 10^19 + 864 * 10^14 const auto DATETIME_NANOSECONDS_MAX = "8640086400000000000000"_sbigint; // 5.5.2 ISODateTimeWithinLimits ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond ), https://tc39.es/proposal-temporal/#sec-temporal-isodatetimewithinlimits bool iso_date_time_within_limits(GlobalObject& global_object, i32 year, u8 month, u8 day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond) { // 1. Assert: year, month, day, hour, minute, second, millisecond, microsecond, and nanosecond are integers. // 2. Let ns be ! GetEpochFromISOParts(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond). auto ns = get_epoch_from_iso_parts(global_object, year, month, day, hour, minute, second, millisecond, microsecond, nanosecond); // 3. If ns โ‰ค -8.64 ร— 10^21 - 8.64 ร— 10^16, then if (ns->big_integer() <= DATETIME_NANOSECONDS_MIN) { // a. Return false. return false; } // 4. If ns โ‰ฅ 8.64 ร— 10^21 + 8.64 ร— 10^16, then if (ns->big_integer() >= DATETIME_NANOSECONDS_MAX) { // a. Return false. return false; } // 5. Return true. return true; } // 5.5.6 CreateTemporalDateTime ( isoYear, isoMonth, isoDay, hour, minute, second, millisecond, microsecond, nanosecond, calendar [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporaldatetime PlainDateTime* create_temporal_date_time(GlobalObject& global_object, i32 iso_year, u8 iso_month, u8 iso_day, u8 hour, u8 minute, u8 second, u16 millisecond, u16 microsecond, u16 nanosecond, Object& calendar, FunctionObject* new_target) { auto& vm = global_object.vm(); // 1. Assert: isoYear, isoMonth, isoDay, hour, minute, second, millisecond, microsecond, and nanosecond are integers. // 2. Assert: Type(calendar) is Object. // 3. If ! IsValidISODate(isoYear, isoMonth, isoDay) is false, throw a RangeError exception. if (!is_valid_iso_date(iso_year, iso_month, iso_day)) { vm.throw_exception(global_object, ErrorType::TemporalInvalidPlainDateTime); return {}; } // 4. If ! IsValidTime(hour, minute, second, millisecond, microsecond, nanosecond) is false, throw a RangeError exception. if (!is_valid_time(hour, minute, second, millisecond, microsecond, nanosecond)) { vm.throw_exception(global_object, ErrorType::TemporalInvalidPlainDateTime); return {}; } // 5. If ! ISODateTimeWithinLimits(isoYear, isoMonth, isoDay, hour, minute, second, millisecond, microsecond, nanosecond) is false, then if (!iso_date_time_within_limits(global_object, iso_year, iso_month, iso_day, hour, minute, second, millisecond, microsecond, nanosecond)) { // a. Throw a RangeError exception. vm.throw_exception(global_object, ErrorType::TemporalInvalidPlainDateTime); return {}; } // 6. If newTarget is not present, set it to %Temporal.PlainDateTime%. if (!new_target) new_target = global_object.temporal_plain_date_time_constructor(); // 7. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.PlainDateTime.prototype%", ยซ [[InitializedTemporalDateTime]], [[ISOYear]], [[ISOMonth]], [[ISODay]], [[ISOHour]], [[ISOMinute]], [[ISOSecond]], [[ISOMillisecond]], [[ISOMicrosecond]], [[ISONanosecond]], [[Calendar]] ยป). // 8. Set object.[[ISOYear]] to isoYear. // 9. Set object.[[ISOMonth]] to isoMonth. // 10. Set object.[[ISODay]] to isoDay. // 11. Set object.[[ISOHour]] to hour. // 12. Set object.[[ISOMinute]] to minute. // 13. Set object.[[ISOSecond]] to second. // 14. Set object.[[ISOMillisecond]] to millisecond. // 15. Set object.[[ISOMicrosecond]] to microsecond. // 16. Set object.[[ISONanosecond]] to nanosecond. // 17. Set object.[[Calendar]] to calendar. auto* object = ordinary_create_from_constructor(global_object, *new_target, &GlobalObject::temporal_plain_date_prototype, iso_year, iso_month, iso_day, hour, minute, second, millisecond, microsecond, nanosecond, calendar); if (vm.exception()) return {}; // 18. Return object. return object; } }