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
16using namespace QV4;
17
18static const double HoursPerDay = 24.0;
19static const double MinutesPerHour = 60.0;
20static const double SecondsPerMinute = 60.0;
21static const double msPerSecond = 1000.0;
22static const double msPerMinute = 60000.0;
23static const double msPerHour = 3600000.0;
24static const double msPerDay = 86400000.0;
25
26static inline double TimeWithinDay(double t)
27{
28 double r = ::fmod(x: t, y: msPerDay);
29 return (r >= 0) ? r : r + msPerDay;
30}
31
32static 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
38static 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
44static 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
50static 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
56static inline double Day(double t)
57{
58 return ::floor(x: t / msPerDay);
59}
60
61static 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
75static 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
83static inline double TimeFromYear(double y)
84{
85 return msPerDay * DayFromYear(y);
86}
87
88static 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
97static 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
107static inline double DayWithinYear(double t)
108{
109 return Day(t) - DayFromYear(y: YearFromTime(t));
110}
111
112static 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
156static 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
180static 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
187static 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
198static 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
218static 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
256static 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*/
278static inline double DaylightSavingTA(double t, double localTZA) // t is a UTC time
279{
280 return QLocalTime::getUtcOffset(atMSecsSinceEpoch: qint64(t)) * 1e3 - localTZA;
281}
282
283static 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
292static 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
298static inline double currentTime()
299{
300 return QDateTime::currentDateTimeUtc().toMSecsSinceEpoch();
301}
302
303static 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
312static 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.zzzt; the time (T and all
319 after it) may be omitted. In each part, the second and later components
320 are optional. There's an extended syntax for negative and large positive
321 years: ±yyyyyy; the leading sign, even when +, isn't optional. If month
322 (MM) or day (dd) is omitted, it is 01; if minute (mm) or second (ss) is
323 omitted, it's 00; if milliseconds (zzz) are omitted, they're 000.
324
325 When the time zone offset (t) 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*/
551static 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
558static 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
578static 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
585static inline QString ToDateString(double t)
586{
587 return ToDateTime(t, zone: QTimeZone::LocalTime).date().toString();
588}
589
590static inline QString ToTimeString(double t)
591{
592 return ToDateTime(t, zone: QTimeZone::LocalTime).time().toString();
593}
594
595static inline QString ToLocaleString(double t)
596{
597 return QLocale().toString(dateTime: ToDateTime(t, zone: QTimeZone::LocalTime), format: QLocale::ShortFormat);
598}
599
600static inline QString ToLocaleDateString(double t)
601{
602 return QLocale().toString(date: ToDateTime(t, zone: QTimeZone::LocalTime).date(), format: QLocale::ShortFormat);
603}
604
605static inline QString ToLocaleTimeString(double t)
606{
607 return QLocale().toString(time: ToDateTime(t, zone: QTimeZone::LocalTime).time(), format: QLocale::ShortFormat);
608}
609
610static double getLocalTZA()
611{
612 return QLocalTime::getCurrentStandardUtcOffset() * 1e3;
613}
614
615DEFINE_OBJECT_VTABLE(DateObject);
616
617quint64 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
630quint64 Date::encode(const QDateTime &dateTime)
631{
632 return encode(value: dateTime.isValid() ? dateTime.toMSecsSinceEpoch() : qt_qnan());
633}
634
635void Date::init(double value)
636{
637 storage = encode(value);
638}
639
640void Date::init(const QDateTime &when)
641{
642 storage = encode(dateTime: when) | HasQDate | HasQTime;
643}
644
645void Date::init(QDate date)
646{
647 storage = encode(dateTime: date.startOfDay(zone: QTimeZone::UTC)) | HasQDate;
648}
649
650void 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
676QDate Date::toQDate() const
677{
678 return toQDateTime().date();
679}
680
681QTime Date::toQTime() const
682{
683 return toQDateTime().time();
684}
685
686QDateTime Date::toQDateTime() const
687{
688 return ToDateTime(t: operator double(), zone: QTimeZone::LocalTime);
689}
690
691QVariant Date::toVariant() const
692{
693 // Note that we shouldn't and don't read-back here, compared to
694 // most other methods, as this is only used when we perform a
695 // write-back, that is we are sending our version of the data back
696 // to the originating element.
697 switch (storage & (HasQDate | HasQTime)) {
698 case HasQDate:
699 return toQDate();
700 case HasQTime:
701 return toQTime();
702 case (HasQDate | HasQTime):
703 return toQDateTime();
704 default:
705 return QVariant();
706 }
707}
708
709QDateTime DateObject::toQDateTime() const
710{
711 if (d()->isAttachedToProperty())
712 d()->readReference();
713 return d()->toQDateTime();
714}
715
716QString DateObject::toString() const
717{
718 if (d()->isAttachedToProperty())
719 d()->readReference();
720 return ToString(t: d()->date(), localTZA: engine()->localTZA);
721}
722
723QString DateObject::dateTimeToString(const QDateTime &dateTime, ExecutionEngine *engine)
724{
725 if (!dateTime.isValid())
726 return QStringLiteral("Invalid Date");
727 return ToString(t: TimeClip(t: dateTime.toMSecsSinceEpoch()), localTZA: engine->localTZA);
728}
729
730double DateObject::dateTimeToNumber(const QDateTime &dateTime)
731{
732 if (!dateTime.isValid())
733 return qQNaN();
734 return TimeClip(t: dateTime.toMSecsSinceEpoch());
735}
736
737QDateTime DateObject::stringToDateTime(const QString &string, ExecutionEngine *engine)
738{
739 return ToDateTime(t: ParseString(s: string, localTZA: engine->localTZA), zone: QTimeZone::LocalTime);
740}
741
742QDateTime DateObject::timestampToDateTime(double timestamp, QTimeZone zone)
743{
744 return ToDateTime(t: timestamp, zone);
745}
746
747double DateObject::componentsToTimestamp(
748 double year, double month, double day, double hours,
749 double mins, double secs, double ms, ExecutionEngine *v4)
750{
751 if (year >= 0 && year <= 99)
752 year += 1900;
753 const double t = MakeDate(day: MakeDay(year, month, day), time: MakeTime(hour: hours, min: mins, sec: secs, ms));
754 return UTC(t, localTZA: v4->localTZA);
755}
756
757QDate DateObject::dateTimeToDate(const QDateTime &dateTime)
758{
759 // If the Date object was parse()d from a string with no time part
760 // or zone specifier it's really the UTC start of the relevant day,
761 // but it's here represented as a local time, which may fall in the
762 // preceding day. See QTBUG-92466 for the gory details.
763 const auto utc = dateTime.toUTC();
764 if (utc.date() != dateTime.date() && utc.addSecs(secs: -1).date() == dateTime.date())
765 return utc.date();
766
767 // This may, of course, be The Wrong Thing if the date was
768 // constructed as a full local date-time that happens to coincide
769 // with the start of a UTC day; however, that would be an odd value
770 // to give to something that, apparently, someone thinks belongs in
771 // a QDate.
772 return dateTime.date();
773}
774
775DEFINE_OBJECT_VTABLE(DateCtor);
776
777Heap::DateObject *Heap::DateObject::detached() const
778{
779 return internalClass->engine->memoryManager->allocate<QV4::DateObject>(args: m_date);
780}
781
782bool Heap::DateObject::setVariant(const QVariant &variant)
783{
784 const QMetaType variantReferenceType = variant.metaType();
785 switch (variantReferenceType.id()) {
786 case QMetaType::Double:
787 m_date.init(value: *static_cast<const double *>(variant.constData()));
788 break;
789 case QMetaType::QDate:
790 m_date.init(date: *static_cast<const QDate *>(variant.constData()));
791 break;
792 case QMetaType::QTime:
793 m_date.init(time: *static_cast<const QTime *>(variant.constData()), engine: internalClass->engine);
794 break;
795 case QMetaType::QDateTime:
796 m_date.init(when: *static_cast<const QDateTime *>(variant.constData()));
797 break;
798 default:
799 return false;
800 }
801
802 return true;
803}
804
805void Heap::DateCtor::init(QV4::ExecutionEngine *engine)
806{
807 Heap::FunctionObject::init(engine, QStringLiteral("Date"));
808}
809
810ReturnedValue DateCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, int argc, const Value *newTarget)
811{
812 ExecutionEngine *v4 = that->engine();
813 double t = 0;
814
815 if (argc == 0)
816 t = currentTime();
817
818 else if (argc == 1) {
819 Scope scope(v4);
820 ScopedValue arg(scope, argv[0]);
821 if (DateObject *d = arg->as<DateObject>()) {
822 t = d->date();
823 } else {
824 arg = RuntimeHelpers::toPrimitive(value: arg, typeHint: PREFERREDTYPE_HINT);
825
826 if (String *s = arg->stringValue())
827 t = ParseString(s: s->toQString(), localTZA: v4->localTZA);
828 else
829 t = arg->toNumber();
830 }
831 }
832
833 else { // d.argc > 1
834 const double year = argv[0].toNumber();
835 const double month = argv[1].toNumber();
836 const double day = argc >= 3 ? argv[2].toNumber() : 1;
837 const double hours = argc >= 4 ? argv[3].toNumber() : 0;
838 const double mins = argc >= 5 ? argv[4].toNumber() : 0;
839 const double secs = argc >= 6 ? argv[5].toNumber() : 0;
840 const double ms = argc >= 7 ? argv[6].toNumber() : 0;
841 t = DateObject::componentsToTimestamp(year, month, day, hours, mins, secs, ms, v4);
842 }
843
844 ReturnedValue o = Encode(v4->newDateObject(dateTime: t));
845 if (!newTarget)
846 return o;
847 Scope scope(v4);
848 ScopedObject obj(scope, o);
849 obj->setProtoFromNewTarget(newTarget);
850 return obj->asReturnedValue();
851}
852
853ReturnedValue DateCtor::virtualCall(const FunctionObject *m, const Value *, const Value *, int)
854{
855 ExecutionEngine *e = m->engine();
856 double t = currentTime();
857 return e->newString(s: ToString(t, localTZA: e->localTZA))->asReturnedValue();
858}
859
860void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
861{
862 Scope scope(engine);
863 ScopedObject o(scope);
864 ctor->defineReadonlyProperty(name: engine->id_prototype(), value: (o = this));
865 ctor->defineReadonlyConfigurableProperty(name: engine->id_length(), value: Value::fromInt32(i: 7));
866 engine->localTZA = getLocalTZA();
867
868 ctor->defineDefaultProperty(QStringLiteral("parse"), code: method_parse, argumentCount: 1);
869 ctor->defineDefaultProperty(QStringLiteral("UTC"), code: method_UTC, argumentCount: 7);
870 ctor->defineDefaultProperty(QStringLiteral("now"), code: method_now, argumentCount: 0);
871
872 defineDefaultProperty(QStringLiteral("constructor"), value: (o = ctor));
873 defineDefaultProperty(name: engine->id_toString(), code: method_toString, argumentCount: 0);
874 defineDefaultProperty(QStringLiteral("toDateString"), code: method_toDateString, argumentCount: 0);
875 defineDefaultProperty(QStringLiteral("toTimeString"), code: method_toTimeString, argumentCount: 0);
876 defineDefaultProperty(name: engine->id_toLocaleString(), code: method_toLocaleString, argumentCount: 0);
877 defineDefaultProperty(QStringLiteral("toLocaleDateString"), code: method_toLocaleDateString, argumentCount: 0);
878 defineDefaultProperty(QStringLiteral("toLocaleTimeString"), code: method_toLocaleTimeString, argumentCount: 0);
879 defineDefaultProperty(name: engine->id_valueOf(), code: method_valueOf, argumentCount: 0);
880 defineDefaultProperty(QStringLiteral("getTime"), code: method_getTime, argumentCount: 0);
881 defineDefaultProperty(QStringLiteral("getYear"), code: method_getYear, argumentCount: 0);
882 defineDefaultProperty(QStringLiteral("getFullYear"), code: method_getFullYear, argumentCount: 0);
883 defineDefaultProperty(QStringLiteral("getUTCFullYear"), code: method_getUTCFullYear, argumentCount: 0);
884 defineDefaultProperty(QStringLiteral("getMonth"), code: method_getMonth, argumentCount: 0);
885 defineDefaultProperty(QStringLiteral("getUTCMonth"), code: method_getUTCMonth, argumentCount: 0);
886 defineDefaultProperty(QStringLiteral("getDate"), code: method_getDate, argumentCount: 0);
887 defineDefaultProperty(QStringLiteral("getUTCDate"), code: method_getUTCDate, argumentCount: 0);
888 defineDefaultProperty(QStringLiteral("getDay"), code: method_getDay, argumentCount: 0);
889 defineDefaultProperty(QStringLiteral("getUTCDay"), code: method_getUTCDay, argumentCount: 0);
890 defineDefaultProperty(QStringLiteral("getHours"), code: method_getHours, argumentCount: 0);
891 defineDefaultProperty(QStringLiteral("getUTCHours"), code: method_getUTCHours, argumentCount: 0);
892 defineDefaultProperty(QStringLiteral("getMinutes"), code: method_getMinutes, argumentCount: 0);
893 defineDefaultProperty(QStringLiteral("getUTCMinutes"), code: method_getUTCMinutes, argumentCount: 0);
894 defineDefaultProperty(QStringLiteral("getSeconds"), code: method_getSeconds, argumentCount: 0);
895 defineDefaultProperty(QStringLiteral("getUTCSeconds"), code: method_getUTCSeconds, argumentCount: 0);
896 defineDefaultProperty(QStringLiteral("getMilliseconds"), code: method_getMilliseconds, argumentCount: 0);
897 defineDefaultProperty(QStringLiteral("getUTCMilliseconds"), code: method_getUTCMilliseconds, argumentCount: 0);
898 defineDefaultProperty(QStringLiteral("getTimezoneOffset"), code: method_getTimezoneOffset, argumentCount: 0);
899 defineDefaultProperty(QStringLiteral("setTime"), code: method_setTime, argumentCount: 1);
900 defineDefaultProperty(QStringLiteral("setMilliseconds"), code: method_setMilliseconds, argumentCount: 1);
901 defineDefaultProperty(QStringLiteral("setUTCMilliseconds"), code: method_setUTCMilliseconds, argumentCount: 1);
902 defineDefaultProperty(QStringLiteral("setSeconds"), code: method_setSeconds, argumentCount: 2);
903 defineDefaultProperty(QStringLiteral("setUTCSeconds"), code: method_setUTCSeconds, argumentCount: 2);
904 defineDefaultProperty(QStringLiteral("setMinutes"), code: method_setMinutes, argumentCount: 3);
905 defineDefaultProperty(QStringLiteral("setUTCMinutes"), code: method_setUTCMinutes, argumentCount: 3);
906 defineDefaultProperty(QStringLiteral("setHours"), code: method_setHours, argumentCount: 4);
907 defineDefaultProperty(QStringLiteral("setUTCHours"), code: method_setUTCHours, argumentCount: 4);
908 defineDefaultProperty(QStringLiteral("setDate"), code: method_setDate, argumentCount: 1);
909 defineDefaultProperty(QStringLiteral("setUTCDate"), code: method_setUTCDate, argumentCount: 1);
910 defineDefaultProperty(QStringLiteral("setMonth"), code: method_setMonth, argumentCount: 2);
911 defineDefaultProperty(QStringLiteral("setUTCMonth"), code: method_setUTCMonth, argumentCount: 2);
912 defineDefaultProperty(QStringLiteral("setYear"), code: method_setYear, argumentCount: 1);
913 defineDefaultProperty(QStringLiteral("setFullYear"), code: method_setFullYear, argumentCount: 3);
914 defineDefaultProperty(QStringLiteral("setUTCFullYear"), code: method_setUTCFullYear, argumentCount: 3);
915
916 // ES6: B.2.4.3 & 20.3.4.43:
917 // We have to use the *same object* for toUTCString and toGMTString
918 {
919 QString toUtcString(QStringLiteral("toUTCString"));
920 QString toGmtString(QStringLiteral("toGMTString"));
921 ScopedString us(scope, engine->newIdentifier(text: toUtcString));
922 ScopedString gs(scope, engine->newIdentifier(text: toGmtString));
923 ScopedFunctionObject toUtcGmtStringFn(scope, FunctionObject::createBuiltinFunction(engine, nameOrSymbol: us, code: method_toUTCString, argumentCount: 0));
924 defineDefaultProperty(name: us, value: toUtcGmtStringFn);
925 defineDefaultProperty(name: gs, value: toUtcGmtStringFn);
926 }
927
928 defineDefaultProperty(QStringLiteral("toISOString"), code: method_toISOString, argumentCount: 0);
929 defineDefaultProperty(QStringLiteral("toJSON"), code: method_toJSON, argumentCount: 1);
930 defineDefaultProperty(name: engine->symbol_toPrimitive(), code: method_symbolToPrimitive, argumentCount: 1, attributes: Attr_ReadOnly_ButConfigurable);
931}
932
933double DatePrototype::getThisDate(ExecutionEngine *v4, const Value *thisObject)
934{
935 if (const DateObject *that = thisObject->as<DateObject>()) {
936 if (that->d()->isAttachedToProperty())
937 that->d()->readReference();
938
939 return that->date();
940 }
941 v4->throwTypeError();
942 return 0;
943}
944
945ReturnedValue DatePrototype::method_parse(const FunctionObject *f, const Value *, const Value *argv, int argc)
946{
947 if (!argc)
948 return Encode(qt_qnan());
949 else
950 return Encode(ParseString(s: argv[0].toQString(), localTZA: f->engine()->localTZA));
951}
952
953ReturnedValue DatePrototype::method_UTC(const FunctionObject *f, const Value *, const Value *argv, int argc)
954{
955 const int numArgs = argc;
956 if (numArgs < 1)
957 return Encode(qQNaN());
958 ExecutionEngine *e = f->engine();
959 double year = argv[0].toNumber();
960 if (e->hasException)
961 return Encode::undefined();
962 double month = numArgs >= 2 ? argv[1].toNumber() : 0;
963 if (e->hasException)
964 return Encode::undefined();
965 double day = numArgs >= 3 ? argv[2].toNumber() : 1;
966 if (e->hasException)
967 return Encode::undefined();
968 double hours = numArgs >= 4 ? argv[3].toNumber() : 0;
969 if (e->hasException)
970 return Encode::undefined();
971 double mins = numArgs >= 5 ? argv[4].toNumber() : 0;
972 if (e->hasException)
973 return Encode::undefined();
974 double secs = numArgs >= 6 ? argv[5].toNumber() : 0;
975 if (e->hasException)
976 return Encode::undefined();
977 double ms = numArgs >= 7 ? argv[6].toNumber() : 0;
978 if (e->hasException)
979 return Encode::undefined();
980 double iyear = QV4::Value::toInteger(d: year);
981 if (!qIsNaN(d: year) && iyear >= 0 && iyear <= 99)
982 year = 1900 + iyear;
983 double t = MakeDate(day: MakeDay(year, month, day),
984 time: MakeTime(hour: hours, min: mins, sec: secs, ms));
985 return Encode(TimeClip(t));
986}
987
988ReturnedValue DatePrototype::method_now(const FunctionObject *, const Value *, const Value *, int)
989{
990 return Encode(currentTime());
991}
992
993ReturnedValue DatePrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
994{
995 ExecutionEngine *v4 = b->engine();
996 double t = getThisDate(v4, thisObject);
997 return Encode(v4->newString(s: ToString(t, localTZA: v4->localTZA)));
998}
999
1000ReturnedValue DatePrototype::method_toDateString(const FunctionObject *b, const Value *thisObject, const Value *, int)
1001{
1002 ExecutionEngine *v4 = b->engine();
1003 double t = getThisDate(v4, thisObject);
1004 return Encode(v4->newString(s: ToDateString(t)));
1005}
1006
1007ReturnedValue DatePrototype::method_toTimeString(const FunctionObject *b, const Value *thisObject, const Value *, int)
1008{
1009 ExecutionEngine *v4 = b->engine();
1010 double t = getThisDate(v4, thisObject);
1011 return Encode(v4->newString(s: ToTimeString(t)));
1012}
1013
1014ReturnedValue DatePrototype::method_toLocaleString(const FunctionObject *b, const Value *thisObject, const Value *, int)
1015{
1016 ExecutionEngine *v4 = b->engine();
1017 double t = getThisDate(v4, thisObject);
1018 return Encode(v4->newString(s: ToLocaleString(t)));
1019}
1020
1021ReturnedValue DatePrototype::method_toLocaleDateString(const FunctionObject *b, const Value *thisObject, const Value *, int)
1022{
1023 ExecutionEngine *v4 = b->engine();
1024 double t = getThisDate(v4, thisObject);
1025 return Encode(v4->newString(s: ToLocaleDateString(t)));
1026}
1027
1028ReturnedValue DatePrototype::method_toLocaleTimeString(const FunctionObject *b, const Value *thisObject, const Value *, int)
1029{
1030 ExecutionEngine *v4 = b->engine();
1031 double t = getThisDate(v4, thisObject);
1032 return Encode(v4->newString(s: ToLocaleTimeString(t)));
1033}
1034
1035ReturnedValue DatePrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int)
1036{
1037 ExecutionEngine *v4 = b->engine();
1038 double t = getThisDate(v4, thisObject);
1039 return Encode(t);
1040}
1041
1042ReturnedValue DatePrototype::method_getTime(const FunctionObject *b, const Value *thisObject, const Value *, int)
1043{
1044 ExecutionEngine *v4 = b->engine();
1045 double t = getThisDate(v4, thisObject);
1046 return Encode(t);
1047}
1048
1049ReturnedValue DatePrototype::method_getYear(const FunctionObject *b, const Value *thisObject, const Value *, int)
1050{
1051 ExecutionEngine *v4 = b->engine();
1052 double t = getThisDate(v4, thisObject);
1053 if (!std::isnan(x: t))
1054 t = YearFromTime(t: LocalTime(t, localTZA: v4->localTZA)) - 1900;
1055 return Encode(t);
1056}
1057
1058ReturnedValue DatePrototype::method_getFullYear(const FunctionObject *b, const Value *thisObject, const Value *, int)
1059{
1060 ExecutionEngine *v4 = b->engine();
1061 double t = getThisDate(v4, thisObject);
1062 if (!std::isnan(x: t))
1063 t = YearFromTime(t: LocalTime(t, localTZA: v4->localTZA));
1064 return Encode(t);
1065}
1066
1067ReturnedValue DatePrototype::method_getUTCFullYear(const FunctionObject *b, const Value *thisObject, const Value *, int)
1068{
1069 ExecutionEngine *v4 = b->engine();
1070 double t = getThisDate(v4, thisObject);
1071 if (!std::isnan(x: t))
1072 t = YearFromTime(t);
1073 return Encode(t);
1074}
1075
1076ReturnedValue DatePrototype::method_getMonth(const FunctionObject *b, const Value *thisObject, const Value *, int)
1077{
1078 ExecutionEngine *v4 = b->engine();
1079 double t = getThisDate(v4, thisObject);
1080 if (!std::isnan(x: t))
1081 t = MonthFromTime(t: LocalTime(t, localTZA: v4->localTZA));
1082 return Encode(t);
1083}
1084
1085ReturnedValue DatePrototype::method_getUTCMonth(const FunctionObject *b, const Value *thisObject, const Value *, int)
1086{
1087 ExecutionEngine *v4 = b->engine();
1088 double t = getThisDate(v4, thisObject);
1089 if (!std::isnan(x: t))
1090 t = MonthFromTime(t);
1091 return Encode(t);
1092}
1093
1094ReturnedValue DatePrototype::method_getDate(const FunctionObject *b, const Value *thisObject, const Value *, int)
1095{
1096 ExecutionEngine *v4 = b->engine();
1097 double t = getThisDate(v4, thisObject);
1098 if (!std::isnan(x: t))
1099 t = DateFromTime(t: LocalTime(t, localTZA: v4->localTZA));
1100 return Encode(t);
1101}
1102
1103ReturnedValue DatePrototype::method_getUTCDate(const FunctionObject *b, const Value *thisObject, const Value *, int)
1104{
1105 ExecutionEngine *v4 = b->engine();
1106 double t = getThisDate(v4, thisObject);
1107 if (!std::isnan(x: t))
1108 t = DateFromTime(t);
1109 return Encode(t);
1110}
1111
1112ReturnedValue DatePrototype::method_getDay(const FunctionObject *b, const Value *thisObject, const Value *, int)
1113{
1114 ExecutionEngine *v4 = b->engine();
1115 double t = getThisDate(v4, thisObject);
1116 if (!std::isnan(x: t))
1117 t = WeekDay(t: LocalTime(t, localTZA: v4->localTZA));
1118 return Encode(t);
1119}
1120
1121ReturnedValue DatePrototype::method_getUTCDay(const FunctionObject *b, const Value *thisObject, const Value *, int)
1122{
1123 ExecutionEngine *v4 = b->engine();
1124 double t = getThisDate(v4, thisObject);
1125 if (!std::isnan(x: t))
1126 t = WeekDay(t);
1127 return Encode(t);
1128}
1129
1130ReturnedValue DatePrototype::method_getHours(const FunctionObject *b, const Value *thisObject, const Value *, int)
1131{
1132 ExecutionEngine *v4 = b->engine();
1133 double t = getThisDate(v4, thisObject);
1134 if (!std::isnan(x: t))
1135 t = HourFromTime(t: LocalTime(t, localTZA: v4->localTZA));
1136 return Encode(t);
1137}
1138
1139ReturnedValue DatePrototype::method_getUTCHours(const FunctionObject *b, const Value *thisObject, const Value *, int)
1140{
1141 ExecutionEngine *v4 = b->engine();
1142 double t = getThisDate(v4, thisObject);
1143 if (!std::isnan(x: t))
1144 t = HourFromTime(t);
1145 return Encode(t);
1146}
1147
1148ReturnedValue DatePrototype::method_getMinutes(const FunctionObject *b, const Value *thisObject, const Value *, int)
1149{
1150 ExecutionEngine *v4 = b->engine();
1151 double t = getThisDate(v4, thisObject);
1152 if (!std::isnan(x: t))
1153 t = MinFromTime(t: LocalTime(t, localTZA: v4->localTZA));
1154 return Encode(t);
1155}
1156
1157ReturnedValue DatePrototype::method_getUTCMinutes(const FunctionObject *b, const Value *thisObject, const Value *, int)
1158{
1159 ExecutionEngine *v4 = b->engine();
1160 double t = getThisDate(v4, thisObject);
1161 if (!std::isnan(x: t))
1162 t = MinFromTime(t);
1163 return Encode(t);
1164}
1165
1166ReturnedValue DatePrototype::method_getSeconds(const FunctionObject *b, const Value *thisObject, const Value *, int)
1167{
1168 ExecutionEngine *v4 = b->engine();
1169 double t = getThisDate(v4, thisObject);
1170 if (!std::isnan(x: t))
1171 t = SecFromTime(t: LocalTime(t, localTZA: v4->localTZA));
1172 return Encode(t);
1173}
1174
1175ReturnedValue DatePrototype::method_getUTCSeconds(const FunctionObject *b, const Value *thisObject, const Value *, int)
1176{
1177 ExecutionEngine *v4 = b->engine();
1178 double t = getThisDate(v4, thisObject);
1179 if (!std::isnan(x: t))
1180 t = SecFromTime(t);
1181 return Encode(t);
1182}
1183
1184ReturnedValue DatePrototype::method_getMilliseconds(const FunctionObject *b, const Value *thisObject, const Value *, int)
1185{
1186 ExecutionEngine *v4 = b->engine();
1187 double t = getThisDate(v4, thisObject);
1188 if (!std::isnan(x: t))
1189 t = msFromTime(t: LocalTime(t, localTZA: v4->localTZA));
1190 return Encode(t);
1191}
1192
1193ReturnedValue DatePrototype::method_getUTCMilliseconds(const FunctionObject *b, const Value *thisObject, const Value *, int)
1194{
1195 ExecutionEngine *v4 = b->engine();
1196 double t = getThisDate(v4, thisObject);
1197 if (!std::isnan(x: t))
1198 t = msFromTime(t);
1199 return Encode(t);
1200}
1201
1202ReturnedValue DatePrototype::method_getTimezoneOffset(const FunctionObject *b, const Value *thisObject, const Value *, int)
1203{
1204 ExecutionEngine *v4 = b->engine();
1205 double t = getThisDate(v4, thisObject);
1206 if (!std::isnan(x: t))
1207 t = (t - LocalTime(t, localTZA: v4->localTZA)) / msPerMinute;
1208 return Encode(t);
1209}
1210
1211ReturnedValue DatePrototype::method_setTime(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1212{
1213 ExecutionEngine *v4 = b->engine();
1214 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1215 if (!self)
1216 return v4->throwTypeError();
1217
1218 double t = argc ? argv[0].toNumber() : qt_qnan();
1219 if (v4->hasException)
1220 return QV4::Encode::undefined();
1221 self->setDate(t);
1222 return Encode(self->date());
1223}
1224
1225ReturnedValue DatePrototype::method_setMilliseconds(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1226{
1227 ExecutionEngine *v4 = b->engine();
1228 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1229 if (!self)
1230 return v4->throwTypeError();
1231
1232 double t = LocalTime(t: self->date(), localTZA: v4->localTZA);
1233 if (v4->hasException)
1234 return QV4::Encode::undefined();
1235 double ms = argc ? argv[0].toNumber() : qt_qnan();
1236 if (v4->hasException)
1237 return QV4::Encode::undefined();
1238 self->setDate(UTC(t: MakeDate(day: Day(t), time: MakeTime(hour: HourFromTime(t), min: MinFromTime(t), sec: SecFromTime(t), ms)), localTZA: v4->localTZA));
1239 return Encode(self->date());
1240}
1241
1242ReturnedValue DatePrototype::method_setUTCMilliseconds(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1243{
1244 ExecutionEngine *v4 = b->engine();
1245 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1246 if (!self)
1247 return v4->throwTypeError();
1248
1249 double t = self->date();
1250 if (v4->hasException)
1251 return QV4::Encode::undefined();
1252 double ms = argc ? argv[0].toNumber() : qt_qnan();
1253 if (v4->hasException)
1254 return QV4::Encode::undefined();
1255 self->setDate(MakeDate(day: Day(t), time: MakeTime(hour: HourFromTime(t), min: MinFromTime(t), sec: SecFromTime(t), ms)));
1256 return Encode(self->date());
1257}
1258
1259ReturnedValue DatePrototype::method_setSeconds(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1260{
1261 ExecutionEngine *v4 = b->engine();
1262 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1263 if (!self)
1264 return v4->throwTypeError();
1265
1266 double t = LocalTime(t: self->date(), localTZA: v4->localTZA);
1267 if (v4->hasException)
1268 return QV4::Encode::undefined();
1269 double sec = argc ? argv[0].toNumber() : qt_qnan();
1270 if (v4->hasException)
1271 return QV4::Encode::undefined();
1272 double ms = (argc < 2) ? msFromTime(t) : argv[1].toNumber();
1273 if (v4->hasException)
1274 return QV4::Encode::undefined();
1275 t = UTC(t: MakeDate(day: Day(t), time: MakeTime(hour: HourFromTime(t), min: MinFromTime(t), sec, ms)), localTZA: v4->localTZA);
1276 self->setDate(t);
1277 return Encode(self->date());
1278}
1279
1280ReturnedValue DatePrototype::method_setUTCSeconds(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1281{
1282 ExecutionEngine *v4 = b->engine();
1283 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1284 if (!self)
1285 return v4->throwTypeError();
1286
1287 double t = self->date();
1288 double sec = argc ? argv[0].toNumber() : qt_qnan();
1289 double ms = (argc < 2) ? msFromTime(t) : argv[1].toNumber();
1290 t = MakeDate(day: Day(t), time: MakeTime(hour: HourFromTime(t), min: MinFromTime(t), sec, ms));
1291 self->setDate(t);
1292 return Encode(self->date());
1293}
1294
1295ReturnedValue DatePrototype::method_setMinutes(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1296{
1297 ExecutionEngine *v4 = b->engine();
1298 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1299 if (!self)
1300 return v4->throwTypeError();
1301
1302 double t = LocalTime(t: self->date(), localTZA: v4->localTZA);
1303 if (v4->hasException)
1304 return QV4::Encode::undefined();
1305 double min = argc ? argv[0].toNumber() : qt_qnan();
1306 if (v4->hasException)
1307 return QV4::Encode::undefined();
1308 double sec = (argc < 2) ? SecFromTime(t) : argv[1].toNumber();
1309 if (v4->hasException)
1310 return QV4::Encode::undefined();
1311 double ms = (argc < 3) ? msFromTime(t) : argv[2].toNumber();
1312 if (v4->hasException)
1313 return QV4::Encode::undefined();
1314 t = UTC(t: MakeDate(day: Day(t), time: MakeTime(hour: HourFromTime(t), min, sec, ms)), localTZA: v4->localTZA);
1315 self->setDate(t);
1316 return Encode(self->date());
1317}
1318
1319ReturnedValue DatePrototype::method_setUTCMinutes(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1320{
1321 ExecutionEngine *v4 = b->engine();
1322 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1323 if (!self)
1324 return v4->throwTypeError();
1325
1326 double t = self->date();
1327 double min = argc ? argv[0].toNumber() : qt_qnan();
1328 double sec = (argc < 2) ? SecFromTime(t) : argv[1].toNumber();
1329 double ms = (argc < 3) ? msFromTime(t) : argv[2].toNumber();
1330 t = MakeDate(day: Day(t), time: MakeTime(hour: HourFromTime(t), min, sec, ms));
1331 self->setDate(t);
1332 return Encode(self->date());
1333}
1334
1335ReturnedValue DatePrototype::method_setHours(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1336{
1337 ExecutionEngine *v4 = b->engine();
1338 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1339 if (!self)
1340 return v4->throwTypeError();
1341
1342 double t = LocalTime(t: self->date(), localTZA: v4->localTZA);
1343 if (v4->hasException)
1344 return QV4::Encode::undefined();
1345 double hour = argc ? argv[0].toNumber() : qt_qnan();
1346 if (v4->hasException)
1347 return QV4::Encode::undefined();
1348 double min = (argc < 2) ? MinFromTime(t) : argv[1].toNumber();
1349 if (v4->hasException)
1350 return QV4::Encode::undefined();
1351 double sec = (argc < 3) ? SecFromTime(t) : argv[2].toNumber();
1352 if (v4->hasException)
1353 return QV4::Encode::undefined();
1354 double ms = (argc < 4) ? msFromTime(t) : argv[3].toNumber();
1355 if (v4->hasException)
1356 return QV4::Encode::undefined();
1357 t = UTC(t: MakeDate(day: Day(t), time: MakeTime(hour, min, sec, ms)), localTZA: v4->localTZA);
1358 self->setDate(t);
1359 return Encode(self->date());
1360}
1361
1362ReturnedValue DatePrototype::method_setUTCHours(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1363{
1364 ExecutionEngine *v4 = b->engine();
1365 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1366 if (!self)
1367 return v4->throwTypeError();
1368
1369 double t = self->date();
1370 double hour = argc ? argv[0].toNumber() : qt_qnan();
1371 double min = (argc < 2) ? MinFromTime(t) : argv[1].toNumber();
1372 double sec = (argc < 3) ? SecFromTime(t) : argv[2].toNumber();
1373 double ms = (argc < 4) ? msFromTime(t) : argv[3].toNumber();
1374 t = MakeDate(day: Day(t), time: MakeTime(hour, min, sec, ms));
1375 self->setDate(t);
1376 return Encode(self->date());
1377}
1378
1379ReturnedValue DatePrototype::method_setDate(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1380{
1381 ExecutionEngine *v4 = b->engine();
1382 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1383 if (!self)
1384 return v4->throwTypeError();
1385
1386 double t = LocalTime(t: self->date(), localTZA: v4->localTZA);
1387 if (v4->hasException)
1388 return QV4::Encode::undefined();
1389 double date = argc ? argv[0].toNumber() : qt_qnan();
1390 if (v4->hasException)
1391 return QV4::Encode::undefined();
1392 t = UTC(t: MakeDate(day: MakeDay(year: YearFromTime(t), month: MonthFromTime(t), day: date), time: TimeWithinDay(t)), localTZA: v4->localTZA);
1393 self->setDate(t);
1394 return Encode(self->date());
1395}
1396
1397ReturnedValue DatePrototype::method_setUTCDate(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1398{
1399 ExecutionEngine *v4 = b->engine();
1400 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1401 if (!self)
1402 return v4->throwTypeError();
1403
1404 double t = self->date();
1405 if (v4->hasException)
1406 return QV4::Encode::undefined();
1407 double date = argc ? argv[0].toNumber() : qt_qnan();
1408 if (v4->hasException)
1409 return QV4::Encode::undefined();
1410 t = MakeDate(day: MakeDay(year: YearFromTime(t), month: MonthFromTime(t), day: date), time: TimeWithinDay(t));
1411 self->setDate(t);
1412 return Encode(self->date());
1413}
1414
1415ReturnedValue DatePrototype::method_setMonth(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1416{
1417 ExecutionEngine *v4 = b->engine();
1418 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1419 if (!self)
1420 return v4->throwTypeError();
1421
1422 double t = LocalTime(t: self->date(), localTZA: v4->localTZA);
1423 if (v4->hasException)
1424 return QV4::Encode::undefined();
1425 double month = argc ? argv[0].toNumber() : qt_qnan();
1426 if (v4->hasException)
1427 return QV4::Encode::undefined();
1428 double date = (argc < 2) ? DateFromTime(t) : argv[1].toNumber();
1429 if (v4->hasException)
1430 return QV4::Encode::undefined();
1431 t = UTC(t: MakeDate(day: MakeDay(year: YearFromTime(t), month, day: date), time: TimeWithinDay(t)), localTZA: v4->localTZA);
1432 self->setDate(t);
1433 return Encode(self->date());
1434}
1435
1436ReturnedValue DatePrototype::method_setUTCMonth(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1437{
1438 ExecutionEngine *v4 = b->engine();
1439 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1440 if (!self)
1441 return v4->throwTypeError();
1442
1443 double t = self->date();
1444 double month = argc ? argv[0].toNumber() : qt_qnan();
1445 double date = (argc < 2) ? DateFromTime(t) : argv[1].toNumber();
1446 t = MakeDate(day: MakeDay(year: YearFromTime(t), month, day: date), time: TimeWithinDay(t));
1447 self->setDate(t);
1448 return Encode(self->date());
1449}
1450
1451ReturnedValue DatePrototype::method_setYear(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1452{
1453 ExecutionEngine *v4 = b->engine();
1454 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1455 if (!self)
1456 return v4->throwTypeError();
1457
1458 double t = self->date();
1459 if (std::isnan(x: t))
1460 t = 0;
1461 else
1462 t = LocalTime(t, localTZA: v4->localTZA);
1463 double year = argc ? argv[0].toNumber() : qt_qnan();
1464 double r;
1465 if (std::isnan(x: year)) {
1466 r = qt_qnan();
1467 } else {
1468 if ((QV4::Value::toInteger(d: year) >= 0) && (QV4::Value::toInteger(d: year) <= 99))
1469 year += 1900;
1470 r = MakeDay(year, month: MonthFromTime(t), day: DateFromTime(t));
1471 r = UTC(t: MakeDate(day: r, time: TimeWithinDay(t)), localTZA: v4->localTZA);
1472 }
1473 self->setDate(r);
1474 return Encode(self->date());
1475}
1476
1477ReturnedValue DatePrototype::method_setUTCFullYear(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1478{
1479 ExecutionEngine *v4 = b->engine();
1480 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1481 if (!self)
1482 return v4->throwTypeError();
1483
1484 double t = self->date();
1485 double year = argc ? argv[0].toNumber() : qt_qnan();
1486 double month = (argc < 2) ? MonthFromTime(t) : argv[1].toNumber();
1487 double date = (argc < 3) ? DateFromTime(t) : argv[2].toNumber();
1488 t = MakeDate(day: MakeDay(year, month, day: date), time: TimeWithinDay(t));
1489 self->setDate(t);
1490 return Encode(self->date());
1491}
1492
1493ReturnedValue DatePrototype::method_setFullYear(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1494{
1495 ExecutionEngine *v4 = b->engine();
1496 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1497 if (!self)
1498 return v4->throwTypeError();
1499
1500 double t = LocalTime(t: self->date(), localTZA: v4->localTZA);
1501 if (v4->hasException)
1502 return QV4::Encode::undefined();
1503 if (std::isnan(x: t))
1504 t = 0;
1505 double year = argc ? argv[0].toNumber() : qt_qnan();
1506 if (v4->hasException)
1507 return QV4::Encode::undefined();
1508 double month = (argc < 2) ? MonthFromTime(t) : argv[1].toNumber();
1509 if (v4->hasException)
1510 return QV4::Encode::undefined();
1511 double date = (argc < 3) ? DateFromTime(t) : argv[2].toNumber();
1512 if (v4->hasException)
1513 return QV4::Encode::undefined();
1514 t = UTC(t: MakeDate(day: MakeDay(year, month, day: date), time: TimeWithinDay(t)), localTZA: v4->localTZA);
1515 self->setDate(t);
1516 return Encode(self->date());
1517}
1518
1519ReturnedValue DatePrototype::method_toUTCString(const FunctionObject *b, const Value *thisObject, const Value *, int)
1520{
1521 ExecutionEngine *v4 = b->engine();
1522 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1523 if (!self)
1524 return v4->throwTypeError();
1525
1526 if (self->d()->isAttachedToProperty())
1527 self->d()->readReference();
1528
1529 double t = self->date();
1530 return Encode(v4->newString(s: ToUTCString(t)));
1531}
1532
1533static void addZeroPrefixedInt(QString &str, int num, int nDigits)
1534{
1535 str.resize(size: str.size() + nDigits);
1536
1537 QChar *c = str.data() + str.size() - 1;
1538 while (nDigits) {
1539 *c = QChar(num % 10 + '0');
1540 num /= 10;
1541 --c;
1542 --nDigits;
1543 }
1544}
1545
1546ReturnedValue DatePrototype::method_toISOString(const FunctionObject *b, const Value *thisObject, const Value *, int)
1547{
1548 ExecutionEngine *v4 = b->engine();
1549 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1550 if (!self)
1551 return v4->throwTypeError();
1552
1553 if (self->d()->isAttachedToProperty())
1554 self->d()->readReference();
1555
1556 double t = self->date();
1557 if (!std::isfinite(x: t))
1558 RETURN_RESULT(v4->throwRangeError(*thisObject));
1559
1560 QString result;
1561 int year = (int)YearFromTime(t);
1562 if (year < 0 || year > 9999) {
1563 if (qAbs(t: year) >= 1000000)
1564 RETURN_RESULT(v4->throwRangeError(*thisObject));
1565 result += year < 0 ? QLatin1Char('-') : QLatin1Char('+');
1566 year = qAbs(t: year);
1567 addZeroPrefixedInt(str&: result, num: year, nDigits: 6);
1568 } else {
1569 addZeroPrefixedInt(str&: result, num: year, nDigits: 4);
1570 }
1571 result += QLatin1Char('-');
1572 addZeroPrefixedInt(str&: result, num: (int)MonthFromTime(t) + 1, nDigits: 2);
1573 result += QLatin1Char('-');
1574 addZeroPrefixedInt(str&: result, num: (int)DateFromTime(t), nDigits: 2);
1575 result += QLatin1Char('T');
1576 addZeroPrefixedInt(str&: result, num: HourFromTime(t), nDigits: 2);
1577 result += QLatin1Char(':');
1578 addZeroPrefixedInt(str&: result, num: MinFromTime(t), nDigits: 2);
1579 result += QLatin1Char(':');
1580 addZeroPrefixedInt(str&: result, num: SecFromTime(t), nDigits: 2);
1581 result += QLatin1Char('.');
1582 addZeroPrefixedInt(str&: result, num: msFromTime(t), nDigits: 3);
1583 result += QLatin1Char('Z');
1584
1585 return Encode(v4->newString(s: result));
1586}
1587
1588ReturnedValue DatePrototype::method_toJSON(const FunctionObject *b, const Value *thisObject, const Value *, int)
1589{
1590 ExecutionEngine *v4 = b->engine();
1591 Scope scope(v4);
1592 ScopedObject O(scope, thisObject->toObject(e: v4));
1593 if (v4->hasException)
1594 return QV4::Encode::undefined();
1595
1596 ScopedValue tv(scope, RuntimeHelpers::toPrimitive(value: O, typeHint: NUMBER_HINT));
1597
1598 if (tv->isNumber() && !std::isfinite(x: tv->toNumber()))
1599 return Encode::null();
1600
1601 ScopedString s(scope, v4->newString(QStringLiteral("toISOString")));
1602 ScopedValue v(scope, O->get(name: s));
1603 FunctionObject *toIso = v->as<FunctionObject>();
1604
1605 if (!toIso)
1606 return v4->throwTypeError();
1607
1608 return checkedResult(v4, result: toIso->call(thisObject: O, argv: nullptr, argc: 0));
1609}
1610
1611ReturnedValue DatePrototype::method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
1612{
1613 ExecutionEngine *e = f->engine();
1614 if (!thisObject->isObject() || !argc || !argv->isString())
1615 return e->throwTypeError();
1616
1617 String *hint = argv->stringValue();
1618 PropertyKey id = hint->toPropertyKey();
1619 if (id == e->id_default()->propertyKey())
1620 hint = e->id_string();
1621 else if (id != e->id_string()->propertyKey() && id != e->id_number()->propertyKey())
1622 return e->throwTypeError();
1623
1624 return RuntimeHelpers::ordinaryToPrimitive(engine: e, object: static_cast<const Object *>(thisObject), typeHint: hint);
1625}
1626
1627void DatePrototype::timezoneUpdated(ExecutionEngine *e)
1628{
1629 e->localTZA = getLocalTZA();
1630}
1631

source code of qtdeclarative/src/qml/jsruntime/qv4dateobject.cpp