boa_engine/builtins/temporal/zoneddatetime/mod.rs
1//! Boa's implementation of the ECMAScript `Temporal.ZonedDateTime` built-in object
2
3use std::str::FromStr;
4
5use crate::{
6 Context, JsArgs, JsBigInt, JsData, JsError, JsNativeError, JsObject, JsResult, JsString,
7 JsSymbol, JsValue, JsVariant,
8 builtins::{
9 BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject,
10 options::{get_option, get_options_object},
11 temporal::{calendar::to_temporal_calendar_identifier, options::get_digits_option},
12 },
13 context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors},
14 js_string,
15 object::internal_methods::get_prototype_from_constructor,
16 property::Attribute,
17 realm::Realm,
18 string::StaticJsStrings,
19 value::{IntoOrUndefined, PreferredType},
20};
21use boa_gc::{Finalize, Trace};
22use cow_utils::CowUtils;
23use icu_calendar::AnyCalendarKind;
24use temporal_rs::{
25 Calendar, MonthCode, TimeZone, TinyAsciiStr, UtcOffset, ZonedDateTime as ZonedDateTimeInner,
26 fields::{CalendarFields, ZonedDateTimeFields},
27 options::{
28 Disambiguation, DisplayCalendar, DisplayOffset, DisplayTimeZone, OffsetDisambiguation,
29 Overflow, RoundingIncrement, RoundingMode, RoundingOptions, ToStringRoundingOptions, Unit,
30 },
31 parsed_intermediates::ParsedZonedDateTime,
32 partial::{PartialTime, PartialZonedDateTime},
33 provider::TransitionDirection,
34};
35
36use super::{
37 calendar::get_temporal_calendar_slot_value_with_default,
38 create_temporal_date, create_temporal_datetime, create_temporal_duration,
39 create_temporal_instant, create_temporal_time, is_partial_temporal_object,
40 options::{TemporalUnitGroup, get_difference_settings, get_temporal_unit},
41 to_temporal_duration, to_temporal_time,
42};
43
44/// The `Temporal.ZonedDateTime` built-in implementation
45///
46/// More information:
47///
48/// - [ECMAScript Temporal proposal][spec]
49/// - [MDN reference][mdn]
50/// - [`temporal_rs` documentation][temporal_rs-docs]
51///
52/// [spec]: https://tc39.es/proposal-temporal/#sec-temporal-zoneddatetime-objects
53/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime
54/// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html
55#[derive(Debug, Clone, Trace, Finalize, JsData)]
56#[boa_gc(unsafe_empty_trace)] // Safety: Does not contain any traceable fields.
57pub struct ZonedDateTime {
58 pub(crate) inner: Box<ZonedDateTimeInner>,
59}
60
61impl ZonedDateTime {
62 pub(crate) fn new(inner: ZonedDateTimeInner) -> Self {
63 Self {
64 inner: Box::new(inner),
65 }
66 }
67}
68
69impl BuiltInObject for ZonedDateTime {
70 const NAME: JsString = StaticJsStrings::ZONED_DT_NAME;
71}
72
73impl IntrinsicObject for ZonedDateTime {
74 fn init(realm: &Realm) {
75 let get_calendar_id = BuiltInBuilder::callable(realm, Self::get_calendar_id)
76 .name(js_string!("get calendarId"))
77 .build();
78
79 let get_timezone_id = BuiltInBuilder::callable(realm, Self::get_timezone_id)
80 .name(js_string!("get timeZoneId"))
81 .build();
82
83 let get_era = BuiltInBuilder::callable(realm, Self::get_era)
84 .name(js_string!("get era"))
85 .build();
86
87 let get_era_year = BuiltInBuilder::callable(realm, Self::get_era_year)
88 .name(js_string!("get eraYear"))
89 .build();
90
91 let get_year = BuiltInBuilder::callable(realm, Self::get_year)
92 .name(js_string!("get year"))
93 .build();
94
95 let get_month = BuiltInBuilder::callable(realm, Self::get_month)
96 .name(js_string!("get month"))
97 .build();
98
99 let get_month_code = BuiltInBuilder::callable(realm, Self::get_month_code)
100 .name(js_string!("get monthCode"))
101 .build();
102
103 let get_day = BuiltInBuilder::callable(realm, Self::get_day)
104 .name(js_string!("get day"))
105 .build();
106
107 let get_hour = BuiltInBuilder::callable(realm, Self::get_hour)
108 .name(js_string!("get hour"))
109 .build();
110
111 let get_minute = BuiltInBuilder::callable(realm, Self::get_minute)
112 .name(js_string!("get minute"))
113 .build();
114
115 let get_second = BuiltInBuilder::callable(realm, Self::get_second)
116 .name(js_string!("get second"))
117 .build();
118
119 let get_millisecond = BuiltInBuilder::callable(realm, Self::get_millisecond)
120 .name(js_string!("get millisecond"))
121 .build();
122
123 let get_microsecond = BuiltInBuilder::callable(realm, Self::get_microsecond)
124 .name(js_string!("get microsecond"))
125 .build();
126
127 let get_nanosecond = BuiltInBuilder::callable(realm, Self::get_nanosecond)
128 .name(js_string!("get nanosecond"))
129 .build();
130
131 let get_epoch_milliseconds = BuiltInBuilder::callable(realm, Self::get_epoch_milliseconds)
132 .name(js_string!("get epochMilliseconds"))
133 .build();
134
135 let get_epoch_nanoseconds = BuiltInBuilder::callable(realm, Self::get_epoch_nanoseconds)
136 .name(js_string!("get epochNanoseconds"))
137 .build();
138
139 let get_day_of_week = BuiltInBuilder::callable(realm, Self::get_day_of_week)
140 .name(js_string!("get dayOfWeek"))
141 .build();
142
143 let get_day_of_year = BuiltInBuilder::callable(realm, Self::get_day_of_year)
144 .name(js_string!("get dayOfYear"))
145 .build();
146
147 let get_week_of_year = BuiltInBuilder::callable(realm, Self::get_week_of_year)
148 .name(js_string!("get weekOfYear"))
149 .build();
150
151 let get_hours_in_day = BuiltInBuilder::callable(realm, Self::get_hours_in_day)
152 .name(js_string!("get daysInWeek"))
153 .build();
154
155 let get_year_of_week = BuiltInBuilder::callable(realm, Self::get_year_of_week)
156 .name(js_string!("get yearOfWeek"))
157 .build();
158
159 let get_days_in_week = BuiltInBuilder::callable(realm, Self::get_days_in_week)
160 .name(js_string!("get daysInWeek"))
161 .build();
162
163 let get_days_in_month = BuiltInBuilder::callable(realm, Self::get_days_in_month)
164 .name(js_string!("get daysInMonth"))
165 .build();
166
167 let get_days_in_year = BuiltInBuilder::callable(realm, Self::get_days_in_year)
168 .name(js_string!("get daysInYear"))
169 .build();
170
171 let get_months_in_year = BuiltInBuilder::callable(realm, Self::get_months_in_year)
172 .name(js_string!("get monthsInYear"))
173 .build();
174
175 let get_in_leap_year = BuiltInBuilder::callable(realm, Self::get_in_leap_year)
176 .name(js_string!("get inLeapYear"))
177 .build();
178
179 let get_offset_nanos = BuiltInBuilder::callable(realm, Self::get_offset_nanoseconds)
180 .name(js_string!("get offsetNanoseconds"))
181 .build();
182
183 let get_offset = BuiltInBuilder::callable(realm, Self::get_offset)
184 .name(js_string!("get offset"))
185 .build();
186
187 BuiltInBuilder::from_standard_constructor::<Self>(realm)
188 .property(
189 JsSymbol::to_string_tag(),
190 StaticJsStrings::ZONED_DT_TAG,
191 Attribute::CONFIGURABLE,
192 )
193 .accessor(
194 js_string!("calendarId"),
195 Some(get_calendar_id),
196 None,
197 Attribute::CONFIGURABLE,
198 )
199 .accessor(
200 js_string!("timeZoneId"),
201 Some(get_timezone_id),
202 None,
203 Attribute::CONFIGURABLE,
204 )
205 .accessor(
206 js_string!("era"),
207 Some(get_era),
208 None,
209 Attribute::CONFIGURABLE,
210 )
211 .accessor(
212 js_string!("eraYear"),
213 Some(get_era_year),
214 None,
215 Attribute::CONFIGURABLE,
216 )
217 .accessor(
218 js_string!("year"),
219 Some(get_year),
220 None,
221 Attribute::CONFIGURABLE,
222 )
223 .accessor(
224 js_string!("month"),
225 Some(get_month),
226 None,
227 Attribute::CONFIGURABLE,
228 )
229 .accessor(
230 js_string!("monthCode"),
231 Some(get_month_code),
232 None,
233 Attribute::CONFIGURABLE,
234 )
235 .accessor(
236 js_string!("day"),
237 Some(get_day),
238 None,
239 Attribute::CONFIGURABLE,
240 )
241 .accessor(
242 js_string!("hour"),
243 Some(get_hour),
244 None,
245 Attribute::CONFIGURABLE,
246 )
247 .accessor(
248 js_string!("minute"),
249 Some(get_minute),
250 None,
251 Attribute::CONFIGURABLE,
252 )
253 .accessor(
254 js_string!("second"),
255 Some(get_second),
256 None,
257 Attribute::CONFIGURABLE,
258 )
259 .accessor(
260 js_string!("millisecond"),
261 Some(get_millisecond),
262 None,
263 Attribute::CONFIGURABLE,
264 )
265 .accessor(
266 js_string!("microsecond"),
267 Some(get_microsecond),
268 None,
269 Attribute::CONFIGURABLE,
270 )
271 .accessor(
272 js_string!("nanosecond"),
273 Some(get_nanosecond),
274 None,
275 Attribute::CONFIGURABLE,
276 )
277 .accessor(
278 js_string!("epochMilliseconds"),
279 Some(get_epoch_milliseconds),
280 None,
281 Attribute::CONFIGURABLE,
282 )
283 .accessor(
284 js_string!("epochNanoseconds"),
285 Some(get_epoch_nanoseconds),
286 None,
287 Attribute::CONFIGURABLE,
288 )
289 .accessor(
290 js_string!("dayOfWeek"),
291 Some(get_day_of_week),
292 None,
293 Attribute::CONFIGURABLE,
294 )
295 .accessor(
296 js_string!("dayOfYear"),
297 Some(get_day_of_year),
298 None,
299 Attribute::CONFIGURABLE,
300 )
301 .accessor(
302 js_string!("weekOfYear"),
303 Some(get_week_of_year),
304 None,
305 Attribute::CONFIGURABLE,
306 )
307 .accessor(
308 js_string!("yearOfWeek"),
309 Some(get_year_of_week),
310 None,
311 Attribute::CONFIGURABLE,
312 )
313 .accessor(
314 js_string!("hoursInDay"),
315 Some(get_hours_in_day),
316 None,
317 Attribute::CONFIGURABLE,
318 )
319 .accessor(
320 js_string!("daysInWeek"),
321 Some(get_days_in_week),
322 None,
323 Attribute::CONFIGURABLE,
324 )
325 .accessor(
326 js_string!("daysInMonth"),
327 Some(get_days_in_month),
328 None,
329 Attribute::CONFIGURABLE,
330 )
331 .accessor(
332 js_string!("daysInYear"),
333 Some(get_days_in_year),
334 None,
335 Attribute::CONFIGURABLE,
336 )
337 .accessor(
338 js_string!("monthsInYear"),
339 Some(get_months_in_year),
340 None,
341 Attribute::CONFIGURABLE,
342 )
343 .accessor(
344 js_string!("inLeapYear"),
345 Some(get_in_leap_year),
346 None,
347 Attribute::CONFIGURABLE,
348 )
349 .accessor(
350 js_string!("offsetNanoseconds"),
351 Some(get_offset_nanos),
352 None,
353 Attribute::CONFIGURABLE,
354 )
355 .accessor(
356 js_string!("offset"),
357 Some(get_offset),
358 None,
359 Attribute::CONFIGURABLE,
360 )
361 .static_method(Self::from, js_string!("from"), 1)
362 .static_method(Self::compare, js_string!("compare"), 2)
363 .method(Self::with, js_string!("with"), 1)
364 .method(Self::with_plain_time, js_string!("withPlainTime"), 0)
365 .method(Self::with_timezone, js_string!("withTimeZone"), 1)
366 .method(Self::with_calendar, js_string!("withCalendar"), 1)
367 .method(Self::add, js_string!("add"), 1)
368 .method(Self::subtract, js_string!("subtract"), 1)
369 .method(Self::until, js_string!("until"), 1)
370 .method(Self::since, js_string!("since"), 1)
371 .method(Self::round, js_string!("round"), 1)
372 .method(Self::equals, js_string!("equals"), 1)
373 .method(Self::to_string, js_string!("toString"), 0)
374 .method(Self::to_locale_string, js_string!("toLocaleString"), 0)
375 .method(Self::to_json, js_string!("toJSON"), 0)
376 .method(Self::value_of, js_string!("valueOf"), 0)
377 .method(Self::start_of_day, js_string!("startOfDay"), 0)
378 .method(
379 Self::get_time_zone_transition,
380 js_string!("getTimeZoneTransition"),
381 1,
382 )
383 .method(Self::to_instant, js_string!("toInstant"), 0)
384 .method(Self::to_plain_date, js_string!("toPlainDate"), 0)
385 .method(Self::to_plain_time, js_string!("toPlainTime"), 0)
386 .method(Self::to_plain_date_time, js_string!("toPlainDateTime"), 0)
387 .build();
388 }
389
390 fn get(intrinsics: &Intrinsics) -> JsObject {
391 Self::STANDARD_CONSTRUCTOR(intrinsics.constructors()).constructor()
392 }
393}
394
395impl BuiltInConstructor for ZonedDateTime {
396 const CONSTRUCTOR_ARGUMENTS: usize = 2;
397 const PROTOTYPE_STORAGE_SLOTS: usize = 77;
398 const CONSTRUCTOR_STORAGE_SLOTS: usize = 2;
399
400 const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor =
401 StandardConstructors::zoned_date_time;
402
403 fn constructor(
404 new_target: &JsValue,
405 args: &[JsValue],
406 context: &mut Context,
407 ) -> JsResult<JsValue> {
408 // 1. If NewTarget is undefined, then
409 if new_target.is_undefined() {
410 // a. Throw a TypeError exception.
411 return Err(JsNativeError::typ()
412 .with_message("NewTarget cannot be undefined.")
413 .into());
414 }
415 // 2. Set epochNanoseconds to ? ToBigInt(epochNanoseconds).
416 // 3. If IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
417 let epoch_nanos = args.get_or_undefined(0).to_bigint(context)?;
418
419 // 4. If timeZone is not a String, throw a TypeError exception.
420 let Some(timezone_str) = args.get_or_undefined(1).as_string() else {
421 return Err(JsNativeError::typ()
422 .with_message("timeZone must be a string.")
423 .into());
424 };
425
426 // 5. Let timeZoneParse be ? ParseTimeZoneIdentifier(timeZone).
427 // 6. If timeZoneParse.[[OffsetMinutes]] is empty, then
428 // a. Let identifierRecord be GetAvailableNamezdtimeZoneIdentifier(timeZoneParse.[[Name]]).
429 // b. If identifierRecord is empty, throw a RangeError exception.
430 // c. Set timeZone to identifierRecord.[[Identifier]].
431 // 7. Else,
432 // a. Set timeZone to FormatOffsetTimeZoneIdentifier(timeZoneParse.[[OffsetMinutes]]).
433 let timezone = TimeZone::try_from_identifier_str_with_provider(
434 &timezone_str.to_std_string_escaped(),
435 context.timezone_provider(),
436 )?;
437
438 // 8. If calendar is undefined, set calendar to "iso8601".
439 // 9. If calendar is not a String, throw a TypeError exception.
440 // 10. Set calendar to ? CanonicalizeCalendar(calendar).
441 let calendar = args
442 .get_or_undefined(2)
443 .map(|s| {
444 s.as_string()
445 .as_ref()
446 .map(JsString::to_std_string_lossy)
447 .ok_or_else(|| JsNativeError::typ().with_message("calendar must be a string."))
448 })
449 .transpose()?
450 .map(|s| Calendar::try_from_utf8(s.as_bytes()))
451 .transpose()?
452 .unwrap_or_default();
453
454 let inner = ZonedDateTimeInner::try_new_with_provider(
455 epoch_nanos.to_i128(),
456 timezone,
457 calendar,
458 context.timezone_provider(),
459 )?;
460
461 // 11. Return ? CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar, NewTarget).
462 create_temporal_zoneddatetime(inner, Some(new_target), context).map(Into::into)
463 }
464}
465
466// ==== `ZonedDateTime` accessor property methods ====
467
468impl ZonedDateTime {
469 /// 6.3.3 get `Temporal.ZonedDateTime.prototype.calendarId`
470 ///
471 /// More information:
472 ///
473 /// - [ECMAScript Temporal proposal][spec]
474 /// - [MDN reference][mdn]
475 /// - [`temporal_rs` documentation][temporal_rs-docs]
476 ///
477 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.calendarid
478 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/calendarId
479 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.calendar
480 fn get_calendar_id(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
481 let object = this.as_object();
482 let zdt = object
483 .as_ref()
484 .and_then(JsObject::downcast_ref::<Self>)
485 .ok_or_else(|| {
486 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
487 })?;
488
489 Ok(JsString::from(zdt.inner.calendar().identifier()).into())
490 }
491
492 /// 6.3.4 get `Temporal.ZonedDateTime.prototype.timeZoneId`
493 ///
494 /// More information:
495 ///
496 /// - [ECMAScript Temporal proposal][spec]
497 /// - [MDN reference][mdn]
498 /// - [`temporal_rs` documentation][temporal_rs-docs]
499 ///
500 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.timezoneid
501 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/timeZoneId
502 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.timezone
503 fn get_timezone_id(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
504 let object = this.as_object();
505 let zdt = object
506 .as_ref()
507 .and_then(JsObject::downcast_ref::<Self>)
508 .ok_or_else(|| {
509 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
510 })?;
511
512 Ok(JsString::from(
513 zdt.inner
514 .time_zone()
515 .identifier_with_provider(context.timezone_provider())?,
516 )
517 .into())
518 }
519
520 /// 6.3.5 get `Temporal.ZonedDateTime.prototype.era`
521 ///
522 /// More information:
523 ///
524 /// - [ECMAScript Temporal proposal][spec]
525 /// - [MDN reference][mdn]
526 /// - [`temporal_rs` documentation][temporal_rs-docs]
527 ///
528 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.era
529 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/era
530 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.era
531 fn get_era(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
532 let object = this.as_object();
533 let zdt = object
534 .as_ref()
535 .and_then(JsObject::downcast_ref::<Self>)
536 .ok_or_else(|| {
537 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
538 })?;
539
540 let era = zdt.inner.era();
541 Ok(era
542 .map(|tinystr| JsString::from(tinystr.cow_to_lowercase()))
543 .into_or_undefined())
544 }
545
546 /// 6.3.6 get `Temporal.ZonedDateTime.prototype.eraYear`
547 ///
548 /// More information:
549 ///
550 /// - [ECMAScript Temporal proposal][spec]
551 /// - [MDN reference][mdn]
552 /// - [`temporal_rs` documentation][temporal_rs-docs]
553 ///
554 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.erayear
555 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/eraYear
556 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.era_year
557 fn get_era_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
558 let object = this.as_object();
559 let zdt = object
560 .as_ref()
561 .and_then(JsObject::downcast_ref::<Self>)
562 .ok_or_else(|| {
563 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
564 })?;
565
566 Ok(zdt.inner.era_year().into_or_undefined())
567 }
568
569 /// 6.3.7 get `Temporal.ZonedDateTime.prototype.year`
570 ///
571 /// More information:
572 ///
573 /// - [ECMAScript Temporal proposal][spec]
574 /// - [MDN reference][mdn]
575 /// - [`temporal_rs` documentation][temporal_rs-docs]
576 ///
577 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.year
578 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/year
579 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.year
580 fn get_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
581 let object = this.as_object();
582 let zdt = object
583 .as_ref()
584 .and_then(JsObject::downcast_ref::<Self>)
585 .ok_or_else(|| {
586 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
587 })?;
588
589 Ok(zdt.inner.year().into())
590 }
591
592 /// 6.3.8 get `Temporal.ZonedDateTime.prototype.month`
593 ///
594 /// More information:
595 ///
596 /// - [ECMAScript Temporal proposal][spec]
597 /// - [MDN reference][mdn]
598 /// - [`temporal_rs` documentation][temporal_rs-docs]
599 ///
600 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.month
601 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/month
602 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.month
603 fn get_month(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
604 let object = this.as_object();
605 let zdt = object
606 .as_ref()
607 .and_then(JsObject::downcast_ref::<Self>)
608 .ok_or_else(|| {
609 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
610 })?;
611
612 Ok(zdt.inner.month().into())
613 }
614
615 /// 6.3.9 get `Temporal.ZonedDateTime.prototype.monthCode`
616 ///
617 /// More information:
618 ///
619 /// - [ECMAScript Temporal proposal][spec]
620 /// - [MDN reference][mdn]
621 /// - [`temporal_rs` documentation][temporal_rs-docs]
622 ///
623 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.monthcode
624 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/monthCode
625 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.month_code
626 fn get_month_code(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
627 let object = this.as_object();
628 let zdt = object
629 .as_ref()
630 .and_then(JsObject::downcast_ref::<Self>)
631 .ok_or_else(|| {
632 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
633 })?;
634
635 Ok(JsString::from(zdt.inner.month_code().as_str()).into())
636 }
637
638 /// 6.3.10 get `Temporal.ZonedDateTime.prototype.day`
639 ///
640 /// More information:
641 ///
642 /// - [ECMAScript Temporal proposal][spec]
643 /// - [MDN reference][mdn]
644 /// - [`temporal_rs` documentation][temporal_rs-docs]
645 ///
646 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.day
647 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/day
648 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.day
649 fn get_day(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
650 let object = this.as_object();
651 let zdt = object
652 .as_ref()
653 .and_then(JsObject::downcast_ref::<Self>)
654 .ok_or_else(|| {
655 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
656 })?;
657
658 Ok(zdt.inner.day().into())
659 }
660
661 /// 6.3.11 get `Temporal.ZonedDateTime.prototype.hour`
662 ///
663 /// More information:
664 ///
665 /// - [ECMAScript Temporal proposal][spec]
666 /// - [MDN reference][mdn]
667 /// - [`temporal_rs` documentation][temporal_rs-docs]
668 ///
669 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.hour
670 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/hour
671 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.hour
672 fn get_hour(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
673 let object = this.as_object();
674 let zdt = object
675 .as_ref()
676 .and_then(JsObject::downcast_ref::<Self>)
677 .ok_or_else(|| {
678 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
679 })?;
680
681 Ok(zdt.inner.hour().into())
682 }
683
684 /// 6.3.12 get `Temporal.ZonedDateTime.prototype.minute`
685 ///
686 /// More information:
687 ///
688 /// - [ECMAScript Temporal proposal][spec]
689 /// - [MDN reference][mdn]
690 /// - [`temporal_rs` documentation][temporal_rs-docs]
691 ///
692 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.minute
693 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/minute
694 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.minute
695 fn get_minute(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
696 let object = this.as_object();
697 let zdt = object
698 .as_ref()
699 .and_then(JsObject::downcast_ref::<Self>)
700 .ok_or_else(|| {
701 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
702 })?;
703
704 Ok(zdt.inner.minute().into())
705 }
706
707 /// 6.3.13 get `Temporal.ZonedDateTime.prototype.second`
708 ///
709 /// More information:
710 ///
711 /// - [ECMAScript Temporal proposal][spec]
712 /// - [MDN reference][mdn]
713 /// - [`temporal_rs` documentation][temporal_rs-docs]
714 ///
715 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.second
716 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/second
717 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.second
718 fn get_second(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
719 let object = this.as_object();
720 let zdt = object
721 .as_ref()
722 .and_then(JsObject::downcast_ref::<Self>)
723 .ok_or_else(|| {
724 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
725 })?;
726
727 Ok(zdt.inner.second().into())
728 }
729
730 /// 6.3.14 get `Temporal.ZonedDateTime.prototype.millisecond`
731 ///
732 /// More information:
733 ///
734 /// - [ECMAScript Temporal proposal][spec]
735 /// - [MDN reference][mdn]
736 /// - [`temporal_rs` documentation][temporal_rs-docs]
737 ///
738 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.millisecond
739 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/millisecond
740 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.millisecond
741 fn get_millisecond(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
742 let object = this.as_object();
743 let zdt = object
744 .as_ref()
745 .and_then(JsObject::downcast_ref::<Self>)
746 .ok_or_else(|| {
747 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
748 })?;
749
750 Ok(zdt.inner.millisecond().into())
751 }
752
753 /// 6.3.15 get `Temporal.ZonedDateTime.prototype.microsecond`
754 ///
755 /// More information:
756 ///
757 /// - [ECMAScript Temporal proposal][spec]
758 /// - [MDN reference][mdn]
759 /// - [`temporal_rs` documentation][temporal_rs-docs]
760 ///
761 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.microsecond
762 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/microsecond
763 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.microsecond
764 fn get_microsecond(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
765 let object = this.as_object();
766 let zdt = object
767 .as_ref()
768 .and_then(JsObject::downcast_ref::<Self>)
769 .ok_or_else(|| {
770 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
771 })?;
772
773 Ok(zdt.inner.microsecond().into())
774 }
775
776 /// 6.3.16 get `Temporal.ZonedDateTime.prototype.nanosecond`
777 ///
778 /// More information:
779 ///
780 /// - [ECMAScript Temporal proposal][spec]
781 /// - [MDN reference][mdn]
782 /// - [`temporal_rs` documentation][temporal_rs-docs]
783 ///
784 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.nanosecond
785 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/nanosecond
786 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.nanosecond
787 fn get_nanosecond(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
788 let object = this.as_object();
789 let zdt = object
790 .as_ref()
791 .and_then(JsObject::downcast_ref::<Self>)
792 .ok_or_else(|| {
793 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
794 })?;
795
796 Ok(zdt.inner.nanosecond().into())
797 }
798
799 /// 6.3.17 get `Temporal.ZonedDateTime.prototype.epochMilliseconds`
800 ///
801 /// More information:
802 ///
803 /// - [ECMAScript Temporal proposal][spec]
804 /// - [MDN reference][mdn]
805 /// - [`temporal_rs` documentation][temporal_rs-docs]
806 ///
807 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.epochmilliseconds
808 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/epochMilliseconds
809 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.epoch_milliseconds
810 fn get_epoch_milliseconds(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
811 let object = this.as_object();
812 let zdt = object
813 .as_ref()
814 .and_then(JsObject::downcast_ref::<Self>)
815 .ok_or_else(|| {
816 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
817 })?;
818
819 Ok(zdt.inner.epoch_milliseconds().into())
820 }
821
822 /// 6.3.18 get `Temporal.ZonedDateTime.prototype.epochNanoseconds`
823 ///
824 /// More information:
825 ///
826 /// - [ECMAScript Temporal proposal][spec]
827 /// - [MDN reference][mdn]
828 /// - [`temporal_rs` documentation][temporal_rs-docs]
829 ///
830 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.epochnanoseconds
831 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/epochNanoseconds
832 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.epoch_nanoseconds
833 fn get_epoch_nanoseconds(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
834 let object = this.as_object();
835 let zdt = object
836 .as_ref()
837 .and_then(JsObject::downcast_ref::<Self>)
838 .ok_or_else(|| {
839 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
840 })?;
841
842 Ok(JsBigInt::from(zdt.inner.epoch_nanoseconds().as_i128()).into())
843 }
844
845 /// 6.3.19 get `Temporal.ZonedDateTime.prototype.dayOfWeek`
846 ///
847 /// More information:
848 ///
849 /// - [ECMAScript Temporal proposal][spec]
850 /// - [MDN reference][mdn]
851 /// - [`temporal_rs` documentation][temporal_rs-docs]
852 ///
853 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.dayofweek
854 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/dayOfWeek
855 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.day_of_week
856 fn get_day_of_week(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
857 let object = this.as_object();
858 let zdt = object
859 .as_ref()
860 .and_then(JsObject::downcast_ref::<Self>)
861 .ok_or_else(|| {
862 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
863 })?;
864
865 Ok(zdt.inner.day_of_week().into())
866 }
867
868 /// 6.3.20 get `Temporal.ZonedDateTime.prototype.dayOfYear`
869 ///
870 /// More information:
871 ///
872 /// - [ECMAScript Temporal proposal][spec]
873 /// - [MDN reference][mdn]
874 /// - [`temporal_rs` documentation][temporal_rs-docs]
875 ///
876 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.dayofyear
877 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/dayOfYear
878 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.day_of_year
879 fn get_day_of_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
880 let object = this.as_object();
881 let zdt = object
882 .as_ref()
883 .and_then(JsObject::downcast_ref::<Self>)
884 .ok_or_else(|| {
885 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
886 })?;
887
888 Ok(zdt.inner.day_of_year().into())
889 }
890
891 /// 6.3.21 get `Temporal.ZonedDateTime.prototype.weekOfYear`
892 ///
893 /// More information:
894 ///
895 /// - [ECMAScript Temporal proposal][spec]
896 /// - [MDN reference][mdn]
897 /// - [`temporal_rs` documentation][temporal_rs-docs]
898 ///
899 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.weekofyear
900 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/weekOfYear
901 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.week_of_year
902 fn get_week_of_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
903 let object = this.as_object();
904 let zdt = object
905 .as_ref()
906 .and_then(JsObject::downcast_ref::<Self>)
907 .ok_or_else(|| {
908 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
909 })?;
910
911 Ok(zdt.inner.week_of_year().into_or_undefined())
912 }
913
914 /// 6.3.22 get `Temporal.ZonedDateTime.prototype.yearOfWeek`
915 ///
916 /// More information:
917 ///
918 /// - [ECMAScript Temporal proposal][spec]
919 /// - [MDN reference][mdn]
920 /// - [`temporal_rs` documentation][temporal_rs-docs]
921 ///
922 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.yearofweek
923 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/yearOfWeek
924 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.year_of_week
925 fn get_year_of_week(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
926 let object = this.as_object();
927 let zdt = object
928 .as_ref()
929 .and_then(JsObject::downcast_ref::<Self>)
930 .ok_or_else(|| {
931 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
932 })?;
933
934 Ok(zdt.inner.year_of_week().into_or_undefined())
935 }
936
937 /// 6.3.23 get `Temporal.ZonedDateTime.prototype.hoursInDay`
938 ///
939 /// More information:
940 ///
941 /// - [ECMAScript Temporal proposal][spec]
942 /// - [MDN reference][mdn]
943 /// - [`temporal_rs` documentation][temporal_rs-docs]
944 ///
945 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.hoursinday
946 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/hoursInDay
947 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.hours_in_day
948 fn get_hours_in_day(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
949 let object = this.as_object();
950 let zdt = object
951 .as_ref()
952 .and_then(JsObject::downcast_ref::<Self>)
953 .ok_or_else(|| {
954 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
955 })?;
956
957 Ok(zdt
958 .inner
959 .hours_in_day_with_provider(context.timezone_provider())?
960 .into())
961 }
962
963 /// 6.3.24 get `Temporal.ZonedDateTime.prototype.daysInWeek`
964 ///
965 /// More information:
966 ///
967 /// - [ECMAScript Temporal proposal][spec]
968 /// - [MDN reference][mdn]
969 /// - [`temporal_rs` documentation][temporal_rs-docs]
970 ///
971 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.daysinweek
972 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/daysInWeek
973 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.days_in_week
974 fn get_days_in_week(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
975 let object = this.as_object();
976 let zdt = object
977 .as_ref()
978 .and_then(JsObject::downcast_ref::<Self>)
979 .ok_or_else(|| {
980 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
981 })?;
982
983 Ok(zdt.inner.days_in_week().into())
984 }
985
986 /// 6.3.25 get `Temporal.ZonedDateTime.prototype.daysInMonth`
987 ///
988 /// More information:
989 ///
990 /// - [ECMAScript Temporal proposal][spec]
991 /// - [MDN reference][mdn]
992 /// - [`temporal_rs` documentation][temporal_rs-docs]
993 ///
994 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.daysinmonth
995 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/daysInMonth
996 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.days_in_month
997 fn get_days_in_month(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
998 let object = this.as_object();
999 let zdt = object
1000 .as_ref()
1001 .and_then(JsObject::downcast_ref::<Self>)
1002 .ok_or_else(|| {
1003 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1004 })?;
1005
1006 Ok(zdt.inner.days_in_month().into())
1007 }
1008
1009 /// 6.3.26 get `Temporal.ZonedDateTime.prototype.daysInYear`
1010 ///
1011 /// More information:
1012 ///
1013 /// - [ECMAScript Temporal proposal][spec]
1014 /// - [MDN reference][mdn]
1015 /// - [`temporal_rs` documentation][temporal_rs-docs]
1016 ///
1017 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.daysinyear
1018 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/daysInYear
1019 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.days_in_year
1020 fn get_days_in_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
1021 let object = this.as_object();
1022 let zdt = object
1023 .as_ref()
1024 .and_then(JsObject::downcast_ref::<Self>)
1025 .ok_or_else(|| {
1026 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1027 })?;
1028
1029 Ok(zdt.inner.days_in_year().into())
1030 }
1031
1032 /// 6.3.27 get `Temporal.ZonedDateTime.prototype.monthsInYear`
1033 ///
1034 /// More information:
1035 ///
1036 /// - [ECMAScript Temporal proposal][spec]
1037 /// - [MDN reference][mdn]
1038 /// - [`temporal_rs` documentation][temporal_rs-docs]
1039 ///
1040 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.monthsinyear
1041 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/monthsInYear
1042 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.months_in_year
1043 fn get_months_in_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
1044 let object = this.as_object();
1045 let zdt = object
1046 .as_ref()
1047 .and_then(JsObject::downcast_ref::<Self>)
1048 .ok_or_else(|| {
1049 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1050 })?;
1051
1052 Ok(zdt.inner.months_in_year().into())
1053 }
1054
1055 /// 6.3.28 get `Temporal.ZonedDateTime.prototype.inLeapYear`
1056 ///
1057 /// More information:
1058 ///
1059 /// - [ECMAScript Temporal proposal][spec]
1060 /// - [MDN reference][mdn]
1061 /// - [`temporal_rs` documentation][temporal_rs-docs]
1062 ///
1063 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.inleapyear
1064 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/inLeapYear
1065 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.in_leap_year
1066 fn get_in_leap_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
1067 let object = this.as_object();
1068 let zdt = object
1069 .as_ref()
1070 .and_then(JsObject::downcast_ref::<Self>)
1071 .ok_or_else(|| {
1072 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1073 })?;
1074
1075 Ok(zdt.inner.in_leap_year().into())
1076 }
1077
1078 /// 6.3.29 get Temporal.ZonedDateTime.prototype.offsetNanoseconds
1079 ///
1080 /// More information:
1081 ///
1082 /// - [ECMAScript Temporal proposal][spec]
1083 /// - [MDN reference][mdn]
1084 /// - [`temporal_rs` documentation][temporal_rs-docs]
1085 ///
1086 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.offsetnanoseconds
1087 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/offsetNanoseconds
1088 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.offset_nanoseconds
1089 fn get_offset_nanoseconds(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
1090 let object = this.as_object();
1091 let zdt = object
1092 .as_ref()
1093 .and_then(JsObject::downcast_ref::<Self>)
1094 .ok_or_else(|| {
1095 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1096 })?;
1097
1098 Ok(zdt.inner.offset_nanoseconds().into())
1099 }
1100
1101 /// 6.3.30 get Temporal.ZonedDateTime.prototype.offset
1102 ///
1103 /// More information:
1104 ///
1105 /// - [ECMAScript Temporal proposal][spec]
1106 /// - [MDN reference][mdn]
1107 /// - [`temporal_rs` documentation][temporal_rs-docs]
1108 ///
1109 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.zoneddatetime.prototype.offset
1110 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/offset
1111 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.offset
1112 fn get_offset(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
1113 let object = this.as_object();
1114 let zdt = object
1115 .as_ref()
1116 .and_then(JsObject::downcast_ref::<Self>)
1117 .ok_or_else(|| {
1118 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1119 })?;
1120
1121 Ok(JsString::from(zdt.inner.offset()).into())
1122 }
1123}
1124
1125// ==== `ZonedDateTime` static methods implementation ====
1126
1127impl ZonedDateTime {
1128 /// 6.2.2 `Temporal.ZonedDateTime.from ( item [ , options ] )`
1129 ///
1130 /// More information:
1131 ///
1132 /// - [ECMAScript Temporal proposal][spec]
1133 /// - [MDN reference][mdn]
1134 ///
1135 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.from
1136 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/from
1137 fn from(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1138 // 1. Return ? ToTemporalZonedDateTime(item, options).
1139 let item = args.get_or_undefined(0);
1140 let options = args.get(1);
1141 let inner = to_temporal_zoneddatetime(item, options, context)?;
1142 create_temporal_zoneddatetime(inner, None, context).map(Into::into)
1143 }
1144
1145 /// 6.2.3 `Temporal.ZonedDateTime.compare ( one, two )`
1146 ///
1147 /// More information:
1148 ///
1149 /// - [ECMAScript Temporal proposal][spec]
1150 /// - [MDN reference][mdn]
1151 /// - [`temporal_rs` documentation][temporal_rs-docs]
1152 ///
1153 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.compare
1154 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/compare
1155 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.compare_instant
1156 fn compare(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1157 // 1. Return ? ToTemporalZonedDateTime(item, options).
1158 let one = to_temporal_zoneddatetime(args.get_or_undefined(0), None, context)?;
1159 let two = to_temporal_zoneddatetime(args.get_or_undefined(1), None, context)?;
1160 Ok((one.compare_instant(&two) as i8).into())
1161 }
1162}
1163
1164// ==== `ZonedDateTime` methods implementation ====
1165
1166impl ZonedDateTime {
1167 /// 6.3.31 `Temporal.ZonedDateTime.prototype.with ( temporalZonedDateTimeLike [ , options ] )`
1168 ///
1169 /// More information:
1170 ///
1171 /// - [ECMAScript Temporal proposal][spec]
1172 /// - [MDN reference][mdn]
1173 /// - [`temporal_rs` documentation][temporal_rs-docs]
1174 ///
1175 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.with
1176 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/with
1177 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.with
1178 fn with(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1179 // 1. Let zonedDateTime be the this value.
1180 // 2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
1181 let object = this.as_object();
1182 let zdt = object
1183 .as_ref()
1184 .and_then(JsObject::downcast_ref::<Self>)
1185 .ok_or_else(|| {
1186 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1187 })?;
1188 // 3. If ? IsPartialTemporalObject(temporalZonedDateTimeLike) is false, throw a TypeError exception.
1189 let Some(obj) = is_partial_temporal_object(args.get_or_undefined(0), context)? else {
1190 return Err(JsNativeError::typ()
1191 .with_message("temporalZonedDateTimeLike was not a partial object")
1192 .into());
1193 };
1194 // 4. Let epochNs be zonedDateTime.[[EpochNanoseconds]].
1195 // 5. Let timeZone be zonedDateTime.[[TimeZone]].
1196 // 6. Let calendar be zonedDateTime.[[Calendar]].
1197 // 7. Let offsetNanoseconds be GetOffsetNanosecondsFor(timeZone, epochNs).
1198 // 8. Let isoDateTime be GetISODateTimeFor(timeZone, epochNs).
1199 // 9. Let fields be ISODateToFields(calendar, isoDateTime.[[ISODate]], date).
1200 // 10. Set fields.[[Hour]] to isoDateTime.[[Time]].[[Hour]].
1201 // 11. Set fields.[[Minute]] to isoDateTime.[[Time]].[[Minute]].
1202 // 12. Set fields.[[Second]] to isoDateTime.[[Time]].[[Second]].
1203 // 13. Set fields.[[Millisecond]] to isoDateTime.[[Time]].[[Millisecond]].
1204 // 14. Set fields.[[Microsecond]] to isoDateTime.[[Time]].[[Microsecond]].
1205 // 15. Set fields.[[Nanosecond]] to isoDateTime.[[Time]].[[Nanosecond]].
1206 // 16. Set fields.[[OffsetString]] to FormatUTCOffsetNanoseconds(offsetNanoseconds).
1207 // 17. Let partialZonedDateTime be ? PrepareCalendarFields(calendar, temporalZonedDateTimeLike, « year, month, month-code, day », « hour, minute, second, millisecond, microsecond, nanosecond, offset », partial).
1208 // 18. Set fields to CalendarMergeFields(calendar, fields, partialZonedDateTime).
1209 let (fields, _) = to_zoned_date_time_fields(
1210 &obj,
1211 zdt.inner.calendar(),
1212 ZdtFieldsType::NoTimeZone,
1213 context,
1214 )?;
1215
1216 // 19. Let resolvedOptions be ? GetOptionsObject(options).
1217 let resolved_options = get_options_object(args.get_or_undefined(1))?;
1218 // 20. Let disambiguation be ? GetTemporalDisambiguationOption(resolvedOptions).
1219 let disambiguation =
1220 get_option::<Disambiguation>(&resolved_options, js_string!("disambiguation"), context)?;
1221 // 21. Let offset be ? GetTemporalOffsetOption(resolvedOptions, prefer).
1222 let offset =
1223 get_option::<OffsetDisambiguation>(&resolved_options, js_string!("offset"), context)?;
1224 // 22. Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
1225 let overflow = get_option::<Overflow>(&resolved_options, js_string!("overflow"), context)?;
1226
1227 let result = zdt.inner.with_with_provider(
1228 fields,
1229 disambiguation,
1230 offset,
1231 overflow,
1232 context.timezone_provider(),
1233 )?;
1234 create_temporal_zoneddatetime(result, None, context).map(Into::into)
1235 }
1236
1237 /// 6.3.32 `Temporal.ZonedDateTime.prototype.withPlainTime ( [ plainTimeLike ] )`
1238 ///
1239 /// More information:
1240 ///
1241 /// - [ECMAScript Temporal proposal][spec]
1242 /// - [MDN reference][mdn]
1243 /// - [`temporal_rs` documentation][temporal_rs-docs]
1244 ///
1245 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.withPlainTime
1246 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/withPlainTime
1247 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.with_plain_time
1248 fn with_plain_time(
1249 this: &JsValue,
1250 args: &[JsValue],
1251 context: &mut Context,
1252 ) -> JsResult<JsValue> {
1253 let object = this.as_object();
1254 let zdt = object
1255 .as_ref()
1256 .and_then(JsObject::downcast_ref::<Self>)
1257 .ok_or_else(|| {
1258 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1259 })?;
1260
1261 let time = args
1262 .get_or_undefined(0)
1263 .map(|v| to_temporal_time(v, None, context))
1264 .transpose()?;
1265
1266 let inner = zdt
1267 .inner
1268 .with_plain_time_and_provider(time, context.timezone_provider())?;
1269 create_temporal_zoneddatetime(inner, None, context).map(Into::into)
1270 }
1271
1272 /// 6.3.33 `Temporal.ZonedDateTime.prototype.withTimeZone ( timeZoneLike )`
1273 ///
1274 /// More information:
1275 ///
1276 /// - [ECMAScript Temporal proposal][spec]
1277 /// - [MDN reference][mdn]
1278 /// - [`temporal_rs` documentation][temporal_rs-docs]
1279 ///
1280 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.withtimezone
1281 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/withTimeZone
1282 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.with_timezone
1283 fn with_timezone(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1284 let object = this.as_object();
1285 let zdt = object
1286 .as_ref()
1287 .and_then(JsObject::downcast_ref::<Self>)
1288 .ok_or_else(|| {
1289 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1290 })?;
1291
1292 let timezone = to_temporal_timezone_identifier(args.get_or_undefined(0), context)?;
1293
1294 let inner = zdt
1295 .inner
1296 .with_time_zone_with_provider(timezone, context.timezone_provider())?;
1297 create_temporal_zoneddatetime(inner, None, context).map(Into::into)
1298 }
1299
1300 /// 6.3.34 `Temporal.ZonedDateTime.prototype.withCalendar ( calendarLike )`
1301 ///
1302 /// More information:
1303 ///
1304 /// - [ECMAScript Temporal proposal][spec]
1305 /// - [MDN reference][mdn]
1306 /// - [`temporal_rs` documentation][temporal_rs-docs]
1307 ///
1308 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.withcalendar
1309 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/withCalendar
1310 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.with_calendar
1311 fn with_calendar(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1312 let object = this.as_object();
1313 let zdt = object
1314 .as_ref()
1315 .and_then(JsObject::downcast_ref::<Self>)
1316 .ok_or_else(|| {
1317 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1318 })?;
1319
1320 let calendar = to_temporal_calendar_identifier(args.get_or_undefined(0))?;
1321
1322 let inner = zdt.inner.with_calendar(calendar);
1323 create_temporal_zoneddatetime(inner, None, context).map(Into::into)
1324 }
1325
1326 /// 6.3.35 `Temporal.ZonedDateTime.prototype.add ( temporalDurationLike [ , options ] )`
1327 ///
1328 /// More information:
1329 ///
1330 /// - [ECMAScript Temporal proposal][spec]
1331 /// - [MDN reference][mdn]
1332 /// - [`temporal_rs` documentation][temporal_rs-docs]
1333 ///
1334 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.add
1335 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/add
1336 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.add
1337 fn add(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1338 let object = this.as_object();
1339 let zdt = object
1340 .as_ref()
1341 .and_then(JsObject::downcast_ref::<Self>)
1342 .ok_or_else(|| {
1343 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1344 })?;
1345
1346 let duration = to_temporal_duration(args.get_or_undefined(0), context)?;
1347
1348 let options = get_options_object(args.get_or_undefined(1))?;
1349 let overflow = get_option::<Overflow>(&options, js_string!("overflow"), context)?;
1350
1351 let result =
1352 zdt.inner
1353 .add_with_provider(&duration, overflow, context.timezone_provider())?;
1354 create_temporal_zoneddatetime(result, None, context).map(Into::into)
1355 }
1356
1357 /// 6.3.36 `Temporal.ZonedDateTime.prototype.subtract ( temporalDurationLike [ , options ] )`
1358 ///
1359 /// More information:
1360 ///
1361 /// - [ECMAScript Temporal proposal][spec]
1362 /// - [MDN reference][mdn]
1363 /// - [`temporal_rs` documentation][temporal_rs-docs]
1364 ///
1365 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.subtract
1366 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/subtract
1367 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.subtract
1368 fn subtract(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1369 let object = this.as_object();
1370 let zdt = object
1371 .as_ref()
1372 .and_then(JsObject::downcast_ref::<Self>)
1373 .ok_or_else(|| {
1374 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1375 })?;
1376
1377 let duration = to_temporal_duration(args.get_or_undefined(0), context)?;
1378
1379 let options = get_options_object(args.get_or_undefined(1))?;
1380 let overflow = get_option::<Overflow>(&options, js_string!("overflow"), context)?;
1381
1382 let result =
1383 zdt.inner
1384 .subtract_with_provider(&duration, overflow, context.timezone_provider())?;
1385 create_temporal_zoneddatetime(result, None, context).map(Into::into)
1386 }
1387
1388 /// 6.3.37 `Temporal.ZonedDateTime.prototype.until ( other [ , options ] )`
1389 ///
1390 /// More information:
1391 ///
1392 /// - [ECMAScript Temporal proposal][spec]
1393 /// - [MDN reference][mdn]
1394 /// - [`temporal_rs` documentation][temporal_rs-docs]
1395 ///
1396 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.until
1397 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/until
1398 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.until
1399 fn until(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1400 let object = this.as_object();
1401 let zdt = object
1402 .as_ref()
1403 .and_then(JsObject::downcast_ref::<Self>)
1404 .ok_or_else(|| {
1405 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1406 })?;
1407
1408 let other = to_temporal_zoneddatetime(args.get_or_undefined(0), None, context)?;
1409
1410 let options = get_options_object(args.get_or_undefined(1))?;
1411 let settings = get_difference_settings(&options, context)?;
1412
1413 let result =
1414 zdt.inner
1415 .until_with_provider(&other, settings, context.timezone_provider())?;
1416 create_temporal_duration(result, None, context).map(Into::into)
1417 }
1418
1419 /// 6.3.38 `Temporal.ZonedDateTime.prototype.since ( other [ , options ] )`
1420 ///
1421 /// More information:
1422 ///
1423 /// - [ECMAScript Temporal proposal][spec]
1424 /// - [MDN reference][mdn]
1425 /// - [`temporal_rs` documentation][temporal_rs-docs]
1426 ///
1427 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.since
1428 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/since
1429 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.since
1430 fn since(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1431 let object = this.as_object();
1432 let zdt = object
1433 .as_ref()
1434 .and_then(JsObject::downcast_ref::<Self>)
1435 .ok_or_else(|| {
1436 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1437 })?;
1438
1439 let other = to_temporal_zoneddatetime(args.get_or_undefined(0), None, context)?;
1440
1441 let options = get_options_object(args.get_or_undefined(1))?;
1442 let settings = get_difference_settings(&options, context)?;
1443
1444 let result =
1445 zdt.inner
1446 .since_with_provider(&other, settings, context.timezone_provider())?;
1447 create_temporal_duration(result, None, context).map(Into::into)
1448 }
1449
1450 /// 6.3.39 `Temporal.ZonedDateTime.prototype.round ( roundTo )`
1451 ///
1452 /// More information:
1453 ///
1454 /// - [ECMAScript Temporal proposal][spec]
1455 /// - [MDN reference][mdn]
1456 /// - [`temporal_rs` documentation][temporal_rs-docs]
1457 ///
1458 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.round
1459 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/round
1460 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.round
1461 fn round(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1462 // 1. Let zonedDateTime be the this value.
1463 // 2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
1464 let object = this.as_object();
1465 let zdt = object
1466 .as_ref()
1467 .and_then(JsObject::downcast_ref::<Self>)
1468 .ok_or_else(|| {
1469 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1470 })?;
1471
1472 // 3. If roundTo is undefined, then
1473 let round_to_arg = args.get_or_undefined(0);
1474 if round_to_arg.is_undefined() {
1475 // a. Throw a TypeError exception.
1476 return Err(JsNativeError::typ()
1477 .with_message("roundTo cannot be undefined.")
1478 .into());
1479 }
1480 // 4. If Type(roundTo) is String, then
1481 let round_to = if let Some(param_string) = round_to_arg.as_string() {
1482 // a. Let paramString be roundTo.
1483 let param_string = param_string.clone();
1484 // b. Set roundTo to OrdinaryObjectCreate(null).
1485 let new_round_to = JsObject::with_null_proto();
1486 // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString).
1487 new_round_to.create_data_property_or_throw(
1488 js_string!("smallestUnit"),
1489 param_string,
1490 context,
1491 )?;
1492 new_round_to
1493 } else {
1494 // 5. Else,
1495 // a. Set roundTo to ? GetOptionsObject(roundTo).
1496 get_options_object(round_to_arg)?
1497 };
1498
1499 // 6. NOTE: The following steps read options and perform independent validation
1500 // in alphabetical order (GetRoundingIncrementOption reads "roundingIncrement"
1501 // and GetRoundingModeOption reads "roundingMode").
1502 let mut options = RoundingOptions::default();
1503
1504 // 7. Let roundingIncrement be ? GetRoundingIncrementOption(roundTo).
1505 options.increment =
1506 get_option::<RoundingIncrement>(&round_to, js_string!("roundingIncrement"), context)?;
1507
1508 // 8. Let roundingMode be ? GetRoundingModeOption(roundTo, half-expand).
1509 options.rounding_mode =
1510 get_option::<RoundingMode>(&round_to, js_string!("roundingMode"), context)?;
1511
1512 // 9. Let smallestUnit be ? GetTemporalUnitValuedOption(roundTo, "smallestUnit", time, required, « day »).
1513 options.smallest_unit = get_temporal_unit(
1514 &round_to,
1515 js_string!("smallestUnit"),
1516 TemporalUnitGroup::Time,
1517 Some(vec![Unit::Day]),
1518 context,
1519 )?;
1520
1521 let result = zdt
1522 .inner
1523 .round_with_provider(options, context.timezone_provider())?;
1524 create_temporal_zoneddatetime(result, None, context).map(Into::into)
1525 }
1526
1527 /// 6.3.40 `Temporal.ZonedDateTime.prototype.equals ( other )`
1528 ///
1529 /// More information:
1530 ///
1531 /// - [ECMAScript Temporal proposal][spec]
1532 /// - [MDN reference][mdn]
1533 /// - [`temporal_rs` documentation][temporal_rs-docs]
1534 ///
1535 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.equals
1536 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/equals
1537 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#impl-PartialEq-for-ZonedDateTime
1538 fn equals(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1539 let object = this.as_object();
1540 let zdt = object
1541 .as_ref()
1542 .and_then(JsObject::downcast_ref::<Self>)
1543 .ok_or_else(|| {
1544 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1545 })?;
1546
1547 let other = to_temporal_zoneddatetime(args.get_or_undefined(0), None, context)?;
1548 Ok(zdt
1549 .inner
1550 .equals_with_provider(&other, context.timezone_provider())?
1551 .into())
1552 }
1553
1554 /// 6.3.41 `Temporal.ZonedDateTime.prototype.toString ( [ options ] )`
1555 ///
1556 /// More information:
1557 ///
1558 /// - [ECMAScript Temporal proposal][spec]
1559 /// - [MDN reference][mdn]
1560 /// - [`temporal_rs` documentation][temporal_rs-docs]
1561 ///
1562 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.tostring
1563 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toString
1564 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.to_ixdtf_string
1565 fn to_string(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1566 let object = this.as_object();
1567 let zdt = object
1568 .as_ref()
1569 .and_then(JsObject::downcast_ref::<Self>)
1570 .ok_or_else(|| {
1571 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1572 })?;
1573
1574 let options = get_options_object(args.get_or_undefined(0))?;
1575
1576 let show_calendar =
1577 get_option::<DisplayCalendar>(&options, js_string!("calendarName"), context)?
1578 .unwrap_or(DisplayCalendar::Auto);
1579 let precision = get_digits_option(&options, context)?;
1580 let show_offset = get_option::<DisplayOffset>(&options, js_string!("offset"), context)?
1581 .unwrap_or(DisplayOffset::Auto);
1582 let rounding_mode =
1583 get_option::<RoundingMode>(&options, js_string!("roundingMode"), context)?;
1584 let smallest_unit = get_option::<Unit>(&options, js_string!("smallestUnit"), context)?;
1585 // NOTE: There may be an order-of-operations here due to a check on Unit groups and smallest_unit value.
1586 let display_timezone =
1587 get_option::<DisplayTimeZone>(&options, js_string!("timeZoneName"), context)?
1588 .unwrap_or(DisplayTimeZone::Auto);
1589
1590 let options = ToStringRoundingOptions {
1591 precision,
1592 smallest_unit,
1593 rounding_mode,
1594 };
1595 let ixdtf = zdt.inner.to_ixdtf_string_with_provider(
1596 show_offset,
1597 display_timezone,
1598 show_calendar,
1599 options,
1600 context.timezone_provider(),
1601 )?;
1602
1603 Ok(JsString::from(ixdtf).into())
1604 }
1605
1606 /// 6.3.42 `Temporal.ZonedDateTime.prototype.toLocaleString ( [ locales [ , options ] ] )`
1607 ///
1608 /// More information:
1609 ///
1610 /// - [ECMAScript Temporal proposal][spec]
1611 /// - [MDN reference][mdn]
1612 ///
1613 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.tolocalestring
1614 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toLocaleString
1615 fn to_locale_string(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1616 // TODO: Update for ECMA-402 compliance
1617 let object = this.as_object();
1618 let zdt = object
1619 .as_ref()
1620 .and_then(JsObject::downcast_ref::<Self>)
1621 .ok_or_else(|| {
1622 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1623 })?;
1624
1625 let ixdtf = zdt.inner.to_ixdtf_string_with_provider(
1626 DisplayOffset::Auto,
1627 DisplayTimeZone::Auto,
1628 DisplayCalendar::Auto,
1629 ToStringRoundingOptions::default(),
1630 context.timezone_provider(),
1631 )?;
1632
1633 Ok(JsString::from(ixdtf).into())
1634 }
1635
1636 /// 6.3.43 `Temporal.ZonedDateTime.prototype.toJSON ( )`
1637 ///
1638 /// More information:
1639 ///
1640 /// - [ECMAScript Temporal proposal][spec]
1641 /// - [MDN reference][mdn]
1642 ///
1643 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.tojson
1644 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toJSON
1645 fn to_json(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1646 let object = this.as_object();
1647 let zdt = object
1648 .as_ref()
1649 .and_then(JsObject::downcast_ref::<Self>)
1650 .ok_or_else(|| {
1651 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1652 })?;
1653
1654 let ixdtf = zdt.inner.to_ixdtf_string_with_provider(
1655 DisplayOffset::Auto,
1656 DisplayTimeZone::Auto,
1657 DisplayCalendar::Auto,
1658 ToStringRoundingOptions::default(),
1659 context.timezone_provider(),
1660 )?;
1661
1662 Ok(JsString::from(ixdtf).into())
1663 }
1664
1665 /// 6.3.44 `Temporal.ZonedDateTime.prototype.valueOf ( )`
1666 ///
1667 /// More information:
1668 ///
1669 /// - [ECMAScript Temporal proposal][spec]
1670 /// - [MDN reference][mdn]
1671 ///
1672 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.valueof
1673 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/valueOf
1674 pub(crate) fn value_of(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
1675 Err(JsNativeError::typ()
1676 .with_message("`valueOf` not supported by Temporal built-ins. See 'compare', 'equals', or `toString`")
1677 .into())
1678 }
1679
1680 /// 6.3.45 `Temporal.ZonedDateTime.prototype.startOfDay ( )`
1681 ///
1682 /// More information:
1683 ///
1684 /// - [ECMAScript Temporal proposal][spec]
1685 /// - [MDN reference][mdn]
1686 /// - [`temporal_rs` documentation][temporal_rs-docs]
1687 ///
1688 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.startofday
1689 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/startOfDay
1690 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.start_of_day
1691 fn start_of_day(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1692 let object = this.as_object();
1693 let zdt = object
1694 .as_ref()
1695 .and_then(JsObject::downcast_ref::<Self>)
1696 .ok_or_else(|| {
1697 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1698 })?;
1699
1700 let new = zdt
1701 .inner
1702 .start_of_day_with_provider(context.timezone_provider())?;
1703 create_temporal_zoneddatetime(new, None, context).map(Into::into)
1704 }
1705
1706 /// 6.3.46 `Temporal.ZonedDateTime.prototype.getTimeZoneTransition ( directionParam )`
1707 ///
1708 /// More information:
1709 ///
1710 /// - [ECMAScript Temporal proposal][spec]
1711 /// - [MDN reference][mdn]
1712 /// - [`temporal_rs` documentation][temporal_rs-docs]
1713 ///
1714 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.gettimezonetransition
1715 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/getTimeZoneTransition
1716 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.get_time_zone_transition_with_provider
1717 fn get_time_zone_transition(
1718 this: &JsValue,
1719 args: &[JsValue],
1720 context: &mut Context,
1721 ) -> JsResult<JsValue> {
1722 // 1. Let zonedDateTime be the this value.
1723 // 2. Perform ? RequireInternalSlot(zonedDateTime, [[InitializedTemporalZonedDateTime]]).
1724 // 3. Let timeZone be zonedDateTime.[[TimeZone]].
1725 let object = this.as_object();
1726 let zdt = object
1727 .as_ref()
1728 .and_then(JsObject::downcast_ref::<Self>)
1729 .ok_or_else(|| {
1730 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1731 })?;
1732
1733 let direction_param = args.get_or_undefined(0);
1734 // 4. If directionParam is undefined, throw a TypeError exception.
1735 if direction_param.is_undefined() {
1736 return Err(JsNativeError::typ()
1737 .with_message("getTimeZoneTransition directionParam cannot be undefined.")
1738 .into());
1739 }
1740 // 5. If directionParam is a String, then
1741 let options_obj = if let Some(param_str) = direction_param.as_string() {
1742 // a. Let paramString be directionParam.
1743 // b. Set directionParam to OrdinaryObjectCreate(null).
1744 let obj = JsObject::with_null_proto();
1745 // c. Perform ! CreateDataPropertyOrThrow(directionParam, "direction", paramString).
1746 obj.create_data_property_or_throw(
1747 js_string!("direction"),
1748 JsValue::from(param_str.clone()),
1749 context,
1750 )?;
1751 obj
1752 // 6. Else,
1753 } else {
1754 // a. Set directionParam to ? GetOptionsObject(directionParam).
1755 get_options_object(direction_param)?
1756 };
1757
1758 // TODO: step 7
1759 // 7. Let direction be ? GetDirectionOption(directionParam).
1760 let direction =
1761 get_option::<TransitionDirection>(&options_obj, js_string!("direction"), context)?
1762 .ok_or_else(|| {
1763 JsNativeError::range().with_message("direction option is required.")
1764 })?;
1765
1766 // Step 8-12
1767 let result = zdt
1768 .inner
1769 .get_time_zone_transition_with_provider(direction, context.timezone_provider())?;
1770
1771 match result {
1772 Some(zdt) => create_temporal_zoneddatetime(zdt, None, context).map(Into::into),
1773 None => Ok(JsValue::null()),
1774 }
1775 }
1776
1777 /// 6.3.47 `Temporal.ZonedDateTime.prototype.toInstant ( )`
1778 ///
1779 /// More information:
1780 ///
1781 /// - [ECMAScript Temporal proposal][spec]
1782 /// - [MDN reference][mdn]
1783 /// - [`temporal_rs` documentation][temporal_rs-docs]
1784 ///
1785 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.toinstant
1786 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toInstant
1787 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.to_instant
1788 fn to_instant(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1789 let object = this.as_object();
1790 let zdt = object
1791 .as_ref()
1792 .and_then(JsObject::downcast_ref::<Self>)
1793 .ok_or_else(|| {
1794 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1795 })?;
1796
1797 create_temporal_instant(zdt.inner.to_instant(), None, context)
1798 }
1799
1800 /// 6.3.48 `Temporal.ZonedDateTime.prototype.toPlainDate ( )`
1801 ///
1802 /// More information:
1803 ///
1804 /// - [ECMAScript Temporal proposal][spec]
1805 /// - [MDN reference][mdn]
1806 /// - [`temporal_rs` documentation][temporal_rs-docs]
1807 ///
1808 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.toplaindate
1809 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toPlainDate
1810 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.to_plain_date
1811 fn to_plain_date(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1812 let object = this.as_object();
1813 let zdt = object
1814 .as_ref()
1815 .and_then(JsObject::downcast_ref::<Self>)
1816 .ok_or_else(|| {
1817 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1818 })?;
1819
1820 let inner = zdt.inner.to_plain_date();
1821 create_temporal_date(inner, None, context).map(Into::into)
1822 }
1823
1824 /// 6.3.49 `Temporal.ZonedDateTime.prototype.toPlainTime ( )`
1825 ///
1826 /// More information:
1827 ///
1828 /// - [ECMAScript Temporal proposal][spec]
1829 /// - [MDN reference][mdn]
1830 /// - [`temporal_rs` documentation][temporal_rs-docs]
1831 ///
1832 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.toplaintime
1833 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toPlainTime
1834 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.to_plain_time
1835 fn to_plain_time(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1836 let object = this.as_object();
1837 let zdt = object
1838 .as_ref()
1839 .and_then(JsObject::downcast_ref::<Self>)
1840 .ok_or_else(|| {
1841 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1842 })?;
1843
1844 let new = zdt.inner.to_plain_time();
1845 create_temporal_time(new, None, context).map(Into::into)
1846 }
1847
1848 /// 6.3.50 `Temporal.ZonedDateTime.prototype.toPlainDateTime ( )`
1849 ///
1850 /// More information:
1851 ///
1852 /// - [ECMAScript Temporal proposal][spec]
1853 /// - [MDN reference][mdn]
1854 /// - [`temporal_rs` documentation][temporal_rs-docs]
1855 ///
1856 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.zoneddatetime.prototype.toplaindatetime
1857 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toPlainDateTime
1858 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.ZonedDateTime.html#method.to_plain_datetime
1859 fn to_plain_date_time(
1860 this: &JsValue,
1861 _: &[JsValue],
1862 context: &mut Context,
1863 ) -> JsResult<JsValue> {
1864 let object = this.as_object();
1865 let zdt = object
1866 .as_ref()
1867 .and_then(JsObject::downcast_ref::<Self>)
1868 .ok_or_else(|| {
1869 JsNativeError::typ().with_message("the this object must be a ZonedDateTime object.")
1870 })?;
1871
1872 let new = zdt.inner.to_plain_date_time();
1873 create_temporal_datetime(new, None, context).map(Into::into)
1874 }
1875}
1876
1877// ==== ZonedDateTime Abstract Operations ====
1878
1879/// 6.5.3 `CreateTemporalZonedDateTime ( epochNanoseconds, timeZone, calendar [ , newTarget ] )`
1880pub(crate) fn create_temporal_zoneddatetime(
1881 inner: ZonedDateTimeInner,
1882 new_target: Option<&JsValue>,
1883 context: &mut Context,
1884) -> JsResult<JsObject> {
1885 // 1. Assert: IsValidEpochNanoseconds(epochNanoseconds) is true.
1886 // 2. If newTarget is not present, set newTarget to %Temporal.ZonedDateTime%.
1887 let new_target = new_target.cloned().unwrap_or(
1888 context
1889 .realm()
1890 .intrinsics()
1891 .constructors()
1892 .zoned_date_time()
1893 .constructor()
1894 .into(),
1895 );
1896 // 3. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.ZonedDateTime.prototype%", « [[InitializezdtemporalZonedDateTime]], [[EpochNanoseconds]], [[TimeZone]], [[Calendar]] »).
1897 let prototype = get_prototype_from_constructor(
1898 &new_target,
1899 StandardConstructors::zoned_date_time,
1900 context,
1901 )?;
1902 // 4. Set object.[[EpochNanoseconds]] to epochNanoseconds.
1903 // 5. Set object.[[TimeZone]] to timeZone.
1904 // 6. Set object.[[Calendar]] to calendar.
1905 let obj = JsObject::from_proto_and_data(prototype, ZonedDateTime::new(inner));
1906
1907 // 7. Return object.
1908 Ok(obj)
1909}
1910
1911/// 6.5.2 `ToTemporalZonedDateTime ( item [ , options ] )`
1912pub(crate) fn to_temporal_zoneddatetime(
1913 value: &JsValue,
1914 options: Option<&JsValue>,
1915 context: &mut Context,
1916) -> JsResult<ZonedDateTimeInner> {
1917 // 1. If options is not present, set options to undefined.
1918 // 2. Let offsetBehaviour be option.
1919 // 3. Let matchBehaviour be match-exactly.
1920 // 4. If item is an Object, then
1921 match value.variant() {
1922 JsVariant::Object(object) => {
1923 // a. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
1924 if let Some(zdt) = object.downcast_ref::<ZonedDateTime>() {
1925 // i. NOTE: The following steps, and similar ones below, read options
1926 // and perform independent validation in alphabetical order
1927 // (GetTemporalDisambiguationOption reads "disambiguation", GetTemporalOffsetOption
1928 // reads "offset", and GetTemporalOverflowOption reads "overflow").
1929 // ii. Let resolvedOptions be ? GetOptionsObject(options).
1930 let options = get_options_object(options.unwrap_or(&JsValue::undefined()))?;
1931 // iii. Perform ? GetTemporalDisambiguationOption(resolvedOptions).
1932 let _disambiguation =
1933 get_option::<Disambiguation>(&options, js_string!("disambiguation"), context)?
1934 .unwrap_or(Disambiguation::Compatible);
1935 // iv. Perform ? GetTemporalOffsetOption(resolvedOptions, reject).
1936 let _offset_option =
1937 get_option::<OffsetDisambiguation>(&options, js_string!("offset"), context)?
1938 .unwrap_or(OffsetDisambiguation::Reject);
1939 // v. Perform ? GetTemporalOverflowOption(resolvedOptions).
1940 let _overflow = get_option::<Overflow>(&options, js_string!("overflow"), context)?
1941 .unwrap_or_default();
1942 // vi. Return ! CreateTemporalZonedDateTime(item.[[EpochNanoseconds]], item.[[TimeZone]], item.[[Calendar]]).
1943 return Ok(zdt.inner.as_ref().clone());
1944 }
1945 let partial = to_partial_zoneddatetime(&object, context)?;
1946 // f. If offsetString is unset, the
1947 // i. Set offsetBehaviour to wall.
1948 // g. Let resolvedOptions be ? GetOptionsObject(options).
1949 let options = get_options_object(options.unwrap_or(&JsValue::undefined()))?;
1950 // h. Let disambiguation be ? GetTemporalDisambiguationOption(resolvedOptions).
1951 let disambiguation =
1952 get_option::<Disambiguation>(&options, js_string!("disambiguation"), context)?;
1953 // i. Let offsetOption be ? GetTemporalOffsetOption(resolvedOptions, reject).
1954 let offset_option =
1955 get_option::<OffsetDisambiguation>(&options, js_string!("offset"), context)?;
1956 // j. Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
1957 let overflow = get_option::<Overflow>(&options, js_string!("overflow"), context)?;
1958 // k. Let result be ? InterpretTemporalDateTimeFields(calendar, fields, overflow).
1959 // l. Let isoDate be result.[[ISODate]].
1960 // m. Let time be result.[[Time]].
1961 Ok(ZonedDateTimeInner::from_partial_with_provider(
1962 partial,
1963 overflow,
1964 disambiguation,
1965 offset_option,
1966 context.timezone_provider(),
1967 )?)
1968 }
1969 JsVariant::String(zdt_source) => {
1970 // b. Let result be ? ParseISODateTime(item, « TemporalDateTimeString[+Zoned] »).
1971 let parsed = ParsedZonedDateTime::from_utf8_with_provider(
1972 zdt_source.to_std_string_escaped().as_bytes(),
1973 context.timezone_provider(),
1974 )?;
1975 // c. Let annotation be result.[[TimeZone]].[[TimeZoneAnnotation]].
1976 // d. Assert: annotation is not empty.
1977 // e. Let timeZone be ? ToTemporalTimeZoneIdentifier(annotation).
1978 // f. Let offsetString be result.[[TimeZone]].[[OffsetString]].
1979 // g. If result.[[TimeZone]].[[Z]] is true, then
1980 // i. Set offsetBehaviour to exact.
1981 // h. Else if offsetString is empty, then
1982 // i. Set offsetBehaviour to wall.
1983 // i. Let calendar be result.[[Calendar]].
1984 // j. If calendar is empty, set calendar to "iso8601".
1985 // k. Set calendar to ? CanonicalizeCalendar(calendar).
1986 // l. Set matchBehaviour to match-minutes.
1987 // m. Let resolvedOptions be ? GetOptionsObject(options).
1988 let options = get_options_object(options.unwrap_or(&JsValue::undefined()))?;
1989 // n. Let disambiguation be ? GetTemporalDisambiguationOption(resolvedOptions).
1990 let disambiguation =
1991 get_option::<Disambiguation>(&options, js_string!("disambiguation"), context)?
1992 .unwrap_or(Disambiguation::Compatible);
1993 // o. Let offsetOption be ? GetTemporalOffsetOption(resolvedOptions, reject).
1994 let offset_option =
1995 get_option::<OffsetDisambiguation>(&options, js_string!("offset"), context)?
1996 .unwrap_or(OffsetDisambiguation::Reject);
1997 // p. Perform ? GetTemporalOverflowOption(resolvedOptions).
1998 let _overflow = get_option::<Overflow>(&options, js_string!("overflow"), context)?;
1999 // q. Let isoDate be CreateISODateRecord(result.[[Year]], result.[[Month]], result.[[Day]]).
2000 // r. Let time be result.[[Time]].
2001 // 6. Let offsetNanoseconds be 0.
2002 // 7. If offsetBehaviour is option, then
2003 // a. Set offsetNanoseconds to ! ParseDateTimeUTCOffset(offsetString).
2004 // 8. Let epochNanoseconds be ? InterpretISODateTimeOffset(isoDate, time, offsetBehaviour, offsetNanoseconds, timeZone, disambiguation, offsetOption, matchBehaviour).
2005 Ok(ZonedDateTimeInner::from_parsed_with_provider(
2006 parsed,
2007 disambiguation,
2008 offset_option,
2009 context.timezone_provider(),
2010 )?)
2011 }
2012 // 5. Else,
2013 // a. If item is not a String, throw a TypeError exception.
2014 _ => Err(JsNativeError::typ()
2015 .with_message("Temporal.ZonedDateTime.from only accepts an object or string.")
2016 .into()),
2017 }
2018 // 9. Return ! CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar).
2019}
2020
2021pub(crate) fn to_temporal_timezone_identifier(
2022 value: &JsValue,
2023 context: &mut Context,
2024) -> JsResult<TimeZone> {
2025 // 1. If temporalTimeZoneLike is an Object, then
2026 // a. If temporalTimeZoneLike has an [[InitializedTemporalZonedDateTime]] internal slot, then
2027 if let Some(obj) = value.as_object()
2028 && let Some(zdt) = obj.downcast_ref::<ZonedDateTime>()
2029 {
2030 // i. Return temporalTimeZoneLike.[[TimeZone]].
2031 return Ok(*zdt.inner.time_zone());
2032 }
2033
2034 // 2. If temporalTimeZoneLike is not a String, throw a TypeError exception.
2035 let Some(tz_string) = value.as_string() else {
2036 return Err(JsNativeError::typ()
2037 .with_message("timeZone must be a string or Temporal.ZonedDateTime")
2038 .into());
2039 };
2040
2041 // 3. Let parseResult be ? ParseTemporalTimeZoneString(temporalTimeZoneLike).
2042 // 4. Let offsetMinutes be parseResult.[[OffsetMinutes]].
2043 // 5. If offsetMinutes is not empty, return FormatOffsetTimeZoneIdentifier(offsetMinutes).
2044 // 6. Let name be parseResult.[[Name]].
2045 // 7. Let timeZoneIdentifierRecord be GetAvailableNamedTimeZoneIdentifier(name).
2046 // 8. If timeZoneIdentifierRecord is empty, throw a RangeError exception.
2047 // 9. Return timeZoneIdentifierRecord.[[Identifier]].
2048 let timezone = TimeZone::try_from_str_with_provider(
2049 &tz_string.to_std_string_escaped(),
2050 context.timezone_provider(),
2051 )?;
2052
2053 Ok(timezone)
2054}
2055
2056fn to_offset_string(value: &JsValue, context: &mut Context) -> JsResult<UtcOffset> {
2057 // 1. Let offset be ? ToPrimitive(argument, string).
2058 let offset = value.to_primitive(context, PreferredType::String)?;
2059 // 2. If offset is not a String, throw a TypeError exception.
2060 let Some(offset_string) = offset.as_string() else {
2061 return Err(JsNativeError::typ()
2062 .with_message("offset must be a String.")
2063 .into());
2064 };
2065 // 3. Perform ? ParseDateTimeUTCOffset(offset).
2066 let result = UtcOffset::from_str(&offset_string.to_std_string_escaped())?;
2067 // 4. Return offset.
2068 Ok(result)
2069}
2070
2071pub(crate) fn to_partial_zoneddatetime(
2072 partial_object: &JsObject,
2073 context: &mut Context,
2074) -> JsResult<PartialZonedDateTime> {
2075 // NOTE (nekevss): Why do we have to list out all of the get operations? Well, order of operations Watson!
2076 // b. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(item).
2077 // c. Let fields be ? PrepareCalendarFields(calendar, item, « year, month, month-code, day », « hour, minute, second, millisecond, microsecond, nanosecond, offset, time-zone », « time-zone »).
2078 let calendar = get_temporal_calendar_slot_value_with_default(partial_object, context)?;
2079 let (fields, timezone) = to_zoned_date_time_fields(
2080 partial_object,
2081 &calendar,
2082 ZdtFieldsType::TimeZoneRequired,
2083 context,
2084 )?;
2085 Ok(PartialZonedDateTime {
2086 fields,
2087 timezone,
2088 calendar,
2089 })
2090}
2091
2092/// This distinguishes the type of `PrepareCalendarField` call used.
2093#[derive(Debug, Clone, Copy, PartialEq)]
2094pub enum ZdtFieldsType {
2095 /// Do not call to the `timeZone` property.
2096 NoTimeZone,
2097 /// Call to `timeZone`, value can be undefined.
2098 TimeZoneNotRequired,
2099 /// Call to `timeZone`, value must exist.
2100 TimeZoneRequired,
2101}
2102
2103pub(crate) fn to_zoned_date_time_fields(
2104 partial_object: &JsObject,
2105 calendar: &Calendar,
2106 zdt_fields_type: ZdtFieldsType,
2107 context: &mut Context,
2108) -> JsResult<(ZonedDateTimeFields, Option<TimeZone>)> {
2109 let day = partial_object
2110 .get(js_string!("day"), context)?
2111 .map(|v| {
2112 let finite = v.to_finitef64(context)?;
2113 finite
2114 .as_positive_integer_with_truncation()
2115 .map_err(JsError::from)
2116 })
2117 .transpose()?;
2118 let hour = partial_object
2119 .get(js_string!("hour"), context)?
2120 .map(|v| {
2121 let finite = v.to_finitef64(context)?;
2122 Ok::<u8, JsError>(finite.as_integer_with_truncation::<u8>())
2123 })
2124 .transpose()?;
2125 // TODO: `temporal_rs` needs a `has_era` method
2126 let has_no_era = calendar.kind() == AnyCalendarKind::Iso
2127 || calendar.kind() == AnyCalendarKind::Chinese
2128 || calendar.kind() == AnyCalendarKind::Dangi;
2129 let (era, era_year) = if has_no_era {
2130 (None, None)
2131 } else {
2132 let era = partial_object
2133 .get(js_string!("era"), context)?
2134 .map(|v| {
2135 let v = v.to_primitive(context, PreferredType::String)?;
2136 let Some(era) = v.as_string() else {
2137 return Err(JsError::from(
2138 JsNativeError::typ()
2139 .with_message("The monthCode field value must be a string."),
2140 ));
2141 };
2142 // TODO: double check if an invalid monthCode is a range or type error.
2143 TinyAsciiStr::<19>::try_from_str(&era.to_std_string_escaped())
2144 .map_err(|e| JsError::from(JsNativeError::range().with_message(e.to_string())))
2145 })
2146 .transpose()?;
2147 let era_year = partial_object
2148 .get(js_string!("eraYear"), context)?
2149 .map(|v| {
2150 let finite = v.to_finitef64(context)?;
2151 Ok::<i32, JsError>(finite.as_integer_with_truncation::<i32>())
2152 })
2153 .transpose()?;
2154 (era, era_year)
2155 };
2156 let microsecond = partial_object
2157 .get(js_string!("microsecond"), context)?
2158 .map(|v| {
2159 let finite = v.to_finitef64(context)?;
2160 Ok::<u16, JsError>(finite.as_integer_with_truncation::<u16>())
2161 })
2162 .transpose()?;
2163
2164 let millisecond = partial_object
2165 .get(js_string!("millisecond"), context)?
2166 .map(|v| {
2167 let finite = v.to_finitef64(context)?;
2168 Ok::<u16, JsError>(finite.as_integer_with_truncation::<u16>())
2169 })
2170 .transpose()?;
2171
2172 let minute = partial_object
2173 .get(js_string!("minute"), context)?
2174 .map(|v| {
2175 let finite = v.to_finitef64(context)?;
2176 Ok::<u8, JsError>(finite.as_integer_with_truncation::<u8>())
2177 })
2178 .transpose()?;
2179
2180 let month = partial_object
2181 .get(js_string!("month"), context)?
2182 .map(|v| {
2183 let finite = v.to_finitef64(context)?;
2184 finite
2185 .as_positive_integer_with_truncation()
2186 .map_err(JsError::from)
2187 })
2188 .transpose()?;
2189
2190 let month_code = partial_object
2191 .get(js_string!("monthCode"), context)?
2192 .map(|v| {
2193 let v = v.to_primitive(context, PreferredType::String)?;
2194 let Some(month_code) = v.as_string() else {
2195 return Err(JsNativeError::typ()
2196 .with_message("The monthCode field value must be a string.")
2197 .into());
2198 };
2199 MonthCode::from_str(&month_code.to_std_string_escaped()).map_err(JsError::from)
2200 })
2201 .transpose()?;
2202
2203 let nanosecond = partial_object
2204 .get(js_string!("nanosecond"), context)?
2205 .map(|v| {
2206 let finite = v.to_finitef64(context)?;
2207 Ok::<u16, JsError>(finite.as_integer_with_truncation::<u16>())
2208 })
2209 .transpose()?;
2210
2211 let offset = partial_object
2212 .get(js_string!("offset"), context)?
2213 .map(|v| to_offset_string(v, context))
2214 .transpose()?;
2215
2216 let second = partial_object
2217 .get(js_string!("second"), context)?
2218 .map(|v| {
2219 let finite = v.to_finitef64(context)?;
2220 Ok::<u8, JsError>(finite.as_integer_with_truncation::<u8>())
2221 })
2222 .transpose()?;
2223
2224 let time_zone = match zdt_fields_type {
2225 ZdtFieldsType::NoTimeZone => None,
2226 ZdtFieldsType::TimeZoneNotRequired | ZdtFieldsType::TimeZoneRequired => {
2227 let time_zone = partial_object
2228 .get(js_string!("timeZone"), context)?
2229 .map(|v| to_temporal_timezone_identifier(v, context))
2230 .transpose()?;
2231 if zdt_fields_type == ZdtFieldsType::TimeZoneRequired && time_zone.is_none() {
2232 return Err(JsNativeError::typ()
2233 .with_message("timeZone is required to construct ZonedDateTime.")
2234 .into());
2235 }
2236 time_zone
2237 }
2238 };
2239
2240 let year = partial_object
2241 .get(js_string!("year"), context)?
2242 .map(|v| {
2243 let finite = v.to_finitef64(context)?;
2244 Ok::<i32, JsError>(finite.as_integer_with_truncation::<i32>())
2245 })
2246 .transpose()?;
2247
2248 let calendar_fields = CalendarFields::new()
2249 .with_optional_year(year)
2250 .with_optional_month(month)
2251 .with_optional_month_code(month_code)
2252 .with_optional_day(day)
2253 .with_era(era)
2254 .with_era_year(era_year);
2255
2256 let time = PartialTime::new()
2257 .with_hour(hour)
2258 .with_minute(minute)
2259 .with_second(second)
2260 .with_millisecond(millisecond)
2261 .with_microsecond(microsecond)
2262 .with_nanosecond(nanosecond);
2263
2264 Ok((
2265 ZonedDateTimeFields {
2266 calendar_fields,
2267 time,
2268 offset,
2269 },
2270 time_zone,
2271 ))
2272}