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