1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qv4dateobject_p.h" |
5 | #include "qv4runtime_p.h" |
6 | #include "qv4symbol_p.h" |
7 | |
8 | #include <QtCore/QDebug> |
9 | #include <QtCore/QDateTime> |
10 | #include <QtCore/private/qlocaltime_p.h> |
11 | #include <QtCore/QStringList> |
12 | #include <QtCore/QTimeZone> |
13 | |
14 | #include <wtf/MathExtras.h> |
15 | |
16 | using namespace QV4; |
17 | |
18 | static const double HoursPerDay = 24.0; |
19 | static const double MinutesPerHour = 60.0; |
20 | static const double SecondsPerMinute = 60.0; |
21 | static const double msPerSecond = 1000.0; |
22 | static const double msPerMinute = 60000.0; |
23 | static const double msPerHour = 3600000.0; |
24 | static const double msPerDay = 86400000.0; |
25 | |
26 | static inline double TimeWithinDay(double t) |
27 | { |
28 | double r = ::fmod(x: t, y: msPerDay); |
29 | return (r >= 0) ? r : r + msPerDay; |
30 | } |
31 | |
32 | static inline int HourFromTime(double t) |
33 | { |
34 | int r = int(::fmod(x: ::floor(x: t / msPerHour), y: HoursPerDay)); |
35 | return (r >= 0) ? r : r + int(HoursPerDay); |
36 | } |
37 | |
38 | static inline int MinFromTime(double t) |
39 | { |
40 | int r = int(::fmod(x: ::floor(x: t / msPerMinute), y: MinutesPerHour)); |
41 | return (r >= 0) ? r : r + int(MinutesPerHour); |
42 | } |
43 | |
44 | static inline int SecFromTime(double t) |
45 | { |
46 | int r = int(::fmod(x: ::floor(x: t / msPerSecond), y: SecondsPerMinute)); |
47 | return (r >= 0) ? r : r + int(SecondsPerMinute); |
48 | } |
49 | |
50 | static inline int msFromTime(double t) |
51 | { |
52 | int r = int(::fmod(x: t, y: msPerSecond)); |
53 | return (r >= 0) ? r : r + int(msPerSecond); |
54 | } |
55 | |
56 | static inline double Day(double t) |
57 | { |
58 | return ::floor(x: t / msPerDay); |
59 | } |
60 | |
61 | static inline double DaysInYear(double y) |
62 | { |
63 | if (::fmod(x: y, y: 4)) |
64 | return 365; |
65 | |
66 | else if (::fmod(x: y, y: 100)) |
67 | return 366; |
68 | |
69 | else if (::fmod(x: y, y: 400)) |
70 | return 365; |
71 | |
72 | return 366; |
73 | } |
74 | |
75 | static inline double DayFromYear(double y) |
76 | { |
77 | return 365 * (y - 1970) |
78 | + ::floor(x: (y - 1969) / 4) |
79 | - ::floor(x: (y - 1901) / 100) |
80 | + ::floor(x: (y - 1601) / 400); |
81 | } |
82 | |
83 | static inline double TimeFromYear(double y) |
84 | { |
85 | return msPerDay * DayFromYear(y); |
86 | } |
87 | |
88 | static inline double YearFromTime(double t) |
89 | { |
90 | int y = 1970; |
91 | y += (int) ::floor(x: t / (msPerDay * 365.2425)); |
92 | |
93 | double t2 = TimeFromYear(y); |
94 | return (t2 > t) ? y - 1 : ((t2 + msPerDay * DaysInYear(y)) <= t) ? y + 1 : y; |
95 | } |
96 | |
97 | static inline bool InLeapYear(double t) |
98 | { |
99 | double x = DaysInYear(y: YearFromTime(t)); |
100 | if (x == 365) |
101 | return 0; |
102 | |
103 | Q_ASSERT(x == 366); |
104 | return 1; |
105 | } |
106 | |
107 | static inline double DayWithinYear(double t) |
108 | { |
109 | return Day(t) - DayFromYear(y: YearFromTime(t)); |
110 | } |
111 | |
112 | static inline double MonthFromTime(double t) |
113 | { |
114 | double d = DayWithinYear(t); |
115 | double l = InLeapYear(t); |
116 | |
117 | if (d < 31.0) |
118 | return 0; |
119 | |
120 | else if (d < 59.0 + l) |
121 | return 1; |
122 | |
123 | else if (d < 90.0 + l) |
124 | return 2; |
125 | |
126 | else if (d < 120.0 + l) |
127 | return 3; |
128 | |
129 | else if (d < 151.0 + l) |
130 | return 4; |
131 | |
132 | else if (d < 181.0 + l) |
133 | return 5; |
134 | |
135 | else if (d < 212.0 + l) |
136 | return 6; |
137 | |
138 | else if (d < 243.0 + l) |
139 | return 7; |
140 | |
141 | else if (d < 273.0 + l) |
142 | return 8; |
143 | |
144 | else if (d < 304.0 + l) |
145 | return 9; |
146 | |
147 | else if (d < 334.0 + l) |
148 | return 10; |
149 | |
150 | else if (d < 365.0 + l) |
151 | return 11; |
152 | |
153 | return qt_qnan(); // ### assert? |
154 | } |
155 | |
156 | static inline double DateFromTime(double t) |
157 | { |
158 | int m = (int) QV4::Value::toInteger(d: MonthFromTime(t)); |
159 | double d = DayWithinYear(t); |
160 | double l = InLeapYear(t); |
161 | |
162 | switch (m) { |
163 | case 0: return d + 1.0; |
164 | case 1: return d - 30.0; |
165 | case 2: return d - 58.0 - l; |
166 | case 3: return d - 89.0 - l; |
167 | case 4: return d - 119.0 - l; |
168 | case 5: return d - 150.0 - l; |
169 | case 6: return d - 180.0 - l; |
170 | case 7: return d - 211.0 - l; |
171 | case 8: return d - 242.0 - l; |
172 | case 9: return d - 272.0 - l; |
173 | case 10: return d - 303.0 - l; |
174 | case 11: return d - 333.0 - l; |
175 | } |
176 | |
177 | return qt_qnan(); // ### assert |
178 | } |
179 | |
180 | static inline double WeekDay(double t) |
181 | { |
182 | double r = ::fmod (x: Day(t) + 4.0, y: 7.0); |
183 | return (r >= 0) ? r : r + 7.0; |
184 | } |
185 | |
186 | |
187 | static inline double MakeTime(double hour, double min, double sec, double ms) |
188 | { |
189 | if (!qIsFinite(d: hour) || !qIsFinite(d: min) || !qIsFinite(d: sec) || !qIsFinite(d: ms)) |
190 | return qQNaN(); |
191 | hour = QV4::Value::toInteger(d: hour); |
192 | min = QV4::Value::toInteger(d: min); |
193 | sec = QV4::Value::toInteger(d: sec); |
194 | ms = QV4::Value::toInteger(d: ms); |
195 | return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms; |
196 | } |
197 | |
198 | static inline double DayFromMonth(double month, double leap) |
199 | { |
200 | switch ((int) month) { |
201 | case 0: return 0; |
202 | case 1: return 31.0; |
203 | case 2: return 59.0 + leap; |
204 | case 3: return 90.0 + leap; |
205 | case 4: return 120.0 + leap; |
206 | case 5: return 151.0 + leap; |
207 | case 6: return 181.0 + leap; |
208 | case 7: return 212.0 + leap; |
209 | case 8: return 243.0 + leap; |
210 | case 9: return 273.0 + leap; |
211 | case 10: return 304.0 + leap; |
212 | case 11: return 334.0 + leap; |
213 | } |
214 | |
215 | return qt_qnan(); // ### assert? |
216 | } |
217 | |
218 | static double MakeDay(double year, double month, double day) |
219 | { |
220 | if (!qIsFinite(d: year) || !qIsFinite(d: month) || !qIsFinite(d: day)) |
221 | return qQNaN(); |
222 | year = QV4::Value::toInteger(d: year); |
223 | month = QV4::Value::toInteger(d: month); |
224 | day = QV4::Value::toInteger(d: day); |
225 | |
226 | year += ::floor(x: month / 12.0); |
227 | |
228 | month = ::fmod(x: month, y: 12.0); |
229 | if (month < 0) |
230 | month += 12.0; |
231 | |
232 | /* Quoting the spec: |
233 | |
234 | Find a value t such that YearFromTime(t) is ym and MonthFromTime(t) is mn |
235 | and DateFromTime(t) is 1; but if this is not possible (because some |
236 | argument is out of range), return NaN. |
237 | */ |
238 | double first = DayFromYear(y: year); |
239 | /* Beware floating-point glitches: don't test the first millisecond of a |
240 | * year, month or day when we could test a moment firmly in the interior of |
241 | * the interval. A rounding glitch might give the first millisecond to the |
242 | * preceding interval. |
243 | */ |
244 | bool leap = InLeapYear(t: (first + 60) * msPerDay); |
245 | |
246 | first += DayFromMonth(month, leap); |
247 | const double t = first * msPerDay + msPerDay / 2; // Noon on the first of the month |
248 | Q_ASSERT(Day(t) == first); |
249 | if (YearFromTime(t) != year || MonthFromTime(t) != month || DateFromTime(t) != 1) { |
250 | qWarning(msg: "Apparently out-of-range date %.0f-%02.0f-%02.0f" , year, month, day); |
251 | return qt_qnan(); |
252 | } |
253 | return first + day - 1; |
254 | } |
255 | |
256 | static inline double MakeDate(double day, double time) |
257 | { |
258 | return day * msPerDay + time; |
259 | } |
260 | |
261 | /* |
262 | ECMAScript specifies use of a fixed (current, standard) time-zone offset, |
263 | LocalTZA; and LocalTZA + DaylightSavingTA(t) is taken to be (see LocalTime and |
264 | UTC, following) local time's offset from UTC at time t. For simple zones, |
265 | DaylightSavingTA(t) is thus the DST offset applicable at date/time t; however, |
266 | if a zone has changed its standard offset, the only way to make LocalTime and |
267 | UTC (if implemented in accord with the spec) perform correct transformations |
268 | is to have DaylightSavingTA(t) correct for the zone's standard offset change |
269 | as well as its actual DST offset. |
270 | |
271 | This means we have to treat any historical changes in the zone's standard |
272 | offset as DST perturbations, regardless of historical reality. (This shall |
273 | mean a whole day of DST offset for some zones, that have crossed the |
274 | international date line. This shall confuse client code.) The bug report |
275 | against the ECMAScript spec is https://github.com/tc39/ecma262/issues/725 |
276 | and they've now changed the spec so that the following conforms to it ;^> |
277 | */ |
278 | static inline double DaylightSavingTA(double t, double localTZA) // t is a UTC time |
279 | { |
280 | return QLocalTime::getUtcOffset(atMSecsSinceEpoch: qint64(t)) * 1e3 - localTZA; |
281 | } |
282 | |
283 | static inline double LocalTime(double t, double localTZA) |
284 | { |
285 | // Flawed, yet verbatim from the spec: |
286 | return t + localTZA + DaylightSavingTA(t, localTZA); |
287 | } |
288 | |
289 | // The spec does note [*] that UTC and LocalTime are not quite mutually inverse. |
290 | // [*] http://www.ecma-international.org/ecma-262/7.0/index.html#sec-utc-t |
291 | |
292 | static inline double UTC(double t, double localTZA) |
293 | { |
294 | // Flawed, yet verbatim from the spec: |
295 | return t - localTZA - DaylightSavingTA(t: t - localTZA, localTZA); |
296 | } |
297 | |
298 | static inline double currentTime() |
299 | { |
300 | return QDateTime::currentDateTimeUtc().toMSecsSinceEpoch(); |
301 | } |
302 | |
303 | static inline double TimeClip(double t) |
304 | { |
305 | if (!qt_is_finite(d: t) || fabs(x: t) > Date::MaxDateVal) |
306 | return qt_qnan(); |
307 | |
308 | // +0 looks weird, but is correct. See ES6 20.3.1.15. We must not return -0. |
309 | return QV4::Value::toInteger(d: t) + 0; |
310 | } |
311 | |
312 | static inline double ParseString(const QString &s, double localTZA) |
313 | { |
314 | /* |
315 | First, try the format defined in ECMA 262's "Date Time String Format"; |
316 | only if that fails, fall back to QDateTime for parsing |
317 | |
318 | The defined string format is YYYY-MM-DDTHH:mm:ss.sssZ; the time (T and all |
319 | after it) may be omitted; in each part, the second and later components |
320 | are optional; and there's an extended syntax for negative and large |
321 | positive years: +/-YYYYYY; the leading sign, even when +, isn't optional. |
322 | If month or day is omitted, it is 01; if minute or second is omitted, it's |
323 | 00; if milliseconds are omitted, they're 000. |
324 | |
325 | When the time zone offset is absent, date-only forms are interpreted as |
326 | indicating a UTC time and date-time forms are interpreted in local time. |
327 | */ |
328 | |
329 | enum Format { |
330 | Year, |
331 | Month, |
332 | Day, |
333 | Hour, |
334 | Minute, |
335 | Second, |
336 | MilliSecond, |
337 | TimezoneHour, |
338 | TimezoneMinute, |
339 | Done |
340 | }; |
341 | |
342 | const QChar *ch = s.constData(); |
343 | const QChar *end = ch + s.size(); |
344 | |
345 | uint format = Year; |
346 | int current = 0; |
347 | int currentSize = 0; |
348 | bool extendedYear = false; |
349 | |
350 | int yearSign = 1; |
351 | int year = 0; |
352 | int month = 0; |
353 | int day = 1; |
354 | int hour = 0; |
355 | int minute = 0; |
356 | int second = 0; |
357 | int msec = 0; |
358 | int offsetSign = 1; |
359 | int offset = 0; |
360 | bool seenT = false; |
361 | bool seenZ = false; // Have seen zone, i.e. +HH:mm or literal Z. |
362 | |
363 | bool error = false; |
364 | if (*ch == u'+' || *ch == u'-') { |
365 | extendedYear = true; |
366 | if (*ch == u'-') |
367 | yearSign = -1; |
368 | ++ch; |
369 | } |
370 | for (; ch <= end && !error && format != Done; ++ch) { |
371 | if (*ch >= u'0' && *ch <= u'9') { |
372 | current *= 10; |
373 | current += ch->unicode() - u'0'; |
374 | ++currentSize; |
375 | } else { // other char, delimits field |
376 | switch (format) { |
377 | case Year: |
378 | year = current; |
379 | if (extendedYear) |
380 | error = (currentSize != 6); |
381 | else |
382 | error = (currentSize != 4); |
383 | break; |
384 | case Month: |
385 | month = current - 1; |
386 | error = (currentSize != 2) || month > 11; |
387 | break; |
388 | case Day: |
389 | day = current; |
390 | error = (currentSize != 2) || day > 31; |
391 | break; |
392 | case Hour: |
393 | hour = current; |
394 | error = (currentSize != 2) || hour > 24; |
395 | break; |
396 | case Minute: |
397 | minute = current; |
398 | error = (currentSize != 2) || minute >= 60; |
399 | break; |
400 | case Second: |
401 | second = current; |
402 | error = (currentSize != 2) || second > 60; |
403 | break; |
404 | case MilliSecond: |
405 | msec = current; |
406 | error = (currentSize != 3); |
407 | break; |
408 | case TimezoneHour: |
409 | Q_ASSERT(offset == 0 && !seenZ); |
410 | offset = current * 60; |
411 | error = (currentSize != 2) || current > 23; |
412 | seenZ = true; |
413 | break; |
414 | case TimezoneMinute: |
415 | offset += current; |
416 | error = (currentSize != 2) || current >= 60; |
417 | break; |
418 | } |
419 | if (*ch == u'T') { |
420 | if (format >= Hour) |
421 | error = true; |
422 | format = Hour; |
423 | seenT = true; |
424 | } else if (*ch == u'-') { |
425 | if (format < Day) |
426 | ++format; |
427 | else if (format < Minute) |
428 | error = true; |
429 | else if (format >= TimezoneHour) |
430 | error = true; |
431 | else { |
432 | Q_ASSERT(offset == 0 && !seenZ); |
433 | offsetSign = -1; |
434 | format = TimezoneHour; |
435 | } |
436 | } else if (*ch == u':') { |
437 | if (format != Hour && format != Minute && format != TimezoneHour) |
438 | error = true; |
439 | ++format; |
440 | } else if (*ch == u'.') { |
441 | if (format != Second) |
442 | error = true; |
443 | ++format; |
444 | } else if (*ch == u'+') { |
445 | if (seenZ || format < Minute || format >= TimezoneHour) |
446 | error = true; |
447 | format = TimezoneHour; |
448 | } else if (*ch == u'Z') { |
449 | if (seenZ || format < Minute || format >= TimezoneHour) |
450 | error = true; |
451 | else |
452 | Q_ASSERT(offset == 0); |
453 | format = Done; |
454 | seenZ = true; |
455 | } else if (ch->unicode() == 0) { |
456 | format = Done; |
457 | } |
458 | current = 0; |
459 | currentSize = 0; |
460 | } |
461 | } |
462 | |
463 | if (!error) { |
464 | double t = MakeDate(day: MakeDay(year: year * yearSign, month, day), time: MakeTime(hour, min: minute, sec: second, ms: msec)); |
465 | if (seenZ) |
466 | t -= offset * offsetSign * 60 * 1000; |
467 | else if (seenT) // No zone specified, treat date-time as local time |
468 | t = UTC(t, localTZA); |
469 | // else: treat plain date as already in UTC |
470 | return TimeClip(t); |
471 | } |
472 | |
473 | QDateTime dt = QDateTime::fromString(string: s, format: Qt::TextDate); |
474 | if (!dt.isValid()) |
475 | dt = QDateTime::fromString(string: s, format: Qt::ISODate); |
476 | if (!dt.isValid()) |
477 | dt = QDateTime::fromString(string: s, format: Qt::RFC2822Date); |
478 | if (!dt.isValid()) { |
479 | const QString formats[] = { |
480 | QStringLiteral("M/d/yyyy" ), |
481 | QStringLiteral("M/d/yyyy hh:mm" ), |
482 | QStringLiteral("M/d/yyyy hh:mm A" ), |
483 | |
484 | QStringLiteral("M/d/yyyy, hh:mm" ), |
485 | QStringLiteral("M/d/yyyy, hh:mm A" ), |
486 | |
487 | QStringLiteral("MMM d yyyy" ), |
488 | QStringLiteral("MMM d yyyy hh:mm" ), |
489 | QStringLiteral("MMM d yyyy hh:mm:ss" ), |
490 | QStringLiteral("MMM d yyyy, hh:mm" ), |
491 | QStringLiteral("MMM d yyyy, hh:mm:ss" ), |
492 | |
493 | QStringLiteral("MMMM d yyyy" ), |
494 | QStringLiteral("MMMM d yyyy hh:mm" ), |
495 | QStringLiteral("MMMM d yyyy hh:mm:ss" ), |
496 | QStringLiteral("MMMM d yyyy, hh:mm" ), |
497 | QStringLiteral("MMMM d yyyy, hh:mm:ss" ), |
498 | |
499 | QStringLiteral("MMM d, yyyy" ), |
500 | QStringLiteral("MMM d, yyyy hh:mm" ), |
501 | QStringLiteral("MMM d, yyyy hh:mm:ss" ), |
502 | |
503 | QStringLiteral("MMMM d, yyyy" ), |
504 | QStringLiteral("MMMM d, yyyy hh:mm" ), |
505 | QStringLiteral("MMMM d, yyyy hh:mm:ss" ), |
506 | |
507 | QStringLiteral("d MMM yyyy" ), |
508 | QStringLiteral("d MMM yyyy hh:mm" ), |
509 | QStringLiteral("d MMM yyyy hh:mm:ss" ), |
510 | QStringLiteral("d MMM yyyy, hh:mm" ), |
511 | QStringLiteral("d MMM yyyy, hh:mm:ss" ), |
512 | |
513 | QStringLiteral("d MMMM yyyy" ), |
514 | QStringLiteral("d MMMM yyyy hh:mm" ), |
515 | QStringLiteral("d MMMM yyyy hh:mm:ss" ), |
516 | QStringLiteral("d MMMM yyyy, hh:mm" ), |
517 | QStringLiteral("d MMMM yyyy, hh:mm:ss" ), |
518 | |
519 | QStringLiteral("d MMM, yyyy" ), |
520 | QStringLiteral("d MMM, yyyy hh:mm" ), |
521 | QStringLiteral("d MMM, yyyy hh:mm:ss" ), |
522 | |
523 | QStringLiteral("d MMMM, yyyy" ), |
524 | QStringLiteral("d MMMM, yyyy hh:mm" ), |
525 | QStringLiteral("d MMMM, yyyy hh:mm:ss" ), |
526 | |
527 | // ISO 8601 and RFC 2822 with a GMT as prefix on its offset, or GMT as zone. |
528 | QStringLiteral("yyyy-MM-dd hh:mm:ss t" ), |
529 | QStringLiteral("ddd, d MMM yyyy hh:mm:ss t" ), |
530 | }; |
531 | |
532 | for (const QString &format : formats) { |
533 | dt = format.indexOf(s: QLatin1String("hh:mm" )) < 0 |
534 | ? QDate::fromString(string: s, format).startOfDay(zone: QTimeZone::UTC) |
535 | : QDateTime::fromString(string: s, format); // as local time |
536 | if (dt.isValid()) |
537 | break; |
538 | } |
539 | } |
540 | if (!dt.isValid()) |
541 | return qt_qnan(); |
542 | return TimeClip(t: dt.toMSecsSinceEpoch()); |
543 | } |
544 | |
545 | /*! |
546 | \internal |
547 | |
548 | Converts the ECMA Date value \a t (in UTC form) to QDateTime |
549 | according to \a spec. |
550 | */ |
551 | static inline QDateTime ToDateTime(double t, QTimeZone zone) |
552 | { |
553 | if (std::isnan(x: t)) |
554 | return QDateTime().toTimeZone(toZone: zone); |
555 | return QDateTime::fromMSecsSinceEpoch(msecs: t, timeZone: zone); |
556 | } |
557 | |
558 | static inline QString ToString(double t, double localTZA) |
559 | { |
560 | if (std::isnan(x: t)) |
561 | return QStringLiteral("Invalid Date" ); |
562 | QString str = ToDateTime(t, zone: QTimeZone::LocalTime).toString() + QLatin1String(" GMT" ); |
563 | double tzoffset = localTZA + DaylightSavingTA(t, localTZA); |
564 | if (tzoffset) { |
565 | int hours = static_cast<int>(::fabs(x: tzoffset) / 1000 / 60 / 60); |
566 | int mins = int(::fabs(x: tzoffset) / 1000 / 60) % 60; |
567 | str.append(c: QLatin1Char((tzoffset > 0) ? '+' : '-')); |
568 | if (hours < 10) |
569 | str.append(c: QLatin1Char('0')); |
570 | str.append(s: QString::number(hours)); |
571 | if (mins < 10) |
572 | str.append(c: QLatin1Char('0')); |
573 | str.append(s: QString::number(mins)); |
574 | } |
575 | return str; |
576 | } |
577 | |
578 | static inline QString ToUTCString(double t) |
579 | { |
580 | if (std::isnan(x: t)) |
581 | return QStringLiteral("Invalid Date" ); |
582 | return ToDateTime(t, zone: QTimeZone::UTC).toString(); |
583 | } |
584 | |
585 | static inline QString ToDateString(double t) |
586 | { |
587 | return ToDateTime(t, zone: QTimeZone::LocalTime).date().toString(); |
588 | } |
589 | |
590 | static inline QString ToTimeString(double t) |
591 | { |
592 | return ToDateTime(t, zone: QTimeZone::LocalTime).time().toString(); |
593 | } |
594 | |
595 | static inline QString ToLocaleString(double t) |
596 | { |
597 | return QLocale().toString(dateTime: ToDateTime(t, zone: QTimeZone::LocalTime), format: QLocale::ShortFormat); |
598 | } |
599 | |
600 | static inline QString ToLocaleDateString(double t) |
601 | { |
602 | return QLocale().toString(date: ToDateTime(t, zone: QTimeZone::LocalTime).date(), format: QLocale::ShortFormat); |
603 | } |
604 | |
605 | static inline QString ToLocaleTimeString(double t) |
606 | { |
607 | return QLocale().toString(time: ToDateTime(t, zone: QTimeZone::LocalTime).time(), format: QLocale::ShortFormat); |
608 | } |
609 | |
610 | static double getLocalTZA() |
611 | { |
612 | return QLocalTime::getCurrentStandardUtcOffset() * 1e3; |
613 | } |
614 | |
615 | DEFINE_OBJECT_VTABLE(DateObject); |
616 | |
617 | quint64 Date::encode(double value) |
618 | { |
619 | if (std::isnan(x: value) || fabs(x: value) > MaxDateVal) |
620 | return InvalidDateVal; |
621 | |
622 | // Do the addition in qint64. This way we won't overflow if value is negative |
623 | // and we will round value in the right direction. |
624 | // We know we can do this because we know we have more than one bit left in quint64. |
625 | const quint64 encoded = quint64(qint64(value) + qint64(MaxDateVal)); |
626 | |
627 | return encoded + Extra; |
628 | } |
629 | |
630 | quint64 Date::encode(const QDateTime &dateTime) |
631 | { |
632 | return encode(value: dateTime.isValid() ? dateTime.toMSecsSinceEpoch() : qt_qnan()); |
633 | } |
634 | |
635 | void Date::init(double value) |
636 | { |
637 | storage = encode(value); |
638 | } |
639 | |
640 | void Date::init(const QDateTime &when) |
641 | { |
642 | storage = encode(dateTime: when) | HasQDate | HasQTime; |
643 | } |
644 | |
645 | void Date::init(QDate date) |
646 | { |
647 | storage = encode(dateTime: date.startOfDay(zone: QTimeZone::UTC)) | HasQDate; |
648 | } |
649 | |
650 | void Date::init(QTime time, ExecutionEngine *engine) |
651 | { |
652 | if (!time.isValid()) { |
653 | storage = encode(value: qt_qnan()) | HasQTime; |
654 | return; |
655 | } |
656 | |
657 | /* We have to chose a date on which to instantiate this time. All we really |
658 | * care about is that it round-trips back to the same time if we extract the |
659 | * time from it, which shall (via toQDateTime(), below) discard the date |
660 | * part. We need a date for which time-zone data is likely to be sane (so |
661 | * MakeDay(0, 0, 0) was a bad choice; 2 BC, December 31st is before |
662 | * time-zones were standardized), with no transition nearby in date. |
663 | * QDateTime ignores DST transitions before 1970, but even then zone |
664 | * transitions did happen; and DaylightSavingTA() will include DST, at odds |
665 | * with QDateTime. So pick a date since 1970 and prefer one when no zone |
666 | * was in DST. One such interval (according to the Olson database, at |
667 | * least) was 1971 March 15th to April 17th. Since converting a time to a |
668 | * date-time without specifying a date is foolish, let's use April Fools' |
669 | * day. |
670 | */ |
671 | static const double d = MakeDay(year: 1971, month: 3, day: 1); |
672 | double t = MakeTime(hour: time.hour(), min: time.minute(), sec: time.second(), ms: time.msec()); |
673 | storage = encode(value: UTC(t: MakeDate(day: d, time: t), localTZA: engine->localTZA)) | HasQTime; |
674 | } |
675 | |
676 | QDate Date::toQDate() const |
677 | { |
678 | return toQDateTime().date(); |
679 | } |
680 | |
681 | QTime Date::toQTime() const |
682 | { |
683 | return toQDateTime().time(); |
684 | } |
685 | |
686 | QDateTime Date::toQDateTime() const |
687 | { |
688 | return ToDateTime(t: operator double(), zone: QTimeZone::LocalTime); |
689 | } |
690 | |
691 | QVariant Date::toVariant() const |
692 | { |
693 | switch (storage & (HasQDate | HasQTime)) { |
694 | case HasQDate: |
695 | return toQDate(); |
696 | case HasQTime: |
697 | return toQTime(); |
698 | case (HasQDate | HasQTime): |
699 | return toQDateTime(); |
700 | default: |
701 | return QVariant(); |
702 | } |
703 | } |
704 | |
705 | QDateTime DateObject::toQDateTime() const |
706 | { |
707 | return d()->toQDateTime(); |
708 | } |
709 | |
710 | QString DateObject::toString() const |
711 | { |
712 | return ToString(t: d()->date(), localTZA: engine()->localTZA); |
713 | } |
714 | |
715 | QString DateObject::dateTimeToString(const QDateTime &dateTime, ExecutionEngine *engine) |
716 | { |
717 | if (!dateTime.isValid()) |
718 | return QStringLiteral("Invalid Date" ); |
719 | return ToString(t: TimeClip(t: dateTime.toMSecsSinceEpoch()), localTZA: engine->localTZA); |
720 | } |
721 | |
722 | QDateTime DateObject::stringToDateTime(const QString &string, ExecutionEngine *engine) |
723 | { |
724 | return ToDateTime(t: ParseString(s: string, localTZA: engine->localTZA), zone: QTimeZone::LocalTime); |
725 | } |
726 | |
727 | QDate DateObject::dateTimeToDate(const QDateTime &dateTime) |
728 | { |
729 | // If the Date object was parse()d from a string with no time part |
730 | // or zone specifier it's really the UTC start of the relevant day, |
731 | // but it's here represented as a local time, which may fall in the |
732 | // preceding day. See QTBUG-92466 for the gory details. |
733 | const auto utc = dateTime.toUTC(); |
734 | if (utc.date() != dateTime.date() && utc.addSecs(secs: -1).date() == dateTime.date()) |
735 | return utc.date(); |
736 | |
737 | // This may, of course, be The Wrong Thing if the date was |
738 | // constructed as a full local date-time that happens to coincide |
739 | // with the start of a UTC day; however, that would be an odd value |
740 | // to give to something that, apparently, someone thinks belongs in |
741 | // a QDate. |
742 | return dateTime.date(); |
743 | } |
744 | |
745 | DEFINE_OBJECT_VTABLE(DateCtor); |
746 | |
747 | void Heap::DateCtor::init(QV4::ExecutionContext *scope) |
748 | { |
749 | Heap::FunctionObject::init(scope, QStringLiteral("Date" )); |
750 | } |
751 | |
752 | ReturnedValue DateCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, int argc, const Value *newTarget) |
753 | { |
754 | ExecutionEngine *v4 = that->engine(); |
755 | double t = 0; |
756 | |
757 | if (argc == 0) |
758 | t = currentTime(); |
759 | |
760 | else if (argc == 1) { |
761 | Scope scope(v4); |
762 | ScopedValue arg(scope, argv[0]); |
763 | if (DateObject *d = arg->as<DateObject>()) { |
764 | t = d->date(); |
765 | } else { |
766 | arg = RuntimeHelpers::toPrimitive(value: arg, typeHint: PREFERREDTYPE_HINT); |
767 | |
768 | if (String *s = arg->stringValue()) |
769 | t = ParseString(s: s->toQString(), localTZA: v4->localTZA); |
770 | else |
771 | t = arg->toNumber(); |
772 | } |
773 | } |
774 | |
775 | else { // d.argc > 1 |
776 | double year = argv[0].toNumber(); |
777 | double month = argv[1].toNumber(); |
778 | double day = argc >= 3 ? argv[2].toNumber() : 1; |
779 | double hours = argc >= 4 ? argv[3].toNumber() : 0; |
780 | double mins = argc >= 5 ? argv[4].toNumber() : 0; |
781 | double secs = argc >= 6 ? argv[5].toNumber() : 0; |
782 | double ms = argc >= 7 ? argv[6].toNumber() : 0; |
783 | if (year >= 0 && year <= 99) |
784 | year += 1900; |
785 | t = MakeDate(day: MakeDay(year, month, day), time: MakeTime(hour: hours, min: mins, sec: secs, ms)); |
786 | t = UTC(t, localTZA: v4->localTZA); |
787 | } |
788 | |
789 | ReturnedValue o = Encode(v4->newDateObject(dateTime: t)); |
790 | if (!newTarget) |
791 | return o; |
792 | Scope scope(v4); |
793 | ScopedObject obj(scope, o); |
794 | obj->setProtoFromNewTarget(newTarget); |
795 | return obj->asReturnedValue(); |
796 | } |
797 | |
798 | ReturnedValue DateCtor::virtualCall(const FunctionObject *m, const Value *, const Value *, int) |
799 | { |
800 | ExecutionEngine *e = m->engine(); |
801 | double t = currentTime(); |
802 | return e->newString(s: ToString(t, localTZA: e->localTZA))->asReturnedValue(); |
803 | } |
804 | |
805 | void DatePrototype::init(ExecutionEngine *engine, Object *ctor) |
806 | { |
807 | Scope scope(engine); |
808 | ScopedObject o(scope); |
809 | ctor->defineReadonlyProperty(name: engine->id_prototype(), value: (o = this)); |
810 | ctor->defineReadonlyConfigurableProperty(name: engine->id_length(), value: Value::fromInt32(i: 7)); |
811 | engine->localTZA = getLocalTZA(); |
812 | |
813 | ctor->defineDefaultProperty(QStringLiteral("parse" ), code: method_parse, argumentCount: 1); |
814 | ctor->defineDefaultProperty(QStringLiteral("UTC" ), code: method_UTC, argumentCount: 7); |
815 | ctor->defineDefaultProperty(QStringLiteral("now" ), code: method_now, argumentCount: 0); |
816 | |
817 | defineDefaultProperty(QStringLiteral("constructor" ), value: (o = ctor)); |
818 | defineDefaultProperty(name: engine->id_toString(), code: method_toString, argumentCount: 0); |
819 | defineDefaultProperty(QStringLiteral("toDateString" ), code: method_toDateString, argumentCount: 0); |
820 | defineDefaultProperty(QStringLiteral("toTimeString" ), code: method_toTimeString, argumentCount: 0); |
821 | defineDefaultProperty(name: engine->id_toLocaleString(), code: method_toLocaleString, argumentCount: 0); |
822 | defineDefaultProperty(QStringLiteral("toLocaleDateString" ), code: method_toLocaleDateString, argumentCount: 0); |
823 | defineDefaultProperty(QStringLiteral("toLocaleTimeString" ), code: method_toLocaleTimeString, argumentCount: 0); |
824 | defineDefaultProperty(name: engine->id_valueOf(), code: method_valueOf, argumentCount: 0); |
825 | defineDefaultProperty(QStringLiteral("getTime" ), code: method_getTime, argumentCount: 0); |
826 | defineDefaultProperty(QStringLiteral("getYear" ), code: method_getYear, argumentCount: 0); |
827 | defineDefaultProperty(QStringLiteral("getFullYear" ), code: method_getFullYear, argumentCount: 0); |
828 | defineDefaultProperty(QStringLiteral("getUTCFullYear" ), code: method_getUTCFullYear, argumentCount: 0); |
829 | defineDefaultProperty(QStringLiteral("getMonth" ), code: method_getMonth, argumentCount: 0); |
830 | defineDefaultProperty(QStringLiteral("getUTCMonth" ), code: method_getUTCMonth, argumentCount: 0); |
831 | defineDefaultProperty(QStringLiteral("getDate" ), code: method_getDate, argumentCount: 0); |
832 | defineDefaultProperty(QStringLiteral("getUTCDate" ), code: method_getUTCDate, argumentCount: 0); |
833 | defineDefaultProperty(QStringLiteral("getDay" ), code: method_getDay, argumentCount: 0); |
834 | defineDefaultProperty(QStringLiteral("getUTCDay" ), code: method_getUTCDay, argumentCount: 0); |
835 | defineDefaultProperty(QStringLiteral("getHours" ), code: method_getHours, argumentCount: 0); |
836 | defineDefaultProperty(QStringLiteral("getUTCHours" ), code: method_getUTCHours, argumentCount: 0); |
837 | defineDefaultProperty(QStringLiteral("getMinutes" ), code: method_getMinutes, argumentCount: 0); |
838 | defineDefaultProperty(QStringLiteral("getUTCMinutes" ), code: method_getUTCMinutes, argumentCount: 0); |
839 | defineDefaultProperty(QStringLiteral("getSeconds" ), code: method_getSeconds, argumentCount: 0); |
840 | defineDefaultProperty(QStringLiteral("getUTCSeconds" ), code: method_getUTCSeconds, argumentCount: 0); |
841 | defineDefaultProperty(QStringLiteral("getMilliseconds" ), code: method_getMilliseconds, argumentCount: 0); |
842 | defineDefaultProperty(QStringLiteral("getUTCMilliseconds" ), code: method_getUTCMilliseconds, argumentCount: 0); |
843 | defineDefaultProperty(QStringLiteral("getTimezoneOffset" ), code: method_getTimezoneOffset, argumentCount: 0); |
844 | defineDefaultProperty(QStringLiteral("setTime" ), code: method_setTime, argumentCount: 1); |
845 | defineDefaultProperty(QStringLiteral("setMilliseconds" ), code: method_setMilliseconds, argumentCount: 1); |
846 | defineDefaultProperty(QStringLiteral("setUTCMilliseconds" ), code: method_setUTCMilliseconds, argumentCount: 1); |
847 | defineDefaultProperty(QStringLiteral("setSeconds" ), code: method_setSeconds, argumentCount: 2); |
848 | defineDefaultProperty(QStringLiteral("setUTCSeconds" ), code: method_setUTCSeconds, argumentCount: 2); |
849 | defineDefaultProperty(QStringLiteral("setMinutes" ), code: method_setMinutes, argumentCount: 3); |
850 | defineDefaultProperty(QStringLiteral("setUTCMinutes" ), code: method_setUTCMinutes, argumentCount: 3); |
851 | defineDefaultProperty(QStringLiteral("setHours" ), code: method_setHours, argumentCount: 4); |
852 | defineDefaultProperty(QStringLiteral("setUTCHours" ), code: method_setUTCHours, argumentCount: 4); |
853 | defineDefaultProperty(QStringLiteral("setDate" ), code: method_setDate, argumentCount: 1); |
854 | defineDefaultProperty(QStringLiteral("setUTCDate" ), code: method_setUTCDate, argumentCount: 1); |
855 | defineDefaultProperty(QStringLiteral("setMonth" ), code: method_setMonth, argumentCount: 2); |
856 | defineDefaultProperty(QStringLiteral("setUTCMonth" ), code: method_setUTCMonth, argumentCount: 2); |
857 | defineDefaultProperty(QStringLiteral("setYear" ), code: method_setYear, argumentCount: 1); |
858 | defineDefaultProperty(QStringLiteral("setFullYear" ), code: method_setFullYear, argumentCount: 3); |
859 | defineDefaultProperty(QStringLiteral("setUTCFullYear" ), code: method_setUTCFullYear, argumentCount: 3); |
860 | |
861 | // ES6: B.2.4.3 & 20.3.4.43: |
862 | // We have to use the *same object* for toUTCString and toGMTString |
863 | { |
864 | QString toUtcString(QStringLiteral("toUTCString" )); |
865 | QString toGmtString(QStringLiteral("toGMTString" )); |
866 | ScopedString us(scope, engine->newIdentifier(text: toUtcString)); |
867 | ScopedString gs(scope, engine->newIdentifier(text: toGmtString)); |
868 | ScopedFunctionObject toUtcGmtStringFn(scope, FunctionObject::createBuiltinFunction(engine, nameOrSymbol: us, code: method_toUTCString, argumentCount: 0)); |
869 | defineDefaultProperty(name: us, value: toUtcGmtStringFn); |
870 | defineDefaultProperty(name: gs, value: toUtcGmtStringFn); |
871 | } |
872 | |
873 | defineDefaultProperty(QStringLiteral("toISOString" ), code: method_toISOString, argumentCount: 0); |
874 | defineDefaultProperty(QStringLiteral("toJSON" ), code: method_toJSON, argumentCount: 1); |
875 | defineDefaultProperty(name: engine->symbol_toPrimitive(), code: method_symbolToPrimitive, argumentCount: 1, attributes: Attr_ReadOnly_ButConfigurable); |
876 | } |
877 | |
878 | double DatePrototype::getThisDate(ExecutionEngine *v4, const Value *thisObject) |
879 | { |
880 | if (const DateObject *that = thisObject->as<DateObject>()) |
881 | return that->date(); |
882 | v4->throwTypeError(); |
883 | return 0; |
884 | } |
885 | |
886 | ReturnedValue DatePrototype::method_parse(const FunctionObject *f, const Value *, const Value *argv, int argc) |
887 | { |
888 | if (!argc) |
889 | return Encode(qt_qnan()); |
890 | else |
891 | return Encode(ParseString(s: argv[0].toQString(), localTZA: f->engine()->localTZA)); |
892 | } |
893 | |
894 | ReturnedValue DatePrototype::method_UTC(const FunctionObject *f, const Value *, const Value *argv, int argc) |
895 | { |
896 | const int numArgs = argc; |
897 | if (numArgs < 1) |
898 | return Encode(qQNaN()); |
899 | ExecutionEngine *e = f->engine(); |
900 | double year = argv[0].toNumber(); |
901 | if (e->hasException) |
902 | return Encode::undefined(); |
903 | double month = numArgs >= 2 ? argv[1].toNumber() : 0; |
904 | if (e->hasException) |
905 | return Encode::undefined(); |
906 | double day = numArgs >= 3 ? argv[2].toNumber() : 1; |
907 | if (e->hasException) |
908 | return Encode::undefined(); |
909 | double hours = numArgs >= 4 ? argv[3].toNumber() : 0; |
910 | if (e->hasException) |
911 | return Encode::undefined(); |
912 | double mins = numArgs >= 5 ? argv[4].toNumber() : 0; |
913 | if (e->hasException) |
914 | return Encode::undefined(); |
915 | double secs = numArgs >= 6 ? argv[5].toNumber() : 0; |
916 | if (e->hasException) |
917 | return Encode::undefined(); |
918 | double ms = numArgs >= 7 ? argv[6].toNumber() : 0; |
919 | if (e->hasException) |
920 | return Encode::undefined(); |
921 | double iyear = QV4::Value::toInteger(d: year); |
922 | if (!qIsNaN(d: year) && iyear >= 0 && iyear <= 99) |
923 | year = 1900 + iyear; |
924 | double t = MakeDate(day: MakeDay(year, month, day), |
925 | time: MakeTime(hour: hours, min: mins, sec: secs, ms)); |
926 | return Encode(TimeClip(t)); |
927 | } |
928 | |
929 | ReturnedValue DatePrototype::method_now(const FunctionObject *, const Value *, const Value *, int) |
930 | { |
931 | return Encode(currentTime()); |
932 | } |
933 | |
934 | ReturnedValue DatePrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int) |
935 | { |
936 | ExecutionEngine *v4 = b->engine(); |
937 | double t = getThisDate(v4, thisObject); |
938 | return Encode(v4->newString(s: ToString(t, localTZA: v4->localTZA))); |
939 | } |
940 | |
941 | ReturnedValue DatePrototype::method_toDateString(const FunctionObject *b, const Value *thisObject, const Value *, int) |
942 | { |
943 | ExecutionEngine *v4 = b->engine(); |
944 | double t = getThisDate(v4, thisObject); |
945 | return Encode(v4->newString(s: ToDateString(t))); |
946 | } |
947 | |
948 | ReturnedValue DatePrototype::method_toTimeString(const FunctionObject *b, const Value *thisObject, const Value *, int) |
949 | { |
950 | ExecutionEngine *v4 = b->engine(); |
951 | double t = getThisDate(v4, thisObject); |
952 | return Encode(v4->newString(s: ToTimeString(t))); |
953 | } |
954 | |
955 | ReturnedValue DatePrototype::method_toLocaleString(const FunctionObject *b, const Value *thisObject, const Value *, int) |
956 | { |
957 | ExecutionEngine *v4 = b->engine(); |
958 | double t = getThisDate(v4, thisObject); |
959 | return Encode(v4->newString(s: ToLocaleString(t))); |
960 | } |
961 | |
962 | ReturnedValue DatePrototype::method_toLocaleDateString(const FunctionObject *b, const Value *thisObject, const Value *, int) |
963 | { |
964 | ExecutionEngine *v4 = b->engine(); |
965 | double t = getThisDate(v4, thisObject); |
966 | return Encode(v4->newString(s: ToLocaleDateString(t))); |
967 | } |
968 | |
969 | ReturnedValue DatePrototype::method_toLocaleTimeString(const FunctionObject *b, const Value *thisObject, const Value *, int) |
970 | { |
971 | ExecutionEngine *v4 = b->engine(); |
972 | double t = getThisDate(v4, thisObject); |
973 | return Encode(v4->newString(s: ToLocaleTimeString(t))); |
974 | } |
975 | |
976 | ReturnedValue DatePrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int) |
977 | { |
978 | ExecutionEngine *v4 = b->engine(); |
979 | double t = getThisDate(v4, thisObject); |
980 | return Encode(t); |
981 | } |
982 | |
983 | ReturnedValue DatePrototype::method_getTime(const FunctionObject *b, const Value *thisObject, const Value *, int) |
984 | { |
985 | ExecutionEngine *v4 = b->engine(); |
986 | double t = getThisDate(v4, thisObject); |
987 | return Encode(t); |
988 | } |
989 | |
990 | ReturnedValue DatePrototype::method_getYear(const FunctionObject *b, const Value *thisObject, const Value *, int) |
991 | { |
992 | ExecutionEngine *v4 = b->engine(); |
993 | double t = getThisDate(v4, thisObject); |
994 | if (!std::isnan(x: t)) |
995 | t = YearFromTime(t: LocalTime(t, localTZA: v4->localTZA)) - 1900; |
996 | return Encode(t); |
997 | } |
998 | |
999 | ReturnedValue DatePrototype::method_getFullYear(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1000 | { |
1001 | ExecutionEngine *v4 = b->engine(); |
1002 | double t = getThisDate(v4, thisObject); |
1003 | if (!std::isnan(x: t)) |
1004 | t = YearFromTime(t: LocalTime(t, localTZA: v4->localTZA)); |
1005 | return Encode(t); |
1006 | } |
1007 | |
1008 | ReturnedValue DatePrototype::method_getUTCFullYear(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1009 | { |
1010 | ExecutionEngine *v4 = b->engine(); |
1011 | double t = getThisDate(v4, thisObject); |
1012 | if (!std::isnan(x: t)) |
1013 | t = YearFromTime(t); |
1014 | return Encode(t); |
1015 | } |
1016 | |
1017 | ReturnedValue DatePrototype::method_getMonth(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1018 | { |
1019 | ExecutionEngine *v4 = b->engine(); |
1020 | double t = getThisDate(v4, thisObject); |
1021 | if (!std::isnan(x: t)) |
1022 | t = MonthFromTime(t: LocalTime(t, localTZA: v4->localTZA)); |
1023 | return Encode(t); |
1024 | } |
1025 | |
1026 | ReturnedValue DatePrototype::method_getUTCMonth(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1027 | { |
1028 | ExecutionEngine *v4 = b->engine(); |
1029 | double t = getThisDate(v4, thisObject); |
1030 | if (!std::isnan(x: t)) |
1031 | t = MonthFromTime(t); |
1032 | return Encode(t); |
1033 | } |
1034 | |
1035 | ReturnedValue DatePrototype::method_getDate(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1036 | { |
1037 | ExecutionEngine *v4 = b->engine(); |
1038 | double t = getThisDate(v4, thisObject); |
1039 | if (!std::isnan(x: t)) |
1040 | t = DateFromTime(t: LocalTime(t, localTZA: v4->localTZA)); |
1041 | return Encode(t); |
1042 | } |
1043 | |
1044 | ReturnedValue DatePrototype::method_getUTCDate(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1045 | { |
1046 | ExecutionEngine *v4 = b->engine(); |
1047 | double t = getThisDate(v4, thisObject); |
1048 | if (!std::isnan(x: t)) |
1049 | t = DateFromTime(t); |
1050 | return Encode(t); |
1051 | } |
1052 | |
1053 | ReturnedValue DatePrototype::method_getDay(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1054 | { |
1055 | ExecutionEngine *v4 = b->engine(); |
1056 | double t = getThisDate(v4, thisObject); |
1057 | if (!std::isnan(x: t)) |
1058 | t = WeekDay(t: LocalTime(t, localTZA: v4->localTZA)); |
1059 | return Encode(t); |
1060 | } |
1061 | |
1062 | ReturnedValue DatePrototype::method_getUTCDay(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1063 | { |
1064 | ExecutionEngine *v4 = b->engine(); |
1065 | double t = getThisDate(v4, thisObject); |
1066 | if (!std::isnan(x: t)) |
1067 | t = WeekDay(t); |
1068 | return Encode(t); |
1069 | } |
1070 | |
1071 | ReturnedValue DatePrototype::method_getHours(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1072 | { |
1073 | ExecutionEngine *v4 = b->engine(); |
1074 | double t = getThisDate(v4, thisObject); |
1075 | if (!std::isnan(x: t)) |
1076 | t = HourFromTime(t: LocalTime(t, localTZA: v4->localTZA)); |
1077 | return Encode(t); |
1078 | } |
1079 | |
1080 | ReturnedValue DatePrototype::method_getUTCHours(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1081 | { |
1082 | ExecutionEngine *v4 = b->engine(); |
1083 | double t = getThisDate(v4, thisObject); |
1084 | if (!std::isnan(x: t)) |
1085 | t = HourFromTime(t); |
1086 | return Encode(t); |
1087 | } |
1088 | |
1089 | ReturnedValue DatePrototype::method_getMinutes(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1090 | { |
1091 | ExecutionEngine *v4 = b->engine(); |
1092 | double t = getThisDate(v4, thisObject); |
1093 | if (!std::isnan(x: t)) |
1094 | t = MinFromTime(t: LocalTime(t, localTZA: v4->localTZA)); |
1095 | return Encode(t); |
1096 | } |
1097 | |
1098 | ReturnedValue DatePrototype::method_getUTCMinutes(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1099 | { |
1100 | ExecutionEngine *v4 = b->engine(); |
1101 | double t = getThisDate(v4, thisObject); |
1102 | if (!std::isnan(x: t)) |
1103 | t = MinFromTime(t); |
1104 | return Encode(t); |
1105 | } |
1106 | |
1107 | ReturnedValue DatePrototype::method_getSeconds(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1108 | { |
1109 | ExecutionEngine *v4 = b->engine(); |
1110 | double t = getThisDate(v4, thisObject); |
1111 | if (!std::isnan(x: t)) |
1112 | t = SecFromTime(t: LocalTime(t, localTZA: v4->localTZA)); |
1113 | return Encode(t); |
1114 | } |
1115 | |
1116 | ReturnedValue DatePrototype::method_getUTCSeconds(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1117 | { |
1118 | ExecutionEngine *v4 = b->engine(); |
1119 | double t = getThisDate(v4, thisObject); |
1120 | if (!std::isnan(x: t)) |
1121 | t = SecFromTime(t); |
1122 | return Encode(t); |
1123 | } |
1124 | |
1125 | ReturnedValue DatePrototype::method_getMilliseconds(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1126 | { |
1127 | ExecutionEngine *v4 = b->engine(); |
1128 | double t = getThisDate(v4, thisObject); |
1129 | if (!std::isnan(x: t)) |
1130 | t = msFromTime(t: LocalTime(t, localTZA: v4->localTZA)); |
1131 | return Encode(t); |
1132 | } |
1133 | |
1134 | ReturnedValue DatePrototype::method_getUTCMilliseconds(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1135 | { |
1136 | ExecutionEngine *v4 = b->engine(); |
1137 | double t = getThisDate(v4, thisObject); |
1138 | if (!std::isnan(x: t)) |
1139 | t = msFromTime(t); |
1140 | return Encode(t); |
1141 | } |
1142 | |
1143 | ReturnedValue DatePrototype::method_getTimezoneOffset(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1144 | { |
1145 | ExecutionEngine *v4 = b->engine(); |
1146 | double t = getThisDate(v4, thisObject); |
1147 | if (!std::isnan(x: t)) |
1148 | t = (t - LocalTime(t, localTZA: v4->localTZA)) / msPerMinute; |
1149 | return Encode(t); |
1150 | } |
1151 | |
1152 | ReturnedValue DatePrototype::method_setTime(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1153 | { |
1154 | ExecutionEngine *v4 = b->engine(); |
1155 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1156 | if (!self) |
1157 | return v4->throwTypeError(); |
1158 | |
1159 | double t = argc ? argv[0].toNumber() : qt_qnan(); |
1160 | if (v4->hasException) |
1161 | return QV4::Encode::undefined(); |
1162 | self->setDate(t); |
1163 | return Encode(self->date()); |
1164 | } |
1165 | |
1166 | ReturnedValue DatePrototype::method_setMilliseconds(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1167 | { |
1168 | ExecutionEngine *v4 = b->engine(); |
1169 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1170 | if (!self) |
1171 | return v4->throwTypeError(); |
1172 | |
1173 | double t = LocalTime(t: self->date(), localTZA: v4->localTZA); |
1174 | if (v4->hasException) |
1175 | return QV4::Encode::undefined(); |
1176 | double ms = argc ? argv[0].toNumber() : qt_qnan(); |
1177 | if (v4->hasException) |
1178 | return QV4::Encode::undefined(); |
1179 | self->setDate(UTC(t: MakeDate(day: Day(t), time: MakeTime(hour: HourFromTime(t), min: MinFromTime(t), sec: SecFromTime(t), ms)), localTZA: v4->localTZA)); |
1180 | return Encode(self->date()); |
1181 | } |
1182 | |
1183 | ReturnedValue DatePrototype::method_setUTCMilliseconds(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1184 | { |
1185 | ExecutionEngine *v4 = b->engine(); |
1186 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1187 | if (!self) |
1188 | return v4->throwTypeError(); |
1189 | |
1190 | double t = self->date(); |
1191 | if (v4->hasException) |
1192 | return QV4::Encode::undefined(); |
1193 | double ms = argc ? argv[0].toNumber() : qt_qnan(); |
1194 | if (v4->hasException) |
1195 | return QV4::Encode::undefined(); |
1196 | self->setDate(MakeDate(day: Day(t), time: MakeTime(hour: HourFromTime(t), min: MinFromTime(t), sec: SecFromTime(t), ms))); |
1197 | return Encode(self->date()); |
1198 | } |
1199 | |
1200 | ReturnedValue DatePrototype::method_setSeconds(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1201 | { |
1202 | ExecutionEngine *v4 = b->engine(); |
1203 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1204 | if (!self) |
1205 | return v4->throwTypeError(); |
1206 | |
1207 | double t = LocalTime(t: self->date(), localTZA: v4->localTZA); |
1208 | if (v4->hasException) |
1209 | return QV4::Encode::undefined(); |
1210 | double sec = argc ? argv[0].toNumber() : qt_qnan(); |
1211 | if (v4->hasException) |
1212 | return QV4::Encode::undefined(); |
1213 | double ms = (argc < 2) ? msFromTime(t) : argv[1].toNumber(); |
1214 | if (v4->hasException) |
1215 | return QV4::Encode::undefined(); |
1216 | t = UTC(t: MakeDate(day: Day(t), time: MakeTime(hour: HourFromTime(t), min: MinFromTime(t), sec, ms)), localTZA: v4->localTZA); |
1217 | self->setDate(t); |
1218 | return Encode(self->date()); |
1219 | } |
1220 | |
1221 | ReturnedValue DatePrototype::method_setUTCSeconds(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1222 | { |
1223 | ExecutionEngine *v4 = b->engine(); |
1224 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1225 | if (!self) |
1226 | return v4->throwTypeError(); |
1227 | |
1228 | double t = self->date(); |
1229 | double sec = argc ? argv[0].toNumber() : qt_qnan(); |
1230 | double ms = (argc < 2) ? msFromTime(t) : argv[1].toNumber(); |
1231 | t = MakeDate(day: Day(t), time: MakeTime(hour: HourFromTime(t), min: MinFromTime(t), sec, ms)); |
1232 | self->setDate(t); |
1233 | return Encode(self->date()); |
1234 | } |
1235 | |
1236 | ReturnedValue DatePrototype::method_setMinutes(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1237 | { |
1238 | ExecutionEngine *v4 = b->engine(); |
1239 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1240 | if (!self) |
1241 | return v4->throwTypeError(); |
1242 | |
1243 | double t = LocalTime(t: self->date(), localTZA: v4->localTZA); |
1244 | if (v4->hasException) |
1245 | return QV4::Encode::undefined(); |
1246 | double min = argc ? argv[0].toNumber() : qt_qnan(); |
1247 | if (v4->hasException) |
1248 | return QV4::Encode::undefined(); |
1249 | double sec = (argc < 2) ? SecFromTime(t) : argv[1].toNumber(); |
1250 | if (v4->hasException) |
1251 | return QV4::Encode::undefined(); |
1252 | double ms = (argc < 3) ? msFromTime(t) : argv[2].toNumber(); |
1253 | if (v4->hasException) |
1254 | return QV4::Encode::undefined(); |
1255 | t = UTC(t: MakeDate(day: Day(t), time: MakeTime(hour: HourFromTime(t), min, sec, ms)), localTZA: v4->localTZA); |
1256 | self->setDate(t); |
1257 | return Encode(self->date()); |
1258 | } |
1259 | |
1260 | ReturnedValue DatePrototype::method_setUTCMinutes(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1261 | { |
1262 | ExecutionEngine *v4 = b->engine(); |
1263 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1264 | if (!self) |
1265 | return v4->throwTypeError(); |
1266 | |
1267 | double t = self->date(); |
1268 | double min = argc ? argv[0].toNumber() : qt_qnan(); |
1269 | double sec = (argc < 2) ? SecFromTime(t) : argv[1].toNumber(); |
1270 | double ms = (argc < 3) ? msFromTime(t) : argv[2].toNumber(); |
1271 | t = MakeDate(day: Day(t), time: MakeTime(hour: HourFromTime(t), min, sec, ms)); |
1272 | self->setDate(t); |
1273 | return Encode(self->date()); |
1274 | } |
1275 | |
1276 | ReturnedValue DatePrototype::method_setHours(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1277 | { |
1278 | ExecutionEngine *v4 = b->engine(); |
1279 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1280 | if (!self) |
1281 | return v4->throwTypeError(); |
1282 | |
1283 | double t = LocalTime(t: self->date(), localTZA: v4->localTZA); |
1284 | if (v4->hasException) |
1285 | return QV4::Encode::undefined(); |
1286 | double hour = argc ? argv[0].toNumber() : qt_qnan(); |
1287 | if (v4->hasException) |
1288 | return QV4::Encode::undefined(); |
1289 | double min = (argc < 2) ? MinFromTime(t) : argv[1].toNumber(); |
1290 | if (v4->hasException) |
1291 | return QV4::Encode::undefined(); |
1292 | double sec = (argc < 3) ? SecFromTime(t) : argv[2].toNumber(); |
1293 | if (v4->hasException) |
1294 | return QV4::Encode::undefined(); |
1295 | double ms = (argc < 4) ? msFromTime(t) : argv[3].toNumber(); |
1296 | if (v4->hasException) |
1297 | return QV4::Encode::undefined(); |
1298 | t = UTC(t: MakeDate(day: Day(t), time: MakeTime(hour, min, sec, ms)), localTZA: v4->localTZA); |
1299 | self->setDate(t); |
1300 | return Encode(self->date()); |
1301 | } |
1302 | |
1303 | ReturnedValue DatePrototype::method_setUTCHours(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1304 | { |
1305 | ExecutionEngine *v4 = b->engine(); |
1306 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1307 | if (!self) |
1308 | return v4->throwTypeError(); |
1309 | |
1310 | double t = self->date(); |
1311 | double hour = argc ? argv[0].toNumber() : qt_qnan(); |
1312 | double min = (argc < 2) ? MinFromTime(t) : argv[1].toNumber(); |
1313 | double sec = (argc < 3) ? SecFromTime(t) : argv[2].toNumber(); |
1314 | double ms = (argc < 4) ? msFromTime(t) : argv[3].toNumber(); |
1315 | t = MakeDate(day: Day(t), time: MakeTime(hour, min, sec, ms)); |
1316 | self->setDate(t); |
1317 | return Encode(self->date()); |
1318 | } |
1319 | |
1320 | ReturnedValue DatePrototype::method_setDate(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1321 | { |
1322 | ExecutionEngine *v4 = b->engine(); |
1323 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1324 | if (!self) |
1325 | return v4->throwTypeError(); |
1326 | |
1327 | double t = LocalTime(t: self->date(), localTZA: v4->localTZA); |
1328 | if (v4->hasException) |
1329 | return QV4::Encode::undefined(); |
1330 | double date = argc ? argv[0].toNumber() : qt_qnan(); |
1331 | if (v4->hasException) |
1332 | return QV4::Encode::undefined(); |
1333 | t = UTC(t: MakeDate(day: MakeDay(year: YearFromTime(t), month: MonthFromTime(t), day: date), time: TimeWithinDay(t)), localTZA: v4->localTZA); |
1334 | self->setDate(t); |
1335 | return Encode(self->date()); |
1336 | } |
1337 | |
1338 | ReturnedValue DatePrototype::method_setUTCDate(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1339 | { |
1340 | ExecutionEngine *v4 = b->engine(); |
1341 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1342 | if (!self) |
1343 | return v4->throwTypeError(); |
1344 | |
1345 | double t = self->date(); |
1346 | if (v4->hasException) |
1347 | return QV4::Encode::undefined(); |
1348 | double date = argc ? argv[0].toNumber() : qt_qnan(); |
1349 | if (v4->hasException) |
1350 | return QV4::Encode::undefined(); |
1351 | t = MakeDate(day: MakeDay(year: YearFromTime(t), month: MonthFromTime(t), day: date), time: TimeWithinDay(t)); |
1352 | self->setDate(t); |
1353 | return Encode(self->date()); |
1354 | } |
1355 | |
1356 | ReturnedValue DatePrototype::method_setMonth(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1357 | { |
1358 | ExecutionEngine *v4 = b->engine(); |
1359 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1360 | if (!self) |
1361 | return v4->throwTypeError(); |
1362 | |
1363 | double t = LocalTime(t: self->date(), localTZA: v4->localTZA); |
1364 | if (v4->hasException) |
1365 | return QV4::Encode::undefined(); |
1366 | double month = argc ? argv[0].toNumber() : qt_qnan(); |
1367 | if (v4->hasException) |
1368 | return QV4::Encode::undefined(); |
1369 | double date = (argc < 2) ? DateFromTime(t) : argv[1].toNumber(); |
1370 | if (v4->hasException) |
1371 | return QV4::Encode::undefined(); |
1372 | t = UTC(t: MakeDate(day: MakeDay(year: YearFromTime(t), month, day: date), time: TimeWithinDay(t)), localTZA: v4->localTZA); |
1373 | self->setDate(t); |
1374 | return Encode(self->date()); |
1375 | } |
1376 | |
1377 | ReturnedValue DatePrototype::method_setUTCMonth(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1378 | { |
1379 | ExecutionEngine *v4 = b->engine(); |
1380 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1381 | if (!self) |
1382 | return v4->throwTypeError(); |
1383 | |
1384 | double t = self->date(); |
1385 | double month = argc ? argv[0].toNumber() : qt_qnan(); |
1386 | double date = (argc < 2) ? DateFromTime(t) : argv[1].toNumber(); |
1387 | t = MakeDate(day: MakeDay(year: YearFromTime(t), month, day: date), time: TimeWithinDay(t)); |
1388 | self->setDate(t); |
1389 | return Encode(self->date()); |
1390 | } |
1391 | |
1392 | ReturnedValue DatePrototype::method_setYear(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1393 | { |
1394 | ExecutionEngine *v4 = b->engine(); |
1395 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1396 | if (!self) |
1397 | return v4->throwTypeError(); |
1398 | |
1399 | double t = self->date(); |
1400 | if (std::isnan(x: t)) |
1401 | t = 0; |
1402 | else |
1403 | t = LocalTime(t, localTZA: v4->localTZA); |
1404 | double year = argc ? argv[0].toNumber() : qt_qnan(); |
1405 | double r; |
1406 | if (std::isnan(x: year)) { |
1407 | r = qt_qnan(); |
1408 | } else { |
1409 | if ((QV4::Value::toInteger(d: year) >= 0) && (QV4::Value::toInteger(d: year) <= 99)) |
1410 | year += 1900; |
1411 | r = MakeDay(year, month: MonthFromTime(t), day: DateFromTime(t)); |
1412 | r = UTC(t: MakeDate(day: r, time: TimeWithinDay(t)), localTZA: v4->localTZA); |
1413 | } |
1414 | self->setDate(r); |
1415 | return Encode(self->date()); |
1416 | } |
1417 | |
1418 | ReturnedValue DatePrototype::method_setUTCFullYear(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1419 | { |
1420 | ExecutionEngine *v4 = b->engine(); |
1421 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1422 | if (!self) |
1423 | return v4->throwTypeError(); |
1424 | |
1425 | double t = self->date(); |
1426 | double year = argc ? argv[0].toNumber() : qt_qnan(); |
1427 | double month = (argc < 2) ? MonthFromTime(t) : argv[1].toNumber(); |
1428 | double date = (argc < 3) ? DateFromTime(t) : argv[2].toNumber(); |
1429 | t = MakeDate(day: MakeDay(year, month, day: date), time: TimeWithinDay(t)); |
1430 | self->setDate(t); |
1431 | return Encode(self->date()); |
1432 | } |
1433 | |
1434 | ReturnedValue DatePrototype::method_setFullYear(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) |
1435 | { |
1436 | ExecutionEngine *v4 = b->engine(); |
1437 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1438 | if (!self) |
1439 | return v4->throwTypeError(); |
1440 | |
1441 | double t = LocalTime(t: self->date(), localTZA: v4->localTZA); |
1442 | if (v4->hasException) |
1443 | return QV4::Encode::undefined(); |
1444 | if (std::isnan(x: t)) |
1445 | t = 0; |
1446 | double year = argc ? argv[0].toNumber() : qt_qnan(); |
1447 | if (v4->hasException) |
1448 | return QV4::Encode::undefined(); |
1449 | double month = (argc < 2) ? MonthFromTime(t) : argv[1].toNumber(); |
1450 | if (v4->hasException) |
1451 | return QV4::Encode::undefined(); |
1452 | double date = (argc < 3) ? DateFromTime(t) : argv[2].toNumber(); |
1453 | if (v4->hasException) |
1454 | return QV4::Encode::undefined(); |
1455 | t = UTC(t: MakeDate(day: MakeDay(year, month, day: date), time: TimeWithinDay(t)), localTZA: v4->localTZA); |
1456 | self->setDate(t); |
1457 | return Encode(self->date()); |
1458 | } |
1459 | |
1460 | ReturnedValue DatePrototype::method_toUTCString(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1461 | { |
1462 | ExecutionEngine *v4 = b->engine(); |
1463 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1464 | if (!self) |
1465 | return v4->throwTypeError(); |
1466 | |
1467 | double t = self->date(); |
1468 | return Encode(v4->newString(s: ToUTCString(t))); |
1469 | } |
1470 | |
1471 | static void addZeroPrefixedInt(QString &str, int num, int nDigits) |
1472 | { |
1473 | str.resize(size: str.size() + nDigits); |
1474 | |
1475 | QChar *c = str.data() + str.size() - 1; |
1476 | while (nDigits) { |
1477 | *c = QChar(num % 10 + '0'); |
1478 | num /= 10; |
1479 | --c; |
1480 | --nDigits; |
1481 | } |
1482 | } |
1483 | |
1484 | ReturnedValue DatePrototype::method_toISOString(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1485 | { |
1486 | ExecutionEngine *v4 = b->engine(); |
1487 | DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>()); |
1488 | if (!self) |
1489 | return v4->throwTypeError(); |
1490 | |
1491 | double t = self->date(); |
1492 | if (!std::isfinite(x: t)) |
1493 | RETURN_RESULT(v4->throwRangeError(*thisObject)); |
1494 | |
1495 | QString result; |
1496 | int year = (int)YearFromTime(t); |
1497 | if (year < 0 || year > 9999) { |
1498 | if (qAbs(t: year) >= 1000000) |
1499 | RETURN_RESULT(v4->throwRangeError(*thisObject)); |
1500 | result += year < 0 ? QLatin1Char('-') : QLatin1Char('+'); |
1501 | year = qAbs(t: year); |
1502 | addZeroPrefixedInt(str&: result, num: year, nDigits: 6); |
1503 | } else { |
1504 | addZeroPrefixedInt(str&: result, num: year, nDigits: 4); |
1505 | } |
1506 | result += QLatin1Char('-'); |
1507 | addZeroPrefixedInt(str&: result, num: (int)MonthFromTime(t) + 1, nDigits: 2); |
1508 | result += QLatin1Char('-'); |
1509 | addZeroPrefixedInt(str&: result, num: (int)DateFromTime(t), nDigits: 2); |
1510 | result += QLatin1Char('T'); |
1511 | addZeroPrefixedInt(str&: result, num: HourFromTime(t), nDigits: 2); |
1512 | result += QLatin1Char(':'); |
1513 | addZeroPrefixedInt(str&: result, num: MinFromTime(t), nDigits: 2); |
1514 | result += QLatin1Char(':'); |
1515 | addZeroPrefixedInt(str&: result, num: SecFromTime(t), nDigits: 2); |
1516 | result += QLatin1Char('.'); |
1517 | addZeroPrefixedInt(str&: result, num: msFromTime(t), nDigits: 3); |
1518 | result += QLatin1Char('Z'); |
1519 | |
1520 | return Encode(v4->newString(s: result)); |
1521 | } |
1522 | |
1523 | ReturnedValue DatePrototype::method_toJSON(const FunctionObject *b, const Value *thisObject, const Value *, int) |
1524 | { |
1525 | ExecutionEngine *v4 = b->engine(); |
1526 | Scope scope(v4); |
1527 | ScopedObject O(scope, thisObject->toObject(e: v4)); |
1528 | if (v4->hasException) |
1529 | return QV4::Encode::undefined(); |
1530 | |
1531 | ScopedValue tv(scope, RuntimeHelpers::toPrimitive(value: O, typeHint: NUMBER_HINT)); |
1532 | |
1533 | if (tv->isNumber() && !std::isfinite(x: tv->toNumber())) |
1534 | return Encode::null(); |
1535 | |
1536 | ScopedString s(scope, v4->newString(QStringLiteral("toISOString" ))); |
1537 | ScopedValue v(scope, O->get(name: s)); |
1538 | FunctionObject *toIso = v->as<FunctionObject>(); |
1539 | |
1540 | if (!toIso) |
1541 | return v4->throwTypeError(); |
1542 | |
1543 | return checkedResult(v4, result: toIso->call(thisObject: O, argv: nullptr, argc: 0)); |
1544 | } |
1545 | |
1546 | ReturnedValue DatePrototype::method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc) |
1547 | { |
1548 | ExecutionEngine *e = f->engine(); |
1549 | if (!thisObject->isObject() || !argc || !argv->isString()) |
1550 | return e->throwTypeError(); |
1551 | |
1552 | String *hint = argv->stringValue(); |
1553 | PropertyKey id = hint->toPropertyKey(); |
1554 | if (id == e->id_default()->propertyKey()) |
1555 | hint = e->id_string(); |
1556 | else if (id != e->id_string()->propertyKey() && id != e->id_number()->propertyKey()) |
1557 | return e->throwTypeError(); |
1558 | |
1559 | return RuntimeHelpers::ordinaryToPrimitive(engine: e, object: static_cast<const Object *>(thisObject), typeHint: hint); |
1560 | } |
1561 | |
1562 | void DatePrototype::timezoneUpdated(ExecutionEngine *e) |
1563 | { |
1564 | e->localTZA = getLocalTZA(); |
1565 | } |
1566 | |