Duration.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /*
  2. * Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
  3. * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
  4. * Copyright (c) 2024, Shannon Booth <shannon@serenityos.org>
  5. * Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
  6. *
  7. * SPDX-License-Identifier: BSD-2-Clause
  8. */
  9. #include <AK/Math.h>
  10. #include <AK/NumericLimits.h>
  11. #include <LibJS/Runtime/AbstractOperations.h>
  12. #include <LibJS/Runtime/Intrinsics.h>
  13. #include <LibJS/Runtime/Realm.h>
  14. #include <LibJS/Runtime/Temporal/Duration.h>
  15. #include <LibJS/Runtime/Temporal/DurationConstructor.h>
  16. #include <LibJS/Runtime/Temporal/Instant.h>
  17. #include <LibJS/Runtime/VM.h>
  18. #include <LibJS/Runtime/ValueInlines.h>
  19. #include <math.h>
  20. namespace JS::Temporal {
  21. GC_DEFINE_ALLOCATOR(Duration);
  22. // 7 Temporal.Duration Objects, https://tc39.es/proposal-temporal/#sec-temporal-duration-objects
  23. Duration::Duration(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, Object& prototype)
  24. : Object(ConstructWithPrototypeTag::Tag, prototype)
  25. , m_years(years)
  26. , m_months(months)
  27. , m_weeks(weeks)
  28. , m_days(days)
  29. , m_hours(hours)
  30. , m_minutes(minutes)
  31. , m_seconds(seconds)
  32. , m_milliseconds(milliseconds)
  33. , m_microseconds(microseconds)
  34. , m_nanoseconds(nanoseconds)
  35. {
  36. auto fields = AK::Array {
  37. &Duration::m_years,
  38. &Duration::m_months,
  39. &Duration::m_weeks,
  40. &Duration::m_days,
  41. &Duration::m_hours,
  42. &Duration::m_minutes,
  43. &Duration::m_seconds,
  44. &Duration::m_milliseconds,
  45. &Duration::m_microseconds,
  46. &Duration::m_nanoseconds,
  47. };
  48. // NOTE: The spec stores these fields as mathematical values. VERIFY() that we have finite, integral values in them,
  49. // and normalize any negative zeros caused by floating point math. This is usually done using ℝ(𝔽(value)) at
  50. // the call site.
  51. for (auto const& field : fields) {
  52. auto& value = this->*field;
  53. VERIFY(isfinite(value));
  54. // FIXME: test-js contains a small number of cases where a Temporal.Duration is constructed with a non-integral
  55. // double. Eliminate these and VERIFY(trunc(value) == value) instead.
  56. if (trunc(value) != value)
  57. value = trunc(value);
  58. else if (bit_cast<u64>(value) == NEGATIVE_ZERO_BITS)
  59. value = 0;
  60. }
  61. }
  62. // maxTimeDuration = 2**53 × 10**9 - 1 = 9,007,199,254,740,991,999,999,999
  63. TimeDuration const MAX_TIME_DURATION = "9007199254740991999999999"_sbigint;
  64. // 7.5.4 ZeroDateDuration ( ), https://tc39.es/proposal-temporal/#sec-temporal-zerodateduration
  65. DateDuration zero_date_duration(VM& vm)
  66. {
  67. // 1. Return ! CreateDateDurationRecord(0, 0, 0, 0).
  68. return MUST(create_date_duration_record(vm, 0, 0, 0, 0));
  69. }
  70. // 7.5.5 ToInternalDurationRecord ( duration ), https://tc39.es/proposal-temporal/#sec-temporal-tointernaldurationrecord
  71. InternalDuration to_internal_duration_record(VM& vm, Duration const& duration)
  72. {
  73. // 1. Let dateDuration be ! CreateDateDurationRecord(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]]).
  74. auto date_duration = MUST(create_date_duration_record(vm, duration.years(), duration.months(), duration.weeks(), duration.days()));
  75. // 2. Let timeDuration be TimeDurationFromComponents(duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]]).
  76. auto time_duration = time_duration_from_components(duration.hours(), duration.minutes(), duration.seconds(), duration.milliseconds(), duration.microseconds(), duration.nanoseconds());
  77. // 3. Return ! CombineDateAndTimeDuration(dateDuration, timeDuration).
  78. return MUST(combine_date_and_time_duration(vm, date_duration, move(time_duration)));
  79. }
  80. // 7.5.9 CreateDateDurationRecord ( years, months, weeks, days ), https://tc39.es/proposal-temporal/#sec-temporal-createdatedurationrecord
  81. ThrowCompletionOr<DateDuration> create_date_duration_record(VM& vm, double years, double months, double weeks, double days)
  82. {
  83. // 1. If IsValidDuration(years, months, weeks, days, 0, 0, 0, 0, 0, 0) is false, throw a RangeError exception.
  84. if (!is_valid_duration(years, months, weeks, days, 0, 0, 0, 0, 0, 0))
  85. return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidDuration);
  86. // 2. Return Date Duration Record { [[Years]]: ℝ(𝔽(years)), [[Months]]: ℝ(𝔽(months)), [[Weeks]]: ℝ(𝔽(weeks)), [[Days]]: ℝ(𝔽(days)) }.
  87. return DateDuration { years, months, weeks, days };
  88. }
  89. // 7.5.11 CombineDateAndTimeDuration ( dateDuration, timeDuration ), https://tc39.es/proposal-temporal/#sec-temporal-combinedateandtimeduration
  90. ThrowCompletionOr<InternalDuration> combine_date_and_time_duration(VM& vm, DateDuration date_duration, TimeDuration time_duration)
  91. {
  92. // 1. Let dateSign be DateDurationSign(dateDuration).
  93. auto date_sign = date_duration_sign(date_duration);
  94. // 2. Let timeSign be TimeDurationSign(timeDuration).
  95. auto time_sign = time_duration_sign(time_duration);
  96. // 3. If dateSign ≠ 0 and timeSign ≠ 0 and dateSign ≠ timeSign, throw a RangeError exception.
  97. if (date_sign != 0 && time_sign != 0 && date_sign != time_sign)
  98. return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidDuration);
  99. // 4. Return Internal Duration Record { [[Date]]: dateDuration, [[Time]]: timeDuration }.
  100. return InternalDuration { date_duration, move(time_duration) };
  101. }
  102. // 7.5.12 ToTemporalDuration ( item ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalduration
  103. ThrowCompletionOr<GC::Ref<Duration>> to_temporal_duration(VM& vm, Value item)
  104. {
  105. // 1. If item is an Object and item has an [[InitializedTemporalDuration]] internal slot, then
  106. if (item.is_object() && is<Duration>(item.as_object())) {
  107. auto const& duration = static_cast<Duration const&>(item.as_object());
  108. // a. Return ! CreateTemporalDuration(item.[[Years]], item.[[Months]], item.[[Weeks]], item.[[Days]], item.[[Hours]], item.[[Minutes]], item.[[Seconds]], item.[[Milliseconds]], item.[[Microseconds]], item.[[Nanoseconds]]).
  109. return MUST(create_temporal_duration(vm, duration.years(), duration.months(), duration.weeks(), duration.days(), duration.hours(), duration.minutes(), duration.seconds(), duration.milliseconds(), duration.microseconds(), duration.nanoseconds()));
  110. }
  111. // 2. If item is not an Object, then
  112. if (!item.is_object()) {
  113. // a. If item is not a String, throw a TypeError exception.
  114. if (!item.is_string())
  115. return vm.throw_completion<TypeError>(ErrorType::NotAString, item);
  116. // b. Return ? ParseTemporalDurationString(item).
  117. return TRY(parse_temporal_duration_string(vm, item.as_string().utf8_string_view()));
  118. }
  119. // 3. Let result be a new Partial Duration Record with each field set to 0.
  120. auto result = PartialDuration::zero();
  121. // 4. Let partial be ? ToTemporalPartialDurationRecord(item).
  122. auto partial = TRY(to_temporal_partial_duration_record(vm, item));
  123. // 5. If partial.[[Years]] is not undefined, set result.[[Years]] to partial.[[Years]].
  124. if (partial.years.has_value())
  125. result.years = *partial.years;
  126. // 6. If partial.[[Months]] is not undefined, set result.[[Months]] to partial.[[Months]].
  127. if (partial.months.has_value())
  128. result.months = *partial.months;
  129. // 7. If partial.[[Weeks]] is not undefined, set result.[[Weeks]] to partial.[[Weeks]].
  130. if (partial.weeks.has_value())
  131. result.weeks = *partial.weeks;
  132. // 8. If partial.[[Days]] is not undefined, set result.[[Days]] to partial.[[Days]].
  133. if (partial.days.has_value())
  134. result.days = *partial.days;
  135. // 9. If partial.[[Hours]] is not undefined, set result.[[Hours]] to partial.[[Hours]].
  136. if (partial.hours.has_value())
  137. result.hours = *partial.hours;
  138. // 10. If partial.[[Minutes]] is not undefined, set result.[[Minutes]] to partial.[[Minutes]].
  139. if (partial.minutes.has_value())
  140. result.minutes = *partial.minutes;
  141. // 11. If partial.[[Seconds]] is not undefined, set result.[[Seconds]] to partial.[[Seconds]].
  142. if (partial.seconds.has_value())
  143. result.seconds = *partial.seconds;
  144. // 12. If partial.[[Milliseconds]] is not undefined, set result.[[Milliseconds]] to partial.[[Milliseconds]].
  145. if (partial.milliseconds.has_value())
  146. result.milliseconds = *partial.milliseconds;
  147. // 13. If partial.[[Microseconds]] is not undefined, set result.[[Microseconds]] to partial.[[Microseconds]].
  148. if (partial.microseconds.has_value())
  149. result.microseconds = *partial.microseconds;
  150. // 14. If partial.[[Nanoseconds]] is not undefined, set result.[[Nanoseconds]] to partial.[[Nanoseconds]].
  151. if (partial.nanoseconds.has_value())
  152. result.nanoseconds = *partial.nanoseconds;
  153. // 15. Return ? CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]).
  154. return TRY(create_temporal_duration(vm, *result.years, *result.months, *result.weeks, *result.days, *result.hours, *result.minutes, *result.seconds, *result.milliseconds, *result.microseconds, *result.nanoseconds));
  155. }
  156. // 7.5.13 DurationSign ( duration ), https://tc39.es/proposal-temporal/#sec-temporal-durationsign
  157. i8 duration_sign(Duration const& duration)
  158. {
  159. // 1. For each value v of « duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]] », do
  160. for (auto value : { duration.years(), duration.months(), duration.weeks(), duration.days(), duration.hours(), duration.minutes(), duration.seconds(), duration.milliseconds(), duration.microseconds(), duration.nanoseconds() }) {
  161. // a. If v < 0, return -1.
  162. if (value < 0)
  163. return -1;
  164. // b. If v > 0, return 1.
  165. if (value > 0)
  166. return 1;
  167. }
  168. // 2. Return 0.
  169. return 0;
  170. }
  171. // 7.5.14 DateDurationSign ( dateDuration ), https://tc39.es/proposal-temporal/#sec-temporal-datedurationsign
  172. i8 date_duration_sign(DateDuration const& date_duration)
  173. {
  174. // 1. For each value v of « dateDuration.[[Years]], dateDuration.[[Months]], dateDuration.[[Weeks]], dateDuration.[[Days]] », do
  175. for (auto value : { date_duration.years, date_duration.months, date_duration.weeks, date_duration.days }) {
  176. // a. If v < 0, return -1.
  177. if (value < 0)
  178. return -1;
  179. // b. If v > 0, return 1.
  180. if (value > 0)
  181. return 1;
  182. }
  183. // 2. Return 0.
  184. return 0;
  185. }
  186. // 7.5.16 IsValidDuration ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-isvalidduration
  187. bool is_valid_duration(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds)
  188. {
  189. // 1. Let sign be 0.
  190. auto sign = 0;
  191. // 2. For each value v of « years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds », do
  192. for (auto value : { years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds }) {
  193. // a. If 𝔽(v) is not finite, return false.
  194. if (!isfinite(value))
  195. return false;
  196. // b. If v < 0, then
  197. if (value < 0) {
  198. // i. If sign > 0, return false.
  199. if (sign > 0)
  200. return false;
  201. // ii. Set sign to -1.
  202. sign = -1;
  203. }
  204. // c. Else if v > 0, then
  205. else if (value > 0) {
  206. // i. If sign < 0, return false.
  207. if (sign < 0)
  208. return false;
  209. // ii. Set sign to 1.
  210. sign = 1;
  211. }
  212. }
  213. // 3. If abs(years) ≥ 2**32, return false.
  214. if (AK::fabs(years) > NumericLimits<u32>::max())
  215. return false;
  216. // 4. If abs(months) ≥ 2**32, return false.
  217. if (AK::fabs(months) > NumericLimits<u32>::max())
  218. return false;
  219. // 5. If abs(weeks) ≥ 2**32, return false.
  220. if (AK::fabs(weeks) > NumericLimits<u32>::max())
  221. return false;
  222. // 6. Let totalFractionalSeconds be days × 86,400 + hours × 3600 + minutes × 60 + seconds + ℝ(𝔽(milliseconds)) × 10**-3 + ℝ(𝔽(microseconds)) × 10**-6 + ℝ(𝔽(nanoseconds)) × 10**-9.
  223. // 7. NOTE: The above step cannot be implemented directly using floating-point arithmetic. Multiplying by 10**-3,
  224. // 10**-6, and 10**-9 respectively may be imprecise when milliseconds, microseconds, or nanoseconds is an
  225. // unsafe integer. This multiplication can be implemented in C++ with an implementation of std::remquo()
  226. // with sufficient bits in the quotient. String manipulation will also give an exact result, since the
  227. // multiplication is by a power of 10.
  228. auto total_fractional_seconds = TimeDuration { days }.multiplied_by(NANOSECONDS_PER_DAY);
  229. total_fractional_seconds = total_fractional_seconds.plus(TimeDuration { hours }.multiplied_by(NANOSECONDS_PER_HOUR));
  230. total_fractional_seconds = total_fractional_seconds.plus(TimeDuration { minutes }.multiplied_by(NANOSECONDS_PER_MINUTE));
  231. total_fractional_seconds = total_fractional_seconds.plus(TimeDuration { seconds }.multiplied_by(NANOSECONDS_PER_SECOND));
  232. total_fractional_seconds = total_fractional_seconds.plus(TimeDuration { milliseconds }.multiplied_by(NANOSECONDS_PER_MILLISECOND));
  233. total_fractional_seconds = total_fractional_seconds.plus(TimeDuration { microseconds }.multiplied_by(NANOSECONDS_PER_MICROSECOND));
  234. total_fractional_seconds = total_fractional_seconds.plus(TimeDuration { nanoseconds });
  235. // 8. If abs(totalFractionalSeconds) ≥ 2**53, return false.
  236. if (total_fractional_seconds.unsigned_value() > MAX_TIME_DURATION.unsigned_value())
  237. return false;
  238. // 9. Return true.
  239. return true;
  240. }
  241. // 7.5.17 DefaultTemporalLargestUnit ( duration ), https://tc39.es/proposal-temporal/#sec-temporal-defaulttemporallargestunit
  242. Unit default_temporal_largest_unit(Duration const& duration)
  243. {
  244. // 1. If duration.[[Years]] ≠ 0, return YEAR.
  245. if (duration.years() != 0)
  246. return Unit::Year;
  247. // 2. If duration.[[Months]] ≠ 0, return MONTH.
  248. if (duration.months() != 0)
  249. return Unit::Month;
  250. // 3. If duration.[[Weeks]] ≠ 0, return WEEK.
  251. if (duration.weeks() != 0)
  252. return Unit::Week;
  253. // 4. If duration.[[Days]] ≠ 0, return DAY.
  254. if (duration.days() != 0)
  255. return Unit::Day;
  256. // 5. If duration.[[Hours]] ≠ 0, return HOUR.
  257. if (duration.hours() != 0)
  258. return Unit::Hour;
  259. // 6. If duration.[[Minutes]] ≠ 0, return MINUTE.
  260. if (duration.minutes() != 0)
  261. return Unit::Minute;
  262. // 7. If duration.[[Seconds]] ≠ 0, return SECOND.
  263. if (duration.seconds() != 0)
  264. return Unit::Second;
  265. // 8. If duration.[[Milliseconds]] ≠ 0, return MILLISECOND.
  266. if (duration.milliseconds() != 0)
  267. return Unit::Millisecond;
  268. // 9. If duration.[[Microseconds]] ≠ 0, return MICROSECOND.
  269. if (duration.microseconds() != 0)
  270. return Unit::Microsecond;
  271. // 10. Return NANOSECOND.
  272. return Unit::Nanosecond;
  273. }
  274. // 7.5.18 ToTemporalPartialDurationRecord ( temporalDurationLike ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalpartialdurationrecord
  275. ThrowCompletionOr<PartialDuration> to_temporal_partial_duration_record(VM& vm, Value temporal_duration_like)
  276. {
  277. // 1. If temporalDurationLike is not an Object, then
  278. if (!temporal_duration_like.is_object()) {
  279. // a. Throw a TypeError exception.
  280. return vm.throw_completion<TypeError>(ErrorType::NotAnObject, temporal_duration_like);
  281. }
  282. // 2. Let result be a new partial Duration Record with each field set to undefined.
  283. PartialDuration result {};
  284. // 3. NOTE: The following steps read properties and perform independent validation in alphabetical order.
  285. auto to_integral_if_defined = [&vm, &temporal_duration = temporal_duration_like.as_object()](auto const& property, auto& field) -> ThrowCompletionOr<void> {
  286. if (auto value = TRY(temporal_duration.get(property)); !value.is_undefined())
  287. field = TRY(to_integer_if_integral(vm, value, ErrorType::TemporalInvalidDurationPropertyValueNonIntegral, property, value));
  288. return {};
  289. };
  290. // 4. Let days be ? Get(temporalDurationLike, "days").
  291. // 5. If days is not undefined, set result.[[Days]] to ? ToIntegerIfIntegral(days).
  292. TRY(to_integral_if_defined(vm.names.days, result.days));
  293. // 6. Let hours be ? Get(temporalDurationLike, "hours").
  294. // 7. If hours is not undefined, set result.[[Hours]] to ? ToIntegerIfIntegral(hours).
  295. TRY(to_integral_if_defined(vm.names.hours, result.hours));
  296. // 8. Let microseconds be ? Get(temporalDurationLike, "microseconds").
  297. // 9. If microseconds is not undefined, set result.[[Microseconds]] to ? ToIntegerIfIntegral(microseconds).
  298. TRY(to_integral_if_defined(vm.names.microseconds, result.microseconds));
  299. // 10. Let milliseconds be ? Get(temporalDurationLike, "milliseconds").
  300. // 11. If milliseconds is not undefined, set result.[[Milliseconds]] to ? ToIntegerIfIntegral(milliseconds).
  301. TRY(to_integral_if_defined(vm.names.milliseconds, result.milliseconds));
  302. // 12. Let minutes be ? Get(temporalDurationLike, "minutes").
  303. // 13. If minutes is not undefined, set result.[[Minutes]] to ? ToIntegerIfIntegral(minutes).
  304. TRY(to_integral_if_defined(vm.names.minutes, result.minutes));
  305. // 14. Let months be ? Get(temporalDurationLike, "months").
  306. // 15. If months is not undefined, set result.[[Months]] to ? ToIntegerIfIntegral(months).
  307. TRY(to_integral_if_defined(vm.names.months, result.months));
  308. // 16. Let nanoseconds be ? Get(temporalDurationLike, "nanoseconds").
  309. // 17. If nanoseconds is not undefined, set result.[[Nanoseconds]] to ? ToIntegerIfIntegral(nanoseconds).
  310. TRY(to_integral_if_defined(vm.names.nanoseconds, result.nanoseconds));
  311. // 18. Let seconds be ? Get(temporalDurationLike, "seconds").
  312. // 19. If seconds is not undefined, set result.[[Seconds]] to ? ToIntegerIfIntegral(seconds).
  313. TRY(to_integral_if_defined(vm.names.seconds, result.seconds));
  314. // 20. Let weeks be ? Get(temporalDurationLike, "weeks").
  315. // 21. If weeks is not undefined, set result.[[Weeks]] to ? ToIntegerIfIntegral(weeks).
  316. TRY(to_integral_if_defined(vm.names.weeks, result.weeks));
  317. // 22. Let years be ? Get(temporalDurationLike, "years").
  318. // 23. If years is not undefined, set result.[[Years]] to ? ToIntegerIfIntegral(years).
  319. TRY(to_integral_if_defined(vm.names.years, result.years));
  320. // 24. If years is undefined, and months is undefined, and weeks is undefined, and days is undefined, and hours is
  321. // undefined, and minutes is undefined, and seconds is undefined, and milliseconds is undefined, and microseconds
  322. // is undefined, and nanoseconds is undefined, throw a TypeError exception.
  323. if (!result.any_field_defined())
  324. return vm.throw_completion<TypeError>(ErrorType::TemporalInvalidDurationLikeObject);
  325. // 25. Return result.
  326. return result;
  327. }
  328. // 7.5.19 CreateTemporalDuration ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporalduration
  329. ThrowCompletionOr<GC::Ref<Duration>> create_temporal_duration(VM& vm, double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, GC::Ptr<FunctionObject> new_target)
  330. {
  331. auto& realm = *vm.current_realm();
  332. // 1. If IsValidDuration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds) is false, throw a RangeError exception.
  333. if (!is_valid_duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds))
  334. return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidDuration);
  335. // 2. If newTarget is not present, set newTarget to %Temporal.Duration%.
  336. if (!new_target)
  337. new_target = realm.intrinsics().temporal_duration_constructor();
  338. // 3. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.Duration.prototype%", « [[InitializedTemporalDuration]], [[Years]], [[Months]], [[Weeks]], [[Days]], [[Hours]], [[Minutes]], [[Seconds]], [[Milliseconds]], [[Microseconds]], [[Nanoseconds]] »).
  339. // 4. Set object.[[Years]] to ℝ(𝔽(years)).
  340. // 5. Set object.[[Months]] to ℝ(𝔽(months)).
  341. // 6. Set object.[[Weeks]] to ℝ(𝔽(weeks)).
  342. // 7. Set object.[[Days]] to ℝ(𝔽(days)).
  343. // 8. Set object.[[Hours]] to ℝ(𝔽(hours)).
  344. // 9. Set object.[[Minutes]] to ℝ(𝔽(minutes)).
  345. // 10. Set object.[[Seconds]] to ℝ(𝔽(seconds)).
  346. // 11. Set object.[[Milliseconds]] to ℝ(𝔽(milliseconds)).
  347. // 12. Set object.[[Microseconds]] to ℝ(𝔽(microseconds)).
  348. // 13. Set object.[[Nanoseconds]] to ℝ(𝔽(nanoseconds)).
  349. auto object = TRY(ordinary_create_from_constructor<Duration>(vm, *new_target, &Intrinsics::temporal_duration_prototype, years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds));
  350. // 14. Return object.
  351. return object;
  352. }
  353. // 7.5.21 TimeDurationFromComponents ( hours, minutes, seconds, milliseconds, microseconds, nanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-timedurationfromcomponents
  354. TimeDuration time_duration_from_components(double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds)
  355. {
  356. // 1. Set minutes to minutes + hours × 60.
  357. auto total_minutes = TimeDuration { minutes }.plus(TimeDuration { hours }.multiplied_by(60_bigint));
  358. // 2. Set seconds to seconds + minutes × 60.
  359. auto total_seconds = TimeDuration { seconds }.plus(total_minutes.multiplied_by(60_bigint));
  360. // 3. Set milliseconds to milliseconds + seconds × 1000.
  361. auto total_milliseconds = TimeDuration { milliseconds }.plus(total_seconds.multiplied_by(1000_bigint));
  362. // 4. Set microseconds to microseconds + milliseconds × 1000.
  363. auto total_microseconds = TimeDuration { microseconds }.plus(total_milliseconds.multiplied_by(1000_bigint));
  364. // 5. Set nanoseconds to nanoseconds + microseconds × 1000.
  365. auto total_nanoseconds = TimeDuration { nanoseconds }.plus(total_microseconds.multiplied_by(1000_bigint));
  366. // 6. Assert: abs(nanoseconds) ≤ maxTimeDuration.
  367. VERIFY(total_nanoseconds.unsigned_value() <= MAX_TIME_DURATION.unsigned_value());
  368. // 7. Return nanoseconds.
  369. return total_nanoseconds;
  370. }
  371. // 7.5.23 Add24HourDaysToTimeDuration ( d, days ), https://tc39.es/proposal-temporal/#sec-temporal-add24hourdaystonormalizedtimeduration
  372. ThrowCompletionOr<TimeDuration> add_24_hour_days_to_time_duration(VM& vm, TimeDuration const& time_duration, double days)
  373. {
  374. // 1. Let result be d + days × nsPerDay.
  375. auto result = time_duration.plus(TimeDuration { days }.multiplied_by(NANOSECONDS_PER_DAY));
  376. // 2. If abs(result) > maxTimeDuration, throw a RangeError exception.
  377. if (result.unsigned_value() > MAX_TIME_DURATION.unsigned_value())
  378. return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidDuration);
  379. // 3. Return result.
  380. return result;
  381. }
  382. // 7.5.25 CompareTimeDuration ( one, two ), https://tc39.es/proposal-temporal/#sec-temporal-comparetimeduration
  383. i8 compare_time_duration(TimeDuration const& one, TimeDuration const& two)
  384. {
  385. // 1. If one > two, return 1.
  386. if (one > two)
  387. return 1;
  388. // 2. If one < two, return -1.
  389. if (one < two)
  390. return -1;
  391. // 3. Return 0.
  392. return 0;
  393. }
  394. // 7.5.28 TimeDurationSign ( d ), https://tc39.es/proposal-temporal/#sec-temporal-timedurationsign
  395. i8 time_duration_sign(TimeDuration const& time_duration)
  396. {
  397. // 1. If d < 0, return -1.
  398. if (time_duration.is_negative())
  399. return -1;
  400. // 2. If d > 0, return 1.
  401. if (time_duration.is_positive())
  402. return 1;
  403. // 3. Return 0.
  404. return 0;
  405. }
  406. }