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 };