PlainDateTime.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Runtime/AbstractOperations.h>
  7. #include <LibJS/Runtime/Date.h>
  8. #include <LibJS/Runtime/GlobalObject.h>
  9. #include <LibJS/Runtime/Temporal/PlainDate.h>
  10. #include <LibJS/Runtime/Temporal/PlainDateTime.h>
  11. #include <LibJS/Runtime/Temporal/PlainDateTimeConstructor.h>
  12. #include <LibJS/Runtime/Temporal/PlainTime.h>
  13. namespace JS::Temporal {
  14. // 5 Temporal.PlainDateTime Objects, https://tc39.es/proposal-temporal/#sec-temporal-plaindatetime-objects
  15. 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)
  16. : Object(prototype)
  17. , m_iso_year(iso_year)
  18. , m_iso_month(iso_month)
  19. , m_iso_day(iso_day)
  20. , m_iso_hour(iso_hour)
  21. , m_iso_minute(iso_minute)
  22. , m_iso_second(iso_second)
  23. , m_iso_millisecond(iso_millisecond)
  24. , m_iso_microsecond(iso_microsecond)
  25. , m_iso_nanosecond(iso_nanosecond)
  26. , m_calendar(calendar)
  27. {
  28. }
  29. void PlainDateTime::visit_edges(Visitor& visitor)
  30. {
  31. visitor.visit(&m_calendar);
  32. }
  33. // 5.5.1 GetEpochFromISOParts ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond ), https://tc39.es/proposal-temporal/#sec-temporal-getepochfromisoparts
  34. 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)
  35. {
  36. auto& vm = global_object.vm();
  37. // 1. Assert: year, month, day, hour, minute, second, millisecond, microsecond, and nanosecond are integers.
  38. // 2. Assert: ! IsValidISODate(year, month, day) is true.
  39. VERIFY(is_valid_iso_date(year, month, day));
  40. // 3. Assert: ! IsValidTime(hour, minute, second, millisecond, microsecond, nanosecond) is true.
  41. VERIFY(is_valid_time(hour, minute, second, millisecond, microsecond, nanosecond));
  42. // 4. Let date be ! MakeDay(𝔽(year), 𝔽(month − 1), 𝔽(day)).
  43. auto date = make_day(global_object, Value(year), Value(month - 1), Value(day));
  44. // 5. Let time be ! MakeTime(𝔽(hour), 𝔽(minute), 𝔽(second), 𝔽(millisecond)).
  45. auto time = make_time(global_object, Value(hour), Value(minute), Value(second), Value(millisecond));
  46. // 6. Let ms be ! MakeDate(date, time).
  47. auto ms = make_date(date, time);
  48. // 7. Assert: ms is finite.
  49. VERIFY(ms.is_finite_number());
  50. // 8. Return ℝ(ms) × 10^6 + microsecond × 10^3 + nanosecond.
  51. return js_bigint(vm.heap(), Crypto::SignedBigInteger::create_from(static_cast<i64>(ms.as_double())).multiplied_by(Crypto::UnsignedBigInteger { 1'000'000 }).plus(Crypto::SignedBigInteger::create_from((i64)microsecond * 1000)).plus(Crypto::SignedBigInteger(nanosecond)));
  52. }
  53. // -864 * 10^19 - 864 * 10^14
  54. const auto DATETIME_NANOSECONDS_MIN = "-8640086400000000000000"_sbigint;
  55. // +864 * 10^19 + 864 * 10^14
  56. const auto DATETIME_NANOSECONDS_MAX = "8640086400000000000000"_sbigint;
  57. // 5.5.2 ISODateTimeWithinLimits ( year, month, day, hour, minute, second, millisecond, microsecond, nanosecond ), https://tc39.es/proposal-temporal/#sec-temporal-isodatetimewithinlimits
  58. 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)
  59. {
  60. // 1. Assert: year, month, day, hour, minute, second, millisecond, microsecond, and nanosecond are integers.
  61. // 2. Let ns be ! GetEpochFromISOParts(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond).
  62. auto ns = get_epoch_from_iso_parts(global_object, year, month, day, hour, minute, second, millisecond, microsecond, nanosecond);
  63. // 3. If ns ≤ -8.64 × 10^21 - 8.64 × 10^16, then
  64. if (ns->big_integer() <= DATETIME_NANOSECONDS_MIN) {
  65. // a. Return false.
  66. return false;
  67. }
  68. // 4. If ns ≥ 8.64 × 10^21 + 8.64 × 10^16, then
  69. if (ns->big_integer() >= DATETIME_NANOSECONDS_MAX) {
  70. // a. Return false.
  71. return false;
  72. }
  73. // 5. Return true.
  74. return true;
  75. }
  76. // 5.5.6 CreateTemporalDateTime ( isoYear, isoMonth, isoDay, hour, minute, second, millisecond, microsecond, nanosecond, calendar [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporaldatetime
  77. 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)
  78. {
  79. auto& vm = global_object.vm();
  80. // 1. Assert: isoYear, isoMonth, isoDay, hour, minute, second, millisecond, microsecond, and nanosecond are integers.
  81. // 2. Assert: Type(calendar) is Object.
  82. // 3. If ! IsValidISODate(isoYear, isoMonth, isoDay) is false, throw a RangeError exception.
  83. if (!is_valid_iso_date(iso_year, iso_month, iso_day)) {
  84. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDateTime);
  85. return {};
  86. }
  87. // 4. If ! IsValidTime(hour, minute, second, millisecond, microsecond, nanosecond) is false, throw a RangeError exception.
  88. if (!is_valid_time(hour, minute, second, millisecond, microsecond, nanosecond)) {
  89. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDateTime);
  90. return {};
  91. }
  92. // 5. If ! ISODateTimeWithinLimits(isoYear, isoMonth, isoDay, hour, minute, second, millisecond, microsecond, nanosecond) is false, then
  93. if (!iso_date_time_within_limits(global_object, iso_year, iso_month, iso_day, hour, minute, second, millisecond, microsecond, nanosecond)) {
  94. // a. Throw a RangeError exception.
  95. vm.throw_exception<RangeError>(global_object, ErrorType::TemporalInvalidPlainDateTime);
  96. return {};
  97. }
  98. // 6. If newTarget is not present, set it to %Temporal.PlainDateTime%.
  99. if (!new_target)
  100. new_target = global_object.temporal_plain_date_time_constructor();
  101. // 7. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.PlainDateTime.prototype%", « [[InitializedTemporalDateTime]], [[ISOYear]], [[ISOMonth]], [[ISODay]], [[ISOHour]], [[ISOMinute]], [[ISOSecond]], [[ISOMillisecond]], [[ISOMicrosecond]], [[ISONanosecond]], [[Calendar]] »).
  102. // 8. Set object.[[ISOYear]] to isoYear.
  103. // 9. Set object.[[ISOMonth]] to isoMonth.
  104. // 10. Set object.[[ISODay]] to isoDay.
  105. // 11. Set object.[[ISOHour]] to hour.
  106. // 12. Set object.[[ISOMinute]] to minute.
  107. // 13. Set object.[[ISOSecond]] to second.
  108. // 14. Set object.[[ISOMillisecond]] to millisecond.
  109. // 15. Set object.[[ISOMicrosecond]] to microsecond.
  110. // 16. Set object.[[ISONanosecond]] to nanosecond.
  111. // 17. Set object.[[Calendar]] to calendar.
  112. auto* object = ordinary_create_from_constructor<PlainDateTime>(global_object, *new_target, &GlobalObject::temporal_plain_date_prototype, iso_year, iso_month, iso_day, hour, minute, second, millisecond, microsecond, nanosecond, calendar);
  113. if (vm.exception())
  114. return {};
  115. // 18. Return object.
  116. return object;
  117. }
  118. }