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.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*/
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 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
705QDateTime DateObject::toQDateTime() const
706{
707 return d()->toQDateTime();
708}
709
710QString DateObject::toString() const
711{
712 return ToString(t: d()->date(), localTZA: engine()->localTZA);
713}
714
715QString 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
722QDateTime DateObject::stringToDateTime(const QString &string, ExecutionEngine *engine)
723{
724 return ToDateTime(t: ParseString(s: string, localTZA: engine->localTZA), zone: QTimeZone::LocalTime);
725}
726
727QDate 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
745DEFINE_OBJECT_VTABLE(DateCtor);
746
747void Heap::DateCtor::init(QV4::ExecutionContext *scope)
748{
749 Heap::FunctionObject::init(scope, QStringLiteral("Date"));
750}
751
752ReturnedValue 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
798ReturnedValue 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
805void 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
878double 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
886ReturnedValue 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
894ReturnedValue 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
929ReturnedValue DatePrototype::method_now(const FunctionObject *, const Value *, const Value *, int)
930{
931 return Encode(currentTime());
932}
933
934ReturnedValue 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
941ReturnedValue 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
948ReturnedValue 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
955ReturnedValue 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
962ReturnedValue 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
969ReturnedValue 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
976ReturnedValue 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
983ReturnedValue 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
990ReturnedValue 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
999ReturnedValue 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
1008ReturnedValue 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
1017ReturnedValue 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
1026ReturnedValue 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
1035ReturnedValue 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
1044ReturnedValue 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
1053ReturnedValue 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
1062ReturnedValue 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
1071ReturnedValue 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
1080ReturnedValue 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
1089ReturnedValue 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
1098ReturnedValue 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
1107ReturnedValue 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
1116ReturnedValue 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
1125ReturnedValue 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
1134ReturnedValue 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
1143ReturnedValue 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
1152ReturnedValue 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
1166ReturnedValue 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
1183ReturnedValue 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
1200ReturnedValue 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
1221ReturnedValue 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
1236ReturnedValue 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
1260ReturnedValue 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
1276ReturnedValue 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
1303ReturnedValue 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
1320ReturnedValue 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
1338ReturnedValue 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
1356ReturnedValue 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
1377ReturnedValue 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
1392ReturnedValue 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
1418ReturnedValue 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
1434ReturnedValue 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
1460ReturnedValue 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
1471static 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
1484ReturnedValue 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
1523ReturnedValue 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
1546ReturnedValue 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
1562void DatePrototype::timezoneUpdated(ExecutionEngine *e)
1563{
1564 e->localTZA = getLocalTZA();
1565}
1566

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