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 QStringLiteral("ddd, d MMM yy hh:mm:ss t"),
532 QStringLiteral("ddd, d MMM yyyy h:mm:ss t"),
533 QStringLiteral("ddd, d MMM yy h:mm:ss t"),
534 };
535
536 for (const QString &format : formats) {
537 dt = format.indexOf(QLatin1String("h:mm")) < 0
538 ? QDate::fromString(s, format).startOfDay(QTimeZone::UTC)
539 : QDateTime::fromString(s, format); // as local time
540 if (dt.isValid())
541 break;
542 }
543 }
544 if (!dt.isValid())
545 return qt_qnan();
546 return TimeClip(dt.toMSecsSinceEpoch());
547}
548
549/*!
550 \internal
551
552 Converts the ECMA Date value \a t (in UTC form) to QDateTime
553 according to \a spec.
554*/
555static inline QDateTime ToDateTime(double t, QTimeZone zone)
556{
557 if (std::isnan(t))
558 return QDateTime().toTimeZone(zone);
559 return QDateTime::fromMSecsSinceEpoch(t, zone);
560}
561
562static inline QString ToString(double t, double localTZA)
563{
564 if (std::isnan(t))
565 return QStringLiteral("Invalid Date");
566 QString str = ToDateTime(t, QTimeZone::LocalTime).toString() + QLatin1String(" GMT");
567 double tzoffset = localTZA + DaylightSavingTA(t, localTZA);
568 if (tzoffset) {
569 int hours = static_cast<int>(::fabs(tzoffset) / 1000 / 60 / 60);
570 int mins = int(::fabs(tzoffset) / 1000 / 60) % 60;
571 str.append(QLatin1Char((tzoffset > 0) ? '+' : '-'));
572 if (hours < 10)
573 str.append(QLatin1Char('0'));
574 str.append(QString::number(hours));
575 if (mins < 10)
576 str.append(QLatin1Char('0'));
577 str.append(QString::number(mins));
578 }
579 return str;
580}
581
582static inline QString ToUTCString(double t)
583{
584 if (std::isnan(t))
585 return QStringLiteral("Invalid Date");
586 return ToDateTime(t, QTimeZone::UTC).toString();
587}
588
589static inline QString ToDateString(double t)
590{
591 return ToDateTime(t, QTimeZone::LocalTime).date().toString();
592}
593
594static inline QString ToTimeString(double t)
595{
596 return ToDateTime(t, QTimeZone::LocalTime).time().toString();
597}
598
599static inline QString ToLocaleString(double t)
600{
601 return QLocale().toString(ToDateTime(t, QTimeZone::LocalTime), QLocale::ShortFormat);
602}
603
604static inline QString ToLocaleDateString(double t)
605{
606 return QLocale().toString(ToDateTime(t, QTimeZone::LocalTime).date(), QLocale::ShortFormat);
607}
608
609static inline QString ToLocaleTimeString(double t)
610{
611 return QLocale().toString(ToDateTime(t, QTimeZone::LocalTime).time(), QLocale::ShortFormat);
612}
613
614static double getLocalTZA()
615{
616 return QLocalTime::getCurrentStandardUtcOffset() * 1e3;
617}
618
620
621quint64 Date::encode(double value)
622{
623 if (std::isnan(value) || fabs(value) > MaxDateVal)
624 return InvalidDateVal;
625
626 // Do the addition in qint64. This way we won't overflow if value is negative
627 // and we will round value in the right direction.
628 // We know we can do this because we know we have more than one bit left in quint64.
629 const quint64 encoded = quint64(qint64(value) + qint64(MaxDateVal));
630
631 return encoded + Extra;
632}
633
634quint64 Date::encode(const QDateTime &dateTime)
635{
636 return encode(dateTime.isValid() ? dateTime.toMSecsSinceEpoch() : qt_qnan());
637}
638
639void Date::init(double value)
640{
641 storage = encode(value);
642}
643
644void Date::init(const QDateTime &when)
645{
646 storage = encode(when) | HasQDate | HasQTime;
647}
648
649void Date::init(QDate date)
650{
651 storage = encode(date.startOfDay(QTimeZone::UTC)) | HasQDate;
652}
653
654void Date::init(QTime time, ExecutionEngine *engine)
655{
656 if (!time.isValid()) {
657 storage = encode(qt_qnan()) | HasQTime;
658 return;
659 }
660
661 /* We have to chose a date on which to instantiate this time. All we really
662 * care about is that it round-trips back to the same time if we extract the
663 * time from it, which shall (via toQDateTime(), below) discard the date
664 * part. We need a date for which time-zone data is likely to be sane (so
665 * MakeDay(0, 0, 0) was a bad choice; 2 BC, December 31st is before
666 * time-zones were standardized), with no transition nearby in date.
667 * QDateTime ignores DST transitions before 1970, but even then zone
668 * transitions did happen; and DaylightSavingTA() will include DST, at odds
669 * with QDateTime. So pick a date since 1970 and prefer one when no zone
670 * was in DST. One such interval (according to the Olson database, at
671 * least) was 1971 March 15th to April 17th. Since converting a time to a
672 * date-time without specifying a date is foolish, let's use April Fools'
673 * day.
674 */
675 static const double d = MakeDay(1971, 3, 1);
676 double t = MakeTime(time.hour(), time.minute(), time.second(), time.msec());
677 storage = encode(UTC(MakeDate(d, t), engine->localTZA)) | HasQTime;
678}
679
680QDate Date::toQDate() const
681{
682 return toQDateTime().date();
683}
684
685QTime Date::toQTime() const
686{
687 return toQDateTime().time();
688}
689
690QDateTime Date::toQDateTime() const
691{
692 return ToDateTime(operator double(), QTimeZone::LocalTime);
693}
694
695QVariant Date::toVariant() const
696{
697 // Note that we shouldn't and don't read-back here, compared to
698 // most other methods, as this is only used when we perform a
699 // write-back, that is we are sending our version of the data back
700 // to the originating element.
701 switch (storage & (HasQDate | HasQTime)) {
702 case HasQDate:
703 return toQDate();
704 case HasQTime:
705 return toQTime();
706 case (HasQDate | HasQTime):
707 return toQDateTime();
708 default:
709 return QVariant();
710 }
711}
712
713QDateTime DateObject::toQDateTime() const
714{
715 if (d()->isAttachedToProperty())
716 d()->readReference();
717 return d()->toQDateTime();
718}
719
720QString DateObject::toString() const
721{
722 if (d()->isAttachedToProperty())
723 d()->readReference();
724 return ToString(d()->date(), engine()->localTZA);
725}
726
727QString DateObject::dateTimeToString(const QDateTime &dateTime, ExecutionEngine *engine)
728{
729 if (!dateTime.isValid())
730 return QStringLiteral("Invalid Date");
731 return ToString(TimeClip(dateTime.toMSecsSinceEpoch()), engine->localTZA);
732}
733
734double DateObject::dateTimeToNumber(const QDateTime &dateTime)
735{
736 if (!dateTime.isValid())
737 return qQNaN();
738 return TimeClip(dateTime.toMSecsSinceEpoch());
739}
740
741QDateTime DateObject::stringToDateTime(const QString &string, ExecutionEngine *engine)
742{
743 return ToDateTime(ParseString(string, engine->localTZA), QTimeZone::LocalTime);
744}
745
746QDateTime DateObject::timestampToDateTime(double timestamp, QTimeZone zone)
747{
748 return ToDateTime(timestamp, zone);
749}
750
751double DateObject::componentsToTimestamp(
752 double year, double month, double day, double hours,
753 double mins, double secs, double ms, ExecutionEngine *v4)
754{
755 if (year >= 0 && year <= 99)
756 year += 1900;
757 const double t = MakeDate(MakeDay(year, month, day), MakeTime(hours, mins, secs, ms));
758 return UTC(t, v4->localTZA);
759}
760
761QDate DateObject::dateTimeToDate(const QDateTime &dateTime)
762{
763 // If the Date object was parse()d from a string with no time part
764 // or zone specifier it's really the UTC start of the relevant day,
765 // but it's here represented as a local time, which may fall in the
766 // preceding day. See QTBUG-92466 for the gory details.
767 const auto utc = dateTime.toUTC();
768 if (utc.date() != dateTime.date() && utc.addSecs(-1).date() == dateTime.date())
769 return utc.date();
770
771 // This may, of course, be The Wrong Thing if the date was
772 // constructed as a full local date-time that happens to coincide
773 // with the start of a UTC day; however, that would be an odd value
774 // to give to something that, apparently, someone thinks belongs in
775 // a QDate.
776 return dateTime.date();
777}
778
780
781Heap::DateObject *Heap::DateObject::detached() const
782{
783 return internalClass->engine->memoryManager->allocate<QV4::DateObject>(m_date);
784}
785
786bool Heap::DateObject::setVariant(const QVariant &variant)
787{
788 const QMetaType variantReferenceType = variant.metaType();
789 switch (variantReferenceType.id()) {
790 case QMetaType::Double:
791 m_date.init(*static_cast<const double *>(variant.constData()));
792 break;
793 case QMetaType::QDate:
794 m_date.init(*static_cast<const QDate *>(variant.constData()));
795 break;
796 case QMetaType::QTime:
797 m_date.init(*static_cast<const QTime *>(variant.constData()), internalClass->engine);
798 break;
799 case QMetaType::QDateTime:
800 m_date.init(*static_cast<const QDateTime *>(variant.constData()));
801 break;
802 default:
803 return false;
804 }
805
806 return true;
807}
808
809void Heap::DateCtor::init(QV4::ExecutionEngine *engine)
810{
811 Heap::FunctionObject::init(engine, QStringLiteral("Date"));
812}
813
814ReturnedValue DateCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, int argc, const Value *newTarget)
815{
816 ExecutionEngine *v4 = that->engine();
817 double t = 0;
818
819 if (argc == 0)
820 t = currentTime();
821
822 else if (argc == 1) {
823 Scope scope(v4);
824 ScopedValue arg(scope, argv[0]);
825 if (DateObject *d = arg->as<DateObject>()) {
826 t = d->date();
827 } else {
828 arg = RuntimeHelpers::toPrimitive(arg, PREFERREDTYPE_HINT);
829
830 if (String *s = arg->stringValue())
831 t = ParseString(s->toQString(), v4->localTZA);
832 else
833 t = arg->toNumber();
834 }
835 }
836
837 else { // d.argc > 1
838 const double year = argv[0].toNumber();
839 const double month = argv[1].toNumber();
840 const double day = argc >= 3 ? argv[2].toNumber() : 1;
841 const double hours = argc >= 4 ? argv[3].toNumber() : 0;
842 const double mins = argc >= 5 ? argv[4].toNumber() : 0;
843 const double secs = argc >= 6 ? argv[5].toNumber() : 0;
844 const double ms = argc >= 7 ? argv[6].toNumber() : 0;
845 t = DateObject::componentsToTimestamp(year, month, day, hours, mins, secs, ms, v4);
846 }
847
848 ReturnedValue o = Encode(v4->newDateObject(t));
849 if (!newTarget)
850 return o;
851 Scope scope(v4);
852 ScopedObject obj(scope, o);
853 obj->setProtoFromNewTarget(newTarget);
854 return obj->asReturnedValue();
855}
856
857ReturnedValue DateCtor::virtualCall(const FunctionObject *m, const Value *, const Value *, int)
858{
859 ExecutionEngine *e = m->engine();
860 double t = currentTime();
861 return e->newString(ToString(t, e->localTZA))->asReturnedValue();
862}
863
864void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
865{
866 Scope scope(engine);
867 ScopedObject o(scope);
868 ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
869 ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(7));
870 engine->localTZA = getLocalTZA();
871
872 ctor->defineDefaultProperty(QStringLiteral("parse"), method_parse, 1);
873 ctor->defineDefaultProperty(QStringLiteral("UTC"), method_UTC, 7);
874 ctor->defineDefaultProperty(QStringLiteral("now"), method_now, 0);
875
876 defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
877 defineDefaultProperty(engine->id_toString(), method_toString, 0);
878 defineDefaultProperty(QStringLiteral("toDateString"), method_toDateString, 0);
879 defineDefaultProperty(QStringLiteral("toTimeString"), method_toTimeString, 0);
880 defineDefaultProperty(engine->id_toLocaleString(), method_toLocaleString, 0);
881 defineDefaultProperty(QStringLiteral("toLocaleDateString"), method_toLocaleDateString, 0);
882 defineDefaultProperty(QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString, 0);
883 defineDefaultProperty(engine->id_valueOf(), method_valueOf, 0);
884 defineDefaultProperty(QStringLiteral("getTime"), method_getTime, 0);
885 defineDefaultProperty(QStringLiteral("getYear"), method_getYear, 0);
886 defineDefaultProperty(QStringLiteral("getFullYear"), method_getFullYear, 0);
887 defineDefaultProperty(QStringLiteral("getUTCFullYear"), method_getUTCFullYear, 0);
888 defineDefaultProperty(QStringLiteral("getMonth"), method_getMonth, 0);
889 defineDefaultProperty(QStringLiteral("getUTCMonth"), method_getUTCMonth, 0);
890 defineDefaultProperty(QStringLiteral("getDate"), method_getDate, 0);
891 defineDefaultProperty(QStringLiteral("getUTCDate"), method_getUTCDate, 0);
892 defineDefaultProperty(QStringLiteral("getDay"), method_getDay, 0);
893 defineDefaultProperty(QStringLiteral("getUTCDay"), method_getUTCDay, 0);
894 defineDefaultProperty(QStringLiteral("getHours"), method_getHours, 0);
895 defineDefaultProperty(QStringLiteral("getUTCHours"), method_getUTCHours, 0);
896 defineDefaultProperty(QStringLiteral("getMinutes"), method_getMinutes, 0);
897 defineDefaultProperty(QStringLiteral("getUTCMinutes"), method_getUTCMinutes, 0);
898 defineDefaultProperty(QStringLiteral("getSeconds"), method_getSeconds, 0);
899 defineDefaultProperty(QStringLiteral("getUTCSeconds"), method_getUTCSeconds, 0);
900 defineDefaultProperty(QStringLiteral("getMilliseconds"), method_getMilliseconds, 0);
901 defineDefaultProperty(QStringLiteral("getUTCMilliseconds"), method_getUTCMilliseconds, 0);
902 defineDefaultProperty(QStringLiteral("getTimezoneOffset"), method_getTimezoneOffset, 0);
903 defineDefaultProperty(QStringLiteral("setTime"), method_setTime, 1);
904 defineDefaultProperty(QStringLiteral("setMilliseconds"), method_setMilliseconds, 1);
905 defineDefaultProperty(QStringLiteral("setUTCMilliseconds"), method_setUTCMilliseconds, 1);
906 defineDefaultProperty(QStringLiteral("setSeconds"), method_setSeconds, 2);
907 defineDefaultProperty(QStringLiteral("setUTCSeconds"), method_setUTCSeconds, 2);
908 defineDefaultProperty(QStringLiteral("setMinutes"), method_setMinutes, 3);
909 defineDefaultProperty(QStringLiteral("setUTCMinutes"), method_setUTCMinutes, 3);
910 defineDefaultProperty(QStringLiteral("setHours"), method_setHours, 4);
911 defineDefaultProperty(QStringLiteral("setUTCHours"), method_setUTCHours, 4);
912 defineDefaultProperty(QStringLiteral("setDate"), method_setDate, 1);
913 defineDefaultProperty(QStringLiteral("setUTCDate"), method_setUTCDate, 1);
914 defineDefaultProperty(QStringLiteral("setMonth"), method_setMonth, 2);
915 defineDefaultProperty(QStringLiteral("setUTCMonth"), method_setUTCMonth, 2);
916 defineDefaultProperty(QStringLiteral("setYear"), method_setYear, 1);
917 defineDefaultProperty(QStringLiteral("setFullYear"), method_setFullYear, 3);
918 defineDefaultProperty(QStringLiteral("setUTCFullYear"), method_setUTCFullYear, 3);
919
920 // ES6: B.2.4.3 & 20.3.4.43:
921 // We have to use the *same object* for toUTCString and toGMTString
922 {
923 QString toUtcString(QStringLiteral("toUTCString"));
924 QString toGmtString(QStringLiteral("toGMTString"));
925 ScopedString us(scope, engine->newIdentifier(toUtcString));
926 ScopedString gs(scope, engine->newIdentifier(toGmtString));
927 ScopedFunctionObject toUtcGmtStringFn(scope, FunctionObject::createBuiltinFunction(engine, us, method_toUTCString, 0));
928 defineDefaultProperty(us, toUtcGmtStringFn);
929 defineDefaultProperty(gs, toUtcGmtStringFn);
930 }
931
932 defineDefaultProperty(QStringLiteral("toISOString"), method_toISOString, 0);
933 defineDefaultProperty(QStringLiteral("toJSON"), method_toJSON, 1);
934 defineDefaultProperty(engine->symbol_toPrimitive(), method_symbolToPrimitive, 1, Attr_ReadOnly_ButConfigurable);
935}
936
937double DatePrototype::getThisDate(ExecutionEngine *v4, const Value *thisObject)
938{
939 if (const DateObject *that = thisObject->as<DateObject>()) {
940 if (that->d()->isAttachedToProperty())
941 that->d()->readReference();
942
943 return that->date();
944 }
945 v4->throwTypeError();
946 return 0;
947}
948
949ReturnedValue DatePrototype::method_parse(const FunctionObject *f, const Value *, const Value *argv, int argc)
950{
951 if (!argc)
952 return Encode(qt_qnan());
953 else
954 return Encode(ParseString(argv[0].toQString(), f->engine()->localTZA));
955}
956
957ReturnedValue DatePrototype::method_UTC(const FunctionObject *f, const Value *, const Value *argv, int argc)
958{
959 const int numArgs = argc;
960 if (numArgs < 1)
961 return Encode(qQNaN());
962 ExecutionEngine *e = f->engine();
963 double year = argv[0].toNumber();
964 if (e->hasException)
965 return Encode::undefined();
966 double month = numArgs >= 2 ? argv[1].toNumber() : 0;
967 if (e->hasException)
968 return Encode::undefined();
969 double day = numArgs >= 3 ? argv[2].toNumber() : 1;
970 if (e->hasException)
971 return Encode::undefined();
972 double hours = numArgs >= 4 ? argv[3].toNumber() : 0;
973 if (e->hasException)
974 return Encode::undefined();
975 double mins = numArgs >= 5 ? argv[4].toNumber() : 0;
976 if (e->hasException)
977 return Encode::undefined();
978 double secs = numArgs >= 6 ? argv[5].toNumber() : 0;
979 if (e->hasException)
980 return Encode::undefined();
981 double ms = numArgs >= 7 ? argv[6].toNumber() : 0;
982 if (e->hasException)
983 return Encode::undefined();
984 double iyear = QV4::Value::toInteger(year);
985 if (!qIsNaN(year) && iyear >= 0 && iyear <= 99)
986 year = 1900 + iyear;
987 double t = MakeDate(MakeDay(year, month, day),
988 MakeTime(hours, mins, secs, ms));
989 return Encode(TimeClip(t));
990}
991
992ReturnedValue DatePrototype::method_now(const FunctionObject *, const Value *, const Value *, int)
993{
994 return Encode(currentTime());
995}
996
997ReturnedValue DatePrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
998{
999 ExecutionEngine *v4 = b->engine();
1000 double t = getThisDate(v4, thisObject);
1001 return Encode(v4->newString(ToString(t, v4->localTZA)));
1002}
1003
1004ReturnedValue DatePrototype::method_toDateString(const FunctionObject *b, const Value *thisObject, const Value *, int)
1005{
1006 ExecutionEngine *v4 = b->engine();
1007 double t = getThisDate(v4, thisObject);
1008 return Encode(v4->newString(ToDateString(t)));
1009}
1010
1011ReturnedValue DatePrototype::method_toTimeString(const FunctionObject *b, const Value *thisObject, const Value *, int)
1012{
1013 ExecutionEngine *v4 = b->engine();
1014 double t = getThisDate(v4, thisObject);
1015 return Encode(v4->newString(ToTimeString(t)));
1016}
1017
1018ReturnedValue DatePrototype::method_toLocaleString(const FunctionObject *b, const Value *thisObject, const Value *, int)
1019{
1020 ExecutionEngine *v4 = b->engine();
1021 double t = getThisDate(v4, thisObject);
1022 return Encode(v4->newString(ToLocaleString(t)));
1023}
1024
1025ReturnedValue DatePrototype::method_toLocaleDateString(const FunctionObject *b, const Value *thisObject, const Value *, int)
1026{
1027 ExecutionEngine *v4 = b->engine();
1028 double t = getThisDate(v4, thisObject);
1029 return Encode(v4->newString(ToLocaleDateString(t)));
1030}
1031
1032ReturnedValue DatePrototype::method_toLocaleTimeString(const FunctionObject *b, const Value *thisObject, const Value *, int)
1033{
1034 ExecutionEngine *v4 = b->engine();
1035 double t = getThisDate(v4, thisObject);
1036 return Encode(v4->newString(ToLocaleTimeString(t)));
1037}
1038
1039ReturnedValue DatePrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int)
1040{
1041 ExecutionEngine *v4 = b->engine();
1042 double t = getThisDate(v4, thisObject);
1043 return Encode(t);
1044}
1045
1046ReturnedValue DatePrototype::method_getTime(const FunctionObject *b, const Value *thisObject, const Value *, int)
1047{
1048 ExecutionEngine *v4 = b->engine();
1049 double t = getThisDate(v4, thisObject);
1050 return Encode(t);
1051}
1052
1053ReturnedValue DatePrototype::method_getYear(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(t))
1058 t = YearFromTime(LocalTime(t, v4->localTZA)) - 1900;
1059 return Encode(t);
1060}
1061
1062ReturnedValue DatePrototype::method_getFullYear(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(t))
1067 t = YearFromTime(LocalTime(t, v4->localTZA));
1068 return Encode(t);
1069}
1070
1071ReturnedValue DatePrototype::method_getUTCFullYear(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(t))
1076 t = YearFromTime(t);
1077 return Encode(t);
1078}
1079
1080ReturnedValue DatePrototype::method_getMonth(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(t))
1085 t = MonthFromTime(LocalTime(t, v4->localTZA));
1086 return Encode(t);
1087}
1088
1089ReturnedValue DatePrototype::method_getUTCMonth(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(t))
1094 t = MonthFromTime(t);
1095 return Encode(t);
1096}
1097
1098ReturnedValue DatePrototype::method_getDate(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(t))
1103 t = DateFromTime(LocalTime(t, v4->localTZA));
1104 return Encode(t);
1105}
1106
1107ReturnedValue DatePrototype::method_getUTCDate(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(t))
1112 t = DateFromTime(t);
1113 return Encode(t);
1114}
1115
1116ReturnedValue DatePrototype::method_getDay(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(t))
1121 t = WeekDay(LocalTime(t, v4->localTZA));
1122 return Encode(t);
1123}
1124
1125ReturnedValue DatePrototype::method_getUTCDay(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(t))
1130 t = WeekDay(t);
1131 return Encode(t);
1132}
1133
1134ReturnedValue DatePrototype::method_getHours(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(t))
1139 t = HourFromTime(LocalTime(t, v4->localTZA));
1140 return Encode(t);
1141}
1142
1143ReturnedValue DatePrototype::method_getUTCHours(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(t))
1148 t = HourFromTime(t);
1149 return Encode(t);
1150}
1151
1152ReturnedValue DatePrototype::method_getMinutes(const FunctionObject *b, const Value *thisObject, const Value *, int)
1153{
1154 ExecutionEngine *v4 = b->engine();
1155 double t = getThisDate(v4, thisObject);
1156 if (!std::isnan(t))
1157 t = MinFromTime(LocalTime(t, v4->localTZA));
1158 return Encode(t);
1159}
1160
1161ReturnedValue DatePrototype::method_getUTCMinutes(const FunctionObject *b, const Value *thisObject, const Value *, int)
1162{
1163 ExecutionEngine *v4 = b->engine();
1164 double t = getThisDate(v4, thisObject);
1165 if (!std::isnan(t))
1166 t = MinFromTime(t);
1167 return Encode(t);
1168}
1169
1170ReturnedValue DatePrototype::method_getSeconds(const FunctionObject *b, const Value *thisObject, const Value *, int)
1171{
1172 ExecutionEngine *v4 = b->engine();
1173 double t = getThisDate(v4, thisObject);
1174 if (!std::isnan(t))
1175 t = SecFromTime(LocalTime(t, v4->localTZA));
1176 return Encode(t);
1177}
1178
1179ReturnedValue DatePrototype::method_getUTCSeconds(const FunctionObject *b, const Value *thisObject, const Value *, int)
1180{
1181 ExecutionEngine *v4 = b->engine();
1182 double t = getThisDate(v4, thisObject);
1183 if (!std::isnan(t))
1184 t = SecFromTime(t);
1185 return Encode(t);
1186}
1187
1188ReturnedValue DatePrototype::method_getMilliseconds(const FunctionObject *b, const Value *thisObject, const Value *, int)
1189{
1190 ExecutionEngine *v4 = b->engine();
1191 double t = getThisDate(v4, thisObject);
1192 if (!std::isnan(t))
1193 t = msFromTime(LocalTime(t, v4->localTZA));
1194 return Encode(t);
1195}
1196
1197ReturnedValue DatePrototype::method_getUTCMilliseconds(const FunctionObject *b, const Value *thisObject, const Value *, int)
1198{
1199 ExecutionEngine *v4 = b->engine();
1200 double t = getThisDate(v4, thisObject);
1201 if (!std::isnan(t))
1202 t = msFromTime(t);
1203 return Encode(t);
1204}
1205
1206ReturnedValue DatePrototype::method_getTimezoneOffset(const FunctionObject *b, const Value *thisObject, const Value *, int)
1207{
1208 ExecutionEngine *v4 = b->engine();
1209 double t = getThisDate(v4, thisObject);
1210 if (!std::isnan(t))
1211 t = (t - LocalTime(t, v4->localTZA)) / msPerMinute;
1212 return Encode(t);
1213}
1214
1215ReturnedValue DatePrototype::method_setTime(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1216{
1217 ExecutionEngine *v4 = b->engine();
1218 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1219 if (!self)
1220 return v4->throwTypeError();
1221
1222 double t = argc ? argv[0].toNumber() : qt_qnan();
1223 if (v4->hasException)
1224 return QV4::Encode::undefined();
1225 self->setDate(t);
1226 return Encode(self->date());
1227}
1228
1229ReturnedValue DatePrototype::method_setMilliseconds(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1230{
1231 ExecutionEngine *v4 = b->engine();
1232 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1233 if (!self)
1234 return v4->throwTypeError();
1235
1236 double t = LocalTime(self->date(), v4->localTZA);
1237 if (v4->hasException)
1238 return QV4::Encode::undefined();
1239 double ms = argc ? argv[0].toNumber() : qt_qnan();
1240 if (v4->hasException)
1241 return QV4::Encode::undefined();
1242 self->setDate(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)), v4->localTZA));
1243 return Encode(self->date());
1244}
1245
1246ReturnedValue DatePrototype::method_setUTCMilliseconds(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1247{
1248 ExecutionEngine *v4 = b->engine();
1249 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1250 if (!self)
1251 return v4->throwTypeError();
1252
1253 double t = self->date();
1254 if (v4->hasException)
1255 return QV4::Encode::undefined();
1256 double ms = argc ? argv[0].toNumber() : qt_qnan();
1257 if (v4->hasException)
1258 return QV4::Encode::undefined();
1259 self->setDate(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)));
1260 return Encode(self->date());
1261}
1262
1263ReturnedValue DatePrototype::method_setSeconds(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1264{
1265 ExecutionEngine *v4 = b->engine();
1266 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1267 if (!self)
1268 return v4->throwTypeError();
1269
1270 double t = LocalTime(self->date(), v4->localTZA);
1271 if (v4->hasException)
1272 return QV4::Encode::undefined();
1273 double sec = argc ? argv[0].toNumber() : qt_qnan();
1274 if (v4->hasException)
1275 return QV4::Encode::undefined();
1276 double ms = (argc < 2) ? msFromTime(t) : argv[1].toNumber();
1277 if (v4->hasException)
1278 return QV4::Encode::undefined();
1279 t = UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)), v4->localTZA);
1280 self->setDate(t);
1281 return Encode(self->date());
1282}
1283
1284ReturnedValue DatePrototype::method_setUTCSeconds(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1285{
1286 ExecutionEngine *v4 = b->engine();
1287 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1288 if (!self)
1289 return v4->throwTypeError();
1290
1291 double t = self->date();
1292 double sec = argc ? argv[0].toNumber() : qt_qnan();
1293 double ms = (argc < 2) ? msFromTime(t) : argv[1].toNumber();
1294 t = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms));
1295 self->setDate(t);
1296 return Encode(self->date());
1297}
1298
1299ReturnedValue DatePrototype::method_setMinutes(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1300{
1301 ExecutionEngine *v4 = b->engine();
1302 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1303 if (!self)
1304 return v4->throwTypeError();
1305
1306 double t = LocalTime(self->date(), v4->localTZA);
1307 if (v4->hasException)
1308 return QV4::Encode::undefined();
1309 double min = argc ? argv[0].toNumber() : qt_qnan();
1310 if (v4->hasException)
1311 return QV4::Encode::undefined();
1312 double sec = (argc < 2) ? SecFromTime(t) : argv[1].toNumber();
1313 if (v4->hasException)
1314 return QV4::Encode::undefined();
1315 double ms = (argc < 3) ? msFromTime(t) : argv[2].toNumber();
1316 if (v4->hasException)
1317 return QV4::Encode::undefined();
1318 t = UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)), v4->localTZA);
1319 self->setDate(t);
1320 return Encode(self->date());
1321}
1322
1323ReturnedValue DatePrototype::method_setUTCMinutes(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1324{
1325 ExecutionEngine *v4 = b->engine();
1326 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1327 if (!self)
1328 return v4->throwTypeError();
1329
1330 double t = self->date();
1331 double min = argc ? argv[0].toNumber() : qt_qnan();
1332 double sec = (argc < 2) ? SecFromTime(t) : argv[1].toNumber();
1333 double ms = (argc < 3) ? msFromTime(t) : argv[2].toNumber();
1334 t = MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms));
1335 self->setDate(t);
1336 return Encode(self->date());
1337}
1338
1339ReturnedValue DatePrototype::method_setHours(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1340{
1341 ExecutionEngine *v4 = b->engine();
1342 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1343 if (!self)
1344 return v4->throwTypeError();
1345
1346 double t = LocalTime(self->date(), v4->localTZA);
1347 if (v4->hasException)
1348 return QV4::Encode::undefined();
1349 double hour = argc ? argv[0].toNumber() : qt_qnan();
1350 if (v4->hasException)
1351 return QV4::Encode::undefined();
1352 double min = (argc < 2) ? MinFromTime(t) : argv[1].toNumber();
1353 if (v4->hasException)
1354 return QV4::Encode::undefined();
1355 double sec = (argc < 3) ? SecFromTime(t) : argv[2].toNumber();
1356 if (v4->hasException)
1357 return QV4::Encode::undefined();
1358 double ms = (argc < 4) ? msFromTime(t) : argv[3].toNumber();
1359 if (v4->hasException)
1360 return QV4::Encode::undefined();
1361 t = UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)), v4->localTZA);
1362 self->setDate(t);
1363 return Encode(self->date());
1364}
1365
1366ReturnedValue DatePrototype::method_setUTCHours(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1367{
1368 ExecutionEngine *v4 = b->engine();
1369 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1370 if (!self)
1371 return v4->throwTypeError();
1372
1373 double t = self->date();
1374 double hour = argc ? argv[0].toNumber() : qt_qnan();
1375 double min = (argc < 2) ? MinFromTime(t) : argv[1].toNumber();
1376 double sec = (argc < 3) ? SecFromTime(t) : argv[2].toNumber();
1377 double ms = (argc < 4) ? msFromTime(t) : argv[3].toNumber();
1378 t = MakeDate(Day(t), MakeTime(hour, min, sec, ms));
1379 self->setDate(t);
1380 return Encode(self->date());
1381}
1382
1383ReturnedValue DatePrototype::method_setDate(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1384{
1385 ExecutionEngine *v4 = b->engine();
1386 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1387 if (!self)
1388 return v4->throwTypeError();
1389
1390 double t = LocalTime(self->date(), v4->localTZA);
1391 if (v4->hasException)
1392 return QV4::Encode::undefined();
1393 double date = argc ? argv[0].toNumber() : qt_qnan();
1394 if (v4->hasException)
1395 return QV4::Encode::undefined();
1396 t = UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)), v4->localTZA);
1397 self->setDate(t);
1398 return Encode(self->date());
1399}
1400
1401ReturnedValue DatePrototype::method_setUTCDate(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1402{
1403 ExecutionEngine *v4 = b->engine();
1404 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1405 if (!self)
1406 return v4->throwTypeError();
1407
1408 double t = self->date();
1409 if (v4->hasException)
1410 return QV4::Encode::undefined();
1411 double date = argc ? argv[0].toNumber() : qt_qnan();
1412 if (v4->hasException)
1413 return QV4::Encode::undefined();
1414 t = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t));
1415 self->setDate(t);
1416 return Encode(self->date());
1417}
1418
1419ReturnedValue DatePrototype::method_setMonth(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1420{
1421 ExecutionEngine *v4 = b->engine();
1422 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1423 if (!self)
1424 return v4->throwTypeError();
1425
1426 double t = LocalTime(self->date(), v4->localTZA);
1427 if (v4->hasException)
1428 return QV4::Encode::undefined();
1429 double month = argc ? argv[0].toNumber() : qt_qnan();
1430 if (v4->hasException)
1431 return QV4::Encode::undefined();
1432 double date = (argc < 2) ? DateFromTime(t) : argv[1].toNumber();
1433 if (v4->hasException)
1434 return QV4::Encode::undefined();
1435 t = UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)), v4->localTZA);
1436 self->setDate(t);
1437 return Encode(self->date());
1438}
1439
1440ReturnedValue DatePrototype::method_setUTCMonth(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1441{
1442 ExecutionEngine *v4 = b->engine();
1443 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1444 if (!self)
1445 return v4->throwTypeError();
1446
1447 double t = self->date();
1448 double month = argc ? argv[0].toNumber() : qt_qnan();
1449 double date = (argc < 2) ? DateFromTime(t) : argv[1].toNumber();
1450 t = MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t));
1451 self->setDate(t);
1452 return Encode(self->date());
1453}
1454
1455ReturnedValue DatePrototype::method_setYear(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1456{
1457 ExecutionEngine *v4 = b->engine();
1458 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1459 if (!self)
1460 return v4->throwTypeError();
1461
1462 double t = self->date();
1463 if (std::isnan(t))
1464 t = 0;
1465 else
1466 t = LocalTime(t, v4->localTZA);
1467 double year = argc ? argv[0].toNumber() : qt_qnan();
1468 double r;
1469 if (std::isnan(year)) {
1470 r = qt_qnan();
1471 } else {
1472 if ((QV4::Value::toInteger(year) >= 0) && (QV4::Value::toInteger(year) <= 99))
1473 year += 1900;
1474 r = MakeDay(year, MonthFromTime(t), DateFromTime(t));
1475 r = UTC(MakeDate(r, TimeWithinDay(t)), v4->localTZA);
1476 }
1477 self->setDate(r);
1478 return Encode(self->date());
1479}
1480
1481ReturnedValue DatePrototype::method_setUTCFullYear(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1482{
1483 ExecutionEngine *v4 = b->engine();
1484 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1485 if (!self)
1486 return v4->throwTypeError();
1487
1488 double t = self->date();
1489 double year = argc ? argv[0].toNumber() : qt_qnan();
1490 double month = (argc < 2) ? MonthFromTime(t) : argv[1].toNumber();
1491 double date = (argc < 3) ? DateFromTime(t) : argv[2].toNumber();
1492 t = MakeDate(MakeDay(year, month, date), TimeWithinDay(t));
1493 self->setDate(t);
1494 return Encode(self->date());
1495}
1496
1497ReturnedValue DatePrototype::method_setFullYear(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
1498{
1499 ExecutionEngine *v4 = b->engine();
1500 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1501 if (!self)
1502 return v4->throwTypeError();
1503
1504 double t = LocalTime(self->date(), v4->localTZA);
1505 if (v4->hasException)
1506 return QV4::Encode::undefined();
1507 if (std::isnan(t))
1508 t = 0;
1509 double year = argc ? argv[0].toNumber() : qt_qnan();
1510 if (v4->hasException)
1511 return QV4::Encode::undefined();
1512 double month = (argc < 2) ? MonthFromTime(t) : argv[1].toNumber();
1513 if (v4->hasException)
1514 return QV4::Encode::undefined();
1515 double date = (argc < 3) ? DateFromTime(t) : argv[2].toNumber();
1516 if (v4->hasException)
1517 return QV4::Encode::undefined();
1518 t = UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)), v4->localTZA);
1519 self->setDate(t);
1520 return Encode(self->date());
1521}
1522
1523ReturnedValue DatePrototype::method_toUTCString(const FunctionObject *b, const Value *thisObject, const Value *, int)
1524{
1525 ExecutionEngine *v4 = b->engine();
1526 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1527 if (!self)
1528 return v4->throwTypeError();
1529
1530 if (self->d()->isAttachedToProperty())
1531 self->d()->readReference();
1532
1533 double t = self->date();
1534 return Encode(v4->newString(ToUTCString(t)));
1535}
1536
1537static void addZeroPrefixedInt(QString &str, int num, int nDigits)
1538{
1539 str.resize(str.size() + nDigits);
1540
1541 QChar *c = str.data() + str.size() - 1;
1542 while (nDigits) {
1543 *c = QChar(num % 10 + '0');
1544 num /= 10;
1545 --c;
1546 --nDigits;
1547 }
1548}
1549
1550ReturnedValue DatePrototype::method_toISOString(const FunctionObject *b, const Value *thisObject, const Value *, int)
1551{
1552 ExecutionEngine *v4 = b->engine();
1553 DateObject *self = const_cast<DateObject *>(thisObject->as<DateObject>());
1554 if (!self)
1555 return v4->throwTypeError();
1556
1557 if (self->d()->isAttachedToProperty())
1558 self->d()->readReference();
1559
1560 double t = self->date();
1561 if (!std::isfinite(t))
1562 RETURN_RESULT(v4->throwRangeError(*thisObject));
1563
1564 QString result;
1565 int year = (int)YearFromTime(t);
1566 if (year < 0 || year > 9999) {
1567 if (qAbs(year) >= 1000000)
1568 RETURN_RESULT(v4->throwRangeError(*thisObject));
1569 result += year < 0 ? QLatin1Char('-') : QLatin1Char('+');
1570 year = qAbs(year);
1571 addZeroPrefixedInt(result, year, 6);
1572 } else {
1573 addZeroPrefixedInt(result, year, 4);
1574 }
1575 result += QLatin1Char('-');
1576 addZeroPrefixedInt(result, (int)MonthFromTime(t) + 1, 2);
1577 result += QLatin1Char('-');
1578 addZeroPrefixedInt(result, (int)DateFromTime(t), 2);
1579 result += QLatin1Char('T');
1580 addZeroPrefixedInt(result, HourFromTime(t), 2);
1581 result += QLatin1Char(':');
1582 addZeroPrefixedInt(result, MinFromTime(t), 2);
1583 result += QLatin1Char(':');
1584 addZeroPrefixedInt(result, SecFromTime(t), 2);
1585 result += QLatin1Char('.');
1586 addZeroPrefixedInt(result, msFromTime(t), 3);
1587 result += QLatin1Char('Z');
1588
1589 return Encode(v4->newString(result));
1590}
1591
1592ReturnedValue DatePrototype::method_toJSON(const FunctionObject *b, const Value *thisObject, const Value *, int)
1593{
1594 ExecutionEngine *v4 = b->engine();
1595 Scope scope(v4);
1596 ScopedObject O(scope, thisObject->toObject(v4));
1597 if (v4->hasException)
1598 return QV4::Encode::undefined();
1599
1600 ScopedValue tv(scope, RuntimeHelpers::toPrimitive(O, NUMBER_HINT));
1601
1602 if (tv->isNumber() && !std::isfinite(tv->toNumber()))
1603 return Encode::null();
1604
1605 ScopedString s(scope, v4->newString(QStringLiteral("toISOString")));
1606 ScopedValue v(scope, O->get(s));
1607 FunctionObject *toIso = v->as<FunctionObject>();
1608
1609 if (!toIso)
1610 return v4->throwTypeError();
1611
1612 return checkedResult(v4, toIso->call(O, nullptr, 0));
1613}
1614
1615ReturnedValue DatePrototype::method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
1616{
1617 ExecutionEngine *e = f->engine();
1618 if (!thisObject->isObject() || !argc || !argv->isString())
1619 return e->throwTypeError();
1620
1621 String *hint = argv->stringValue();
1622 PropertyKey id = hint->toPropertyKey();
1623 if (id == e->id_default()->propertyKey())
1624 hint = e->id_string();
1625 else if (id != e->id_string()->propertyKey() && id != e->id_number()->propertyKey())
1626 return e->throwTypeError();
1627
1628 return RuntimeHelpers::ordinaryToPrimitive(e, static_cast<const Object *>(thisObject), hint);
1629}
1630
1631void DatePrototype::timezoneUpdated(ExecutionEngine *e)
1632{
1633 e->localTZA = getLocalTZA();
1634}
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)