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