Duration.cpp 94 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833
  1. /*
  2. * Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
  3. * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/StringBuilder.h>
  8. #include <LibJS/Runtime/AbstractOperations.h>
  9. #include <LibJS/Runtime/Completion.h>
  10. #include <LibJS/Runtime/GlobalObject.h>
  11. #include <LibJS/Runtime/Object.h>
  12. #include <LibJS/Runtime/Temporal/AbstractOperations.h>
  13. #include <LibJS/Runtime/Temporal/Calendar.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/Temporal/PlainDate.h>
  18. #include <LibJS/Runtime/Temporal/TimeZone.h>
  19. #include <LibJS/Runtime/Temporal/ZonedDateTime.h>
  20. namespace JS::Temporal {
  21. // 7 Temporal.Duration Objects, https://tc39.es/proposal-temporal/#sec-temporal-duration-objects
  22. Duration::Duration(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, Object& prototype)
  23. : Object(prototype)
  24. , m_years(years)
  25. , m_months(months)
  26. , m_weeks(weeks)
  27. , m_days(days)
  28. , m_hours(hours)
  29. , m_minutes(minutes)
  30. , m_seconds(seconds)
  31. , m_milliseconds(milliseconds)
  32. , m_microseconds(microseconds)
  33. , m_nanoseconds(nanoseconds)
  34. {
  35. }
  36. // 7.5.5 ToTemporalDuration ( item ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalduration
  37. ThrowCompletionOr<Duration*> to_temporal_duration(GlobalObject& global_object, Value item)
  38. {
  39. DurationRecord result;
  40. // 1. If Type(item) is Object, then
  41. if (item.is_object()) {
  42. // a. If item has an [[InitializedTemporalDuration]] internal slot, then
  43. if (is<Duration>(item.as_object())) {
  44. // i. Return item.
  45. return &static_cast<Duration&>(item.as_object());
  46. }
  47. // b. Let result be ? ToTemporalDurationRecord(item).
  48. result = TRY(to_temporal_duration_record(global_object, item.as_object()));
  49. }
  50. // 2. Else,
  51. else {
  52. // a. Let string be ? ToString(item).
  53. auto string = TRY(item.to_string(global_object));
  54. // b. Let result be ? ParseTemporalDurationString(string).
  55. result = TRY(parse_temporal_duration_string(global_object, string));
  56. }
  57. // 3. Return ? CreateTemporalDuration(result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]).
  58. return create_temporal_duration(global_object, result.years, result.months, result.weeks, result.days, result.hours, result.minutes, result.seconds, result.milliseconds, result.microseconds, result.nanoseconds);
  59. }
  60. // 7.5.6 ToTemporalDurationRecord ( temporalDurationLike ), https://tc39.es/proposal-temporal/#sec-temporal-totemporaldurationrecord
  61. ThrowCompletionOr<DurationRecord> to_temporal_duration_record(GlobalObject& global_object, Object const& temporal_duration_like)
  62. {
  63. auto& vm = global_object.vm();
  64. // 1. If temporalDurationLike has an [[InitializedTemporalDuration]] internal slot, then
  65. if (is<Duration>(temporal_duration_like)) {
  66. auto& duration = static_cast<Duration const&>(temporal_duration_like);
  67. // a. Return the Record { [[Years]]: temporalDurationLike.[[Years]], [[Months]]: temporalDurationLike.[[Months]], [[Weeks]]: temporalDurationLike.[[Weeks]], [[Days]]: temporalDurationLike.[[Days]], [[Hours]]: temporalDurationLike.[[Hours]], [[Minutes]]: temporalDurationLike.[[Minutes]], [[Seconds]]: temporalDurationLike.[[Seconds]], [[Milliseconds]]: temporalDurationLike.[[Milliseconds]], [[Microseconds]]: temporalDurationLike.[[Microseconds]], [[Nanoseconds]]: temporalDurationLike.[[Nanoseconds]] }.
  68. return DurationRecord { .years = duration.years(), .months = duration.months(), .weeks = duration.weeks(), .days = duration.days(), .hours = duration.hours(), .minutes = duration.minutes(), .seconds = duration.seconds(), .milliseconds = duration.milliseconds(), .microseconds = duration.microseconds(), .nanoseconds = duration.nanoseconds() };
  69. }
  70. // 2. Let result be a new Duration Record.
  71. auto result = DurationRecord {};
  72. // 3. Let any be false.
  73. auto any = false;
  74. // 4. For each row of Table 7, except the header row, in table order, do
  75. for (auto& [field, property] : temporal_duration_like_properties<DurationRecord, double>(vm)) {
  76. // a. Let prop be the Property Name value of the current row.
  77. // b. Let val be ? Get(temporalDurationLike, prop).
  78. auto value = TRY(temporal_duration_like.get(property));
  79. // c. If val is undefined, then
  80. if (value.is_undefined()) {
  81. // i. Set result's field whose name is the Field Name value of the current row to 0.
  82. result.*field = 0;
  83. }
  84. // d. Else,
  85. else {
  86. // i. Set any to true.
  87. any = true;
  88. // ii. Let val be 𝔽(? ToIntegerWithoutRounding(val)).
  89. value = Value(TRY(to_integer_without_rounding(global_object, value, ErrorType::TemporalInvalidDurationPropertyValueNonIntegral, property.as_string(), value.to_string_without_side_effects())));
  90. // iii. Set result's field whose name is the Field Name value of the current row to val.
  91. result.*field = value.as_double();
  92. }
  93. }
  94. // 5. If any is false, then
  95. if (!any) {
  96. // a. Throw a TypeError exception.
  97. return vm.throw_completion<TypeError>(global_object, ErrorType::TemporalInvalidDurationLikeObject);
  98. }
  99. // 6. Return result.
  100. return result;
  101. }
  102. // 7.5.7 DurationSign ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-durationsign
  103. i8 duration_sign(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds)
  104. {
  105. // 1. For each value v of « years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds », do
  106. for (auto& v : { years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds }) {
  107. // a. If v < 0, return −1.
  108. if (v < 0)
  109. return -1;
  110. // b. If v > 0, return 1.
  111. if (v > 0)
  112. return 1;
  113. }
  114. // 2. Return 0.
  115. return 0;
  116. }
  117. // 7.5.8 IsValidDuration ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-isvalidduration
  118. bool is_valid_duration(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds)
  119. {
  120. // 1. Let sign be ! DurationSign(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
  121. auto sign = duration_sign(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds);
  122. // 2. For each value v of « years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds », do
  123. for (auto& v : { years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds }) {
  124. // a. If v is not finite, return false.
  125. if (!isfinite(v))
  126. return false;
  127. // b. If v < 0 and sign > 0, return false.
  128. if (v < 0 && sign > 0)
  129. return false;
  130. // c. If v > 0 and sign < 0, return false.
  131. if (v > 0 && sign < 0)
  132. return false;
  133. }
  134. // 3. Return true.
  135. return true;
  136. }
  137. // 7.5.9 DefaultTemporalLargestUnit ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds ), https://tc39.es/proposal-temporal/#sec-temporal-defaulttemporallargestunit
  138. StringView default_temporal_largest_unit(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds)
  139. {
  140. // 1. If years is not zero, return "year".
  141. if (years != 0)
  142. return "year"sv;
  143. // 2. If months is not zero, return "month".
  144. if (months != 0)
  145. return "month"sv;
  146. // 3. If weeks is not zero, return "week".
  147. if (weeks != 0)
  148. return "week"sv;
  149. // 4. If days is not zero, return "day".
  150. if (days != 0)
  151. return "day"sv;
  152. // 5. If hours is not zero, return "hour".
  153. if (hours != 0)
  154. return "hour"sv;
  155. // 6. If minutes is not zero, return "minute".
  156. if (minutes != 0)
  157. return "minute"sv;
  158. // 7. If seconds is not zero, return "second".
  159. if (seconds != 0)
  160. return "second"sv;
  161. // 8. If milliseconds is not zero, return "millisecond".
  162. if (milliseconds != 0)
  163. return "millisecond"sv;
  164. // 9. If microseconds is not zero, return "microsecond".
  165. if (microseconds != 0)
  166. return "microsecond"sv;
  167. // 10. Return "nanosecond".
  168. return "nanosecond"sv;
  169. }
  170. // 7.5.10 ToPartialDuration ( temporalDurationLike ), https://tc39.es/proposal-temporal/#sec-temporal-topartialduration
  171. ThrowCompletionOr<PartialDurationRecord> to_partial_duration(GlobalObject& global_object, Value temporal_duration_like)
  172. {
  173. auto& vm = global_object.vm();
  174. // 1. If Type(temporalDurationLike) is not Object, then
  175. if (!temporal_duration_like.is_object()) {
  176. // a. Throw a TypeError exception.
  177. return vm.throw_completion<TypeError>(global_object, ErrorType::NotAnObject, temporal_duration_like.to_string_without_side_effects());
  178. }
  179. // 2. Let result be a new partial Duration Record with each field set to undefined.
  180. auto result = PartialDurationRecord {};
  181. // 3. Let any be false.
  182. auto any = false;
  183. // 4. For each row of Table 7, except the header row, in table order, do
  184. for (auto& [field, property] : temporal_duration_like_properties<PartialDurationRecord, Optional<double>>(vm)) {
  185. // a. Let property be the Property Name value of the current row.
  186. // b. Let value be ? Get(temporalDurationLike, property).
  187. auto value = TRY(temporal_duration_like.as_object().get(property));
  188. // c. If value is not undefined, then
  189. if (!value.is_undefined()) {
  190. // i. Set any to true.
  191. any = true;
  192. // ii. Set value to 𝔽(? ToIntegerWithoutRounding(value)).
  193. value = Value(TRY(to_integer_without_rounding(global_object, value, ErrorType::TemporalInvalidDurationPropertyValueNonIntegral, property.as_string(), value.to_string_without_side_effects())));
  194. // iii. Set result's field whose name is the Field Name value of the current row to value.
  195. result.*field = value.as_double();
  196. }
  197. }
  198. // 5. If any is false, then
  199. if (!any) {
  200. // a. Throw a TypeError exception.
  201. return vm.throw_completion<TypeError>(global_object, ErrorType::TemporalInvalidDurationLikeObject);
  202. }
  203. // 6. Return result.
  204. return result;
  205. }
  206. // 7.5.11 CreateTemporalDuration ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporalduration
  207. ThrowCompletionOr<Duration*> create_temporal_duration(GlobalObject& global_object, double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, FunctionObject const* new_target)
  208. {
  209. auto& vm = global_object.vm();
  210. // 1. If ! IsValidDuration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds) is false, throw a RangeError exception.
  211. if (!is_valid_duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds))
  212. return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidDuration);
  213. // 2. If newTarget is not present, set it to %Temporal.Duration%.
  214. if (!new_target)
  215. new_target = global_object.temporal_duration_constructor();
  216. // 3. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.Duration.prototype%", « [[InitializedTemporalDuration]], [[Years]], [[Months]], [[Weeks]], [[Days]], [[Hours]], [[Minutes]], [[Seconds]], [[Milliseconds]], [[Microseconds]], [[Nanoseconds]] »).
  217. // 4. Set object.[[Years]] to years.
  218. // 5. Set object.[[Months]] to months.
  219. // 6. Set object.[[Weeks]] to weeks.
  220. // 7. Set object.[[Days]] to days.
  221. // 8. Set object.[[Hours]] to hours.
  222. // 9. Set object.[[Minutes]] to minutes.
  223. // 10. Set object.[[Seconds]] to seconds.
  224. // 11. Set object.[[Milliseconds]] to milliseconds.
  225. // 12. Set object.[[Microseconds]] to microseconds.
  226. // 13. Set object.[[Nanoseconds]] to nanoseconds.
  227. auto* object = TRY(ordinary_create_from_constructor<Duration>(global_object, *new_target, &GlobalObject::temporal_duration_prototype, years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds));
  228. // 14. Return object.
  229. return object;
  230. }
  231. // 7.5.12 CreateNegatedTemporalDuration ( duration ), https://tc39.es/proposal-temporal/#sec-temporal-createnegatedtemporalduration
  232. Duration* create_negated_temporal_duration(GlobalObject& global_object, Duration const& duration)
  233. {
  234. // 1. Return ! CreateTemporalDuration(−duration.[[Years]], −duration.[[Months]], −duration.[[Weeks]], −duration.[[Days]], −duration.[[Hours]], −duration.[[Minutes]], −duration.[[Seconds]], −duration.[[Milliseconds]], −duration.[[Microseconds]], −duration.[[Nanoseconds]]).
  235. return MUST(create_temporal_duration(global_object, -duration.years(), -duration.months(), -duration.weeks(), -duration.days(), -duration.hours(), -duration.minutes(), -duration.seconds(), -duration.milliseconds(), -duration.microseconds(), -duration.nanoseconds()));
  236. }
  237. // 7.5.13 CalculateOffsetShift ( relativeTo, y, mon, w, d, h, min, s, ms, mus, ns ), https://tc39.es/proposal-temporal/#sec-temporal-calculateoffsetshift
  238. ThrowCompletionOr<double> calculate_offset_shift(GlobalObject& global_object, Value relative_to_value, double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds)
  239. {
  240. // 1. If Type(relativeTo) is not Object or relativeTo does not have an [[InitializedTemporalZonedDateTime]] internal slot, return 0.
  241. if (!relative_to_value.is_object() || !is<ZonedDateTime>(relative_to_value.as_object()))
  242. return 0.0;
  243. auto& relative_to = static_cast<ZonedDateTime&>(relative_to_value.as_object());
  244. // 2. Let instant be ! CreateTemporalInstant(relativeTo.[[Nanoseconds]]).
  245. auto* instant = MUST(create_temporal_instant(global_object, relative_to.nanoseconds()));
  246. // 3. Let offsetBefore be ? GetOffsetNanosecondsFor(relativeTo.[[TimeZone]], instant).
  247. auto offset_before = TRY(get_offset_nanoseconds_for(global_object, &relative_to.time_zone(), *instant));
  248. // 4. Let after be ? AddZonedDateTime(relativeTo.[[Nanoseconds]], relativeTo.[[TimeZone]], relativeTo.[[Calendar]], y, mon, w, d, h, min, s, ms, mus, ns).
  249. auto* after = TRY(add_zoned_date_time(global_object, relative_to.nanoseconds(), &relative_to.time_zone(), relative_to.calendar(), years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds));
  250. // 5. Let instantAfter be ! CreateTemporalInstant(after).
  251. auto* instant_after = MUST(create_temporal_instant(global_object, *after));
  252. // 6. Let offsetAfter be ? GetOffsetNanosecondsFor(relativeTo.[[TimeZone]], instantAfter).
  253. auto offset_after = TRY(get_offset_nanoseconds_for(global_object, &relative_to.time_zone(), *instant_after));
  254. // 7. Return offsetAfter − offsetBefore.
  255. return offset_after - offset_before;
  256. }
  257. // 7.5.14 TotalDurationNanoseconds ( days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, offsetShift ), https://tc39.es/proposal-temporal/#sec-temporal-totaldurationnanoseconds
  258. BigInt* total_duration_nanoseconds(GlobalObject& global_object, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, BigInt const& nanoseconds, double offset_shift)
  259. {
  260. auto& vm = global_object.vm();
  261. VERIFY(offset_shift == trunc(offset_shift));
  262. // 1. Set nanoseconds to ℝ(nanoseconds).
  263. auto result_nanoseconds = nanoseconds.big_integer();
  264. // TODO: Add a way to create SignedBigIntegers from doubles with full precision and remove this restriction
  265. VERIFY(AK::is_within_range<i64>(days) && AK::is_within_range<i64>(hours) && AK::is_within_range<i64>(minutes) && AK::is_within_range<i64>(seconds) && AK::is_within_range<i64>(milliseconds) && AK::is_within_range<i64>(microseconds));
  266. // 2. If days ≠ 0, then
  267. if (days != 0) {
  268. // a. Set nanoseconds to nanoseconds − offsetShift.
  269. result_nanoseconds = result_nanoseconds.minus(Crypto::SignedBigInteger::create_from(offset_shift));
  270. }
  271. // 3. Set hours to ℝ(hours) + ℝ(days) × 24.
  272. auto total_hours = Crypto::SignedBigInteger::create_from(hours).plus(Crypto::SignedBigInteger::create_from(days).multiplied_by(Crypto::UnsignedBigInteger(24)));
  273. // 4. Set minutes to ℝ(minutes) + hours × 60.
  274. auto total_minutes = Crypto::SignedBigInteger::create_from(minutes).plus(total_hours.multiplied_by(Crypto::UnsignedBigInteger(60)));
  275. // 5. Set seconds to ℝ(seconds) + minutes × 60.
  276. auto total_seconds = Crypto::SignedBigInteger::create_from(seconds).plus(total_minutes.multiplied_by(Crypto::UnsignedBigInteger(60)));
  277. // 6. Set milliseconds to ℝ(milliseconds) + seconds × 1000.
  278. auto total_milliseconds = Crypto::SignedBigInteger::create_from(milliseconds).plus(total_seconds.multiplied_by(Crypto::UnsignedBigInteger(1000)));
  279. // 7. Set microseconds to ℝ(microseconds) + milliseconds × 1000.
  280. auto total_microseconds = Crypto::SignedBigInteger::create_from(microseconds).plus(total_milliseconds.multiplied_by(Crypto::UnsignedBigInteger(1000)));
  281. // 8. Return nanoseconds + microseconds × 1000.
  282. return js_bigint(vm, result_nanoseconds.plus(total_microseconds.multiplied_by(Crypto::UnsignedBigInteger(1000))));
  283. }
  284. // 7.5.15 BalanceDuration ( days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, largestUnit [ , relativeTo ] ), https://tc39.es/proposal-temporal/#sec-temporal-balanceduration
  285. ThrowCompletionOr<TimeDurationRecord> balance_duration(GlobalObject& global_object, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, BigInt const& nanoseconds, String const& largest_unit, Object* relative_to)
  286. {
  287. auto& vm = global_object.vm();
  288. // 1. If relativeTo is not present, set relativeTo to undefined.
  289. Crypto::SignedBigInteger total_nanoseconds;
  290. // 2. If Type(relativeTo) is Object and relativeTo has an [[InitializedTemporalZonedDateTime]] internal slot, then
  291. if (relative_to && is<ZonedDateTime>(*relative_to)) {
  292. auto& relative_to_zoned_date_time = static_cast<ZonedDateTime&>(*relative_to);
  293. // a. Let endNs be ? AddZonedDateTime(relativeTo.[[Nanoseconds]], relativeTo.[[TimeZone]], relativeTo.[[Calendar]], 0, 0, 0, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
  294. auto* end_ns = TRY(add_zoned_date_time(global_object, relative_to_zoned_date_time.nanoseconds(), &relative_to_zoned_date_time.time_zone(), relative_to_zoned_date_time.calendar(), 0, 0, 0, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds.big_integer().to_double()));
  295. // b. Set nanoseconds to endNs − relativeTo.[[Nanoseconds]].
  296. total_nanoseconds = end_ns->big_integer().minus(relative_to_zoned_date_time.nanoseconds().big_integer());
  297. }
  298. // 3. Else,
  299. else {
  300. // a. Set nanoseconds to ℤ(! TotalDurationNanoseconds(days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, 0)).
  301. total_nanoseconds = total_duration_nanoseconds(global_object, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, 0)->big_integer();
  302. }
  303. // 4. If largestUnit is one of "year", "month", "week", or "day", then
  304. if (largest_unit.is_one_of("year"sv, "month"sv, "week"sv, "day"sv)) {
  305. // a. Let result be ? NanosecondsToDays(nanoseconds, relativeTo).
  306. auto result = TRY(nanoseconds_to_days(global_object, *js_bigint(vm, total_nanoseconds), relative_to ?: js_undefined()));
  307. // b. Set days to result.[[Days]].
  308. days = result.days;
  309. // c. Set nanoseconds to result.[[Nanoseconds]].
  310. total_nanoseconds = result.nanoseconds->big_integer();
  311. }
  312. // 5. Else,
  313. else {
  314. // a. Set days to 0.
  315. days = 0;
  316. }
  317. // 6. Set hours, minutes, seconds, milliseconds, and microseconds to 0.
  318. hours = 0;
  319. minutes = 0;
  320. seconds = 0;
  321. milliseconds = 0;
  322. microseconds = 0;
  323. // 7. Set nanoseconds to ℝ(nanoseconds).
  324. double result_nanoseconds = total_nanoseconds.to_double();
  325. // 8. If nanoseconds < 0, let sign be −1; else, let sign be 1.
  326. i8 sign = total_nanoseconds.is_negative() ? -1 : 1;
  327. // 9. Set nanoseconds to abs(nanoseconds).
  328. total_nanoseconds = Crypto::SignedBigInteger(total_nanoseconds.unsigned_value());
  329. result_nanoseconds = fabs(result_nanoseconds);
  330. // 10. If largestUnit is "year", "month", "week", "day", or "hour", then
  331. if (largest_unit.is_one_of("year"sv, "month"sv, "week"sv, "day"sv, "hour"sv)) {
  332. // a. Set microseconds to floor(nanoseconds / 1000).
  333. auto nanoseconds_division_result = total_nanoseconds.divided_by(Crypto::UnsignedBigInteger(1000));
  334. // b. Set nanoseconds to nanoseconds modulo 1000.
  335. result_nanoseconds = nanoseconds_division_result.remainder.to_double();
  336. // c. Set milliseconds to floor(microseconds / 1000).
  337. auto microseconds_division_result = nanoseconds_division_result.quotient.divided_by(Crypto::UnsignedBigInteger(1000));
  338. // d. Set microseconds to microseconds modulo 1000.
  339. microseconds = microseconds_division_result.remainder.to_double();
  340. // e. Set seconds to floor(milliseconds / 1000).
  341. auto milliseconds_division_result = microseconds_division_result.quotient.divided_by(Crypto::UnsignedBigInteger(1000));
  342. // f. Set milliseconds to milliseconds modulo 1000.
  343. milliseconds = milliseconds_division_result.remainder.to_double();
  344. // g. Set minutes to floor(seconds / 60).
  345. auto seconds_division_result = milliseconds_division_result.quotient.divided_by(Crypto::UnsignedBigInteger(60));
  346. // h. Set seconds to seconds modulo 60.
  347. seconds = seconds_division_result.remainder.to_double();
  348. // i. Set hours to floor(minutes / 60).
  349. auto minutes_division_result = seconds_division_result.quotient.divided_by(Crypto::UnsignedBigInteger(60));
  350. hours = minutes_division_result.quotient.to_double();
  351. // j. Set minutes to minutes modulo 60.
  352. minutes = minutes_division_result.remainder.to_double();
  353. }
  354. // 11. Else if largestUnit is "minute", then
  355. else if (largest_unit == "minute"sv) {
  356. // a. Set microseconds to floor(nanoseconds / 1000).
  357. auto nanoseconds_division_result = total_nanoseconds.divided_by(Crypto::UnsignedBigInteger(1000));
  358. // b. Set nanoseconds to nanoseconds modulo 1000.
  359. result_nanoseconds = nanoseconds_division_result.remainder.to_double();
  360. // c. Set milliseconds to floor(microseconds / 1000).
  361. auto microseconds_division_result = nanoseconds_division_result.quotient.divided_by(Crypto::UnsignedBigInteger(1000));
  362. // d. Set microseconds to microseconds modulo 1000.
  363. microseconds = microseconds_division_result.remainder.to_double();
  364. // e. Set seconds to floor(milliseconds / 1000).
  365. auto milliseconds_division_result = microseconds_division_result.quotient.divided_by(Crypto::UnsignedBigInteger(1000));
  366. // f. Set milliseconds to milliseconds modulo 1000.
  367. milliseconds = milliseconds_division_result.remainder.to_double();
  368. // g. Set minutes to floor(seconds / 60).
  369. auto seconds_division_result = milliseconds_division_result.quotient.divided_by(Crypto::UnsignedBigInteger(60));
  370. minutes = seconds_division_result.quotient.to_double();
  371. // h. Set seconds to seconds modulo 60.
  372. seconds = seconds_division_result.remainder.to_double();
  373. }
  374. // 12. Else if largestUnit is "second", then
  375. else if (largest_unit == "second"sv) {
  376. // a. Set microseconds to floor(nanoseconds / 1000).
  377. auto nanoseconds_division_result = total_nanoseconds.divided_by(Crypto::UnsignedBigInteger(1000));
  378. // b. Set nanoseconds to nanoseconds modulo 1000.
  379. result_nanoseconds = nanoseconds_division_result.remainder.to_double();
  380. // c. Set milliseconds to floor(microseconds / 1000).
  381. auto microseconds_division_result = nanoseconds_division_result.quotient.divided_by(Crypto::UnsignedBigInteger(1000));
  382. // d. Set microseconds to microseconds modulo 1000.
  383. microseconds = microseconds_division_result.remainder.to_double();
  384. // e. Set seconds to floor(milliseconds / 1000).
  385. auto milliseconds_division_result = microseconds_division_result.quotient.divided_by(Crypto::UnsignedBigInteger(1000));
  386. seconds = milliseconds_division_result.quotient.to_double();
  387. // f. Set milliseconds to milliseconds modulo 1000.
  388. milliseconds = milliseconds_division_result.remainder.to_double();
  389. }
  390. // 13. Else if largestUnit is "millisecond", then
  391. else if (largest_unit == "millisecond"sv) {
  392. // a. Set microseconds to floor(nanoseconds / 1000).
  393. auto nanoseconds_division_result = total_nanoseconds.divided_by(Crypto::UnsignedBigInteger(1000));
  394. // b. Set nanoseconds to nanoseconds modulo 1000.
  395. result_nanoseconds = nanoseconds_division_result.remainder.to_double();
  396. // c. Set milliseconds to floor(microseconds / 1000).
  397. auto microseconds_division_result = nanoseconds_division_result.quotient.divided_by(Crypto::UnsignedBigInteger(1000));
  398. milliseconds = microseconds_division_result.quotient.to_double();
  399. // d. Set microseconds to microseconds modulo 1000.
  400. microseconds = microseconds_division_result.remainder.to_double();
  401. }
  402. // 14. Else if largestUnit is "microsecond", then
  403. else if (largest_unit == "microsecond"sv) {
  404. // a. Set microseconds to floor(nanoseconds / 1000).
  405. auto nanoseconds_division_result = total_nanoseconds.divided_by(Crypto::UnsignedBigInteger(1000));
  406. microseconds = nanoseconds_division_result.quotient.to_double();
  407. // b. Set nanoseconds to nanoseconds modulo 1000.
  408. result_nanoseconds = nanoseconds_division_result.remainder.to_double();
  409. }
  410. // 15. Else,
  411. else {
  412. // a. Assert: largestUnit is "nanosecond".
  413. VERIFY(largest_unit == "nanosecond"sv);
  414. }
  415. // 16. Return the Record { [[Days]]: 𝔽(days), [[Hours]]: 𝔽(hours × sign), [[Minutes]]: 𝔽(minutes × sign), [[Seconds]]: 𝔽(seconds × sign), [[Milliseconds]]: 𝔽(milliseconds × sign), [[Microseconds]]: 𝔽(microseconds × sign), [[Nanoseconds]]: 𝔽(nanoseconds × sign) }.
  416. return TimeDurationRecord { .days = days, .hours = hours * sign, .minutes = minutes * sign, .seconds = seconds * sign, .milliseconds = milliseconds * sign, .microseconds = microseconds * sign, .nanoseconds = result_nanoseconds * sign };
  417. }
  418. // 7.5.16 UnbalanceDurationRelative ( years, months, weeks, days, largestUnit, relativeTo ), https://tc39.es/proposal-temporal/#sec-temporal-unbalancedurationrelative
  419. ThrowCompletionOr<DateDurationRecord> unbalance_duration_relative(GlobalObject& global_object, double years, double months, double weeks, double days, String const& largest_unit, Value relative_to)
  420. {
  421. auto& vm = global_object.vm();
  422. // 1. If largestUnit is "year", or years, months, weeks, and days are all 0, then
  423. if (largest_unit == "year"sv || (years == 0 && months == 0 && weeks == 0 && days == 0)) {
  424. // a. Return the Record { [[Years]]: years, [[Months]]: months, [[Weeks]]: weeks, [[Days]]: days }.
  425. return DateDurationRecord { .years = years, .months = months, .weeks = weeks, .days = days };
  426. }
  427. // 2. Let sign be ! DurationSign(years, months, weeks, days, 0, 0, 0, 0, 0, 0).
  428. auto sign = duration_sign(years, months, weeks, days, 0, 0, 0, 0, 0, 0);
  429. // 3. Assert: sign ≠ 0.
  430. VERIFY(sign != 0);
  431. // 4. Let oneYear be ! CreateTemporalDuration(sign, 0, 0, 0, 0, 0, 0, 0, 0, 0).
  432. auto* one_year = MUST(create_temporal_duration(global_object, sign, 0, 0, 0, 0, 0, 0, 0, 0, 0));
  433. // 5. Let oneMonth be ! CreateTemporalDuration(0, sign, 0, 0, 0, 0, 0, 0, 0, 0).
  434. auto* one_month = MUST(create_temporal_duration(global_object, 0, sign, 0, 0, 0, 0, 0, 0, 0, 0));
  435. // 6. Let oneWeek be ! CreateTemporalDuration(0, 0, sign, 0, 0, 0, 0, 0, 0, 0).
  436. auto* one_week = MUST(create_temporal_duration(global_object, 0, 0, sign, 0, 0, 0, 0, 0, 0, 0));
  437. Object* calendar;
  438. // 7. If relativeTo is not undefined, then
  439. if (!relative_to.is_undefined()) {
  440. // a. Set relativeTo to ? ToTemporalDate(relativeTo).
  441. auto* relative_to_plain_date = TRY(to_temporal_date(global_object, relative_to));
  442. relative_to = relative_to_plain_date;
  443. // b. Let calendar be relativeTo.[[Calendar]].
  444. calendar = &relative_to_plain_date->calendar();
  445. }
  446. // 8. Else,
  447. else {
  448. // a. Let calendar be undefined.
  449. calendar = nullptr;
  450. }
  451. // 9. If largestUnit is "month", then
  452. if (largest_unit == "month"sv) {
  453. // a. If calendar is undefined, then
  454. if (!calendar) {
  455. // i. Throw a RangeError exception.
  456. return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalMissingStartingPoint, "months");
  457. }
  458. // b. Let dateAdd be ? GetMethod(calendar, "dateAdd").
  459. auto* date_add = TRY(Value(calendar).get_method(global_object, vm.names.dateAdd));
  460. // c. Let dateUntil be ? GetMethod(calendar, "dateUntil").
  461. auto* date_until = TRY(Value(calendar).get_method(global_object, vm.names.dateUntil));
  462. // d. Repeat, while years ≠ 0,
  463. while (years != 0) {
  464. // i. Let addOptions be ! OrdinaryObjectCreate(null).
  465. auto* add_options = Object::create(global_object, nullptr);
  466. // ii. Let newRelativeTo be ? CalendarDateAdd(calendar, relativeTo, oneYear, addOptions, dateAdd).
  467. auto* new_relative_to = TRY(calendar_date_add(global_object, *calendar, relative_to, *one_year, add_options, date_add));
  468. // iii. Let untilOptions be ! OrdinaryObjectCreate(null).
  469. auto* until_options = Object::create(global_object, nullptr);
  470. // iv. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit", "month").
  471. MUST(until_options->create_data_property_or_throw(vm.names.largestUnit, js_string(vm, "month"sv)));
  472. // v. Let untilResult be ? CalendarDateUntil(calendar, relativeTo, newRelativeTo, untilOptions, dateUntil).
  473. auto* until_result = TRY(calendar_date_until(global_object, *calendar, relative_to, new_relative_to, *until_options, date_until));
  474. // vi. Let oneYearMonths be untilResult.[[Months]].
  475. auto one_year_months = until_result->months();
  476. // vii. Set relativeTo to newRelativeTo.
  477. relative_to = new_relative_to;
  478. // viii. Set years to years − sign.
  479. years -= sign;
  480. // ix. Set months to months + oneYearMonths.
  481. months += one_year_months;
  482. }
  483. }
  484. // 10. Else if largestUnit is "week", then
  485. else if (largest_unit == "week"sv) {
  486. // a. If calendar is undefined, then
  487. if (!calendar) {
  488. // i. Throw a RangeError exception.
  489. return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalMissingStartingPoint, "weeks");
  490. }
  491. // b. Repeat, while years ≠ 0,
  492. while (years != 0) {
  493. // i. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneYear).
  494. auto move_result = TRY(move_relative_date(global_object, *calendar, verify_cast<PlainDate>(relative_to.as_object()), *one_year));
  495. // ii. Set relativeTo to moveResult.[[RelativeTo]].
  496. relative_to = move_result.relative_to.cell();
  497. // iii. Set days to days + moveResult.[[Days]].
  498. days += move_result.days;
  499. // iv. Set years to years − sign.
  500. years -= sign;
  501. }
  502. // c. Repeat, while months ≠ 0,
  503. while (months != 0) {
  504. // i. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneMonth).
  505. auto move_result = TRY(move_relative_date(global_object, *calendar, verify_cast<PlainDate>(relative_to.as_object()), *one_month));
  506. // ii. Set relativeTo to moveResult.[[RelativeTo]].
  507. relative_to = move_result.relative_to.cell();
  508. // iii. Set days to days + moveResult.[[Days]].
  509. days += move_result.days;
  510. // iv. Set months to months − sign.
  511. months -= sign;
  512. }
  513. }
  514. // 11. Else,
  515. else {
  516. // a. If any of years, months, and weeks are not zero, then
  517. if (years != 0 || months != 0 || weeks != 0) {
  518. // i. If calendar is undefined, then
  519. if (!calendar) {
  520. // i. Throw a RangeError exception.
  521. return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalMissingStartingPoint, "calendar units");
  522. }
  523. // ii. Repeat, while years ≠ 0,
  524. while (years != 0) {
  525. // 1. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneYear).
  526. auto move_result = TRY(move_relative_date(global_object, *calendar, verify_cast<PlainDate>(relative_to.as_object()), *one_year));
  527. // 2. Set relativeTo to moveResult.[[RelativeTo]].
  528. relative_to = move_result.relative_to.cell();
  529. // 3. Set days to days + moveResult.[[Days]].
  530. days += move_result.days;
  531. // 4. Set years to years − sign.
  532. years -= sign;
  533. }
  534. // iii. Repeat, while months ≠ 0,
  535. while (months != 0) {
  536. // 1. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneMonth).
  537. auto move_result = TRY(move_relative_date(global_object, *calendar, verify_cast<PlainDate>(relative_to.as_object()), *one_month));
  538. // 2. Set relativeTo to moveResult.[[RelativeTo]].
  539. relative_to = move_result.relative_to.cell();
  540. // 3. Set days to days +moveResult.[[Days]].
  541. days += move_result.days;
  542. // 4. Set months to months − sign.
  543. months -= sign;
  544. }
  545. // iv. Repeat, while weeks ≠ 0,
  546. while (weeks != 0) {
  547. // 1. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneWeek).
  548. auto move_result = TRY(move_relative_date(global_object, *calendar, verify_cast<PlainDate>(relative_to.as_object()), *one_week));
  549. // 2. Set relativeTo to moveResult.[[RelativeTo]].
  550. relative_to = move_result.relative_to.cell();
  551. // 3. Set days to days + moveResult.[[Days]].
  552. days += move_result.days;
  553. // 4. Set weeks to weeks − sign.
  554. weeks -= sign;
  555. }
  556. }
  557. }
  558. // 12. Return the Record { [[Years]]: years, [[Months]]: months, [[Weeks]]: weeks, [[Days]]: days }.
  559. return DateDurationRecord { .years = years, .months = months, .weeks = weeks, .days = days };
  560. }
  561. // 7.5.17 BalanceDurationRelative ( years, months, weeks, days, largestUnit, relativeTo ), https://tc39.es/proposal-temporal/#sec-temporal-balancedurationrelative
  562. ThrowCompletionOr<DateDurationRecord> balance_duration_relative(GlobalObject& global_object, double years, double months, double weeks, double days, String const& largest_unit, Value relative_to_value)
  563. {
  564. auto& vm = global_object.vm();
  565. // 1. If largestUnit is not one of "year", "month", or "week", or years, months, weeks, and days are all 0, then
  566. if (!largest_unit.is_one_of("year"sv, "month"sv, "week"sv) || (years == 0 && months == 0 && weeks == 0 && days == 0)) {
  567. // a. Return the Record { [[Years]]: years, [[Months]]: months, [[Weeks]]: weeks, [[Days]]: days }.
  568. return DateDurationRecord { .years = years, .months = months, .weeks = weeks, .days = days };
  569. }
  570. // 2. Let sign be ! DurationSign(years, months, weeks, days, 0, 0, 0, 0, 0, 0).
  571. auto sign = duration_sign(years, months, weeks, days, 0, 0, 0, 0, 0, 0);
  572. // 3. Assert: sign ≠ 0.
  573. VERIFY(sign != 0);
  574. // 4. Let oneYear be ! CreateTemporalDuration(sign, 0, 0, 0, 0, 0, 0, 0, 0, 0).
  575. auto* one_year = MUST(create_temporal_duration(global_object, sign, 0, 0, 0, 0, 0, 0, 0, 0, 0));
  576. // 5. Let oneMonth be ! CreateTemporalDuration(0, sign, 0, 0, 0, 0, 0, 0, 0, 0).
  577. auto* one_month = MUST(create_temporal_duration(global_object, 0, sign, 0, 0, 0, 0, 0, 0, 0, 0));
  578. // 6. Let oneWeek be ! CreateTemporalDuration(0, 0, sign, 0, 0, 0, 0, 0, 0, 0).
  579. auto* one_week = MUST(create_temporal_duration(global_object, 0, 0, sign, 0, 0, 0, 0, 0, 0, 0));
  580. // 7. Set relativeTo to ? ToTemporalDate(relativeTo).
  581. auto* relative_to = TRY(to_temporal_date(global_object, relative_to_value));
  582. // 8. Let calendar be relativeTo.[[Calendar]].
  583. auto& calendar = relative_to->calendar();
  584. // 9. If largestUnit is "year", then
  585. if (largest_unit == "year"sv) {
  586. // a. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneYear).
  587. auto move_result = TRY(move_relative_date(global_object, calendar, *relative_to, *one_year));
  588. // b. Set relativeTo to moveResult.[[RelativeTo]].
  589. relative_to = move_result.relative_to.cell();
  590. // c. Let oneYearDays be moveResult.[[Days]].
  591. auto one_year_days = move_result.days;
  592. // d. Repeat, while abs(days) ≥ abs(oneYearDays),
  593. while (fabs(days) >= fabs(one_year_days)) {
  594. // i. Set days to days − oneYearDays.
  595. days -= one_year_days;
  596. // ii. Set years to years + sign.
  597. years += sign;
  598. // iii. Set moveResult to ? MoveRelativeDate(calendar, relativeTo, oneYear).
  599. move_result = TRY(move_relative_date(global_object, calendar, *relative_to, *one_year));
  600. // iv. Set relativeTo to moveResult.[[RelativeTo]].
  601. relative_to = move_result.relative_to.cell();
  602. // v. Set oneYearDays to moveResult.[[Days]].
  603. one_year_days = move_result.days;
  604. }
  605. // e. Set moveResult to ? MoveRelativeDate(calendar, relativeTo, oneMonth).
  606. move_result = TRY(move_relative_date(global_object, calendar, *relative_to, *one_month));
  607. // f. Set relativeTo to moveResult.[[RelativeTo]].
  608. relative_to = move_result.relative_to.cell();
  609. // g. Let oneMonthDays be moveResult.[[Days]].
  610. auto one_month_days = move_result.days;
  611. // h. Repeat, while abs(days) ≥ abs(oneMonthDays),
  612. while (fabs(days) >= fabs(one_month_days)) {
  613. // i. Set days to days − oneMonthDays.
  614. days -= one_month_days;
  615. // ii. Set months to months + sign.
  616. months += sign;
  617. // iii. Set moveResult to ? MoveRelativeDate(calendar, relativeTo, oneMonth).
  618. move_result = TRY(move_relative_date(global_object, calendar, *relative_to, *one_month));
  619. // iv. Set relativeTo to moveResult.[[RelativeTo]].
  620. relative_to = move_result.relative_to.cell();
  621. // v. Set oneMonthDays to moveResult.[[Days]].
  622. one_month_days = move_result.days;
  623. }
  624. // i. Let dateAdd be ? GetMethod(calendar, "dateAdd").
  625. auto* date_add = TRY(Value(&calendar).get_method(global_object, vm.names.dateAdd));
  626. // j. Let addOptions be ! OrdinaryObjectCreate(null).
  627. auto* add_options = Object::create(global_object, nullptr);
  628. // k. Let newRelativeTo be ? CalendarDateAdd(calendar, relativeTo, oneYear, addOptions, dateAdd).
  629. auto* new_relative_to = TRY(calendar_date_add(global_object, calendar, relative_to, *one_year, add_options, date_add));
  630. // l. Let dateUntil be ? GetMethod(calendar, "dateUntil").
  631. auto* date_until = TRY(Value(&calendar).get_method(global_object, vm.names.dateUntil));
  632. // m. Let untilOptions be ! OrdinaryObjectCreate(null).
  633. auto* until_options = Object::create(global_object, nullptr);
  634. // n. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit", "month").
  635. MUST(until_options->create_data_property_or_throw(vm.names.largestUnit, js_string(vm, "month"sv)));
  636. // o. Let untilResult be ? CalendarDateUntil(calendar, relativeTo, newRelativeTo, untilOptions, dateUntil).
  637. auto* until_result = TRY(calendar_date_until(global_object, calendar, relative_to, new_relative_to, *until_options, date_until));
  638. // p. Let oneYearMonths be untilResult.[[Months]].
  639. auto one_year_months = until_result->months();
  640. // q. Repeat, while abs(months) ≥ abs(oneYearMonths),
  641. while (fabs(months) >= fabs(one_year_months)) {
  642. // i. Set months to months − oneYearMonths.
  643. months -= one_year_months;
  644. // ii. Set years to years + sign.
  645. years += sign;
  646. // iii. Set relativeTo to newRelativeTo.
  647. relative_to = new_relative_to;
  648. // iv. Set addOptions to ! OrdinaryObjectCreate(null).
  649. add_options = Object::create(global_object, nullptr);
  650. // v. Set newRelativeTo to ? CalendarDateAdd(calendar, relativeTo, oneYear, addOptions, dateAdd).
  651. new_relative_to = TRY(calendar_date_add(global_object, calendar, relative_to, *one_year, add_options, date_add));
  652. // vi. Set untilOptions to ! OrdinaryObjectCreate(null).
  653. until_options = Object::create(global_object, nullptr);
  654. // vii. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit", "month").
  655. MUST(until_options->create_data_property_or_throw(vm.names.largestUnit, js_string(vm, "month"sv)));
  656. // viii. Set untilResult to ? CalendarDateUntil(calendar, relativeTo, newRelativeTo, untilOptions, dateUntil).
  657. until_result = TRY(calendar_date_until(global_object, calendar, relative_to, new_relative_to, *until_options, date_until));
  658. // ix. Set oneYearMonths to untilResult.[[Months]].
  659. one_year_months = until_result->months();
  660. }
  661. }
  662. // 10. Else if largestUnit is "month", then
  663. else if (largest_unit == "month"sv) {
  664. // a. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneMonth).
  665. auto move_result = TRY(move_relative_date(global_object, calendar, *relative_to, *one_month));
  666. // b. Set relativeTo to moveResult.[[RelativeTo]].
  667. relative_to = move_result.relative_to.cell();
  668. // c. Let oneMonthDays be moveResult.[[Days]].
  669. auto one_month_days = move_result.days;
  670. // d. Repeat, while abs(days) ≥ abs(oneMonthDays),
  671. while (fabs(days) >= fabs(one_month_days)) {
  672. // i. Set days to days − oneMonthDays.
  673. days -= one_month_days;
  674. // ii. Set months to months + sign.
  675. months += sign;
  676. // iii. Set moveResult to ? MoveRelativeDate(calendar, relativeTo, oneMonth).
  677. move_result = TRY(move_relative_date(global_object, calendar, *relative_to, *one_month));
  678. // iv. Set relativeTo to moveResult.[[RelativeTo]].
  679. relative_to = move_result.relative_to.cell();
  680. // v. Set oneMonthDays to moveResult.[[Days]].
  681. one_month_days = move_result.days;
  682. }
  683. }
  684. // 11. Else,
  685. else {
  686. // a. Assert: largestUnit is "week".
  687. VERIFY(largest_unit == "week"sv);
  688. // b. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneWeek).
  689. auto move_result = TRY(move_relative_date(global_object, calendar, *relative_to, *one_week));
  690. // c. Set relativeTo to moveResult.[[RelativeTo]].
  691. relative_to = move_result.relative_to.cell();
  692. // d. Let oneWeekDays be moveResult.[[Days]].
  693. auto one_week_days = move_result.days;
  694. // e. Repeat, while abs(days) ≥ abs(oneWeekDays),
  695. while (fabs(days) >= fabs(one_week_days)) {
  696. // i. Set days to days − oneWeekDays.
  697. days -= one_week_days;
  698. // ii. Set weeks to weeks + sign.
  699. weeks += sign;
  700. // iii. Set moveResult to ? MoveRelativeDate(calendar, relativeTo, oneWeek).
  701. move_result = TRY(move_relative_date(global_object, calendar, *relative_to, *one_week));
  702. // iv. Set relativeTo to moveResult.[[RelativeTo]].
  703. relative_to = move_result.relative_to.cell();
  704. // v. Set oneWeekDays to moveResult.[[Days]].
  705. one_week_days = move_result.days;
  706. }
  707. }
  708. // 12. Return the Record { [[Years]]: years, [[Months]]: months, [[Weeks]]: weeks, [[Days]]: days }.
  709. return DateDurationRecord { .years = years, .months = months, .weeks = weeks, .days = days };
  710. }
  711. // 7.5.18 AddDuration ( y1, mon1, w1, d1, h1, min1, s1, ms1, mus1, ns1, y2, mon2, w2, d2, h2, min2, s2, ms2, mus2, ns2, relativeTo ), https://tc39.es/proposal-temporal/#sec-temporal-addduration
  712. ThrowCompletionOr<DurationRecord> add_duration(GlobalObject& global_object, double years1, double months1, double weeks1, double days1, double hours1, double minutes1, double seconds1, double milliseconds1, double microseconds1, double nanoseconds1, double years2, double months2, double weeks2, double days2, double hours2, double minutes2, double seconds2, double milliseconds2, double microseconds2, double nanoseconds2, Value relative_to_value)
  713. {
  714. auto& vm = global_object.vm();
  715. VERIFY(all_of(AK::Array { years1, months1, weeks1, days1, hours1, minutes1, seconds1, milliseconds1, microseconds1, nanoseconds1, years2, months2, weeks2, days2, hours2, minutes2, seconds2, milliseconds2, microseconds2, nanoseconds2 }, [](auto value) { return value == trunc(value); }));
  716. // 1. Let largestUnit1 be ! DefaultTemporalLargestUnit(y1, mon1, w1, d1, h1, min1, s1, ms1, mus1).
  717. auto largest_unit1 = default_temporal_largest_unit(years1, months1, weeks1, days1, hours1, minutes1, seconds1, milliseconds1, microseconds1);
  718. // 2. Let largestUnit2 be ! DefaultTemporalLargestUnit(y2, mon2, w2, d2, h2, min2, s2, ms2, mus2).
  719. auto largest_unit2 = default_temporal_largest_unit(years2, months2, weeks2, days2, hours2, minutes2, seconds2, milliseconds2, microseconds2);
  720. // 3. Let largestUnit be ! LargerOfTwoTemporalUnits(largestUnit1, largestUnit2).
  721. auto largest_unit = larger_of_two_temporal_units(largest_unit1, largest_unit2);
  722. double years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds;
  723. // 4. If relativeTo is undefined, then
  724. if (relative_to_value.is_undefined()) {
  725. // a. If largestUnit is one of "year", "month", or "week", then
  726. if (largest_unit.is_one_of("year"sv, "month"sv, "week"sv)) {
  727. // i. Throw a RangeError exception.
  728. return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalMissingStartingPoint, "year, month or week");
  729. }
  730. // b. Let result be ! BalanceDuration(d1 + d2, h1 + h2, min1 + min2, s1 + s2, ms1 + ms2, mus1 + mus2, ns1 + ns2, largestUnit).
  731. // FIXME: Narrowing conversion from 'double' to 'i64'
  732. auto* added_nanoseconds_bigint = js_bigint(vm, Crypto::SignedBigInteger::create_from(nanoseconds1 + nanoseconds2));
  733. auto result = MUST(balance_duration(global_object, days1 + days2, hours1 + hours2, minutes1 + minutes2, seconds1 + seconds2, milliseconds1 + milliseconds2, microseconds1 + microseconds2, *added_nanoseconds_bigint, largest_unit));
  734. // c. Let years be 0.
  735. years = 0;
  736. // d. Let months be 0.
  737. months = 0;
  738. // e. Let weeks be 0.
  739. weeks = 0;
  740. // f. Let days be result.[[Days]].
  741. days = result.days;
  742. // g. Let hours be result.[[Hours]].
  743. hours = result.hours;
  744. // h. Let minutes be result.[[Minutes]].
  745. minutes = result.minutes;
  746. // i. Let seconds be result.[[Seconds]].
  747. seconds = result.seconds;
  748. // j. Let milliseconds be result.[[Milliseconds]].
  749. milliseconds = result.milliseconds;
  750. // k. Let microseconds be result.[[Microseconds]].
  751. microseconds = result.microseconds;
  752. // l. Let nanoseconds be result.[[Nanoseconds]].
  753. nanoseconds = result.nanoseconds;
  754. }
  755. // 5. Else if relativeTo has an [[InitializedTemporalDate]] internal slot, then
  756. else if (is<PlainDate>(relative_to_value.as_object())) {
  757. auto& relative_to = static_cast<PlainDate&>(relative_to_value.as_object());
  758. // a. Let calendar be relativeTo.[[Calendar]].
  759. auto& calendar = relative_to.calendar();
  760. // b. Let dateDuration1 be ? CreateTemporalDuration(y1, mon1, w1, d1, 0, 0, 0, 0, 0, 0).
  761. auto* date_duration1 = TRY(create_temporal_duration(global_object, years1, months1, weeks1, days1, 0, 0, 0, 0, 0, 0));
  762. // c. Let dateDuration2 be ? CreateTemporalDuration(y2, mon2, w2, d2, 0, 0, 0, 0, 0, 0).
  763. auto* date_duration2 = TRY(create_temporal_duration(global_object, years2, months2, weeks2, days2, 0, 0, 0, 0, 0, 0));
  764. // d. Let dateAdd be ? GetMethod(calendar, "dateAdd").
  765. auto* date_add = TRY(Value(&calendar).get_method(global_object, vm.names.dateAdd));
  766. // e. Let firstAddOptions be ! OrdinaryObjectCreate(null).
  767. auto* first_add_options = Object::create(global_object, nullptr);
  768. // f. Let intermediate be ? CalendarDateAdd(calendar, relativeTo, dateDuration1, firstAddOptions, dateAdd).
  769. auto* intermediate = TRY(calendar_date_add(global_object, calendar, &relative_to, *date_duration1, first_add_options, date_add));
  770. // g. Let secondAddOptions be ! OrdinaryObjectCreate(null).
  771. auto* second_add_options = Object::create(global_object, nullptr);
  772. // h. Let end be ? CalendarDateAdd(calendar, intermediate, dateDuration2, secondAddOptions, dateAdd).
  773. auto* end = TRY(calendar_date_add(global_object, calendar, intermediate, *date_duration2, second_add_options, date_add));
  774. // i. Let dateLargestUnit be ! LargerOfTwoTemporalUnits("day", largestUnit).
  775. auto date_largest_unit = larger_of_two_temporal_units("day"sv, largest_unit);
  776. // j. Let differenceOptions be ! OrdinaryObjectCreate(null).
  777. auto* difference_options = Object::create(global_object, nullptr);
  778. // k. Perform ! CreateDataPropertyOrThrow(differenceOptions, "largestUnit", dateLargestUnit).
  779. MUST(difference_options->create_data_property_or_throw(vm.names.largestUnit, js_string(vm, date_largest_unit)));
  780. // l. Let dateDifference be ? CalendarDateUntil(calendar, relativeTo, end, differenceOptions).
  781. auto* date_difference = TRY(calendar_date_until(global_object, calendar, &relative_to, end, *difference_options));
  782. // m. Let result be ! BalanceDuration(dateDifference.[[Days]], h1 + h2, min1 + min2, s1 + s2, ms1 + ms2, mus1 + mus2, ns1 + ns2, largestUnit).
  783. // FIXME: Narrowing conversion from 'double' to 'i64'
  784. auto* added_nanoseconds_bigint = js_bigint(vm, Crypto::SignedBigInteger::create_from(nanoseconds1 + nanoseconds2));
  785. auto result = MUST(balance_duration(global_object, date_difference->days(), hours1 + hours2, minutes1 + minutes2, seconds1 + seconds2, milliseconds1 + milliseconds2, microseconds1 + microseconds2, *added_nanoseconds_bigint, largest_unit));
  786. // n. Let years be dateDifference.[[Years]].
  787. years = date_difference->years();
  788. // o. Let months be dateDifference.[[Months]].
  789. months = date_difference->months();
  790. // p. Let weeks be dateDifference.[[Weeks]].
  791. weeks = date_difference->weeks();
  792. // q. Let days be result.[[Days]].
  793. days = result.days;
  794. // r. Let hours be result.[[Hours]].
  795. hours = result.hours;
  796. // s. Let minutes be result.[[Minutes]].
  797. minutes = result.minutes;
  798. // t. Let seconds be result.[[Seconds]].
  799. seconds = result.seconds;
  800. // u. Let milliseconds be result.[[Milliseconds]].
  801. milliseconds = result.milliseconds;
  802. // v. Let microseconds be result.[[Microseconds]].
  803. microseconds = result.microseconds;
  804. // w. Let nanoseconds be result.[[Nanoseconds]].
  805. nanoseconds = result.nanoseconds;
  806. }
  807. // 6. Else,
  808. else {
  809. // a. Assert: relativeTo has an [[InitializedTemporalZonedDateTime]] internal slot.
  810. auto& relative_to = verify_cast<ZonedDateTime>(relative_to_value.as_object());
  811. // b. Let timeZone be relativeTo.[[TimeZone]].
  812. auto& time_zone = relative_to.time_zone();
  813. // c. Let calendar be relativeTo.[[Calendar]].
  814. auto& calendar = relative_to.calendar();
  815. // d. Let intermediateNs be ? AddZonedDateTime(relativeTo.[[Nanoseconds]], timeZone, calendar, y1, mon1, w1, d1, h1, min1, s1, ms1, mus1, ns1).
  816. auto* intermediate_ns = TRY(add_zoned_date_time(global_object, relative_to.nanoseconds(), &time_zone, calendar, years1, months1, weeks1, days1, hours1, minutes1, seconds1, milliseconds1, microseconds1, nanoseconds1));
  817. // e. Let endNs be ? AddZonedDateTime(intermediateNs, timeZone, calendar, y2, mon2, w2, d2, h2, min2, s2, ms2, mus2, ns2).
  818. auto* end_ns = TRY(add_zoned_date_time(global_object, *intermediate_ns, &time_zone, calendar, years2, months2, weeks2, days2, hours2, minutes2, seconds2, milliseconds2, microseconds2, nanoseconds2));
  819. // f. If largestUnit is not one of "year", "month", "week", or "day", then
  820. if (!largest_unit.is_one_of("year"sv, "month"sv, "week"sv, "day"sv)) {
  821. // i. Let diffNs be ! DifferenceInstant(relativeTo.[[Nanoseconds]], endNs, 1, "nanosecond", "halfExpand").
  822. auto* diff_ns = difference_instant(global_object, relative_to.nanoseconds(), *end_ns, 1, "nanosecond"sv, "halfExpand"sv);
  823. // ii. Let result be ! BalanceDuration(0, 0, 0, 0, 0, 0, diffNs, largestUnit).
  824. auto result = MUST(balance_duration(global_object, 0, 0, 0, 0, 0, 0, *diff_ns, largest_unit));
  825. // iii. Let years be 0.
  826. years = 0;
  827. // iv. Let months be 0.
  828. months = 0;
  829. // v. Let weeks be 0.
  830. weeks = 0;
  831. // vi. Let days be 0.
  832. days = 0;
  833. // vii. Let hours be result.[[Hours]].
  834. hours = result.hours;
  835. // viii. Let minutes be result.[[Minutes]].
  836. minutes = result.minutes;
  837. // ix. Let seconds be result.[[Seconds]].
  838. seconds = result.seconds;
  839. // x. Let milliseconds be result.[[Milliseconds]].
  840. milliseconds = result.milliseconds;
  841. // xi. Let microseconds be result.[[Microseconds]].
  842. microseconds = result.microseconds;
  843. // xii. Let nanoseconds be result.[[Nanoseconds]].
  844. nanoseconds = result.nanoseconds;
  845. }
  846. // g. Else,
  847. else {
  848. // i. Let result be ? DifferenceZonedDateTime(relativeTo.[[Nanoseconds]], endNs, timeZone, calendar, largestUnit).
  849. auto result = TRY(difference_zoned_date_time(global_object, relative_to.nanoseconds(), *end_ns, time_zone, calendar, largest_unit));
  850. // ii. Let years be result.[[Years]].
  851. years = result.years;
  852. // iii. Let months be result.[[Months]].
  853. months = result.months;
  854. // iv. Let weeks be result.[[Weeks]].
  855. weeks = result.weeks;
  856. // v. Let days be result.[[Days]].
  857. days = result.days;
  858. // vi. Let hours be result.[[Hours]].
  859. hours = result.hours;
  860. // vii. Let minutes be result.[[Minutes]].
  861. minutes = result.minutes;
  862. // viii. Let seconds be result.[[Seconds]].
  863. seconds = result.seconds;
  864. // ix. Let milliseconds be result.[[Milliseconds]].
  865. milliseconds = result.milliseconds;
  866. // x. Let microseconds be result.[[Microseconds]].
  867. microseconds = result.microseconds;
  868. // xi. Let nanoseconds be result.[[Nanoseconds]].
  869. nanoseconds = result.nanoseconds;
  870. }
  871. }
  872. // 7. If ! IsValidDuration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds) is false, throw a RangeError exception.
  873. if (!is_valid_duration(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds))
  874. return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidDuration);
  875. // 8. Return the Record { [[Years]]: years, [[Months]]: months, [[Weeks]]: weeks, [[Days]]: days, [[Hours]]: hours, [[Minutes]]: minutes, [[Seconds]]: seconds, [[Milliseconds]]: milliseconds, [[Microseconds]]: microseconds, [[Nanoseconds]]: nanoseconds }.
  876. return DurationRecord { .years = years, .months = months, .weeks = weeks, .days = days, .hours = hours, .minutes = minutes, .seconds = seconds, .milliseconds = milliseconds, .microseconds = microseconds, .nanoseconds = nanoseconds };
  877. }
  878. // 7.5.20 MoveRelativeDate ( calendar, relativeTo, duration ), https://tc39.es/proposal-temporal/#sec-temporal-moverelativedate
  879. ThrowCompletionOr<MoveRelativeDateResult> move_relative_date(GlobalObject& global_object, Object& calendar, PlainDate& relative_to, Duration& duration)
  880. {
  881. // 1. Let options be ! OrdinaryObjectCreate(null).
  882. auto* options = Object::create(global_object, nullptr);
  883. // 2. Let newDate be ? CalendarDateAdd(calendar, relativeTo, duration, options).
  884. auto* new_date = TRY(calendar_date_add(global_object, calendar, &relative_to, duration, options));
  885. // 3. Let days be ! DaysUntil(relativeTo, newDate).
  886. auto days = days_until(global_object, relative_to, *new_date);
  887. // 4. Return the Record { [[RelativeTo]]: newDate, [[Days]]: days }.
  888. return MoveRelativeDateResult { .relative_to = make_handle(new_date), .days = days };
  889. }
  890. // 7.5.21 MoveRelativeZonedDateTime ( zonedDateTime, years, months, weeks, days ), https://tc39.es/proposal-temporal/#sec-temporal-moverelativezoneddatetime
  891. ThrowCompletionOr<ZonedDateTime*> move_relative_zoned_date_time(GlobalObject& global_object, ZonedDateTime& zoned_date_time, double years, double months, double weeks, double days)
  892. {
  893. // 1. Let intermediateNs be ? AddZonedDateTime(zonedDateTime.[[Nanoseconds]], zonedDateTime.[[TimeZone]], zonedDateTime.[[Calendar]], years, months, weeks, days, 0, 0, 0, 0, 0, 0).
  894. auto* intermediate_ns = TRY(add_zoned_date_time(global_object, zoned_date_time.nanoseconds(), &zoned_date_time.time_zone(), zoned_date_time.calendar(), years, months, weeks, days, 0, 0, 0, 0, 0, 0));
  895. // 2. Return ! CreateTemporalZonedDateTime(intermediateNs, zonedDateTime.[[TimeZone]], zonedDateTime.[[Calendar]]).
  896. return MUST(create_temporal_zoned_date_time(global_object, *intermediate_ns, zoned_date_time.time_zone(), zoned_date_time.calendar()));
  897. }
  898. // 7.5.22 RoundDuration ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, increment, unit, roundingMode [ , relativeTo ] ), https://tc39.es/proposal-temporal/#sec-temporal-roundduration
  899. ThrowCompletionOr<RoundedDuration> round_duration(GlobalObject& global_object, double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, u32 increment, StringView unit, StringView rounding_mode, Object* relative_to_object)
  900. {
  901. auto& vm = global_object.vm();
  902. Object* calendar = nullptr;
  903. double fractional_seconds = 0;
  904. // 1. If relativeTo is not present, set relativeTo to undefined.
  905. // NOTE: `relative_to_object` and `relative_to` in the various code paths below are all the same as far as the
  906. // spec is concerned, but the latter is more strictly typed for convenience.
  907. PlainDate* relative_to = nullptr;
  908. // 2. Let years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, and increment each be the mathematical values of themselves.
  909. // FIXME: assuming "smallestUnit" as the option name here leads to confusing error messages in some cases:
  910. // > new Temporal.Duration().total({ unit: "month" })
  911. // Uncaught exception: [RangeError] month is not a valid value for option smallestUnit
  912. // 3. If unit is "year", "month", or "week", and relativeTo is undefined, then
  913. if (unit.is_one_of("year"sv, "month"sv, "week"sv) && !relative_to_object) {
  914. // a. Throw a RangeError exception.
  915. return vm.throw_completion<RangeError>(global_object, ErrorType::OptionIsNotValidValue, unit, "smallestUnit"sv);
  916. }
  917. // 4. Let zonedRelativeTo be undefined.
  918. ZonedDateTime* zoned_relative_to = nullptr;
  919. // 5. If relativeTo is not undefined, then
  920. if (relative_to_object) {
  921. // a. If relativeTo has an [[InitializedTemporalZonedDateTime]] internal slot, then
  922. if (is<ZonedDateTime>(relative_to_object)) {
  923. auto* relative_to_zoned_date_time = static_cast<ZonedDateTime*>(relative_to_object);
  924. // i. Set zonedRelativeTo to relativeTo.
  925. zoned_relative_to = relative_to_zoned_date_time;
  926. // ii. Set relativeTo to ? ToTemporalDate(relativeTo).
  927. relative_to = TRY(to_temporal_date(global_object, relative_to_object));
  928. }
  929. // b. Else,
  930. else {
  931. // i. Assert: relativeTo has an [[InitializedTemporalDate]] internal slot.
  932. VERIFY(is<PlainDate>(relative_to_object));
  933. relative_to = static_cast<PlainDate*>(relative_to_object);
  934. }
  935. // c. Let calendar be relativeTo.[[Calendar]].
  936. calendar = &relative_to->calendar();
  937. }
  938. // 6. Else,
  939. // a. NOTE: calendar will not be used below.
  940. // 7. If unit is one of "year", "month", "week", or "day", then
  941. if (unit.is_one_of("year"sv, "month"sv, "week"sv, "day"sv)) {
  942. auto* nanoseconds_bigint = js_bigint(vm, Crypto::SignedBigInteger::create_from((i64)nanoseconds));
  943. // a. Let nanoseconds be ! TotalDurationNanoseconds(0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, 0).
  944. nanoseconds_bigint = total_duration_nanoseconds(global_object, 0, hours, minutes, seconds, milliseconds, microseconds, *nanoseconds_bigint, 0);
  945. // b. Let intermediate be undefined.
  946. ZonedDateTime* intermediate = nullptr;
  947. // c. If zonedRelativeTo is not undefined, then
  948. if (zoned_relative_to) {
  949. // i. Let intermediate be ? MoveRelativeZonedDateTime(zonedRelativeTo, years, months, weeks, days).
  950. intermediate = TRY(move_relative_zoned_date_time(global_object, *zoned_relative_to, years, months, weeks, days));
  951. }
  952. // d. Let result be ? NanosecondsToDays(nanoseconds, intermediate).
  953. auto result = TRY(nanoseconds_to_days(global_object, *nanoseconds_bigint, intermediate));
  954. // e. Set days to days + result.[[Days]] + result.[[Nanoseconds]] / result.[[DayLength]].
  955. auto nanoseconds_division_result = result.nanoseconds->big_integer().divided_by(Crypto::UnsignedBigInteger::create_from((u64)result.day_length));
  956. days += result.days + nanoseconds_division_result.quotient.to_double() + nanoseconds_division_result.remainder.to_double() / result.day_length;
  957. // f. Set hours, minutes, seconds, milliseconds, microseconds, and nanoseconds to 0.
  958. hours = 0;
  959. minutes = 0;
  960. seconds = 0;
  961. milliseconds = 0;
  962. microseconds = 0;
  963. nanoseconds = 0;
  964. }
  965. // 8. Else,
  966. else {
  967. // a. Let fractionalSeconds be nanoseconds × 10^−9 + microseconds × 10^−6 + milliseconds × 10^−3 + seconds.
  968. fractional_seconds = nanoseconds * 0.000000001 + microseconds * 0.000001 + milliseconds * 0.001 + seconds;
  969. }
  970. // 9. Let remainder be undefined.
  971. double remainder = 0;
  972. // 10. If unit is "year", then
  973. if (unit == "year"sv) {
  974. VERIFY(relative_to);
  975. // a. Let yearsDuration be ? CreateTemporalDuration(years, 0, 0, 0, 0, 0, 0, 0, 0, 0).
  976. auto* years_duration = TRY(create_temporal_duration(global_object, years, 0, 0, 0, 0, 0, 0, 0, 0, 0));
  977. // b. Let dateAdd be ? GetMethod(calendar, "dateAdd").
  978. auto* date_add = TRY(Value(calendar).get_method(global_object, vm.names.dateAdd));
  979. // c. Let firstAddOptions be ! OrdinaryObjectCreate(null).
  980. auto* first_add_options = Object::create(global_object, nullptr);
  981. // d. Let yearsLater be ? CalendarDateAdd(calendar, relativeTo, yearsDuration, firstAddOptions, dateAdd).
  982. auto* years_later = TRY(calendar_date_add(global_object, *calendar, relative_to, *years_duration, first_add_options, date_add));
  983. // e. Let yearsMonthsWeeks be ? CreateTemporalDuration(years, months, weeks, 0, 0, 0, 0, 0, 0, 0).
  984. auto* years_months_weeks = TRY(create_temporal_duration(global_object, years, months, weeks, 0, 0, 0, 0, 0, 0, 0));
  985. // f. Let secondAddOptions be ! OrdinaryObjectCreate(null).
  986. auto* second_add_options = Object::create(global_object, nullptr);
  987. // g. Let yearsMonthsWeeksLater be ? CalendarDateAdd(calendar, relativeTo, yearsMonthsWeeks, secondAddOptions, dateAdd).
  988. auto* years_months_weeks_later = TRY(calendar_date_add(global_object, *calendar, relative_to, *years_months_weeks, second_add_options, date_add));
  989. // h. Let monthsWeeksInDays be ? DaysUntil(yearsLater, yearsMonthsWeeksLater).
  990. auto months_weeks_in_days = days_until(global_object, *years_later, *years_months_weeks_later);
  991. // i. Set relativeTo to yearsLater.
  992. relative_to = years_later;
  993. // j. Let days be days + monthsWeeksInDays.
  994. days += months_weeks_in_days;
  995. // k. Let daysDuration be ? CreateTemporalDuration(0, 0, 0, days, 0, 0, 0, 0, 0, 0).
  996. auto* days_duration = TRY(create_temporal_duration(global_object, 0, 0, 0, days, 0, 0, 0, 0, 0, 0));
  997. // l. Let thirdAddOptions be ! OrdinaryObjectCreate(null).
  998. auto* third_add_options = Object::create(global_object, nullptr);
  999. // m. Let daysLater be ? CalendarDateAdd(calendar, relativeTo, daysDuration, thirdAddOptions, dateAdd).
  1000. auto* days_later = TRY(calendar_date_add(global_object, *calendar, relative_to, *days_duration, third_add_options, date_add));
  1001. // n. Let untilOptions be ! OrdinaryObjectCreate(null).
  1002. auto* until_options = Object::create(global_object, nullptr);
  1003. // o. Perform ! CreateDataPropertyOrThrow(untilOptions, "largestUnit", "year").
  1004. MUST(until_options->create_data_property_or_throw(vm.names.largestUnit, js_string(vm, "year"sv)));
  1005. // p. Let timePassed be ? CalendarDateUntil(calendar, relativeTo, daysLater, untilOptions).
  1006. auto* time_passed = TRY(calendar_date_until(global_object, *calendar, relative_to, days_later, *until_options));
  1007. // q. Let yearsPassed be timePassed.[[Years]].
  1008. auto years_passed = time_passed->years();
  1009. // r. Set years to years + yearsPassed.
  1010. years += years_passed;
  1011. // s. Let oldRelativeTo be relativeTo.
  1012. auto* old_relative_to = relative_to;
  1013. // t. Let yearsDuration be ? CreateTemporalDuration(yearsPassed, 0, 0, 0, 0, 0, 0, 0, 0, 0).
  1014. years_duration = TRY(create_temporal_duration(global_object, years_passed, 0, 0, 0, 0, 0, 0, 0, 0, 0));
  1015. // u. Let fourthAddOptions be ! OrdinaryObjectCreate(null).
  1016. auto* fourth_add_options = Object::create(global_object, nullptr);
  1017. // v. Set relativeTo to ? CalendarDateAdd(calendar, relativeTo, yearsDuration, fourthAddOptions, dateAdd).
  1018. relative_to = TRY(calendar_date_add(global_object, *calendar, relative_to, *years_duration, fourth_add_options, date_add));
  1019. // w. Let daysPassed be ? DaysUntil(oldRelativeTo, relativeTo).
  1020. auto days_passed = days_until(global_object, *old_relative_to, *relative_to);
  1021. // x. Set days to days - daysPassed.
  1022. days -= days_passed;
  1023. // y. Let sign be ! Sign(days).
  1024. auto sign = JS::Temporal::sign(days);
  1025. // z. If sign is 0, set sign to 1.
  1026. if (sign == 0)
  1027. sign = 1;
  1028. // aa. Let oneYear be ? CreateTemporalDuration(sign, 0, 0, 0, 0, 0, 0, 0, 0, 0).
  1029. auto* one_year = TRY(create_temporal_duration(global_object, sign, 0, 0, 0, 0, 0, 0, 0, 0, 0));
  1030. // ab. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneYear).
  1031. auto move_result = TRY(move_relative_date(global_object, *calendar, *relative_to, *one_year));
  1032. // ac. Let oneYearDays be moveResult.[[Days]].
  1033. auto one_year_days = move_result.days;
  1034. // ad. Let fractionalYears be years + days / abs(oneYearDays).
  1035. auto fractional_years = years + days / fabs(one_year_days);
  1036. // ae. Set years to ! RoundNumberToIncrement(fractionalYears, increment, roundingMode).
  1037. years = (double)round_number_to_increment(fractional_years, increment, rounding_mode);
  1038. // af. Set remainder to fractionalYears - years.
  1039. remainder = fractional_years - years;
  1040. // ag. Set months, weeks, and days to 0.
  1041. months = 0;
  1042. weeks = 0;
  1043. days = 0;
  1044. }
  1045. // 11. Else if unit is "month", then
  1046. else if (unit == "month"sv) {
  1047. VERIFY(relative_to);
  1048. // a. Let yearsMonths be ? CreateTemporalDuration(years, months, 0, 0, 0, 0, 0, 0, 0, 0).
  1049. auto* years_months = TRY(create_temporal_duration(global_object, years, months, 0, 0, 0, 0, 0, 0, 0, 0));
  1050. // b. Let dateAdd be ? GetMethod(calendar, "dateAdd").
  1051. auto* date_add = TRY(Value(calendar).get_method(global_object, vm.names.dateAdd));
  1052. // c. Let firstAddOptions be ! OrdinaryObjectCreate(null).
  1053. auto* first_add_options = Object::create(global_object, nullptr);
  1054. // d. Let yearsMonthsLater be ? CalendarDateAdd(calendar, relativeTo, yearsMonths, firstAddOptions, dateAdd).
  1055. auto* years_months_later = TRY(calendar_date_add(global_object, *calendar, relative_to, *years_months, first_add_options, date_add));
  1056. // e. Let yearsMonthsWeeks be ? CreateTemporalDuration(years, months, weeks, 0, 0, 0, 0, 0, 0, 0).
  1057. auto* years_months_weeks = TRY(create_temporal_duration(global_object, years, months, weeks, 0, 0, 0, 0, 0, 0, 0));
  1058. // f. Let secondAddOptions be ! OrdinaryObjectCreate(null).
  1059. auto* seconds_add_options = Object::create(global_object, nullptr);
  1060. // g. Let yearsMonthsWeeksLater be ? CalendarDateAdd(calendar, relativeTo, yearsMonthsWeeks, secondAddOptions, dateAdd).
  1061. auto* years_months_weeks_later = TRY(calendar_date_add(global_object, *calendar, relative_to, *years_months_weeks, seconds_add_options, date_add));
  1062. // h. Let weeksInDays be ? DaysUntil(yearsMonthsLater, yearsMonthsWeeksLater).
  1063. auto weeks_in_days = days_until(global_object, *years_months_later, *years_months_weeks_later);
  1064. // i. Set relativeTo to yearsMonthsLater.
  1065. relative_to = years_months_later;
  1066. // j. Let days be days + weeksInDays.
  1067. days += weeks_in_days;
  1068. // k. Let sign be ! Sign(days).
  1069. auto sign = JS::Temporal::sign(days);
  1070. // l. If sign is 0, set sign to 1.
  1071. if (sign == 0)
  1072. sign = 1;
  1073. // m. Let oneMonth be ? CreateTemporalDuration(0, sign, 0, 0, 0, 0, 0, 0, 0, 0).
  1074. auto* one_month = TRY(create_temporal_duration(global_object, 0, sign, 0, 0, 0, 0, 0, 0, 0, 0));
  1075. // n. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneMonth).
  1076. auto move_result = TRY(move_relative_date(global_object, *calendar, *relative_to, *one_month));
  1077. // o. Set relativeTo to moveResult.[[RelativeTo]].
  1078. relative_to = move_result.relative_to.cell();
  1079. // p. Let oneMonthDays be moveResult.[[Days]].
  1080. auto one_month_days = move_result.days;
  1081. // q. Repeat, while abs(days) ≥ abs(oneMonthDays),
  1082. while (fabs(days) >= fabs(one_month_days)) {
  1083. // i. Set months to months + sign.
  1084. months += sign;
  1085. // ii. Set days to days − oneMonthDays.
  1086. days -= one_month_days;
  1087. // iii. Set moveResult to ? MoveRelativeDate(calendar, relativeTo, oneMonth).
  1088. move_result = TRY(move_relative_date(global_object, *calendar, *relative_to, *one_month));
  1089. // iv. Set relativeTo to moveResult.[[RelativeTo]].
  1090. relative_to = move_result.relative_to.cell();
  1091. // v. Set oneMonthDays to moveResult.[[Days]].
  1092. one_month_days = move_result.days;
  1093. }
  1094. // r. Let fractionalMonths be months + days / abs(oneMonthDays).
  1095. auto fractional_months = months + days / fabs(one_month_days);
  1096. // s. Set months to ! RoundNumberToIncrement(fractionalMonths, increment, roundingMode).
  1097. months = (double)round_number_to_increment(fractional_months, increment, rounding_mode);
  1098. // t. Set remainder to fractionalMonths - months.
  1099. remainder = fractional_months - months;
  1100. // u. Set weeks and days to 0.
  1101. weeks = 0;
  1102. days = 0;
  1103. }
  1104. // 12. Else if unit is "week", then
  1105. else if (unit == "week"sv) {
  1106. VERIFY(relative_to);
  1107. // a. Let sign be ! Sign(days).
  1108. auto sign = JS::Temporal::sign(days);
  1109. // b. If sign is 0, set sign to 1.
  1110. if (sign == 0)
  1111. sign = 1;
  1112. // c. Let oneWeek be ? CreateTemporalDuration(0, 0, sign, 0, 0, 0, 0, 0, 0, 0).
  1113. auto* one_week = TRY(create_temporal_duration(global_object, 0, 0, sign, 0, 0, 0, 0, 0, 0, 0));
  1114. // d. Let moveResult be ? MoveRelativeDate(calendar, relativeTo, oneWeek).
  1115. auto move_result = TRY(move_relative_date(global_object, *calendar, *relative_to, *one_week));
  1116. // e. Set relativeTo to moveResult.[[RelativeTo]].
  1117. relative_to = move_result.relative_to.cell();
  1118. // f. Let oneWeekDays be moveResult.[[Days]].
  1119. auto one_week_days = move_result.days;
  1120. // g. Repeat, while abs(days) ≥ abs(oneWeekDays),
  1121. while (fabs(days) >= fabs(one_week_days)) {
  1122. // i. Set weeks to weeks + sign.
  1123. weeks += sign;
  1124. // ii. Set days to days − oneWeekDays.
  1125. days -= one_week_days;
  1126. // iii. Set moveResult to ? MoveRelativeDate(calendar, relativeTo, oneWeek).
  1127. move_result = TRY(move_relative_date(global_object, *calendar, *relative_to, *one_week));
  1128. // iv. Set relativeTo to moveResult.[[RelativeTo]].
  1129. relative_to = move_result.relative_to.cell();
  1130. // v. Set oneWeekDays to moveResult.[[Days]].
  1131. one_week_days = move_result.days;
  1132. }
  1133. // h. Let fractionalWeeks be weeks + days / abs(oneWeekDays).
  1134. auto fractional_weeks = weeks + days / fabs(one_week_days);
  1135. // i. Set weeks to ! RoundNumberToIncrement(fractionalWeeks, increment, roundingMode).
  1136. weeks = (double)round_number_to_increment(fractional_weeks, increment, rounding_mode);
  1137. // j. Set remainder to fractionalWeeks - weeks.
  1138. remainder = fractional_weeks - weeks;
  1139. // k. Set days to 0.
  1140. days = 0;
  1141. }
  1142. // 13. Else if unit is "day", then
  1143. else if (unit == "day"sv) {
  1144. // a. Let fractionalDays be days.
  1145. auto fractional_days = days;
  1146. // b. Set days to ! RoundNumberToIncrement(days, increment, roundingMode).
  1147. days = (double)round_number_to_increment(days, increment, rounding_mode);
  1148. // c. Set remainder to fractionalDays - days.
  1149. remainder = fractional_days - days;
  1150. }
  1151. // 14. Else if unit is "hour", then
  1152. else if (unit == "hour"sv) {
  1153. // a. Let fractionalHours be (fractionalSeconds / 60 + minutes) / 60 + hours.
  1154. auto fractional_hours = (fractional_seconds / 60 + minutes) / 60 + hours;
  1155. // b. Set hours to ! RoundNumberToIncrement(fractionalHours, increment, roundingMode).
  1156. hours = (double)round_number_to_increment(fractional_hours, increment, rounding_mode);
  1157. // c. Set remainder to fractionalHours - hours.
  1158. remainder = fractional_hours - hours;
  1159. // d. Set minutes, seconds, milliseconds, microseconds, and nanoseconds to 0.
  1160. minutes = 0;
  1161. seconds = 0;
  1162. milliseconds = 0;
  1163. microseconds = 0;
  1164. nanoseconds = 0;
  1165. }
  1166. // 15. Else if unit is "minute", then
  1167. else if (unit == "minute"sv) {
  1168. // a. Let fractionalMinutes be fractionalSeconds / 60 + minutes.
  1169. auto fractional_minutes = fractional_seconds / 60 + minutes;
  1170. // b. Set minutes to ! RoundNumberToIncrement(fractionalMinutes, increment, roundingMode).
  1171. minutes = (double)round_number_to_increment(fractional_minutes, increment, rounding_mode);
  1172. // c. Set remainder to fractionalMinutes - minutes.
  1173. remainder = fractional_minutes - minutes;
  1174. // d. Set seconds, milliseconds, microseconds, and nanoseconds to 0.
  1175. seconds = 0;
  1176. milliseconds = 0;
  1177. microseconds = 0;
  1178. nanoseconds = 0;
  1179. }
  1180. // 16. Else if unit is "second", then
  1181. else if (unit == "second"sv) {
  1182. // a. Set seconds to ! RoundNumberToIncrement(fractionalSeconds, increment, roundingMode).
  1183. seconds = (double)round_number_to_increment(fractional_seconds, increment, rounding_mode);
  1184. // b. Set remainder to fractionalSeconds - seconds.
  1185. remainder = fractional_seconds - seconds;
  1186. // c. Set milliseconds, microseconds, and nanoseconds to 0.
  1187. milliseconds = 0;
  1188. microseconds = 0;
  1189. nanoseconds = 0;
  1190. }
  1191. // 17. Else if unit is "millisecond", then
  1192. else if (unit == "millisecond"sv) {
  1193. // a. Let fractionalMilliseconds be nanoseconds × 10^−6 + microseconds × 10^−3 + milliseconds.
  1194. auto fractional_milliseconds = nanoseconds * 0.000001 + microseconds * 0.001 + milliseconds;
  1195. // b. Set milliseconds to ! RoundNumberToIncrement(fractionalMilliseconds, increment, roundingMode).
  1196. milliseconds = (double)round_number_to_increment(fractional_milliseconds, increment, rounding_mode);
  1197. // c. Set remainder to fractionalMilliseconds - milliseconds.
  1198. remainder = fractional_milliseconds - milliseconds;
  1199. // d. Set microseconds and nanoseconds to 0.
  1200. microseconds = 0;
  1201. nanoseconds = 0;
  1202. }
  1203. // 18. Else if unit is "microsecond", then
  1204. else if (unit == "microsecond"sv) {
  1205. // a. Let fractionalMicroseconds be nanoseconds × 10^−3 + microseconds.
  1206. auto fractional_microseconds = nanoseconds * 0.001 + microseconds;
  1207. // b. Set microseconds to ! RoundNumberToIncrement(fractionalMicroseconds, increment, roundingMode).
  1208. microseconds = (double)round_number_to_increment(fractional_microseconds, increment, rounding_mode);
  1209. // c. Set remainder to fractionalMicroseconds - microseconds.
  1210. remainder = fractional_microseconds - microseconds;
  1211. // d. Set nanoseconds to 0.
  1212. nanoseconds = 0;
  1213. }
  1214. // 19. Else,
  1215. else {
  1216. // a. Assert: unit is "nanosecond".
  1217. VERIFY(unit == "nanosecond"sv);
  1218. // b. Set remainder to nanoseconds.
  1219. remainder = nanoseconds;
  1220. // c. Set nanoseconds to ! RoundNumberToIncrement(nanoseconds, increment, roundingMode).
  1221. nanoseconds = (double)round_number_to_increment(nanoseconds, increment, rounding_mode);
  1222. // d. Set remainder to remainder − nanoseconds.
  1223. remainder -= nanoseconds;
  1224. }
  1225. // 20. Let duration be Duration Record { [[Years]]: years, [[Months]]: months, [[Weeks]]: weeks, [[Days]]: days, [[Hours]]: hours, [[Minutes]]: minutes, [[Seconds]]: seconds, [[Milliseconds]]: milliseconds, [[Microseconds]]: microseconds, [[Nanoseconds]]: nanoseconds }.
  1226. auto duration = DurationRecord { .years = years, .months = months, .weeks = weeks, .days = days, .hours = hours, .minutes = minutes, .seconds = seconds, .milliseconds = milliseconds, .microseconds = microseconds, .nanoseconds = nanoseconds };
  1227. // 21. Return the Record { [[DurationRecord]]: duration, [[Remainder]]: remainder }.
  1228. return RoundedDuration { .duration_record = duration, .remainder = remainder };
  1229. }
  1230. // 7.5.23 AdjustRoundedDurationDays ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, increment, unit, roundingMode [ , relativeTo ] ), https://tc39.es/proposal-temporal/#sec-temporal-adjustroundeddurationdays
  1231. ThrowCompletionOr<DurationRecord> adjust_rounded_duration_days(GlobalObject& global_object, double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, u32 increment, StringView unit, StringView rounding_mode, Object* relative_to_object)
  1232. {
  1233. auto& vm = global_object.vm();
  1234. // 1. If relativeTo is not present; or Type(relativeTo) is not Object; or relativeTo does not have an [[InitializedTemporalZonedDateTime]] internal slot; or unit is one of "year", "month", "week", or "day"; or unit is "nanosecond" and increment is 1, then
  1235. if (relative_to_object == nullptr || !is<ZonedDateTime>(relative_to_object) || unit.is_one_of("year"sv, "month"sv, "week"sv, "day"sv) || (unit == "nanosecond"sv && increment == 1)) {
  1236. // a. Return the Record { [[Years]]: years, [[Months]]: months, [[Weeks]]: weeks, [[Days]]: days, [[Hours]]: hours, [[Minutes]]: minutes, [[Seconds]]: seconds, [[Milliseconds]]: milliseconds, [[Microseconds]]: microseconds, [[Nanoseconds]]: nanoseconds }.
  1237. return DurationRecord { .years = years, .months = months, .weeks = weeks, .days = days, .hours = hours, .minutes = minutes, .seconds = seconds, .milliseconds = milliseconds, .microseconds = microseconds, .nanoseconds = nanoseconds };
  1238. }
  1239. auto& relative_to = static_cast<ZonedDateTime&>(*relative_to_object);
  1240. // 2. Let timeRemainderNs be ! TotalDurationNanoseconds(0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, 0).
  1241. auto time_remainder_ns = total_duration_nanoseconds(global_object, 0, hours, minutes, seconds, milliseconds, microseconds, *js_bigint(vm, Crypto::SignedBigInteger::create_from((i64)nanoseconds)), 0)->big_integer();
  1242. // 3. Let direction be ! ℝ(Sign(𝔽(timeRemainderNs))).
  1243. auto direction = Temporal::sign(time_remainder_ns);
  1244. // 4. Let dayStart be ? AddZonedDateTime(relativeTo.[[Nanoseconds]], relativeTo.[[TimeZone]], relativeTo.[[Calendar]], years, months, weeks, days, 0, 0, 0, 0, 0, 0).
  1245. auto* day_start = TRY(add_zoned_date_time(global_object, relative_to.nanoseconds(), &relative_to.time_zone(), relative_to.calendar(), years, months, weeks, days, 0, 0, 0, 0, 0, 0));
  1246. // 5. Let dayEnd be ? AddZonedDateTime(dayStart, relativeTo.[[TimeZone]], relativeTo.[[Calendar]], 0, 0, 0, direction, 0, 0, 0, 0, 0, 0).
  1247. auto* day_end = TRY(add_zoned_date_time(global_object, *day_start, &relative_to.time_zone(), relative_to.calendar(), 0, 0, 0, direction, 0, 0, 0, 0, 0, 0));
  1248. // 6. Let dayLengthNs be ℝ(dayEnd − dayStart).
  1249. auto day_length_ns = day_end->big_integer().minus(day_start->big_integer());
  1250. // 7. If (timeRemainderNs − dayLengthNs) × direction < 0, then
  1251. if (time_remainder_ns.minus(day_length_ns).multiplied_by(Crypto::SignedBigInteger { (i32)direction }).is_negative()) {
  1252. // a. Return the Record { [[Years]]: years, [[Months]]: months, [[Weeks]]: weeks, [[Days]]: days, [[Hours]]: hours, [[Minutes]]: minutes, [[Seconds]]: seconds, [[Milliseconds]]: milliseconds, [[Microseconds]]: microseconds, [[Nanoseconds]]: nanoseconds }.
  1253. return DurationRecord { .years = years, .months = months, .weeks = weeks, .days = days, .hours = hours, .minutes = minutes, .seconds = seconds, .milliseconds = milliseconds, .microseconds = microseconds, .nanoseconds = nanoseconds };
  1254. }
  1255. // 8. Set timeRemainderNs to ! RoundTemporalInstant(ℤ(timeRemainderNs − dayLengthNs), increment, unit, roundingMode).
  1256. time_remainder_ns = round_temporal_instant(global_object, *js_bigint(vm, time_remainder_ns.minus(day_length_ns)), increment, unit, rounding_mode)->big_integer();
  1257. // 9. Let adjustedDateDuration be ? AddDuration(years, months, weeks, days, 0, 0, 0, 0, 0, 0, 0, 0, 0, direction, 0, 0, 0, 0, 0, 0, relativeTo).
  1258. auto adjusted_date_duration = TRY(add_duration(global_object, years, months, weeks, days, 0, 0, 0, 0, 0, 0, 0, 0, 0, direction, 0, 0, 0, 0, 0, 0, &relative_to));
  1259. // 10. Let adjustedTimeDuration be ? BalanceDuration(0, 0, 0, 0, 0, 0, timeRemainderNs, "hour").
  1260. auto adjusted_time_duration = TRY(balance_duration(global_object, 0, 0, 0, 0, 0, 0, *js_bigint(vm, move(time_remainder_ns)), "hour"sv));
  1261. // 11. Return the Record { [[Years]]: adjustedDateDuration.[[Years]], [[Months]]: adjustedDateDuration.[[Months]], [[Weeks]]: adjustedDateDuration.[[Weeks]], [[Days]]: adjustedDateDuration.[[Days]], [[Hours]]: adjustedTimeDuration.[[Hours]], [[Minutes]]: adjustedTimeDuration.[[Minutes]], [[Seconds]]: adjustedTimeDuration.[[Seconds]], [[Milliseconds]]: adjustedTimeDuration.[[Milliseconds]], [[Microseconds]]: adjustedTimeDuration.[[Microseconds]], [[Nanoseconds]]: adjustedTimeDuration.[[Nanoseconds]] }.
  1262. return DurationRecord { .years = adjusted_date_duration.years, .months = adjusted_date_duration.months, .weeks = adjusted_date_duration.weeks, .days = adjusted_date_duration.days, .hours = adjusted_time_duration.hours, .minutes = adjusted_time_duration.minutes, .seconds = adjusted_time_duration.seconds, .milliseconds = adjusted_time_duration.milliseconds, .microseconds = adjusted_time_duration.microseconds, .nanoseconds = adjusted_time_duration.nanoseconds };
  1263. }
  1264. // 7.5.24 ToLimitedTemporalDuration ( temporalDurationLike, disallowedFields ), https://tc39.es/proposal-temporal/#sec-temporal-tolimitedtemporalduration
  1265. ThrowCompletionOr<DurationRecord> to_limited_temporal_duration(GlobalObject& global_object, Value temporal_duration_like, Vector<StringView> const& disallowed_fields)
  1266. {
  1267. auto& vm = global_object.vm();
  1268. DurationRecord duration;
  1269. // 1. If Type(temporalDurationLike) is not Object, then
  1270. if (!temporal_duration_like.is_object()) {
  1271. // a. Let str be ? ToString(temporalDurationLike).
  1272. auto str = TRY(temporal_duration_like.to_string(global_object));
  1273. // b. Let duration be ? ParseTemporalDurationString(str).
  1274. duration = TRY(parse_temporal_duration_string(global_object, str));
  1275. }
  1276. // 2. Else,
  1277. else {
  1278. // a. Let duration be ? ToTemporalDurationRecord(temporalDurationLike).
  1279. duration = TRY(to_temporal_duration_record(global_object, temporal_duration_like.as_object()));
  1280. }
  1281. // 3. If ! IsValidDuration(duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]]) is false, throw a RangeError exception.
  1282. if (!is_valid_duration(duration.years, duration.months, duration.weeks, duration.days, duration.hours, duration.minutes, duration.seconds, duration.milliseconds, duration.microseconds, duration.nanoseconds))
  1283. return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidDuration);
  1284. // 4. For each row of Table 7, except the header row, in table order, do
  1285. for (auto& [field, property] : temporal_duration_like_properties<DurationRecord, double>(vm)) {
  1286. // a. Let prop be the Property Name value of the current row.
  1287. // b. Let value be duration's field whose name is the Field Name value of the current row.
  1288. auto value = duration.*field;
  1289. // If value is not 0 and disallowedFields contains prop, then
  1290. if (value != 0 && disallowed_fields.contains_slow(property.as_string())) {
  1291. // i. Throw a RangeError exception.
  1292. return vm.throw_completion<RangeError>(global_object, ErrorType::TemporalInvalidDurationPropertyValueNonZero, property.as_string(), value);
  1293. }
  1294. }
  1295. // 5. Return duration.
  1296. return duration;
  1297. }
  1298. // 7.5.25 TemporalDurationToString ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, precision ), https://tc39.es/proposal-temporal/#sec-temporal-temporaldurationtostring
  1299. String temporal_duration_to_string(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, Variant<StringView, u8> const& precision)
  1300. {
  1301. if (precision.has<StringView>())
  1302. VERIFY(precision.get<StringView>() == "auto"sv);
  1303. // 1. Set seconds to the mathematical value of seconds.
  1304. // 2. Set milliseconds to the mathematical value of milliseconds.
  1305. // 3. Set microseconds to the mathematical value of microseconds.
  1306. // 4. Set nanoseconds to the mathematical value of nanoseconds.
  1307. // 5. Let sign be ! DurationSign(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds).
  1308. auto sign = duration_sign(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds);
  1309. // 6. Set microseconds to microseconds + the integral part of nanoseconds / 1000.
  1310. microseconds += trunc(nanoseconds / 1000);
  1311. // 7. Set nanoseconds to remainder(nanoseconds, 1000).
  1312. nanoseconds = fmod(nanoseconds, 1000);
  1313. // 8. Set milliseconds to milliseconds + the integral part of microseconds / 1000.
  1314. milliseconds += trunc(microseconds / 1000);
  1315. // 9. Set microseconds to remainder(microseconds, 1000).
  1316. microseconds = fmod(microseconds, 1000);
  1317. // 10. Set seconds to seconds + the integral part of milliseconds / 1000.
  1318. seconds += trunc(milliseconds / 1000);
  1319. // 11. Set milliseconds to remainder(milliseconds, 1000).
  1320. milliseconds = fmod(milliseconds, 1000);
  1321. // 12. Let datePart be "".
  1322. StringBuilder date_part;
  1323. // 13. If years is not 0, then
  1324. if (years != 0) {
  1325. // a. Set datePart to the string concatenation of abs(years) formatted as a decimal number and the code unit 0x0059 (LATIN CAPITAL LETTER Y).
  1326. date_part.appendff("{}", fabs(years));
  1327. date_part.append('Y');
  1328. }
  1329. // 14. If months is not 0, then
  1330. if (months != 0) {
  1331. // a. Set datePart to the string concatenation of datePart, abs(months) formatted as a decimal number, and the code unit 0x004D (LATIN CAPITAL LETTER M).
  1332. date_part.appendff("{}", fabs(months));
  1333. date_part.append('M');
  1334. }
  1335. // 15. If weeks is not 0, then
  1336. if (weeks != 0) {
  1337. // a. Set datePart to the string concatenation of datePart, abs(weeks) formatted as a decimal number, and the code unit 0x0057 (LATIN CAPITAL LETTER W).
  1338. date_part.appendff("{}", fabs(weeks));
  1339. date_part.append('W');
  1340. }
  1341. // 16. If days is not 0, then
  1342. if (days != 0) {
  1343. // a. Set datePart to the string concatenation of datePart, abs(days) formatted as a decimal number, and the code unit 0x0044 (LATIN CAPITAL LETTER D).
  1344. date_part.appendff("{}", fabs(days));
  1345. date_part.append('D');
  1346. }
  1347. // 17. Let timePart be "".
  1348. StringBuilder time_part;
  1349. // 18. If hours is not 0, then
  1350. if (hours != 0) {
  1351. // a. Set timePart to the string concatenation of abs(hours) formatted as a decimal number and the code unit 0x0048 (LATIN CAPITAL LETTER H).
  1352. time_part.appendff("{}", fabs(hours));
  1353. time_part.append('H');
  1354. }
  1355. // 19. If minutes is not 0, then
  1356. if (minutes != 0) {
  1357. // a. Set timePart to the string concatenation of timePart, abs(minutes) formatted as a decimal number, and the code unit 0x004D (LATIN CAPITAL LETTER M).
  1358. time_part.appendff("{}", fabs(minutes));
  1359. time_part.append('M');
  1360. }
  1361. // 20. If any of seconds, milliseconds, microseconds, and nanoseconds are not 0; or years, months, weeks, days, hours, and minutes are all 0; or precision is not "auto"; then
  1362. if ((seconds != 0 || milliseconds != 0 || microseconds != 0 || nanoseconds != 0) || (years == 0 && months == 0 && weeks == 0 && days == 0 && hours == 0 && minutes == 0) || (!precision.has<StringView>() || precision.get<StringView>() != "auto"sv)) {
  1363. // a. Let fraction be abs(milliseconds) × 10^6 + abs(microseconds) × 10^3 + abs(nanoseconds).
  1364. auto fraction = fabs(milliseconds) * 1'000'000 + fabs(microseconds) * 1'000 + fabs(nanoseconds);
  1365. // b. Let decimalPart be fraction formatted as a nine-digit decimal number, padded to the left with zeroes if necessary.
  1366. // NOTE: padding with zeros leads to weird results when applied to a double. Not sure if that's a bug in AK/Format.h or if I'm doing this wrong.
  1367. auto decimal_part = String::formatted("{:09}", (u64)fraction);
  1368. // c. If precision is "auto", then
  1369. if (precision.has<StringView>() && precision.get<StringView>() == "auto"sv) {
  1370. // i. Set decimalPart to the longest possible substring of decimalPart starting at position 0 and not ending with the code unit 0x0030 (DIGIT ZERO).
  1371. // NOTE: trim() would keep the left-most 0.
  1372. while (decimal_part.ends_with('0'))
  1373. decimal_part = decimal_part.substring(0, decimal_part.length() - 1);
  1374. }
  1375. // d. Else if precision = 0, then
  1376. else if (precision.get<u8>() == 0) {
  1377. // i. Set decimalPart to "".
  1378. decimal_part = String::empty();
  1379. }
  1380. // e. Else,
  1381. else {
  1382. // i. Set decimalPart to the substring of decimalPart from 0 to precision.
  1383. decimal_part = decimal_part.substring(0, precision.get<u8>());
  1384. }
  1385. // f. Let secondsPart be abs(seconds) formatted as a decimal number.
  1386. StringBuilder seconds_part;
  1387. seconds_part.appendff("{}", fabs(seconds));
  1388. // g. If decimalPart is not "", then
  1389. if (!decimal_part.is_empty()) {
  1390. // i. Set secondsPart to the string-concatenation of secondsPart, the code unit 0x002E (FULL STOP), and decimalPart.
  1391. seconds_part.append('.');
  1392. seconds_part.append(decimal_part);
  1393. }
  1394. // h. Set timePart to the string concatenation of timePart, secondsPart, and the code unit 0x0053 (LATIN CAPITAL LETTER S).
  1395. time_part.append(seconds_part.string_view());
  1396. time_part.append('S');
  1397. }
  1398. // 21. Let signPart be the code unit 0x002D (HYPHEN-MINUS) if sign < 0, and otherwise the empty String.
  1399. auto sign_part = sign < 0 ? "-"sv : ""sv;
  1400. // 22. Let result be the string concatenation of signPart, the code unit 0x0050 (LATIN CAPITAL LETTER P) and datePart.
  1401. StringBuilder result;
  1402. result.append(sign_part);
  1403. result.append('P');
  1404. result.append(date_part.string_view());
  1405. // 23. If timePart is not "", then
  1406. if (!time_part.is_empty()) {
  1407. // a. Set result to the string concatenation of result, the code unit 0x0054 (LATIN CAPITAL LETTER T), and timePart.
  1408. result.append('T');
  1409. result.append(time_part.string_view());
  1410. }
  1411. // 24. Return result.
  1412. return result.to_string();
  1413. }
  1414. }