tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TemporalNow.cpp (7280B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "builtin/temporal/TemporalNow.h"
      8 
      9 #include "mozilla/Assertions.h"
     10 
     11 #include <stdint.h>
     12 
     13 #include "jsdate.h"
     14 #include "jspubtd.h"
     15 #include "jstypes.h"
     16 #include "NamespaceImports.h"
     17 
     18 #include "builtin/temporal/Calendar.h"
     19 #include "builtin/temporal/Instant.h"
     20 #include "builtin/temporal/PlainDate.h"
     21 #include "builtin/temporal/PlainDateTime.h"
     22 #include "builtin/temporal/PlainTime.h"
     23 #include "builtin/temporal/TemporalParser.h"
     24 #include "builtin/temporal/TemporalTypes.h"
     25 #include "builtin/temporal/TimeZone.h"
     26 #include "builtin/temporal/ZonedDateTime.h"
     27 #include "js/CallArgs.h"
     28 #include "js/Class.h"
     29 #include "js/Date.h"
     30 #include "js/PropertyDescriptor.h"
     31 #include "js/PropertySpec.h"
     32 #include "js/RootingAPI.h"
     33 #include "js/TypeDecls.h"
     34 #include "vm/DateTime.h"
     35 #include "vm/GlobalObject.h"
     36 #include "vm/JSContext.h"
     37 #include "vm/Realm.h"
     38 #include "vm/StringType.h"
     39 
     40 #include "vm/JSObject-inl.h"
     41 
     42 using namespace js;
     43 using namespace js::temporal;
     44 
     45 /**
     46 * SystemUTCEpochNanoseconds ( )
     47 */
     48 static int64_t SystemUTCEpochMilliseconds(JSContext* cx) {
     49  // Steps 1-2.
     50  JS::ClippedTime nowMillis = DateNow(cx);
     51  MOZ_ASSERT(nowMillis.isValid());
     52  MOZ_ASSERT(nowMillis.toDouble() >= js::StartOfTime);
     53  MOZ_ASSERT(nowMillis.toDouble() <= js::EndOfTime);
     54 
     55  // Step 3.
     56  return int64_t(nowMillis.toDouble());
     57 }
     58 
     59 /**
     60 * SystemUTCEpochNanoseconds ( )
     61 */
     62 static EpochNanoseconds SystemUTCEpochNanoseconds(JSContext* cx) {
     63  return EpochNanoseconds::fromMilliseconds(SystemUTCEpochMilliseconds(cx));
     64 }
     65 
     66 /**
     67 * SystemDateTime ( temporalTimeZoneLike )
     68 */
     69 static bool SystemDateTime(JSContext* cx, Handle<Value> temporalTimeZoneLike,
     70                           ISODateTime* dateTime) {
     71  // Step 1.
     72  //
     73  // Optimization to directly retrieve the system time zone offset.
     74  if (temporalTimeZoneLike.isUndefined()) {
     75    // Step 2. (Not applicable)
     76 
     77    // Step 3.
     78    int64_t epochMillis = SystemUTCEpochMilliseconds(cx);
     79 
     80    // Step 4.
     81    int32_t offsetMillis = DateTimeInfo::getOffsetMilliseconds(
     82        cx->realm()->getDateTimeInfo(), epochMillis,
     83        DateTimeInfo::TimeZoneOffset::UTC);
     84    MOZ_ASSERT(std::abs(offsetMillis) < ToMilliseconds(TemporalUnit::Day));
     85 
     86    *dateTime = GetISODateTimeFor(
     87        EpochNanoseconds::fromMilliseconds(epochMillis),
     88        offsetMillis * ToNanoseconds(TemporalUnit::Millisecond));
     89    return true;
     90  }
     91 
     92  // Step 2.
     93  Rooted<TimeZoneValue> timeZone(cx);
     94  if (!ToTemporalTimeZone(cx, temporalTimeZoneLike, &timeZone)) {
     95    return false;
     96  }
     97 
     98  // Step 3.
     99  auto epochNs = SystemUTCEpochNanoseconds(cx);
    100 
    101  // Step 4.
    102  return GetISODateTimeFor(cx, timeZone, epochNs, dateTime);
    103 }
    104 
    105 /**
    106 * Temporal.Now.timeZoneId ( )
    107 */
    108 static bool Temporal_Now_timeZoneId(JSContext* cx, unsigned argc, Value* vp) {
    109  CallArgs args = CallArgsFromVp(argc, vp);
    110 
    111  // Step 1.
    112  auto* result = SystemTimeZoneIdentifier(cx);
    113  if (!result) {
    114    return false;
    115  }
    116 
    117  args.rval().setString(result);
    118  return true;
    119 }
    120 
    121 /**
    122 * Temporal.Now.instant ( )
    123 */
    124 static bool Temporal_Now_instant(JSContext* cx, unsigned argc, Value* vp) {
    125  CallArgs args = CallArgsFromVp(argc, vp);
    126 
    127  // Step 1.
    128  auto epochNs = SystemUTCEpochNanoseconds(cx);
    129 
    130  // Step 2.
    131  auto* result = CreateTemporalInstant(cx, epochNs);
    132  if (!result) {
    133    return false;
    134  }
    135 
    136  args.rval().setObject(*result);
    137  return true;
    138 }
    139 
    140 /**
    141 * Temporal.Now.plainDateTimeISO ( [ temporalTimeZoneLike ] )
    142 */
    143 static bool Temporal_Now_plainDateTimeISO(JSContext* cx, unsigned argc,
    144                                          Value* vp) {
    145  CallArgs args = CallArgsFromVp(argc, vp);
    146 
    147  // Step 1.
    148  ISODateTime dateTime;
    149  if (!SystemDateTime(cx, args.get(0), &dateTime)) {
    150    return false;
    151  }
    152 
    153  // Step 2.
    154  Rooted<CalendarValue> calendar(cx, CalendarValue(CalendarId::ISO8601));
    155  auto* result = CreateTemporalDateTime(cx, dateTime, calendar);
    156  if (!result) {
    157    return false;
    158  }
    159 
    160  args.rval().setObject(*result);
    161  return true;
    162 }
    163 
    164 /**
    165 * Temporal.Now.zonedDateTimeISO ( [ temporalTimeZoneLike ] )
    166 */
    167 static bool Temporal_Now_zonedDateTimeISO(JSContext* cx, unsigned argc,
    168                                          Value* vp) {
    169  CallArgs args = CallArgsFromVp(argc, vp);
    170 
    171  // Steps 1-2.
    172  Rooted<TimeZoneValue> timeZone(cx);
    173  if (!args.hasDefined(0)) {
    174    if (!SystemTimeZone(cx, &timeZone)) {
    175      return false;
    176    }
    177  } else {
    178    if (!ToTemporalTimeZone(cx, args[0], &timeZone)) {
    179      return false;
    180    }
    181  }
    182 
    183  // Step 3.
    184  auto epochNs = SystemUTCEpochNanoseconds(cx);
    185 
    186  // Step 4.
    187  Rooted<CalendarValue> calendar(cx, CalendarValue(CalendarId::ISO8601));
    188  auto* result = CreateTemporalZonedDateTime(cx, epochNs, timeZone, calendar);
    189  if (!result) {
    190    return false;
    191  }
    192 
    193  args.rval().setObject(*result);
    194  return true;
    195 }
    196 
    197 /**
    198 * Temporal.Now.plainDateISO ( [ temporalTimeZoneLike ] )
    199 */
    200 static bool Temporal_Now_plainDateISO(JSContext* cx, unsigned argc, Value* vp) {
    201  CallArgs args = CallArgsFromVp(argc, vp);
    202 
    203  // Step 1.
    204  ISODateTime dateTime;
    205  if (!SystemDateTime(cx, args.get(0), &dateTime)) {
    206    return false;
    207  }
    208 
    209  // Step 2.
    210  Rooted<CalendarValue> calendar(cx, CalendarValue(CalendarId::ISO8601));
    211  auto* result = CreateTemporalDate(cx, dateTime.date, calendar);
    212  if (!result) {
    213    return false;
    214  }
    215 
    216  args.rval().setObject(*result);
    217  return true;
    218 }
    219 
    220 /**
    221 * Temporal.Now.plainTimeISO ( [ temporalTimeZoneLike ] )
    222 */
    223 static bool Temporal_Now_plainTimeISO(JSContext* cx, unsigned argc, Value* vp) {
    224  CallArgs args = CallArgsFromVp(argc, vp);
    225 
    226  // Step 1.
    227  ISODateTime dateTime;
    228  if (!SystemDateTime(cx, args.get(0), &dateTime)) {
    229    return false;
    230  }
    231 
    232  // Step 2.
    233  auto* result = CreateTemporalTime(cx, dateTime.time);
    234  if (!result) {
    235    return false;
    236  }
    237 
    238  args.rval().setObject(*result);
    239  return true;
    240 }
    241 
    242 const JSClass TemporalNowObject::class_ = {
    243    "Temporal.Now",
    244    JSCLASS_HAS_CACHED_PROTO(JSProto_TemporalNow),
    245    JS_NULL_CLASS_OPS,
    246    &TemporalNowObject::classSpec_,
    247 };
    248 
    249 static const JSFunctionSpec TemporalNow_methods[] = {
    250    JS_FN("timeZoneId", Temporal_Now_timeZoneId, 0, 0),
    251    JS_FN("instant", Temporal_Now_instant, 0, 0),
    252    JS_FN("plainDateTimeISO", Temporal_Now_plainDateTimeISO, 0, 0),
    253    JS_FN("zonedDateTimeISO", Temporal_Now_zonedDateTimeISO, 0, 0),
    254    JS_FN("plainDateISO", Temporal_Now_plainDateISO, 0, 0),
    255    JS_FN("plainTimeISO", Temporal_Now_plainTimeISO, 0, 0),
    256    JS_FS_END,
    257 };
    258 
    259 static const JSPropertySpec TemporalNow_properties[] = {
    260    JS_STRING_SYM_PS(toStringTag, "Temporal.Now", JSPROP_READONLY),
    261    JS_PS_END,
    262 };
    263 
    264 static JSObject* CreateTemporalNowObject(JSContext* cx, JSProtoKey key) {
    265  Rooted<JSObject*> proto(cx, &cx->global()->getObjectPrototype());
    266  return NewTenuredObjectWithGivenProto(cx, &TemporalNowObject::class_, proto);
    267 }
    268 
    269 const ClassSpec TemporalNowObject::classSpec_ = {
    270    CreateTemporalNowObject,
    271    nullptr,
    272    TemporalNow_methods,
    273    TemporalNow_properties,
    274    nullptr,
    275    nullptr,
    276    nullptr,
    277    ClassSpec::DontDefineConstructor,
    278 };