2021-07-06 23:53:27 +01:00
/*
* Copyright ( c ) 2021 , Linus Groh < linusg @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2021-07-11 21:04:11 +03:00
# include <AK/DateTimeLexer.h>
2021-07-27 00:21:16 +01:00
# include <LibCrypto/BigInt/UnsignedBigInteger.h>
2021-07-06 23:53:27 +01:00
# include <LibJS/Runtime/AbstractOperations.h>
2021-07-27 00:21:16 +01:00
# include <LibJS/Runtime/Date.h>
2021-07-06 23:53:27 +01:00
# include <LibJS/Runtime/GlobalObject.h>
2021-07-27 00:21:16 +01:00
# include <LibJS/Runtime/Temporal/AbstractOperations.h>
# include <LibJS/Runtime/Temporal/Instant.h>
# include <LibJS/Runtime/Temporal/PlainDateTime.h>
2021-07-06 23:53:27 +01:00
# include <LibJS/Runtime/Temporal/TimeZone.h>
# include <LibJS/Runtime/Temporal/TimeZoneConstructor.h>
2021-08-01 17:55:44 +01:00
# include <LibJS/Runtime/Temporal/ZonedDateTime.h>
2021-07-06 23:53:27 +01:00
namespace JS : : Temporal {
// 11 Temporal.TimeZone Objects, https://tc39.es/proposal-temporal/#sec-temporal-timezone-objects
TimeZone : : TimeZone ( String identifier , Object & prototype )
: Object ( prototype )
, m_identifier ( move ( identifier ) )
{
}
// 11.1.1 IsValidTimeZoneName ( timeZone ), https://tc39.es/proposal-temporal/#sec-isvalidtimezonename
// NOTE: This is the minimum implementation of IsValidTimeZoneName, supporting only the "UTC" time zone.
bool is_valid_time_zone_name ( String const & time_zone )
{
// 1. Assert: Type(timeZone) is String.
// 2. Let tzText be ! StringToCodePoints(timeZone).
// 3. Let tzUpperText be the result of toUppercase(tzText), according to the Unicode Default Case Conversion algorithm.
// 4. Let tzUpper be ! CodePointsToString(tzUpperText).
auto tz_upper = time_zone . to_uppercase ( ) ;
// 5. If tzUpper and "UTC" are the same sequence of code points, return true.
if ( tz_upper = = " UTC " )
return true ;
// 6. Return false.
return false ;
}
// 11.1.2 CanonicalizeTimeZoneName ( timeZone ), https://tc39.es/proposal-temporal/#sec-canonicalizetimezonename
// NOTE: This is the minimum implementation of CanonicalizeTimeZoneName, supporting only the "UTC" time zone.
String canonicalize_time_zone_name ( String const & time_zone )
{
// 1. Assert: Type(timeZone) is String.
// 2. Assert: ! IsValidTimeZoneName(timeZone) is true.
VERIFY ( is_valid_time_zone_name ( time_zone ) ) ;
// 3. Return "UTC".
return " UTC " ;
}
// 11.1.3 DefaultTimeZone ( ), https://tc39.es/proposal-temporal/#sec-defaulttimezone
// NOTE: This is the minimum implementation of DefaultTimeZone, supporting only the "UTC" time zone.
String default_time_zone ( )
{
// 1. Return "UTC".
return " UTC " ;
}
2021-07-27 00:21:16 +01:00
// 11.6.1 ParseTemporalTimeZone ( string ), https://tc39.es/proposal-temporal/#sec-temporal-parsetemporaltimezone
String parse_temporal_time_zone ( GlobalObject & global_object , String const & string )
{
auto & vm = global_object . vm ( ) ;
// 1. Assert: Type(string) is String.
// 2. Let result be ? ParseTemporalTimeZoneString(string).
auto result = parse_temporal_time_zone_string ( global_object , string ) ;
if ( vm . exception ( ) )
return { } ;
// 3. If result.[[Z]] is not undefined, return "UTC".
if ( result - > z )
return " UTC " ;
// 4. Return result.[[Name]].
return * result - > name ;
}
2021-07-06 23:53:27 +01:00
// 11.6.2 CreateTemporalTimeZone ( identifier [ , newTarget ] ), https://tc39.es/proposal-temporal/#sec-temporal-createtemporaltimezone
2021-09-09 21:10:12 +01:00
TimeZone * create_temporal_time_zone ( GlobalObject & global_object , String const & identifier , FunctionObject const * new_target )
2021-07-06 23:53:27 +01:00
{
// 1. If newTarget is not present, set it to %Temporal.TimeZone%.
if ( ! new_target )
new_target = global_object . temporal_time_zone_constructor ( ) ;
// 2. Let object be ? OrdinaryCreateFromConstructor(newTarget, "%Temporal.TimeZone.prototype%", « [[InitializedTemporalTimeZone]], [[Identifier]], [[OffsetNanoseconds]] »).
// 3. Set object.[[Identifier]] to identifier.
2021-09-16 00:57:38 +03:00
auto * object = TRY_OR_DISCARD ( ordinary_create_from_constructor < TimeZone > ( global_object , * new_target , & GlobalObject : : temporal_time_zone_prototype , identifier ) ) ;
2021-07-06 23:53:27 +01:00
// 4. If identifier satisfies the syntax of a TimeZoneNumericUTCOffset (see 13.33), then
2021-07-11 21:04:11 +03:00
if ( is_valid_time_zone_numeric_utc_offset_syntax ( identifier ) ) {
2021-07-06 23:53:27 +01:00
// a. Set object.[[OffsetNanoseconds]] to ! ParseTimeZoneOffsetString(identifier).
2021-07-11 21:04:11 +03:00
object - > set_offset_nanoseconds ( parse_time_zone_offset_string ( global_object , identifier ) ) ;
2021-07-06 23:53:27 +01:00
}
// 5. Else,
else {
// a. Assert: ! CanonicalizeTimeZoneName(identifier) is identifier.
VERIFY ( canonicalize_time_zone_name ( identifier ) = = identifier ) ;
// b. Set object.[[OffsetNanoseconds]] to undefined.
// NOTE: No-op.
}
// 6. Return object.
return object ;
}
2021-07-27 00:21:16 +01:00
// 11.6.3 GetISOPartsFromEpoch ( epochNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-getisopartsfromepoch
Optional < ISODateTime > get_iso_parts_from_epoch ( BigInt const & epoch_nanoseconds )
{
2021-09-02 21:42:48 +01:00
// 1. Let remainderNs be remainder(epochNanoseconds, 10^6).
2021-07-27 00:21:16 +01:00
auto remainder_ns_bigint = epoch_nanoseconds . big_integer ( ) . divided_by ( Crypto : : UnsignedBigInteger { 1'000'000 } ) . remainder ;
auto remainder_ns = remainder_ns_bigint . to_base ( 10 ) . to_int < i64 > ( ) . value ( ) ;
// 2. Let epochMilliseconds be (epochNanoseconds − remainderNs) / 10^6.
auto epoch_milliseconds_bigint = epoch_nanoseconds . big_integer ( ) . minus ( remainder_ns_bigint ) . divided_by ( Crypto : : UnsignedBigInteger { 1'000'000 } ) . quotient ;
auto epoch_milliseconds = ( double ) epoch_milliseconds_bigint . to_base ( 10 ) . to_int < i64 > ( ) . value ( ) ;
// 3. Let year be ! YearFromTime(epochMilliseconds).
auto year = year_from_time ( epoch_milliseconds ) ;
// 4. Let month be ! MonthFromTime(epochMilliseconds) + 1.
auto month = static_cast < u8 > ( month_from_time ( epoch_milliseconds ) + 1 ) ;
// 5. Let day be ! DateFromTime(epochMilliseconds).
auto day = date_from_time ( epoch_milliseconds ) ;
// 6. Let hour be ! HourFromTime(epochMilliseconds).
auto hour = hour_from_time ( epoch_milliseconds ) ;
// 7. Let minute be ! MinFromTime(epochMilliseconds).
auto minute = min_from_time ( epoch_milliseconds ) ;
// 8. Let second be ! SecFromTime(epochMilliseconds).
auto second = sec_from_time ( epoch_milliseconds ) ;
// 9. Let millisecond be ! msFromTime(epochMilliseconds).
auto millisecond = ms_from_time ( epoch_milliseconds ) ;
// 10. Let microsecond be floor(remainderNs / 1000) modulo 1000.
auto microsecond = static_cast < u16 > ( ( remainder_ns / 1000 ) % 1000 ) ;
// 11. Let nanosecond be remainderNs modulo 1000.
auto nanosecond = static_cast < u16 > ( remainder_ns % 1000 ) ;
2021-08-17 20:38:29 +01:00
// 12. Return the Record { [[Year]]: year, [[Month]]: month, [[Day]]: day, [[Hour]]: hour, [[Minute]]: minute, [[Second]]: second, [[Millisecond]]: millisecond, [[Microsecond]]: microsecond, [[Nanosecond]]: nanosecond }.
2021-07-27 00:21:16 +01:00
return ISODateTime { . year = year , . month = month , . day = day , . hour = hour , . minute = minute , . second = second , . millisecond = millisecond , . microsecond = microsecond , . nanosecond = nanosecond } ;
}
2021-07-25 20:19:37 +01:00
// 11.6.5 GetIANATimeZoneOffsetNanoseconds ( epochNanoseconds, timeZoneIdentifier ), https://tc39.es/proposal-temporal/#sec-temporal-getianatimezoneoffsetnanoseconds
i64 get_iana_time_zone_offset_nanoseconds ( [[maybe_unused]] BigInt const& epoch_nanoseconds, [[maybe_unused]] String const & time_zone_identifier )
{
// The abstract operation GetIANATimeZoneOffsetNanoseconds is an implementation-defined algorithm that returns an integer representing the offset of the IANA time zone identified by timeZoneIdentifier from UTC, at the instant corresponding to epochNanoseconds.
// Given the same values of epochNanoseconds and timeZoneIdentifier, the result must be the same for the lifetime of the surrounding agent.
// TODO: Implement this
return 0 ;
}
2021-07-11 21:04:11 +03:00
// https://tc39.es/proposal-temporal/#prod-TimeZoneNumericUTCOffset
static bool parse_time_zone_numeric_utc_offset_syntax ( String const & offset_string , StringView & sign , StringView & hours , Optional < StringView > & minutes , Optional < StringView > & seconds , Optional < StringView > & fraction )
{
DateTimeLexer lexer ( offset_string ) ;
auto sign_part = lexer . consume_sign ( ) ;
if ( ! sign_part . has_value ( ) )
return false ;
sign = * sign_part ;
auto hours_part = lexer . consume_hours ( ) ;
if ( ! hours_part . has_value ( ) )
return false ;
hours = * hours_part ;
if ( ! lexer . tell_remaining ( ) )
return true ;
auto uses_separator = lexer . consume_specific ( ' : ' ) ;
minutes = lexer . consume_minutes_or_seconds ( ) ;
if ( ! minutes . has_value ( ) )
return false ;
if ( ! lexer . tell_remaining ( ) )
return true ;
if ( lexer . consume_specific ( ' : ' ) ! = uses_separator )
return false ;
seconds = lexer . consume_minutes_or_seconds ( ) ;
if ( ! seconds . has_value ( ) )
return false ;
if ( ! lexer . tell_remaining ( ) )
return true ;
if ( ! lexer . consume_specific ( ' . ' ) & & ! lexer . consume_specific ( ' , ' ) )
return false ;
fraction = lexer . consume_fractional_seconds ( ) ;
return fraction . has_value ( ) ;
}
bool is_valid_time_zone_numeric_utc_offset_syntax ( String const & offset_string )
{
StringView discarded ;
Optional < StringView > optionally_discarded ;
// FIXME: This is very wasteful
return parse_time_zone_numeric_utc_offset_syntax ( offset_string , discarded , discarded , optionally_discarded , optionally_discarded , optionally_discarded ) ;
}
// 11.6.8 ParseTimeZoneOffsetString ( offsetString ), https://tc39.es/proposal-temporal/#sec-temporal-parsetimezoneoffsetstring
double parse_time_zone_offset_string ( GlobalObject & global_object , String const & offset_string )
{
auto & vm = global_object . vm ( ) ;
// 1. Assert: Type(offsetString) is String.
// 2. If offsetString does not satisfy the syntax of a TimeZoneNumericUTCOffset (see 13.33), then
// a. Throw a RangeError exception.
// 3. Let sign, hours, minutes, seconds, and fraction be the parts of offsetString produced respectively by the TimeZoneUTCOffsetSign, TimeZoneUTCOffsetHour, TimeZoneUTCOffsetMinute, TimeZoneUTCOffsetSecond, and TimeZoneUTCOffsetFraction productions, or undefined if not present.
StringView sign_part ;
StringView hours_part ;
Optional < StringView > minutes_part ;
Optional < StringView > seconds_part ;
Optional < StringView > fraction_part ;
auto success = parse_time_zone_numeric_utc_offset_syntax ( offset_string , sign_part , hours_part , minutes_part , seconds_part , fraction_part ) ;
if ( ! success ) {
vm . throw_exception < RangeError > ( global_object , ErrorType : : InvalidFormat , " TimeZone offset " ) ;
return { } ;
}
// 4. If either hours or sign are undefined, throw a RangeError exception.
// NOTE: Both of these checks are always false, due to the handling of Step 2
double sign ;
// 5. If sign is the code unit 0x002D (HYPHEN-MINUS) or 0x2212 (MINUS SIGN), then
if ( sign_part . is_one_of ( " - " , " \xE2 \x88 \x92 " ) ) {
// a. Set sign to − 1.
sign = - 1 ;
}
// 6. Else,
else {
// a. Set sign to 1.
sign = 1 ;
}
// 7. Set hours to ! ToIntegerOrInfinity(hours).
auto hours = Value ( js_string ( vm , hours_part ) ) . to_integer_or_infinity ( global_object ) ;
// 8. Set minutes to ! ToIntegerOrInfinity(minutes).
auto minutes = Value ( js_string ( vm , minutes_part . value_or ( " " sv ) ) ) . to_integer_or_infinity ( global_object ) ;
// 9. Set seconds to ! ToIntegerOrInfinity(seconds).
auto seconds = Value ( js_string ( vm , seconds_part . value_or ( " " sv ) ) ) . to_integer_or_infinity ( global_object ) ;
double nanoseconds ;
// 10. If fraction is not undefined, then
if ( fraction_part . has_value ( ) ) {
// a. Set fraction to the string-concatenation of the previous value of fraction and the string "000000000".
auto fraction = String : : formatted ( " {}000000000 " , * fraction_part ) ;
// b. Let nanoseconds be the String value equal to the substring of fraction consisting of the code units with indices 0 (inclusive) through 9 (exclusive).
// c. Set nanoseconds to ! ToIntegerOrInfinity(nanoseconds).
nanoseconds = Value ( js_string ( vm , fraction_part - > substring_view ( 0 , 9 ) ) ) . to_integer_or_infinity ( global_object ) ;
}
// 11. Else,
else {
// a. Let nanoseconds be 0.
nanoseconds = 0 ;
}
// 12. Return sign × (((hours × 60 + minutes) × 60 + seconds) × 10^9 + nanoseconds).
return sign * ( ( ( hours * 60 + minutes ) * 60 + seconds ) * 1000000000 + nanoseconds ) ;
}
// 11.6.9 FormatTimeZoneOffsetString ( offsetNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-formattimezoneoffsetstring
String format_time_zone_offset_string ( double offset_nanoseconds )
{
auto offset = static_cast < i64 > ( offset_nanoseconds ) ;
// 1. Assert: offsetNanoseconds is an integer.
VERIFY ( offset = = offset_nanoseconds ) ;
StringBuilder builder ;
// 2. If offsetNanoseconds ≥ 0, let sign be "+"; otherwise, let sign be "-".
if ( offset > = 0 )
builder . append ( ' + ' ) ;
else
builder . append ( ' - ' ) ;
// 3. Let nanoseconds be abs(offsetNanoseconds) modulo 10^9.
2021-07-13 21:24:59 +02:00
auto nanoseconds = AK : : abs ( offset ) % 1000000000 ;
2021-07-11 21:04:11 +03:00
// 4. Let seconds be floor(offsetNanoseconds / 10^9) modulo 60.
auto seconds = ( offset / 1000000000 ) % 60 ;
// 5. Let minutes be floor(offsetNanoseconds / (6 × 10^10)) modulo 60.
auto minutes = ( offset / 60000000000 ) % 60 ;
// 6. Let hours be floor(offsetNanoseconds / (3.6 × 10^12)).
auto hours = offset / 3600000000000 ;
// 7. Let h be hours, formatted as a two-digit decimal number, padded to the left with a zero if necessary.
builder . appendff ( " {:02} " , hours ) ;
// 8. Let m be minutes, formatted as a two-digit decimal number, padded to the left with a zero if necessary.
builder . appendff ( " :{:02} " , minutes ) ;
// 9. Let s be seconds, formatted as a two-digit decimal number, padded to the left with a zero if necessary.
// Handled by steps 10 & 11
// 10. If nanoseconds ≠ 0, then
if ( nanoseconds ! = 0 ) {
// a. Let fraction be nanoseconds, formatted as a nine-digit decimal number, padded to the left with zeroes if necessary.
// b. Set fraction to the longest possible substring of fraction starting at position 0 and not ending with the code unit 0x0030 (DIGIT ZERO).
// c. Let post be the string-concatenation of the code unit 0x003A (COLON), s, the code unit 0x002E (FULL STOP), and fraction.
builder . appendff ( " :{:02}.{:9} " , seconds , nanoseconds ) ;
}
// 11. Else if seconds ≠ 0, then
else if ( seconds ! = 0 ) {
// a. Let post be the string-concatenation of the code unit 0x003A (COLON) and s.
builder . appendff ( " :{:02} " , seconds ) ;
}
// 12. Return the string-concatenation of sign, h, the code unit 0x003A (COLON), m, and post.
return builder . to_string ( ) ;
}
2021-07-27 00:21:16 +01:00
// 11.6.10 ToTemporalTimeZone ( temporalTimeZoneLike ), https://tc39.es/proposal-temporal/#sec-temporal-totemporaltimezone
Object * to_temporal_time_zone ( GlobalObject & global_object , Value temporal_time_zone_like )
{
auto & vm = global_object . vm ( ) ;
// 1. If Type(temporalTimeZoneLike) is Object, then
if ( temporal_time_zone_like . is_object ( ) ) {
// a. If temporalTimeZoneLike has an [[InitializedTemporalZonedDateTime]] internal slot, then
2021-08-01 17:55:44 +01:00
if ( is < ZonedDateTime > ( temporal_time_zone_like . as_object ( ) ) ) {
auto & zoned_date_time = static_cast < ZonedDateTime & > ( temporal_time_zone_like . as_object ( ) ) ;
// i. Return temporalTimeZoneLike.[[TimeZone]].
return & zoned_date_time . time_zone ( ) ;
}
2021-07-27 00:21:16 +01:00
// b. If ? HasProperty(temporalTimeZoneLike, "timeZone") is false, return temporalTimeZoneLike.
auto has_property = temporal_time_zone_like . as_object ( ) . has_property ( vm . names . timeZone ) ;
if ( vm . exception ( ) )
return { } ;
if ( ! has_property )
return & temporal_time_zone_like . as_object ( ) ;
// c. Set temporalTimeZoneLike to ? Get(temporalTimeZoneLike, "timeZone").
temporal_time_zone_like = temporal_time_zone_like . as_object ( ) . get ( vm . names . timeZone ) ;
if ( vm . exception ( ) )
return { } ;
// d. If Type(temporalTimeZoneLike) is Object and ? HasProperty(temporalTimeZoneLike, "timeZone") is false, return temporalTimeZoneLike.
if ( temporal_time_zone_like . is_object ( ) ) {
has_property = temporal_time_zone_like . as_object ( ) . has_property ( vm . names . timeZone ) ;
if ( vm . exception ( ) )
return { } ;
if ( ! has_property )
return & temporal_time_zone_like . as_object ( ) ;
}
}
// 2. Let identifier be ? ToString(temporalTimeZoneLike).
auto identifier = temporal_time_zone_like . to_string ( global_object ) ;
if ( vm . exception ( ) )
return { } ;
// 3. Let result be ? ParseTemporalTimeZone(identifier).
auto result = parse_temporal_time_zone ( global_object , identifier ) ;
if ( vm . exception ( ) )
return { } ;
// 4. Return ? CreateTemporalTimeZone(result).
return create_temporal_time_zone ( global_object , result ) ;
}
// 11.6.11 GetOffsetNanosecondsFor ( timeZone, instant ), https://tc39.es/proposal-temporal/#sec-temporal-getoffsetnanosecondsfor
2021-07-31 22:21:53 +01:00
double get_offset_nanoseconds_for ( GlobalObject & global_object , Value time_zone , Instant & instant )
2021-07-27 00:21:16 +01:00
{
auto & vm = global_object . vm ( ) ;
// 1. Let getOffsetNanosecondsFor be ? GetMethod(timeZone, "getOffsetNanosecondsFor").
2021-07-31 22:21:53 +01:00
auto * get_offset_nanoseconds_for = time_zone . get_method ( global_object , vm . names . getOffsetNanosecondsFor ) ;
2021-07-27 00:21:16 +01:00
if ( vm . exception ( ) )
return { } ;
// 2. If getOffsetNanosecondsFor is undefined, set getOffsetNanosecondsFor to %Temporal.TimeZone.prototype.getOffsetNanosecondsFor%.
if ( ! get_offset_nanoseconds_for )
get_offset_nanoseconds_for = global_object . temporal_time_zone_prototype_get_offset_nanoseconds_for_function ( ) ;
// 3. Let offsetNanoseconds be ? Call(getOffsetNanosecondsFor, timeZone, « instant »).
2021-07-31 22:21:53 +01:00
auto offset_nanoseconds_value = vm . call ( * get_offset_nanoseconds_for , time_zone , & instant ) ;
2021-07-27 00:21:16 +01:00
if ( vm . exception ( ) )
return { } ;
// 4. If Type(offsetNanoseconds) is not Number, throw a TypeError exception.
if ( ! offset_nanoseconds_value . is_number ( ) ) {
vm . throw_exception < TypeError > ( global_object , ErrorType : : IsNotA , " Offset nanoseconds value " , " number " ) ;
return { } ;
}
// 5. If ! IsIntegralNumber(offsetNanoseconds) is false, throw a RangeError exception.
if ( ! offset_nanoseconds_value . is_integral_number ( ) ) {
2021-07-30 19:51:10 +01:00
vm . throw_exception < RangeError > ( global_object , ErrorType : : IsNotAn , " Offset nanoseconds value " , " integral number " ) ;
2021-07-27 00:21:16 +01:00
return { } ;
}
// 6. Set offsetNanoseconds to ℝ (offsetNanoseconds).
auto offset_nanoseconds = offset_nanoseconds_value . as_double ( ) ;
// 7. If abs(offsetNanoseconds) > 86400 × 10^9, throw a RangeError exception.
if ( fabs ( offset_nanoseconds ) > 86400000000000.0 ) {
vm . throw_exception < RangeError > ( global_object , ErrorType : : TemporalInvalidOffsetNanosecondsValue ) ;
return { } ;
}
// 8. Return offsetNanoseconds.
return offset_nanoseconds ;
}
2021-08-08 11:04:30 +01:00
// 11.6.12 BuiltinTimeZoneGetOffsetStringFor ( timeZone, instant ), https://tc39.es/proposal-temporal/#sec-temporal-builtintimezonegetoffsetstringfor
2021-08-31 00:15:36 +01:00
Optional < String > builtin_time_zone_get_offset_string_for ( GlobalObject & global_object , Value time_zone , Instant & instant )
2021-07-31 21:54:35 +01:00
{
auto & vm = global_object . vm ( ) ;
// 1. Let offsetNanoseconds be ? GetOffsetNanosecondsFor(timeZone, instant).
2021-08-31 00:15:36 +01:00
auto offset_nanoseconds = get_offset_nanoseconds_for ( global_object , time_zone , instant ) ;
2021-07-31 21:54:35 +01:00
if ( vm . exception ( ) )
return { } ;
// 2. Return ! FormatTimeZoneOffsetString(offsetNanoseconds).
return format_time_zone_offset_string ( offset_nanoseconds ) ;
}
2021-07-27 00:21:16 +01:00
// 11.6.13 BuiltinTimeZoneGetPlainDateTimeFor ( timeZone, instant, calendar ), https://tc39.es/proposal-temporal/#sec-temporal-builtintimezonegetplaindatetimefor
2021-07-31 22:21:53 +01:00
PlainDateTime * builtin_time_zone_get_plain_date_time_for ( GlobalObject & global_object , Value time_zone , Instant & instant , Object & calendar )
2021-07-27 00:21:16 +01:00
{
auto & vm = global_object . vm ( ) ;
// 1. Let offsetNanoseconds be ? GetOffsetNanosecondsFor(timeZone, instant).
auto offset_nanoseconds = get_offset_nanoseconds_for ( global_object , time_zone , instant ) ;
if ( vm . exception ( ) )
return { } ;
// 2. Let result be ! GetISOPartsFromEpoch(instant.[[Nanoseconds]]).
auto result = get_iso_parts_from_epoch ( instant . nanoseconds ( ) ) ;
// 3. Set result to ! BalanceISODateTime(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]] + offsetNanoseconds).
result = balance_iso_date_time ( result - > year , result - > month , result - > day , result - > hour , result - > minute , result - > second , result - > millisecond , result - > microsecond , result - > nanosecond + offset_nanoseconds ) ;
// 4. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]], result.[[Day]], result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], result.[[Microsecond]], result.[[Nanosecond]], calendar).
return create_temporal_date_time ( global_object , result - > year , result - > month , result - > day , result - > hour , result - > minute , result - > second , result - > millisecond , result - > microsecond , result - > nanosecond , calendar ) ;
}
2021-07-06 23:53:27 +01:00
}