1- use std:: str:: FromStr ;
2-
31use crate :: {
42 builtins:: {
53 options:: { get_option, get_options_object} ,
@@ -13,13 +11,12 @@ use crate::{
1311 realm:: Realm ,
1412 string:: StaticJsStrings ,
1513 value:: { IntoOrUndefined , PreferredType } ,
16- Context , JsArgs , JsBigInt , JsData , JsError , JsNativeError , JsObject , JsResult , JsString ,
17- JsSymbol , JsValue , JsVariant ,
14+ Context , JsArgs , JsBigInt , JsData , JsNativeError , JsObject , JsResult , JsString , JsSymbol ,
15+ JsValue , JsVariant ,
1816} ;
1917use boa_gc:: { Finalize , Trace } ;
2018use boa_profiler:: Profiler ;
2119use cow_utils:: CowUtils ;
22- use num_traits:: ToPrimitive ;
2320use temporal_rs:: {
2421 options:: {
2522 ArithmeticOverflow , Disambiguation , DisplayCalendar , DisplayOffset , DisplayTimeZone ,
@@ -31,7 +28,8 @@ use temporal_rs::{
3128
3229use super :: {
3330 calendar:: to_temporal_calendar_slot_value, create_temporal_date, create_temporal_datetime,
34- create_temporal_instant, create_temporal_time, to_partial_date_record, to_partial_time_record,
31+ create_temporal_duration, create_temporal_instant, create_temporal_time,
32+ options:: get_difference_settings, to_partial_date_record, to_partial_time_record,
3533 to_temporal_duration, to_temporal_time,
3634} ;
3735
@@ -329,6 +327,8 @@ impl IntrinsicObject for ZonedDateTime {
329327 . method ( Self :: with_calendar, js_string ! ( "withCalendar" ) , 1 )
330328 . method ( Self :: add, js_string ! ( "add" ) , 1 )
331329 . method ( Self :: subtract, js_string ! ( "subtract" ) , 1 )
330+ . method ( Self :: until, js_string ! ( "until" ) , 1 )
331+ . method ( Self :: since, js_string ! ( "since" ) , 1 )
332332 . method ( Self :: equals, js_string ! ( "equals" ) , 1 )
333333 . method ( Self :: to_string, js_string ! ( "toString" ) , 0 )
334334 . method ( Self :: to_json, js_string ! ( "toJSON" ) , 0 )
@@ -367,14 +367,8 @@ impl BuiltInConstructor for ZonedDateTime {
367367 . into ( ) ) ;
368368 }
369369 // 2. Set epochNanoseconds to ? ToBigInt(epochNanoseconds).
370- let epoch_nanos = args. get_or_undefined ( 0 ) . to_bigint ( context) ?;
371370 // 3. If IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception.
372- // TODO: Better primitive for handling epochNanoseconds is needed in temporal_rs
373- let Some ( nanos) = epoch_nanos. to_f64 ( ) . to_i128 ( ) else {
374- return Err ( JsNativeError :: range ( )
375- . with_message ( "epochNanoseconds exceeded valid range." )
376- . into ( ) ) ;
377- } ;
371+ let epoch_nanos = args. get_or_undefined ( 0 ) . to_bigint ( context) ?;
378372
379373 // 4. If timeZone is not a String, throw a TypeError exception.
380374 let Some ( timezone_str) = args. get_or_undefined ( 1 ) . as_string ( ) else {
@@ -399,21 +393,18 @@ impl BuiltInConstructor for ZonedDateTime {
399393 // 9. If calendar is not a String, throw a TypeError exception.
400394 // 10. Set calendar to ? CanonicalizeCalendar(calendar).
401395 let calendar = args
402- . get ( 2 )
403- . map ( |v| {
404- if let Some ( calendar_str) = v. as_string ( ) {
405- Calendar :: from_str ( & calendar_str. to_std_string_escaped ( ) )
406- . map_err ( Into :: < JsError > :: into)
407- } else {
408- Err ( JsNativeError :: typ ( )
409- . with_message ( "calendar must be a string." )
410- . into ( ) )
411- }
396+ . get_or_undefined ( 2 )
397+ . map ( |s| {
398+ s. as_string ( )
399+ . map ( JsString :: to_std_string_lossy)
400+ . ok_or_else ( || JsNativeError :: typ ( ) . with_message ( "calendar must be a string." ) )
412401 } )
413402 . transpose ( ) ?
403+ . map ( |s| Calendar :: from_utf8 ( s. as_bytes ( ) ) )
404+ . transpose ( ) ?
414405 . unwrap_or_default ( ) ;
415406
416- let inner = ZonedDateTimeInner :: try_new ( nanos , calendar, timezone) ?;
407+ let inner = ZonedDateTimeInner :: try_new ( epoch_nanos . to_i128 ( ) , calendar, timezone) ?;
417408
418409 // 11. Return ? CreateTemporalZonedDateTime(epochNanoseconds, timeZone, calendar, NewTarget).
419410 create_temporal_zoneddatetime ( inner, Some ( new_target) , context) . map ( Into :: into)
@@ -893,13 +884,10 @@ impl ZonedDateTime {
893884 let options = get_options_object ( args. get_or_undefined ( 1 ) ) ?;
894885 let overflow = get_option :: < ArithmeticOverflow > ( & options, js_string ! ( "overflow" ) , context) ?;
895886
896- create_temporal_zoneddatetime (
897- zdt. inner
898- . add_with_provider ( & duration, overflow, context. tz_provider ( ) ) ?,
899- None ,
900- context,
901- )
902- . map ( Into :: into)
887+ let result = zdt
888+ . inner
889+ . add_with_provider ( & duration, overflow, context. tz_provider ( ) ) ?;
890+ create_temporal_zoneddatetime ( result, None , context) . map ( Into :: into)
903891 }
904892
905893 /// 6.3.36 `Temporal.ZonedDateTime.prototype.subtract ( temporalDurationLike [ , options ] )`
@@ -916,13 +904,48 @@ impl ZonedDateTime {
916904 let options = get_options_object ( args. get_or_undefined ( 1 ) ) ?;
917905 let overflow = get_option :: < ArithmeticOverflow > ( & options, js_string ! ( "overflow" ) , context) ?;
918906
919- create_temporal_zoneddatetime (
907+ let result =
920908 zdt. inner
921- . subtract_with_provider ( & duration, overflow, context. tz_provider ( ) ) ?,
922- None ,
923- context,
924- )
925- . map ( Into :: into)
909+ . subtract_with_provider ( & duration, overflow, context. tz_provider ( ) ) ?;
910+ create_temporal_zoneddatetime ( result, None , context) . map ( Into :: into)
911+ }
912+
913+ fn since ( this : & JsValue , args : & [ JsValue ] , context : & mut Context ) -> JsResult < JsValue > {
914+ let zdt = this
915+ . as_object ( )
916+ . and_then ( JsObject :: downcast_ref :: < Self > )
917+ . ok_or_else ( || {
918+ JsNativeError :: typ ( ) . with_message ( "the this object must be a ZonedDateTime object." )
919+ } ) ?;
920+
921+ let other = to_temporal_zoneddatetime ( args. get_or_undefined ( 0 ) , None , context) ?;
922+
923+ let options = get_options_object ( args. get_or_undefined ( 1 ) ) ?;
924+ let settings = get_difference_settings ( & options, context) ?;
925+
926+ let result = zdt
927+ . inner
928+ . since_with_provider ( & other, settings, context. tz_provider ( ) ) ?;
929+ create_temporal_duration ( result, None , context) . map ( Into :: into)
930+ }
931+
932+ fn until ( this : & JsValue , args : & [ JsValue ] , context : & mut Context ) -> JsResult < JsValue > {
933+ let zdt = this
934+ . as_object ( )
935+ . and_then ( JsObject :: downcast_ref :: < Self > )
936+ . ok_or_else ( || {
937+ JsNativeError :: typ ( ) . with_message ( "the this object must be a ZonedDateTime object." )
938+ } ) ?;
939+
940+ let other = to_temporal_zoneddatetime ( args. get_or_undefined ( 0 ) , None , context) ?;
941+
942+ let options = get_options_object ( args. get_or_undefined ( 1 ) ) ?;
943+ let settings = get_difference_settings ( & options, context) ?;
944+
945+ let result = zdt
946+ . inner
947+ . until_with_provider ( & other, settings, context. tz_provider ( ) ) ?;
948+ create_temporal_duration ( result, None , context) . map ( Into :: into)
926949 }
927950
928951 /// 6.3.40 `Temporal.ZonedDateTime.prototype.equals ( other )`
0 commit comments