boa_engine/builtins/temporal/plain_date_time/mod.rs
1//! Boa's implementation of the ECMAScript `Temporal.PlainDateTime` built-in object.
2
3use std::str::FromStr;
4
5use crate::{
6 Context, JsArgs, JsData, JsError, JsNativeError, JsObject, JsResult, JsString, JsSymbol,
7 JsValue,
8 builtins::{
9 BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject,
10 options::{get_option, get_options_object},
11 temporal::calendar::to_temporal_calendar_identifier,
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,
20};
21use boa_gc::{Finalize, Trace};
22
23#[cfg(test)]
24mod tests;
25
26use icu_calendar::AnyCalendarKind;
27use temporal_rs::{
28 Calendar, MonthCode, PlainDateTime as InnerDateTime, TinyAsciiStr,
29 fields::{CalendarFields, DateTimeFields},
30 options::{
31 Disambiguation, DisplayCalendar, Overflow, RoundingIncrement, RoundingMode,
32 RoundingOptions, ToStringRoundingOptions, Unit,
33 },
34 partial::{PartialDateTime, PartialTime},
35};
36
37use super::{
38 PlainDate, ZonedDateTime,
39 calendar::get_temporal_calendar_slot_value_with_default,
40 create_temporal_date, create_temporal_duration, create_temporal_time,
41 create_temporal_zoneddatetime,
42 options::{TemporalUnitGroup, get_difference_settings, get_digits_option, get_temporal_unit},
43 to_temporal_duration_record, to_temporal_time, to_temporal_timezone_identifier,
44};
45use crate::value::JsVariant;
46
47/// The `Temporal.PlainDateTime` built-in implementation.
48///
49/// More information:
50///
51/// - [ECMAScript Temporal proposal][spec]
52/// - [MDN reference][mdn]
53/// - [`temporal_rs` documentation][temporal_rs-docs]
54///
55/// [spec]: https://tc39.es/proposal-temporal/#sec-temporal-plaindatetime-objects
56/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime
57/// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html
58#[derive(Debug, Clone, Trace, Finalize, JsData)]
59#[boa_gc(unsafe_empty_trace)] // Safety: InnerDateTime does not contain any traceable types.
60pub struct PlainDateTime {
61 pub(crate) inner: InnerDateTime,
62}
63
64impl PlainDateTime {
65 fn new(inner: InnerDateTime) -> Self {
66 Self { inner }
67 }
68
69 pub(crate) fn inner(&self) -> &InnerDateTime {
70 &self.inner
71 }
72}
73
74impl BuiltInObject for PlainDateTime {
75 const NAME: JsString = StaticJsStrings::PLAIN_DATETIME_NAME;
76}
77
78impl IntrinsicObject for PlainDateTime {
79 fn init(realm: &Realm) {
80 let get_calendar_id = BuiltInBuilder::callable(realm, Self::get_calendar_id)
81 .name(js_string!("get calendarId"))
82 .build();
83
84 let get_era = BuiltInBuilder::callable(realm, Self::get_era)
85 .name(js_string!("get era"))
86 .build();
87
88 let get_era_year = BuiltInBuilder::callable(realm, Self::get_era_year)
89 .name(js_string!("get eraYear"))
90 .build();
91
92 let get_year = BuiltInBuilder::callable(realm, Self::get_year)
93 .name(js_string!("get year"))
94 .build();
95
96 let get_month = BuiltInBuilder::callable(realm, Self::get_month)
97 .name(js_string!("get month"))
98 .build();
99
100 let get_month_code = BuiltInBuilder::callable(realm, Self::get_month_code)
101 .name(js_string!("get monthCode"))
102 .build();
103
104 let get_day = BuiltInBuilder::callable(realm, Self::get_day)
105 .name(js_string!("get day"))
106 .build();
107
108 let get_hour = BuiltInBuilder::callable(realm, Self::get_hour)
109 .name(js_string!("get hour"))
110 .build();
111
112 let get_minute = BuiltInBuilder::callable(realm, Self::get_minute)
113 .name(js_string!("get minute"))
114 .build();
115
116 let get_second = BuiltInBuilder::callable(realm, Self::get_second)
117 .name(js_string!("get second"))
118 .build();
119
120 let get_millisecond = BuiltInBuilder::callable(realm, Self::get_millisecond)
121 .name(js_string!("get millisecond"))
122 .build();
123
124 let get_microsecond = BuiltInBuilder::callable(realm, Self::get_microsecond)
125 .name(js_string!("get microsecond"))
126 .build();
127
128 let get_nanosecond = BuiltInBuilder::callable(realm, Self::get_nanosecond)
129 .name(js_string!("get nanosecond"))
130 .build();
131
132 let get_day_of_week = BuiltInBuilder::callable(realm, Self::get_day_of_week)
133 .name(js_string!("get dayOfWeek"))
134 .build();
135
136 let get_day_of_year = BuiltInBuilder::callable(realm, Self::get_day_of_year)
137 .name(js_string!("get dayOfYear"))
138 .build();
139
140 let get_week_of_year = BuiltInBuilder::callable(realm, Self::get_week_of_year)
141 .name(js_string!("get weekOfYear"))
142 .build();
143
144 let get_year_of_week = BuiltInBuilder::callable(realm, Self::get_year_of_week)
145 .name(js_string!("get yearOfWeek"))
146 .build();
147
148 let get_days_in_week = BuiltInBuilder::callable(realm, Self::get_days_in_week)
149 .name(js_string!("get daysInWeek"))
150 .build();
151
152 let get_days_in_month = BuiltInBuilder::callable(realm, Self::get_days_in_month)
153 .name(js_string!("get daysInMonth"))
154 .build();
155
156 let get_days_in_year = BuiltInBuilder::callable(realm, Self::get_days_in_year)
157 .name(js_string!("get daysInYear"))
158 .build();
159
160 let get_months_in_year = BuiltInBuilder::callable(realm, Self::get_months_in_year)
161 .name(js_string!("get monthsInYear"))
162 .build();
163
164 let get_in_leap_year = BuiltInBuilder::callable(realm, Self::get_in_leap_year)
165 .name(js_string!("get inLeapYear"))
166 .build();
167
168 BuiltInBuilder::from_standard_constructor::<Self>(realm)
169 .property(
170 JsSymbol::to_string_tag(),
171 StaticJsStrings::PLAIN_DATETIME_TAG,
172 Attribute::CONFIGURABLE,
173 )
174 .accessor(
175 js_string!("calendarId"),
176 Some(get_calendar_id),
177 None,
178 Attribute::CONFIGURABLE,
179 )
180 .accessor(
181 js_string!("era"),
182 Some(get_era),
183 None,
184 Attribute::CONFIGURABLE,
185 )
186 .accessor(
187 js_string!("eraYear"),
188 Some(get_era_year),
189 None,
190 Attribute::CONFIGURABLE,
191 )
192 .accessor(
193 js_string!("year"),
194 Some(get_year),
195 None,
196 Attribute::CONFIGURABLE,
197 )
198 .accessor(
199 js_string!("month"),
200 Some(get_month),
201 None,
202 Attribute::CONFIGURABLE,
203 )
204 .accessor(
205 js_string!("monthCode"),
206 Some(get_month_code),
207 None,
208 Attribute::CONFIGURABLE,
209 )
210 .accessor(
211 js_string!("day"),
212 Some(get_day),
213 None,
214 Attribute::CONFIGURABLE,
215 )
216 .accessor(
217 js_string!("hour"),
218 Some(get_hour),
219 None,
220 Attribute::CONFIGURABLE,
221 )
222 .accessor(
223 js_string!("minute"),
224 Some(get_minute),
225 None,
226 Attribute::CONFIGURABLE,
227 )
228 .accessor(
229 js_string!("second"),
230 Some(get_second),
231 None,
232 Attribute::CONFIGURABLE,
233 )
234 .accessor(
235 js_string!("millisecond"),
236 Some(get_millisecond),
237 None,
238 Attribute::CONFIGURABLE,
239 )
240 .accessor(
241 js_string!("microsecond"),
242 Some(get_microsecond),
243 None,
244 Attribute::CONFIGURABLE,
245 )
246 .accessor(
247 js_string!("nanosecond"),
248 Some(get_nanosecond),
249 None,
250 Attribute::CONFIGURABLE,
251 )
252 .accessor(
253 js_string!("dayOfWeek"),
254 Some(get_day_of_week),
255 None,
256 Attribute::CONFIGURABLE,
257 )
258 .accessor(
259 js_string!("dayOfYear"),
260 Some(get_day_of_year),
261 None,
262 Attribute::CONFIGURABLE,
263 )
264 .accessor(
265 js_string!("weekOfYear"),
266 Some(get_week_of_year),
267 None,
268 Attribute::CONFIGURABLE,
269 )
270 .accessor(
271 js_string!("yearOfWeek"),
272 Some(get_year_of_week),
273 None,
274 Attribute::CONFIGURABLE,
275 )
276 .accessor(
277 js_string!("daysInWeek"),
278 Some(get_days_in_week),
279 None,
280 Attribute::CONFIGURABLE,
281 )
282 .accessor(
283 js_string!("daysInMonth"),
284 Some(get_days_in_month),
285 None,
286 Attribute::CONFIGURABLE,
287 )
288 .accessor(
289 js_string!("daysInYear"),
290 Some(get_days_in_year),
291 None,
292 Attribute::CONFIGURABLE,
293 )
294 .accessor(
295 js_string!("monthsInYear"),
296 Some(get_months_in_year),
297 None,
298 Attribute::CONFIGURABLE,
299 )
300 .accessor(
301 js_string!("inLeapYear"),
302 Some(get_in_leap_year),
303 None,
304 Attribute::CONFIGURABLE,
305 )
306 .static_method(Self::from, js_string!("from"), 1)
307 .static_method(Self::compare, js_string!("compare"), 2)
308 .method(Self::with, js_string!("with"), 1)
309 .method(Self::with_plain_time, js_string!("withPlainTime"), 0)
310 .method(Self::with_calendar, js_string!("withCalendar"), 1)
311 .method(Self::add, js_string!("add"), 1)
312 .method(Self::subtract, js_string!("subtract"), 1)
313 .method(Self::until, js_string!("until"), 1)
314 .method(Self::since, js_string!("since"), 1)
315 .method(Self::round, js_string!("round"), 1)
316 .method(Self::equals, js_string!("equals"), 1)
317 .method(Self::to_string, js_string!("toString"), 0)
318 .method(Self::to_locale_string, js_string!("toLocaleString"), 0)
319 .method(Self::to_json, js_string!("toJSON"), 0)
320 .method(Self::value_of, js_string!("valueOf"), 0)
321 .method(Self::to_zoned_date_time, js_string!("toZonedDateTime"), 1)
322 .method(Self::to_plain_date, js_string!("toPlainDate"), 0)
323 .method(Self::to_plain_time, js_string!("toPlainTime"), 0)
324 .build();
325 }
326
327 fn get(intrinsics: &Intrinsics) -> JsObject {
328 Self::STANDARD_CONSTRUCTOR(intrinsics.constructors()).constructor()
329 }
330}
331
332impl BuiltInConstructor for PlainDateTime {
333 const CONSTRUCTOR_ARGUMENTS: usize = 3;
334 const PROTOTYPE_STORAGE_SLOTS: usize = 61;
335 const CONSTRUCTOR_STORAGE_SLOTS: usize = 2;
336
337 const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor =
338 StandardConstructors::plain_date_time;
339
340 fn constructor(
341 new_target: &JsValue,
342 args: &[JsValue],
343 context: &mut Context,
344 ) -> JsResult<JsValue> {
345 // 1. If NewTarget is undefined, then
346 if new_target.is_undefined() {
347 // a. Throw a TypeError exception.
348 return Err(JsNativeError::typ()
349 .with_message("NewTarget cannot be undefined when contructing PlainDatedt.")
350 .into());
351 }
352
353 // 2. Set isoYear to ? ToIntegerWithTruncation(isoYear).
354 let iso_year = args
355 .get_or_undefined(0)
356 .to_finitef64(context)?
357 .as_integer_with_truncation::<i32>();
358 // 3. Set isoMonth to ? ToIntegerWithTruncation(isoMonth).
359 let iso_month = args
360 .get_or_undefined(1)
361 .to_finitef64(context)?
362 .as_integer_with_truncation::<u8>();
363 // 4. Set isoDay to ? ToIntegerWithTruncation(isoDay).
364 let iso_day = args
365 .get_or_undefined(2)
366 .to_finitef64(context)?
367 .as_integer_with_truncation::<u8>();
368 // 5. If hour is undefined, set hour to 0; else set hour to ? ToIntegerWithTruncation(hour).
369 let hour = args.get_or_undefined(3).map_or(Ok::<u8, JsError>(0), |v| {
370 let finite = v.to_finitef64(context)?;
371 let int = finite.as_integer_with_truncation::<i8>();
372 if int < 0 {
373 return Err(JsNativeError::range()
374 .with_message("invalid time field")
375 .into());
376 }
377 Ok(int as u8)
378 })?;
379 // 6. If minute is undefined, set minute to 0; else set minute to ? ToIntegerWithTruncation(minute).
380 let minute = args.get_or_undefined(4).map_or(Ok::<u8, JsError>(0), |v| {
381 let finite = v.to_finitef64(context)?;
382 let int = finite.as_integer_with_truncation::<i8>();
383 if int < 0 {
384 return Err(JsNativeError::range()
385 .with_message("invalid time field")
386 .into());
387 }
388 Ok(int as u8)
389 })?;
390
391 // 7. If second is undefined, set second to 0; else set second to ? ToIntegerWithTruncation(second).
392 let second = args.get_or_undefined(5).map_or(Ok::<u8, JsError>(0), |v| {
393 let finite = v.to_finitef64(context)?;
394 let int = finite.as_integer_with_truncation::<i8>();
395 if int < 0 {
396 return Err(JsNativeError::range()
397 .with_message("invalid time field")
398 .into());
399 }
400 Ok(int as u8)
401 })?;
402
403 // 8. If millisecond is undefined, set millisecond to 0; else set millisecond to ? ToIntegerWithTruncation(millisecond).
404 let millisecond = args
405 .get_or_undefined(6)
406 .map_or(Ok::<u16, JsError>(0), |v| {
407 let finite = v.to_finitef64(context)?;
408 let int = finite.as_integer_with_truncation::<i16>();
409 if int < 0 {
410 return Err(JsNativeError::range()
411 .with_message("invalid time field")
412 .into());
413 }
414 Ok(int as u16)
415 })?;
416
417 // 9. If microsecond is undefined, set microsecond to 0; else set microsecond to ? ToIntegerWithTruncation(microsecond).
418 let microsecond = args
419 .get_or_undefined(7)
420 .map_or(Ok::<u16, JsError>(0), |v| {
421 let finite = v.to_finitef64(context)?;
422 let int = finite.as_integer_with_truncation::<i16>();
423 if int < 0 {
424 return Err(JsNativeError::range()
425 .with_message("invalid time field")
426 .into());
427 }
428 Ok(int as u16)
429 })?;
430
431 // 10. If nanosecond is undefined, set nanosecond to 0; else set nanosecond to ? ToIntegerWithTruncation(nanosecond).
432 let nanosecond = args
433 .get_or_undefined(8)
434 .map_or(Ok::<u16, JsError>(0), |v| {
435 let finite = v.to_finitef64(context)?;
436 let int = finite.as_integer_with_truncation::<i16>();
437 if int < 0 {
438 return Err(JsNativeError::range()
439 .with_message("invalid time field")
440 .into());
441 }
442 Ok(int as u16)
443 })?;
444
445 let calendar_slot = args
446 .get_or_undefined(9)
447 .map(|s| {
448 s.as_string()
449 .as_ref()
450 .map(JsString::to_std_string_lossy)
451 .ok_or_else(|| JsNativeError::typ().with_message("calendar must be a string."))
452 })
453 .transpose()?
454 .map(|s| Calendar::try_from_utf8(s.as_bytes()))
455 .transpose()?
456 .unwrap_or_default();
457
458 let dt = InnerDateTime::try_new(
459 iso_year,
460 iso_month,
461 iso_day,
462 hour,
463 minute,
464 second,
465 millisecond,
466 microsecond,
467 nanosecond,
468 calendar_slot,
469 )?;
470
471 // 12. Return ? CreateTemporalDateTime(isoYear, isoMonth, isoDay, hour, minute, second, millisecond, microsecond, nanosecond, calendar, NewTarget).
472 create_temporal_datetime(dt, Some(new_target), context).map(Into::into)
473 }
474}
475
476// ==== `PlainDateTimeTime` accessor methods implmentation ====
477
478impl PlainDateTime {
479 /// 5.3.3 get `Temporal.PlainDateTime.prototype.calendarId`
480 ///
481 /// More information:
482 ///
483 /// - [ECMAScript Temporal proposal][spec]
484 /// - [MDN reference][mdn]
485 /// - [`temporal_rs` documentation][temporal_rs-docs]
486 ///
487 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.calendarid
488 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/calendarId
489 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.calendar
490 fn get_calendar_id(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
491 let object = this.as_object();
492 let dt = object
493 .as_ref()
494 .and_then(JsObject::downcast_ref::<Self>)
495 .ok_or_else(|| {
496 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
497 })?;
498
499 Ok(JsString::from(dt.inner.calendar().identifier()).into())
500 }
501
502 /// 5.3.4 get `Temporal.PlainDateTime.prototype.era`
503 ///
504 /// More information:
505 ///
506 /// - [ECMAScript Temporal proposal][spec]
507 /// - [MDN reference][mdn]
508 /// - [`temporal_rs` documentation][temporal_rs-docs]
509 ///
510 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.era
511 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/era
512 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.era
513 fn get_era(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
514 let object = this.as_object();
515 let dt = object
516 .as_ref()
517 .and_then(JsObject::downcast_ref::<Self>)
518 .ok_or_else(|| {
519 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
520 })?;
521
522 Ok(dt
523 .inner
524 .era()
525 .map(|s| JsString::from(s.as_str()))
526 .into_or_undefined())
527 }
528
529 /// 5.3.5 get `Temporal.PlainDateTime.prototype.eraYear`
530 ///
531 /// More information:
532 ///
533 /// - [ECMAScript Temporal proposal][spec]
534 /// - [MDN reference][mdn]
535 /// - [`temporal_rs` documentation][temporal_rs-docs]
536 ///
537 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.erayear
538 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/eraYear
539 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.era_year
540 fn get_era_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
541 let object = this.as_object();
542 let dt = object
543 .as_ref()
544 .and_then(JsObject::downcast_ref::<Self>)
545 .ok_or_else(|| {
546 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
547 })?;
548
549 Ok(dt.inner.era_year().into_or_undefined())
550 }
551
552 /// 5.3.6 get `Temporal.PlainDateTime.prototype.year`
553 ///
554 /// More information:
555 ///
556 /// - [ECMAScript Temporal proposal][spec]
557 /// - [MDN reference][mdn]
558 /// - [`temporal_rs` documentation][temporal_rs-docs]
559 ///
560 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.year
561 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/year
562 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.year
563 fn get_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
564 let object = this.as_object();
565 let dt = object
566 .as_ref()
567 .and_then(JsObject::downcast_ref::<Self>)
568 .ok_or_else(|| {
569 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
570 })?;
571
572 Ok(dt.inner.year().into())
573 }
574
575 /// 5.3.7 get `Temporal.PlainDateTime.prototype.month`
576 ///
577 /// More information:
578 ///
579 /// - [ECMAScript Temporal proposal][spec]
580 /// - [MDN reference][mdn]
581 /// - [`temporal_rs` documentation][temporal_rs-docs]
582 ///
583 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.month
584 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/month
585 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html
586 fn get_month(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
587 let object = this.as_object();
588 let dt = object
589 .as_ref()
590 .and_then(JsObject::downcast_ref::<Self>)
591 .ok_or_else(|| {
592 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
593 })?;
594
595 Ok(dt.inner.month().into())
596 }
597
598 /// 5.3.8 get `Temporal.PlainDateTime.prototype.monthCode`
599 ///
600 /// More information:
601 ///
602 /// - [ECMAScript Temporal proposal][spec]
603 /// - [MDN reference][mdn]
604 /// - [`temporal_rs` documentation][temporal_rs-docs]
605 ///
606 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.monthcode
607 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/monthCode
608 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.month_code
609 fn get_month_code(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
610 let object = this.as_object();
611 let dt = object
612 .as_ref()
613 .and_then(JsObject::downcast_ref::<Self>)
614 .ok_or_else(|| {
615 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
616 })?;
617
618 Ok(JsString::from(dt.inner.month_code().as_str()).into())
619 }
620
621 /// 5.3.9 get `Temporal.PlainDateTime.prototype.day`
622 ///
623 /// More information:
624 ///
625 /// - [ECMAScript Temporal proposal][spec]
626 /// - [MDN reference][mdn]
627 /// - [`temporal_rs` documentation][temporal_rs-docs]
628 ///
629 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.day
630 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/day
631 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.day
632 fn get_day(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
633 let object = this.as_object();
634 let dt = object
635 .as_ref()
636 .and_then(JsObject::downcast_ref::<Self>)
637 .ok_or_else(|| {
638 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
639 })?;
640
641 Ok(dt.inner.day().into())
642 }
643
644 /// 5.3.10 get `Temporal.PlainDateTime.prototype.hour`
645 ///
646 /// More information:
647 ///
648 /// - [ECMAScript Temporal proposal][spec]
649 /// - [MDN reference][mdn]
650 /// - [`temporal_rs` documentation][temporal_rs-docs]
651 ///
652 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.hour
653 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/hour
654 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.hour
655 fn get_hour(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
656 // 1. Let dateTime be the this value.
657 // 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
658 let object = this.as_object();
659 let dt = object
660 .as_ref()
661 .and_then(JsObject::downcast_ref::<Self>)
662 .ok_or_else(|| {
663 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
664 })?;
665
666 // 3. Return 𝔽(datedt.[[ISOHour]]).
667 Ok(dt.inner.hour().into())
668 }
669
670 /// 5.3.11 get `Temporal.PlainDateTime.prototype.minute`
671 ///
672 /// More information:
673 ///
674 /// - [ECMAScript Temporal proposal][spec]
675 /// - [MDN reference][mdn]
676 /// - [`temporal_rs` documentation][temporal_rs-docs]
677 ///
678 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.minute
679 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/minute
680 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.minute
681 fn get_minute(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
682 // 1. Let dateTime be the this value.
683 // 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
684 let object = this.as_object();
685 let dt = object
686 .as_ref()
687 .and_then(JsObject::downcast_ref::<Self>)
688 .ok_or_else(|| {
689 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
690 })?;
691
692 // 3. Return 𝔽(datedt.[[ISOMinute]]).
693 Ok(dt.inner.minute().into())
694 }
695
696 /// 5.3.12 get `Temporal.PlainDateTime.prototype.second`
697 ///
698 /// More information:
699 ///
700 /// - [ECMAScript Temporal proposal][spec]
701 /// - [MDN reference][mdn]
702 /// - [`temporal_rs` documentation][temporal_rs-docs]
703 ///
704 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.second
705 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/second
706 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.second
707 fn get_second(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
708 // 1. Let dateTime be the this value.
709 // 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
710 let object = this.as_object();
711 let dt = object
712 .as_ref()
713 .and_then(JsObject::downcast_ref::<Self>)
714 .ok_or_else(|| {
715 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
716 })?;
717
718 // 3. Return 𝔽(datedt.[[ISOSecond]]).
719 Ok(dt.inner.second().into())
720 }
721
722 /// 5.3.13 get `Temporal.PlainDateTime.prototype.millisecond`
723 ///
724 /// More information:
725 ///
726 /// - [ECMAScript Temporal proposal][spec]
727 /// - [MDN reference][mdn]
728 /// - [`temporal_rs` documentation][temporal_rs-docs]
729 ///
730 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.millisecond
731 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/millisecond
732 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.millisecond
733 fn get_millisecond(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
734 // 1. Let dateTime be the this value.
735 // 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
736 let object = this.as_object();
737 let dt = object
738 .as_ref()
739 .and_then(JsObject::downcast_ref::<Self>)
740 .ok_or_else(|| {
741 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
742 })?;
743
744 // 3. Return 𝔽(datedt.[[ISOMillisecond]]).
745 Ok(dt.inner.millisecond().into())
746 }
747
748 /// 5.3.14 get `Temporal.PlainDateTime.prototype.microsecond`
749 ///
750 /// More information:
751 ///
752 /// - [ECMAScript Temporal proposal][spec]
753 /// - [MDN reference][mdn]
754 /// - [`temporal_rs` documentation][temporal_rs-docs]
755 ///
756 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.microsecond
757 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/microsecond
758 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.microsecond
759 fn get_microsecond(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
760 // 1. Let dateTime be the this value.
761 // 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
762 let object = this.as_object();
763 let dt = object
764 .as_ref()
765 .and_then(JsObject::downcast_ref::<Self>)
766 .ok_or_else(|| {
767 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
768 })?;
769
770 // 3. Return 𝔽(datedt.[[ISOMicrosecond]]).
771 Ok(dt.inner.microsecond().into())
772 }
773
774 /// 5.3.15 get `Temporal.PlainDateTime.prototype.nanosecond`
775 ///
776 /// More information:
777 ///
778 /// - [ECMAScript Temporal proposal][spec]
779 /// - [MDN reference][mdn]
780 /// - [`temporal_rs` documentation][temporal_rs-docs]
781 ///
782 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.nanosecond
783 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/nanosecond
784 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.nanosecond
785 fn get_nanosecond(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
786 // 1. Let dateTime be the this value.
787 // 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
788 let object = this.as_object();
789 let dt = 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 PlainDateTime object.")
794 })?;
795
796 // 3. Return 𝔽(datedt.[[ISONanosecond]]).
797 Ok(dt.inner.nanosecond().into())
798 }
799
800 /// 5.3.16 get `Temporal.PlainDateTime.prototype.dayOfWeek`
801 ///
802 /// More information:
803 ///
804 /// - [ECMAScript Temporal proposal][spec]
805 /// - [MDN reference][mdn]
806 /// - [`temporal_rs` documentation][temporal_rs-docs]
807 ///
808 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.dayofweek
809 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/dayOfWeek
810 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.day_of_week
811 fn get_day_of_week(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
812 let object = this.as_object();
813 let dt = object
814 .as_ref()
815 .and_then(JsObject::downcast_ref::<Self>)
816 .ok_or_else(|| {
817 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
818 })?;
819
820 Ok(dt.inner.day_of_week().into())
821 }
822
823 /// 5.3.17 get `Temporal.PlainDateTime.prototype.dayOfYear`
824 ///
825 /// More information:
826 ///
827 /// - [ECMAScript Temporal proposal][spec]
828 /// - [MDN reference][mdn]
829 /// - [`temporal_rs` documentation][temporal_rs-docs]
830 ///
831 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.dayofyear
832 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/dayOfYear
833 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.day_of_year
834 fn get_day_of_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
835 let object = this.as_object();
836 let dt = object
837 .as_ref()
838 .and_then(JsObject::downcast_ref::<Self>)
839 .ok_or_else(|| {
840 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
841 })?;
842
843 Ok(dt.inner.day_of_year().into())
844 }
845
846 /// 5.3.18 get `Temporal.PlainDateTime.prototype.weekOfYear`
847 ///
848 /// More information:
849 ///
850 /// - [ECMAScript Temporal proposal][spec]
851 /// - [MDN reference][mdn]
852 /// - [`temporal_rs` documentation][temporal_rs-docs]
853 ///
854 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.weekofyear
855 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/weekOfYear
856 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.week_of_year
857 fn get_week_of_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
858 let object = this.as_object();
859 let dt = object
860 .as_ref()
861 .and_then(JsObject::downcast_ref::<Self>)
862 .ok_or_else(|| {
863 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
864 })?;
865
866 Ok(dt.inner.week_of_year().into_or_undefined())
867 }
868
869 /// 5.3.19 get `Temporal.PlainDateTime.prototype.yearOfWeek`
870 ///
871 /// More information:
872 ///
873 /// - [ECMAScript Temporal proposal][spec]
874 /// - [MDN reference][mdn]
875 /// - [`temporal_rs` documentation][temporal_rs-docs]
876 ///
877 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.yearofweek
878 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/yearOfWeek
879 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.year_of_week
880 fn get_year_of_week(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
881 let object = this.as_object();
882 let dt = object
883 .as_ref()
884 .and_then(JsObject::downcast_ref::<Self>)
885 .ok_or_else(|| {
886 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
887 })?;
888
889 Ok(dt.inner.year_of_week().into_or_undefined())
890 }
891
892 /// 5.3.20 get `Temporal.PlainDateTime.prototype.daysInWeek`
893 ///
894 /// More information:
895 ///
896 /// - [ECMAScript Temporal proposal][spec]
897 /// - [MDN reference][mdn]
898 /// - [`temporal_rs` documentation][temporal_rs-docs]
899 ///
900 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.daysinweek
901 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/daysInWeek
902 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.days_in_week
903 fn get_days_in_week(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
904 let object = this.as_object();
905 let dt = object
906 .as_ref()
907 .and_then(JsObject::downcast_ref::<Self>)
908 .ok_or_else(|| {
909 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
910 })?;
911
912 Ok(dt.inner.days_in_week().into())
913 }
914
915 /// 5.3.21 get `Temporal.PlainDateTime.prototype.daysInMonth`
916 ///
917 /// More information:
918 ///
919 /// - [ECMAScript Temporal proposal][spec]
920 /// - [MDN reference][mdn]
921 /// - [`temporal_rs` documentation][temporal_rs-docs]
922 ///
923 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.daysinmonth
924 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/daysInMonth
925 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.days_in_month
926 fn get_days_in_month(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
927 let object = this.as_object();
928 let dt = object
929 .as_ref()
930 .and_then(JsObject::downcast_ref::<Self>)
931 .ok_or_else(|| {
932 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
933 })?;
934
935 Ok(dt.inner.days_in_month().into())
936 }
937
938 /// 5.3.22 get `Temporal.PlainDateTime.prototype.daysInYear`
939 ///
940 /// More information:
941 ///
942 /// - [ECMAScript Temporal proposal][spec]
943 /// - [MDN reference][mdn]
944 /// - [`temporal_rs` documentation][temporal_rs-docs]
945 ///
946 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.daysinyear
947 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/daysInYear
948 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.days_in_year
949 fn get_days_in_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
950 let object = this.as_object();
951 let dt = object
952 .as_ref()
953 .and_then(JsObject::downcast_ref::<Self>)
954 .ok_or_else(|| {
955 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
956 })?;
957
958 Ok(dt.inner.days_in_year().into())
959 }
960
961 /// 5.3.23 get `Temporal.PlainDateTime.prototype.monthsInYear`
962 ///
963 /// More information:
964 ///
965 /// - [ECMAScript Temporal proposal][spec]
966 /// - [MDN reference][mdn]
967 /// - [`temporal_rs` documentation][temporal_rs-docs]
968 ///
969 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.monthsinyear
970 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/monthsInYear
971 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.months_in_year
972 fn get_months_in_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
973 let object = this.as_object();
974 let dt = object
975 .as_ref()
976 .and_then(JsObject::downcast_ref::<Self>)
977 .ok_or_else(|| {
978 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
979 })?;
980
981 Ok(dt.inner.months_in_year().into())
982 }
983
984 /// 5.3.24 get `Temporal.PlainDateTime.prototype.inLeapYear`
985 ///
986 /// More information:
987 ///
988 /// - [ECMAScript Temporal proposal][spec]
989 /// - [MDN reference][mdn]
990 /// - [`temporal_rs` documentation][temporal_rs-docs]
991 ///
992 /// [spec]: https://tc39.es/proposal-temporal/#sec-get-temporal.plaindatetime.prototype.inleapyear
993 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/inLeapYear
994 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.in_leap_year
995 fn get_in_leap_year(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
996 let object = this.as_object();
997 let dt = object
998 .as_ref()
999 .and_then(JsObject::downcast_ref::<Self>)
1000 .ok_or_else(|| {
1001 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1002 })?;
1003
1004 Ok(dt.inner.in_leap_year().into())
1005 }
1006}
1007
1008// ==== PlainDateTime static methods implementation ====
1009
1010impl PlainDateTime {
1011 /// 5.2.2 `Temporal.PlainDateTime.from ( item [ , options ] )`
1012 ///
1013 /// More information:
1014 ///
1015 /// - [ECMAScript Temporal proposal][spec]
1016 /// - [MDN reference][mdn]
1017 ///
1018 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.from
1019 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/from
1020 fn from(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1021 let item = args.get_or_undefined(0);
1022 // 1. Set options to ? GetOptionsObject(options).
1023 let options = args.get(1);
1024 // 2. If item is an Object and item has an [[InitializedTemporalDateTime]] internal slot, then
1025 let object = item.as_object();
1026 let dt = if let Some(pdt) = object.as_ref().and_then(JsObject::downcast_ref::<Self>) {
1027 // a. Perform ? GetTemporalOverflowOption(options).
1028 let options = get_options_object(args.get_or_undefined(1))?;
1029 let _ = get_option::<Overflow>(&options, js_string!("overflow"), context)?;
1030 // b. Return ! CreateTemporalDateTime(item.[[ISOYear]], item.[[ISOMonth]],
1031 // item.[[ISODay]], item.[[ISOHour]], item.[[ISOMinute]], item.[[ISOSecond]],
1032 // item.[[ISOMillisecond]], item.[[ISOMicrosecond]], item.[[ISONanosecond]],
1033 // item.[[Calendar]]).
1034 pdt.inner.clone()
1035 } else {
1036 to_temporal_datetime(item, options.cloned(), context)?
1037 };
1038
1039 // 3. Return ? ToTemporalDateTime(item, options).
1040 create_temporal_datetime(dt, None, context).map(Into::into)
1041 }
1042
1043 /// 5.2.3 `Temporal.PlainDateTime.compare ( one, two )`
1044 ///
1045 /// More information:
1046 ///
1047 /// - [ECMAScript Temporal proposal][spec]
1048 /// - [MDN reference][mdn]
1049 /// - [`temporal_rs` documentation][temporal_rs-docs]
1050 ///
1051 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.compare
1052 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/compare
1053 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.compare_iso
1054 fn compare(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1055 // 1. Set one to ? ToTemporalDateTime(one).
1056 let one = to_temporal_datetime(args.get_or_undefined(0), None, context)?;
1057 // 2. Set two to ? ToTemporalDateTime(two).
1058 let two = to_temporal_datetime(args.get_or_undefined(1), None, context)?;
1059
1060 // 3. Return 𝔽(CompareISODateTime(one.[[ISOYear]], one.[[ISOMonth]], one.[[ISODay]],
1061 // one.[[ISOHour]], one.[[ISOMinute]], one.[[ISOSecond]], one.[[ISOMillisecond]],
1062 // one.[[ISOMicrosecond]], one.[[ISONanosecond]], two.[[ISOYear]], two.[[ISOMonth]],
1063 // two.[[ISODay]], two.[[ISOHour]], two.[[ISOMinute]], two.[[ISOSecond]],
1064 // two.[[ISOMillisecond]], two.[[ISOMicrosecond]], two.[[ISONanosecond]])).
1065 Ok((one.compare_iso(&two) as i8).into())
1066 }
1067}
1068
1069// ==== PlainDateTime methods implementation ====
1070
1071impl PlainDateTime {
1072 /// 5.3.25 `Temporal.PlainDateTime.prototype.with ( temporalDateTimeLike [ , options ] )`
1073 ///
1074 /// More information:
1075 ///
1076 /// - [ECMAScript Temporal proposal][spec]
1077 /// - [MDN reference][mdn]
1078 /// - [`temporal_rs` documentation][temporal_rs-docs]
1079 ///
1080 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.with
1081 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/with
1082 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.with
1083 fn with(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1084 // 1. Let plainDateTime be the this value.
1085 // 2. Perform ? RequireInternalSlot(plainDateTime, [[InitializedTemporalDateTime]]).
1086 let object = this.as_object();
1087 let dt = object
1088 .as_ref()
1089 .and_then(JsObject::downcast_ref::<Self>)
1090 .ok_or_else(|| {
1091 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1092 })?;
1093
1094 // 3. If ? IsPartialTemporalObject(temporalDateTimeLike) is false, throw a TypeError exception.
1095 let Some(partial_object) =
1096 super::is_partial_temporal_object(args.get_or_undefined(0), context)?
1097 else {
1098 return Err(JsNativeError::typ()
1099 .with_message("with object was not a PartialTemporalObject.")
1100 .into());
1101 };
1102 // 4. Let calendar be plainDateTime.[[Calendar]].
1103 // 5. Let fields be ISODateToFields(calendar, plainDateTime.[[ISODateTime]].[[ISODate]], date).
1104 // 6. Set fields.[[Hour]] to plainDateTime.[[ISODateTime]].[[Time]].[[Hour]].
1105 // 7. Set fields.[[Minute]] to plainDateTime.[[ISODateTime]].[[Time]].[[Minute]].
1106 // 8. Set fields.[[Second]] to plainDateTime.[[ISODateTime]].[[Time]].[[Second]].
1107 // 9. Set fields.[[Millisecond]] to plainDateTime.[[ISODateTime]].[[Time]].[[Millisecond]].
1108 // 10. Set fields.[[Microsecond]] to plainDateTime.[[ISODateTime]].[[Time]].[[Microsecond]].
1109 // 11. Set fields.[[Nanosecond]] to plainDateTime.[[ISODateTime]].[[Time]].[[Nanosecond]].
1110 // 12. Let partialDateTime be ? PrepareCalendarFields(calendar, temporalDateTimeLike, « year, month, month-code, day », « hour, minute, second, millisecond, microsecond, nanosecond », partial).
1111 // 13. Set fields to CalendarMergeFields(calendar, fields, partialDateTime).
1112 let fields = to_date_time_fields(&partial_object, dt.inner.calendar(), context)?;
1113 // 14. Let resolvedOptions be ? GetOptionsObject(options).
1114 let options = get_options_object(args.get_or_undefined(1))?;
1115 // 15. Let overflow be ? GetTemporalOverflowOption(resolvedOptions).
1116 let overflow = get_option::<Overflow>(&options, js_string!("overflow"), context)?;
1117
1118 // 16. Let result be ? InterpretTemporalDateTimeFields(calendar, fields, overflow).
1119 // 17. Return ? CreateTemporalDateTime(result, calendar).
1120 create_temporal_datetime(dt.inner.with(fields, overflow)?, None, context).map(Into::into)
1121 }
1122
1123 /// 5.3.26 Temporal.PlainDateTime.prototype.withPlainTime ( `[ plainTimeLike ]` )
1124 ///
1125 /// More information:
1126 ///
1127 /// - [ECMAScript Temporal proposal][spec]
1128 /// - [MDN reference][mdn]
1129 /// - [`temporal_rs` documentation][temporal_rs-docs]
1130 ///
1131 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.withplaintime
1132 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/withPlainTime
1133 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.with_plain_time
1134 fn with_plain_time(
1135 this: &JsValue,
1136 args: &[JsValue],
1137 context: &mut Context,
1138 ) -> JsResult<JsValue> {
1139 let object = this.as_object();
1140 let dt = object
1141 .as_ref()
1142 .and_then(JsObject::downcast_ref::<Self>)
1143 .ok_or_else(|| {
1144 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1145 })?;
1146
1147 let time = args
1148 .get_or_undefined(0)
1149 .map(|v| to_temporal_time(v, None, context))
1150 .transpose()?;
1151
1152 create_temporal_datetime(dt.inner.with_time(time)?, None, context).map(Into::into)
1153 }
1154
1155 /// 5.3.27 `Temporal.PlainDateTime.prototype.withCalendar ( calendarLike )`
1156 ///
1157 /// More information:
1158 ///
1159 /// - [ECMAScript Temporal proposal][spec]
1160 /// - [MDN reference][mdn]
1161 /// - [`temporal_rs` documentation][temporal_rs-docs]
1162 ///
1163 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.withCalendar
1164 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/withCalendar
1165 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.with_calendar
1166 fn with_calendar(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1167 let object = this.as_object();
1168 let dt = object
1169 .as_ref()
1170 .and_then(JsObject::downcast_ref::<Self>)
1171 .ok_or_else(|| {
1172 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1173 })?;
1174
1175 let calendar = to_temporal_calendar_identifier(args.get_or_undefined(0))?;
1176
1177 create_temporal_datetime(dt.inner.with_calendar(calendar), None, context).map(Into::into)
1178 }
1179
1180 /// 5.3.28 `Temporal.PlainDateTime.prototype.add ( temporalDurationLike [ , options ] )`
1181 ///
1182 /// More information:
1183 ///
1184 /// - [ECMAScript Temporal proposal][spec]
1185 /// - [MDN reference][mdn]
1186 /// - [`temporal_rs` documentation][temporal_rs-docs]
1187 ///
1188 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.add
1189 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/add
1190 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.add
1191 fn add(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1192 // 1. Let temporalDate be the this value.
1193 // 2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
1194 let object = this.as_object();
1195 let dt = object
1196 .as_ref()
1197 .and_then(JsObject::downcast_ref::<Self>)
1198 .ok_or_else(|| {
1199 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1200 })?;
1201
1202 // 3. Let duration be ? ToTemporalDuration(temporalDurationLike).
1203 let duration = to_temporal_duration_record(args.get_or_undefined(0), context)?;
1204
1205 // 4. Set options to ? GetOptionsObject(options).
1206 let options = get_options_object(args.get_or_undefined(1))?;
1207 let overflow = get_option::<Overflow>(&options, js_string!("overflow"), context)?;
1208
1209 // 5. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »).
1210 // 6. Return ? AddDate(calendarRec, temporalDate, duration, options).
1211 create_temporal_datetime(dt.inner.add(&duration, overflow)?, None, context).map(Into::into)
1212 }
1213
1214 /// 5.3.29 `Temporal.PlainDateTime.prototype.subtract ( temporalDurationLike [ , options ] )`
1215 ///
1216 /// More information:
1217 ///
1218 /// - [ECMAScript Temporal proposal][spec]
1219 /// - [MDN reference][mdn]
1220 /// - [`temporal_rs` documentation][temporal_rs-docs]
1221 ///
1222 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.subtract
1223 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/subtract
1224 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.subtract
1225 fn subtract(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1226 // 1. Let temporalDate be the this value.
1227 // 2. Perform ? RequireInternalSlot(temporalDate, [[InitializedTemporalDate]]).
1228 let object = this.as_object();
1229 let dt = object
1230 .as_ref()
1231 .and_then(JsObject::downcast_ref::<Self>)
1232 .ok_or_else(|| {
1233 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1234 })?;
1235
1236 // 3. Let duration be ? ToTemporalDuration(temporalDurationLike).
1237 let duration = to_temporal_duration_record(args.get_or_undefined(0), context)?;
1238
1239 // 4. Set options to ? GetOptionsObject(options).
1240 let options = get_options_object(args.get_or_undefined(1))?;
1241 let overflow = get_option::<Overflow>(&options, js_string!("overflow"), context)?;
1242
1243 // 5. Let negatedDuration be CreateNegatedTemporalDuration(duration).
1244 // 6. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »).
1245 // 7. Return ? AddDate(calendarRec, temporalDate, negatedDuration, options).
1246 create_temporal_datetime(dt.inner.subtract(&duration, overflow)?, None, context)
1247 .map(Into::into)
1248 }
1249
1250 /// 5.3.30 `Temporal.PlainDateTime.prototype.until ( other [ , options ] )`
1251 ///
1252 /// More information:
1253 ///
1254 /// - [ECMAScript Temporal proposal][spec]
1255 /// - [MDN reference][mdn]
1256 /// - [`temporal_rs` documentation][temporal_rs-docs]
1257 ///
1258 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.until
1259 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/until
1260 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.until
1261 fn until(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1262 let object = this.as_object();
1263 let dt = object
1264 .as_ref()
1265 .and_then(JsObject::downcast_ref::<Self>)
1266 .ok_or_else(|| {
1267 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1268 })?;
1269
1270 let other = to_temporal_datetime(args.get_or_undefined(0), None, context)?;
1271
1272 let options = get_options_object(args.get_or_undefined(1))?;
1273 let settings = get_difference_settings(&options, context)?;
1274
1275 create_temporal_duration(dt.inner.until(&other, settings)?, None, context).map(Into::into)
1276 }
1277
1278 /// 5.3.31 `Temporal.PlainDateTime.prototype.since ( other [ , options ] )`
1279 ///
1280 /// More information:
1281 ///
1282 /// - [ECMAScript Temporal proposal][spec]
1283 /// - [MDN reference][mdn]
1284 /// - [`temporal_rs` documentation][temporal_rs-docs]
1285 ///
1286 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.since
1287 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/since
1288 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.since
1289 fn since(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1290 let object = this.as_object();
1291 let dt = object
1292 .as_ref()
1293 .and_then(JsObject::downcast_ref::<Self>)
1294 .ok_or_else(|| {
1295 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1296 })?;
1297
1298 let other = to_temporal_datetime(args.get_or_undefined(0), None, context)?;
1299
1300 let options = get_options_object(args.get_or_undefined(1))?;
1301 let settings = get_difference_settings(&options, context)?;
1302
1303 create_temporal_duration(dt.inner.since(&other, settings)?, None, context).map(Into::into)
1304 }
1305
1306 /// 5.3.32 Temporal.PlainDateTime.prototype.round ( roundTo )
1307 ///
1308 /// More information:
1309 ///
1310 /// - [ECMAScript Temporal proposal][spec]
1311 /// - [MDN reference][mdn]
1312 /// - [`temporal_rs` documentation][temporal_rs-docs]
1313 ///
1314 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.round
1315 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/round
1316 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.round
1317 fn round(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1318 let object = this.as_object();
1319 let dt = object
1320 .as_ref()
1321 .and_then(JsObject::downcast_ref::<Self>)
1322 .ok_or_else(|| {
1323 JsNativeError::typ().with_message("the this object must be a PlainTime object.")
1324 })?;
1325
1326 let round_to = match args.first().map(JsValue::variant) {
1327 // 3. If roundTo is undefined, then
1328 None | Some(JsVariant::Undefined) => {
1329 return Err(JsNativeError::typ()
1330 .with_message("roundTo cannot be undefined.")
1331 .into());
1332 }
1333 // 4. If Type(roundTo) is String, then
1334 Some(JsVariant::String(rt)) => {
1335 // a. Let paramString be roundTo.
1336 let param_string = rt.clone();
1337 // b. Set roundTo to OrdinaryObjectCreate(null).
1338 let new_round_to = JsObject::with_null_proto();
1339 // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString).
1340 new_round_to.create_data_property_or_throw(
1341 js_string!("smallestUnit"),
1342 param_string,
1343 context,
1344 )?;
1345 new_round_to
1346 }
1347 // 5. Else,
1348 Some(round_to) => {
1349 // a. Set roundTo to ? GetOptionsObject(roundTo).
1350 get_options_object(&JsValue::from(round_to))?
1351 }
1352 };
1353
1354 let mut options = RoundingOptions::default();
1355
1356 options.increment =
1357 get_option::<RoundingIncrement>(&round_to, js_string!("roundingIncrement"), context)?;
1358
1359 // 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand").
1360 options.rounding_mode =
1361 get_option::<RoundingMode>(&round_to, js_string!("roundingMode"), context)?;
1362
1363 // 9. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", TIME, REQUIRED, undefined).
1364 options.smallest_unit = get_temporal_unit(
1365 &round_to,
1366 js_string!("smallestUnit"),
1367 TemporalUnitGroup::Time,
1368 Some(vec![Unit::Day]),
1369 context,
1370 )?;
1371
1372 create_temporal_datetime(dt.inner().round(options)?, None, context).map(Into::into)
1373 }
1374
1375 /// 5.3.33 Temporal.PlainDateTime.prototype.equals ( other )
1376 ///
1377 /// More information:
1378 ///
1379 /// - [ECMAScript Temporal proposal][spec]
1380 /// - [MDN reference][mdn]
1381 /// - [`temporal_rs` documentation][temporal_rs-docs]
1382 ///
1383 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.equals
1384 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/equals
1385 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#impl-Eq-for-PlainDateTime
1386 fn equals(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1387 // 1. Let dateTime be the this value.
1388 // 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
1389 let object = this.as_object();
1390 let dt = object
1391 .as_ref()
1392 .and_then(JsObject::downcast_ref::<Self>)
1393 .ok_or_else(|| {
1394 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1395 })?;
1396
1397 // 3. Set other to ? ToTemporalDateTime(other).
1398 let other = to_temporal_datetime(args.get_or_undefined(0), None, context)?;
1399
1400 // 4. Let result be CompareISODateTime(dateTime.[[ISOYear]], dateTime.[[ISOMonth]],
1401 // dateTime.[[ISODay]], dateTime.[[ISOHour]], dateTime.[[ISOMinute]],
1402 // dateTime.[[ISOSecond]], dateTime.[[ISOMillisecond]], dateTime.[[ISOMicrosecond]],
1403 // dateTime.[[ISONanosecond]], other.[[ISOYear]], other.[[ISOMonth]], other.[[ISODay]],
1404 // other.[[ISOHour]], other.[[ISOMinute]], other.[[ISOSecond]], other.[[ISOMillisecond]],
1405 // other.[[ISOMicrosecond]], other.[[ISONanosecond]]).
1406 // 5. If result is not 0, return false.
1407 // 6. Return ? CalendarEquals(dateTime.[[Calendar]], other.[[Calendar]]).
1408 Ok((dt.inner == other).into())
1409 }
1410
1411 /// 5.3.34 `Temporal.PlainDateTime.prototype.toString ( [ options ] )`
1412 ///
1413 /// More information:
1414 ///
1415 /// - [ECMAScript Temporal proposal][spec]
1416 /// - [MDN reference][mdn]
1417 /// - [`temporal_rs` documentation][temporal_rs-docs]
1418 ///
1419 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.with
1420 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/with
1421 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.to_ixdtf_string
1422 fn to_string(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1423 let object = this.as_object();
1424 let dt = object
1425 .as_ref()
1426 .and_then(JsObject::downcast_ref::<Self>)
1427 .ok_or_else(|| {
1428 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1429 })?;
1430
1431 let options = get_options_object(args.get_or_undefined(0))?;
1432
1433 let show_calendar =
1434 get_option::<DisplayCalendar>(&options, js_string!("calendarName"), context)?
1435 .unwrap_or(DisplayCalendar::Auto);
1436 let precision = get_digits_option(&options, context)?;
1437 let rounding_mode =
1438 get_option::<RoundingMode>(&options, js_string!("roundingMode"), context)?;
1439 let smallest_unit = get_option::<Unit>(&options, js_string!("smallestUnit"), context)?;
1440
1441 let ixdtf = dt.inner.to_ixdtf_string(
1442 ToStringRoundingOptions {
1443 precision,
1444 smallest_unit,
1445 rounding_mode,
1446 },
1447 show_calendar,
1448 )?;
1449 Ok(JsString::from(ixdtf).into())
1450 }
1451
1452 /// 5.3.35 `Temporal.PlainDateTime.prototype.toLocaleString ( [ locales [ , options ] ] )`
1453 ///
1454 /// More information:
1455 ///
1456 /// - [ECMAScript Temporal proposal][spec]
1457 /// - [MDN reference][mdn]
1458 ///
1459 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.with
1460 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/with
1461 fn to_locale_string(this: &JsValue, _args: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
1462 // TODO: Update for ECMA-402 compliance
1463 let object = this.as_object();
1464 let dt = object
1465 .as_ref()
1466 .and_then(JsObject::downcast_ref::<Self>)
1467 .ok_or_else(|| {
1468 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1469 })?;
1470
1471 let ixdtf = dt
1472 .inner
1473 .to_ixdtf_string(ToStringRoundingOptions::default(), DisplayCalendar::Auto)?;
1474 Ok(JsString::from(ixdtf).into())
1475 }
1476
1477 /// 5.3.36 `Temporal.PlainDateTime.prototype.toJSON ( )`
1478 ///
1479 /// More information:
1480 ///
1481 /// - [ECMAScript Temporal proposal][spec]
1482 /// - [MDN reference][mdn]
1483 ///
1484 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.with
1485 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/with
1486 fn to_json(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
1487 let object = this.as_object();
1488 let dt = object
1489 .as_ref()
1490 .and_then(JsObject::downcast_ref::<Self>)
1491 .ok_or_else(|| {
1492 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1493 })?;
1494
1495 let ixdtf = dt
1496 .inner
1497 .to_ixdtf_string(ToStringRoundingOptions::default(), DisplayCalendar::Auto)?;
1498 Ok(JsString::from(ixdtf).into())
1499 }
1500
1501 /// 5.3.37 `Temporal.PlainDateTime.prototype.valueOf ( )`
1502 ///
1503 /// More information:
1504 ///
1505 /// - [ECMAScript Temporal proposal][spec]
1506 /// - [MDN reference][mdn]
1507 ///
1508 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.with
1509 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/with
1510 pub(crate) fn value_of(_this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
1511 Err(JsNativeError::typ()
1512 .with_message("`valueOf` not supported by Temporal built-ins. See 'compare', 'equals', or `toString`")
1513 .into())
1514 }
1515
1516 /// 5.3.38 `Temporal.PlainDateTime.prototype.toZonedDateTime ( temporalTimeZoneLike [ , options ] )`
1517 ///
1518 /// More information:
1519 ///
1520 /// - [ECMAScript Temporal proposal][spec]
1521 /// - [MDN reference][mdn]
1522 /// - [`temporal_rs` documentation][temporal_rs-docs]
1523 ///
1524 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.tozoneddatetime
1525 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/toZonedDateTime
1526 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.to_zoned_date_time
1527 fn to_zoned_date_time(
1528 this: &JsValue,
1529 args: &[JsValue],
1530 context: &mut Context,
1531 ) -> JsResult<JsValue> {
1532 // 1. Let dateTime be the this value.
1533 // 2. Perform ? RequireInternalSlot(dateTime, [[InitializedTemporalDateTime]]).
1534 let object = this.as_object();
1535 let dt = object
1536 .as_ref()
1537 .and_then(JsObject::downcast_ref::<Self>)
1538 .ok_or_else(|| {
1539 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1540 })?;
1541 // 3. Let timeZone be ? ToTemporalTimeZoneIdentifier(temporalTimeZoneLike).
1542 let timezone = to_temporal_timezone_identifier(args.get_or_undefined(0), context)?;
1543 // 4. Let resolvedOptions be ? GetOptionsObject(options).
1544 let options = get_options_object(args.get_or_undefined(1))?;
1545 // 5. Let disambiguation be ? GetTemporalDisambiguationOption(resolvedOptions).
1546 let disambiguation =
1547 get_option::<Disambiguation>(&options, js_string!("disambiguation"), context)?
1548 .unwrap_or_default();
1549
1550 // 6. Let epochNs be ? GetEpochNanosecondsFor(timeZone, dateTime.[[ISODateTime]], disambiguation).
1551 // 7. Return ! CreateTemporalZonedDateTime(epochNs, timeZone, dateTime.[[Calendar]]).
1552
1553 let result = dt.inner.to_zoned_date_time_with_provider(
1554 timezone,
1555 disambiguation,
1556 context.tz_provider(),
1557 )?;
1558 create_temporal_zoneddatetime(result, None, context).map(Into::into)
1559 }
1560
1561 /// 5.3.39 `Temporal.PlainDateTime.prototype.toPlainDate ( )`
1562 ///
1563 /// More information:
1564 ///
1565 /// - [ECMAScript Temporal proposal][spec]
1566 /// - [MDN reference][mdn]
1567 /// - [`temporal_rs` documentation][temporal_rs-docs]
1568 ///
1569 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.toplaindate
1570 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/toPlainDate
1571 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.to_plain_date
1572 fn to_plain_date(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1573 let object = this.as_object();
1574 let dt = object
1575 .as_ref()
1576 .and_then(JsObject::downcast_ref::<Self>)
1577 .ok_or_else(|| {
1578 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1579 })?;
1580
1581 let result = dt.inner.to_plain_date();
1582 create_temporal_date(result, None, context).map(Into::into)
1583 }
1584
1585 /// 5.3.40 `Temporal.PlainDateTime.prototype.toPlainTime ( )`
1586 ///
1587 /// More information:
1588 ///
1589 /// - [ECMAScript Temporal proposal][spec]
1590 /// - [MDN reference][mdn]
1591 /// - [`temporal_rs` documentation][temporal_rs-docs]
1592 ///
1593 /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal.plaindatetime.prototype.toplaintime
1594 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime/toPlainTime
1595 /// [temporal_rs-docs]: https://docs.rs/temporal_rs/latest/temporal_rs/struct.PlainDateTime.html#method.to_plain_time
1596 fn to_plain_time(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
1597 let object = this.as_object();
1598 let dt = object
1599 .as_ref()
1600 .and_then(JsObject::downcast_ref::<Self>)
1601 .ok_or_else(|| {
1602 JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
1603 })?;
1604
1605 let result = dt.inner.to_plain_time();
1606 create_temporal_time(result, None, context).map(Into::into)
1607 }
1608}
1609
1610// ==== PlainDateTime Abstract Operations ====
1611
1612pub(crate) fn create_temporal_datetime(
1613 inner: InnerDateTime,
1614 new_target: Option<&JsValue>,
1615 context: &mut Context,
1616) -> JsResult<JsObject> {
1617 // NOTE(nekevss): The below validations should be upheld with the creation of `InnerDateTime`.
1618 // 1. If IsValidISODate(isoYear, isoMonth, isoDay) is false, throw a RangeError exception.
1619 // 2. If IsValidTime(hour, minute, second, millisecond, microsecond, nanosecond) is false, throw a RangeError exception.
1620 // 3. If ISODateTimeWithinLimits(isoYear, isoMonth, isoDay, hour, minute, second, millisecond, microsecond, nanosecond) is false, then
1621 // a. Throw a RangeError exception.
1622
1623 // 4. If newTarget is not present, set newTarget to %Temporal.PlainDateTime%.
1624 let new_target = if let Some(new_target) = new_target {
1625 new_target.clone()
1626 } else {
1627 context
1628 .realm()
1629 .intrinsics()
1630 .constructors()
1631 .plain_date_time()
1632 .constructor()
1633 .into()
1634 };
1635
1636 // 5. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.PlainDateTime.prototype%", « [[InitializedTemporalDateTime]], [[ISOYear]], [[ISOMonth]], [[ISODay]], [[ISOHour]], [[ISOMinute]], [[ISOSecond]], [[ISOMillisecond]], [[ISOMicrosecond]], [[ISONanosecond]], [[Calendar]] »).
1637 let prototype = get_prototype_from_constructor(
1638 &new_target,
1639 StandardConstructors::plain_date_time,
1640 context,
1641 )?;
1642
1643 // 6. Set object.[[ISOYear]] to isoYear.
1644 // 7. Set object.[[ISOMonth]] to isoMonth.
1645 // 8. Set object.[[ISODay]] to isoDay.
1646 // 9. Set object.[[ISOHour]] to hour.
1647 // 10. Set object.[[ISOMinute]] to minute.
1648 // 11. Set object.[[ISOSecond]] to second.
1649 // 12. Set object.[[ISOMillisecond]] to millisecond.
1650 // 13. Set object.[[ISOMicrosecond]] to microsecond.
1651 // 14. Set object.[[ISONanosecond]] to nanosecond.
1652 // 15. Set object.[[Calendar]] to calendar.
1653 let obj = JsObject::from_proto_and_data(prototype, PlainDateTime::new(inner));
1654
1655 // 16. Return object.
1656 Ok(obj)
1657}
1658
1659pub(crate) fn to_temporal_datetime(
1660 value: &JsValue,
1661 options: Option<JsValue>,
1662 context: &mut Context,
1663) -> JsResult<InnerDateTime> {
1664 // 1. If options is not present, set options to undefined.
1665 // 2. Let resolvedOptions be ? SnapshotOwnProperties(! GetOptionsObject(options), null).
1666 // 3. If item is an Object, then
1667 if let Some(object) = value.as_object() {
1668 // a. If item has an [[InitializedTemporalDateTime]] internal slot, then
1669 if let Some(dt) = object.downcast_ref::<PlainDateTime>() {
1670 // i. Return item.
1671 return Ok(dt.inner.clone());
1672 // b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then
1673 } else if let Some(zdt) = object.downcast_ref::<ZonedDateTime>() {
1674 // i. Perform ? GetTemporalOverflowOption(resolvedOptions).
1675 let options = get_options_object(&options.unwrap_or_default())?;
1676 let _ = get_option::<Overflow>(&options, js_string!("overflow"), context)?;
1677 // ii. Let instant be ! CreateTemporalInstant(item.[[Nanoseconds]]).
1678 // iii. Let timeZoneRec be ? CreateTimeZoneMethodsRecord(item.[[TimeZone]], « get-offset-nanoseconds-for »).
1679 // iv. Return ? GetPlainDateTimeFor(timeZoneRec, instant, item.[[Calendar]]).
1680 return Ok(zdt.inner.to_plain_date_time());
1681 // c. If item has an [[InitializedTemporalDate]] internal slot, then
1682 } else if let Some(date) = object.downcast_ref::<PlainDate>() {
1683 // i. Perform ? GetTemporalOverflowOption(resolvedOptions).
1684 let options = get_options_object(&options.unwrap_or_default())?;
1685 let _ = get_option::<Overflow>(&options, js_string!("overflow"), context)?;
1686 // ii. Return ? CreateTemporalDateTime(item.[[ISOYear]], item.[[ISOMonth]], item.[[ISODay]], 0, 0, 0, 0, 0, 0, item.[[Calendar]]).
1687 return Ok(date.inner.to_plain_date_time(None)?);
1688 }
1689
1690 // d. Let calendar be ? GetTemporalCalendarSlotValueWithISODefault(item).
1691 // e. Let calendarRec be ? CreateCalendarMethodsRecord(calendar, « date-from-fields, fields »).
1692 // f. Let fields be ? PrepareCalendarFields(calendarRec, item, « "day", "month",
1693 // "monthCode", "year" », « "hour", "microsecond", "millisecond", "minute",
1694 // "nanosecond", "second" », «»)
1695 // TODO: Move validation to `temporal_rs`.
1696 let partial_dt = to_partial_datetime(&object, context)?;
1697 let resolved_options = get_options_object(&options.unwrap_or_default())?;
1698 // g. Let result be ? InterpretTemporalDateTimeFields(calendarRec, fields, resolvedOptions).
1699 let overflow = get_option::<Overflow>(&resolved_options, js_string!("overflow"), context)?;
1700 return InnerDateTime::from_partial(partial_dt, overflow).map_err(Into::into);
1701 }
1702 // 4. Else,
1703 // a. If item is not a String, throw a TypeError exception.
1704 let Some(string) = value.as_string() else {
1705 return Err(JsNativeError::typ()
1706 .with_message("Cannot convert unrecognized value to PlainDateTime.")
1707 .into());
1708 };
1709 // b. Let result be ? ParseTemporalDateTimeString(item).
1710 // c. Assert: IsValidISODate(result.[[Year]], result.[[Month]], result.[[Day]]) is true.
1711 // d. Assert: IsValidTime(result.[[Hour]], result.[[Minute]], result.[[Second]],
1712 // result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]]) is true.
1713 // e. Let calendar be result.[[Calendar]].
1714 // f. If calendar is empty, set calendar to "iso8601".
1715 // g. If IsBuiltinCalendar(calendar) is false, throw a RangeError exception.
1716 // h. Set calendar to CanonicalizeUValue("ca", calendar).
1717 let date = string.to_std_string_escaped().parse::<InnerDateTime>()?;
1718 // i. Perform ? GetTemporalOverflowOption(resolvedOptions).
1719 let resolved_options = get_options_object(&options.unwrap_or_default())?;
1720 let _ = get_option::<Overflow>(&resolved_options, js_string!("overflow"), context)?;
1721 // 5. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]], result.[[Day]],
1722 // result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]],
1723 // result.[[Microsecond]], result.[[Nanosecond]], calendar).
1724 Ok(date)
1725}
1726
1727fn to_partial_datetime(
1728 partial_object: &JsObject,
1729 context: &mut Context,
1730) -> JsResult<PartialDateTime> {
1731 let calendar = get_temporal_calendar_slot_value_with_default(partial_object, context)?;
1732 let fields = to_date_time_fields(partial_object, &calendar, context)?;
1733 Ok(PartialDateTime { fields, calendar })
1734}
1735
1736fn to_date_time_fields(
1737 partial_object: &JsObject,
1738 calendar: &Calendar,
1739 context: &mut Context,
1740) -> JsResult<DateTimeFields> {
1741 let day = partial_object
1742 .get(js_string!("day"), context)?
1743 .map(|v| {
1744 let finite = v.to_finitef64(context)?;
1745 finite
1746 .as_positive_integer_with_truncation()
1747 .map_err(JsError::from)
1748 })
1749 .transpose()?;
1750 let hour = partial_object
1751 .get(js_string!("hour"), context)?
1752 .map(|v| {
1753 let finite = v.to_finitef64(context)?;
1754 Ok::<u8, JsError>(finite.as_integer_with_truncation::<u8>())
1755 })
1756 .transpose()?;
1757 // TODO: `temporal_rs` needs a `has_era` method
1758 let has_no_era = calendar.kind() == AnyCalendarKind::Iso
1759 || calendar.kind() == AnyCalendarKind::Chinese
1760 || calendar.kind() == AnyCalendarKind::Dangi;
1761 let (era, era_year) = if has_no_era {
1762 (None, None)
1763 } else {
1764 let era = partial_object
1765 .get(js_string!("era"), context)?
1766 .map(|v| {
1767 let v = v.to_primitive(context, crate::value::PreferredType::String)?;
1768 let Some(era) = v.as_string() else {
1769 return Err(JsError::from(
1770 JsNativeError::typ()
1771 .with_message("The monthCode field value must be a string."),
1772 ));
1773 };
1774 // TODO: double check if an invalid monthCode is a range or type error.
1775 TinyAsciiStr::<19>::try_from_str(&era.to_std_string_escaped())
1776 .map_err(|e| JsError::from(JsNativeError::range().with_message(e.to_string())))
1777 })
1778 .transpose()?;
1779 let era_year = partial_object
1780 .get(js_string!("eraYear"), context)?
1781 .map(|v| {
1782 let finite = v.to_finitef64(context)?;
1783 Ok::<i32, JsError>(finite.as_integer_with_truncation::<i32>())
1784 })
1785 .transpose()?;
1786 (era, era_year)
1787 };
1788 let microsecond = partial_object
1789 .get(js_string!("microsecond"), context)?
1790 .map(|v| {
1791 let finite = v.to_finitef64(context)?;
1792 Ok::<u16, JsError>(finite.as_integer_with_truncation::<u16>())
1793 })
1794 .transpose()?;
1795
1796 let millisecond = partial_object
1797 .get(js_string!("millisecond"), context)?
1798 .map(|v| {
1799 let finite = v.to_finitef64(context)?;
1800 Ok::<u16, JsError>(finite.as_integer_with_truncation::<u16>())
1801 })
1802 .transpose()?;
1803
1804 let minute = partial_object
1805 .get(js_string!("minute"), context)?
1806 .map(|v| {
1807 let finite = v.to_finitef64(context)?;
1808 Ok::<u8, JsError>(finite.as_integer_with_truncation::<u8>())
1809 })
1810 .transpose()?;
1811
1812 let month = partial_object
1813 .get(js_string!("month"), context)?
1814 .map(|v| {
1815 let finite = v.to_finitef64(context)?;
1816 finite
1817 .as_positive_integer_with_truncation()
1818 .map_err(JsError::from)
1819 })
1820 .transpose()?;
1821
1822 let month_code = partial_object
1823 .get(js_string!("monthCode"), context)?
1824 .map(|v| {
1825 let v = v.to_primitive(context, crate::value::PreferredType::String)?;
1826 let Some(month_code) = v.as_string() else {
1827 return Err(JsNativeError::typ()
1828 .with_message("The monthCode field value must be a string.")
1829 .into());
1830 };
1831 MonthCode::from_str(&month_code.to_std_string_escaped()).map_err(JsError::from)
1832 })
1833 .transpose()?;
1834
1835 let nanosecond = partial_object
1836 .get(js_string!("nanosecond"), context)?
1837 .map(|v| {
1838 let finite = v.to_finitef64(context)?;
1839 Ok::<u16, JsError>(finite.as_integer_with_truncation::<u16>())
1840 })
1841 .transpose()?;
1842
1843 let second = partial_object
1844 .get(js_string!("second"), context)?
1845 .map(|v| {
1846 let finite = v.to_finitef64(context)?;
1847 Ok::<u8, JsError>(finite.as_integer_with_truncation::<u8>())
1848 })
1849 .transpose()?;
1850
1851 let year = partial_object
1852 .get(js_string!("year"), context)?
1853 .map(|v| {
1854 let finite = v.to_finitef64(context)?;
1855 Ok::<i32, JsError>(finite.as_integer_with_truncation::<i32>())
1856 })
1857 .transpose()?;
1858
1859 let calendar_fields = CalendarFields {
1860 year,
1861 month,
1862 month_code,
1863 day,
1864 era,
1865 era_year,
1866 };
1867 let time = PartialTime {
1868 hour,
1869 minute,
1870 second,
1871 millisecond,
1872 microsecond,
1873 nanosecond,
1874 };
1875
1876 Ok(DateTimeFields {
1877 calendar_fields,
1878 time,
1879 })
1880}