1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 The Qt Company Ltd.
4 ** Copyright (C) 2016 Intel Corporation.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtCore module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 #include "qplatformdefs.h"
42 #include "private/qdatetime_p.h"
43 #if QT_CONFIG(datetimeparser)
44 #include "private/qdatetimeparser_p.h"
45 #endif
46 
47 #include "qdatastream.h"
48 #include "qset.h"
49 #include "qlocale.h"
50 #include "qdatetime.h"
51 #if QT_CONFIG(timezone)
52 #include "qtimezoneprivate_p.h"
53 #endif
54 #include "qregexp.h"
55 #include "qdebug.h"
56 #ifndef Q_OS_WIN
57 #include <locale.h>
58 #endif
59 
60 #include <cmath>
61 #ifdef Q_CC_MINGW
62 #  include <unistd.h> // Define _POSIX_THREAD_SAFE_FUNCTIONS to obtain localtime_r()
63 #endif
64 #include <time.h>
65 #ifdef Q_OS_WIN
66 #  include <qt_windows.h>
67 #  ifdef Q_OS_WINRT
68 #    include "qfunctions_winrt.h"
69 #  endif
70 #endif
71 
72 #if defined(Q_OS_MAC)
73 #include <private/qcore_mac_p.h>
74 #endif
75 
76 #include "qcalendar.h"
77 #include "qgregoriancalendar_p.h"
78 
79 QT_BEGIN_NAMESPACE
80 
81 /*****************************************************************************
82   Date/Time Constants
83  *****************************************************************************/
84 
85 enum {
86     SECS_PER_DAY = 86400,
87     MSECS_PER_DAY = 86400000,
88     SECS_PER_HOUR = 3600,
89     MSECS_PER_HOUR = 3600000,
90     SECS_PER_MIN = 60,
91     MSECS_PER_MIN = 60000,
92     TIME_T_MAX = 2145916799,  // int maximum 2037-12-31T23:59:59 UTC
93     JULIAN_DAY_FOR_EPOCH = 2440588 // result of julianDayFromDate(1970, 1, 1)
94 };
95 
96 /*****************************************************************************
97   QDate static helper functions
98  *****************************************************************************/
99 
fixedDate(QCalendar::YearMonthDay && parts,QCalendar cal)100 static inline QDate fixedDate(QCalendar::YearMonthDay &&parts, QCalendar cal)
101 {
102     if ((parts.year < 0 && !cal.isProleptic()) || (parts.year == 0 && !cal.hasYearZero()))
103         return QDate();
104 
105     parts.day = qMin(parts.day, cal.daysInMonth(parts.month, parts.year));
106     return cal.dateFromParts(parts);
107 }
108 
fixedDate(QCalendar::YearMonthDay && parts)109 static inline QDate fixedDate(QCalendar::YearMonthDay &&parts)
110 {
111     if (parts.year) {
112         parts.day = qMin(parts.day, QGregorianCalendar::monthLength(parts.month, parts.year));
113         qint64 jd;
114         if (QGregorianCalendar::julianFromParts(parts.year, parts.month, parts.day, &jd))
115             return QDate::fromJulianDay(jd);
116     }
117     return QDate();
118 }
119 
120 /*****************************************************************************
121   Date/Time formatting helper functions
122  *****************************************************************************/
123 
124 #if QT_CONFIG(textdate)
125 static const char qt_shortMonthNames[][4] = {
126     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
127     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
128 };
129 
qt_monthNumberFromShortName(QStringView shortName)130 static int qt_monthNumberFromShortName(QStringView shortName)
131 {
132     for (unsigned int i = 0; i < sizeof(qt_shortMonthNames) / sizeof(qt_shortMonthNames[0]); ++i) {
133         if (shortName == QLatin1String(qt_shortMonthNames[i], 3))
134             return i + 1;
135     }
136     return -1;
137 }
qt_monthNumberFromShortName(const QString & shortName)138 static int qt_monthNumberFromShortName(const QString &shortName)
139 { return qt_monthNumberFromShortName(QStringView(shortName)); }
140 
fromShortMonthName(QStringView monthName,int year)141 static int fromShortMonthName(QStringView monthName, int year)
142 {
143     // Assume that English monthnames are the default
144     int month = qt_monthNumberFromShortName(monthName);
145     if (month != -1)
146         return month;
147     // If English names can't be found, search the localized ones
148     for (int i = 1; i <= 12; ++i) {
149         if (monthName == QCalendar().monthName(QLocale::system(), i, year, QLocale::ShortFormat))
150             return i;
151     }
152     return -1;
153 }
154 #endif // textdate
155 
156 #if QT_CONFIG(datestring)
157 struct ParsedRfcDateTime {
158     QDate date;
159     QTime time;
160     int utcOffset;
161 };
162 
rfcDateImpl(const QString & s)163 static ParsedRfcDateTime rfcDateImpl(const QString &s)
164 {
165     ParsedRfcDateTime result;
166 
167     // Matches "[ddd,] dd MMM yyyy[ hh:mm[:ss]] [±hhmm]" - correct RFC 822, 2822, 5322 format
168     QRegExp rex(QStringLiteral("^[ \\t]*(?:[A-Z][a-z]+,)?[ \\t]*(\\d{1,2})[ \\t]+([A-Z][a-z]+)[ \\t]+(\\d\\d\\d\\d)(?:[ \\t]+(\\d\\d):(\\d\\d)(?::(\\d\\d))?)?[ \\t]*(?:([+-])(\\d\\d)(\\d\\d))?"));
169     if (s.indexOf(rex) == 0) {
170         const QStringList cap = rex.capturedTexts();
171         result.date = QDate(cap[3].toInt(), qt_monthNumberFromShortName(cap[2]), cap[1].toInt());
172         if (!cap[4].isEmpty())
173             result.time = QTime(cap[4].toInt(), cap[5].toInt(), cap[6].toInt());
174         const bool positiveOffset = (cap[7] == QLatin1String("+"));
175         const int hourOffset = cap[8].toInt();
176         const int minOffset = cap[9].toInt();
177         result.utcOffset = ((hourOffset * 60 + minOffset) * (positiveOffset ? 60 : -60));
178     } else {
179         // Matches "ddd MMM dd[ hh:mm:ss] yyyy [±hhmm]" - permissive RFC 850, 1036 (read only)
180         QRegExp rex(QStringLiteral("^[ \\t]*[A-Z][a-z]+[ \\t]+([A-Z][a-z]+)[ \\t]+(\\d\\d)(?:[ \\t]+(\\d\\d):(\\d\\d):(\\d\\d))?[ \\t]+(\\d\\d\\d\\d)[ \\t]*(?:([+-])(\\d\\d)(\\d\\d))?"));
181         if (s.indexOf(rex) == 0) {
182             const QStringList cap = rex.capturedTexts();
183             result.date = QDate(cap[6].toInt(), qt_monthNumberFromShortName(cap[1]), cap[2].toInt());
184             if (!cap[3].isEmpty())
185                 result.time = QTime(cap[3].toInt(), cap[4].toInt(), cap[5].toInt());
186             const bool positiveOffset = (cap[7] == QLatin1String("+"));
187             const int hourOffset = cap[8].toInt();
188             const int minOffset = cap[9].toInt();
189             result.utcOffset = ((hourOffset * 60 + minOffset) * (positiveOffset ? 60 : -60));
190         }
191     }
192 
193     return result;
194 }
195 #endif // datestring
196 
197 // Return offset in [+-]HH:mm format
toOffsetString(Qt::DateFormat format,int offset)198 static QString toOffsetString(Qt::DateFormat format, int offset)
199 {
200     return QString::asprintf("%c%02d%s%02d",
201                              offset >= 0 ? '+' : '-',
202                              qAbs(offset) / SECS_PER_HOUR,
203                              // Qt::ISODate puts : between the hours and minutes, but Qt:TextDate does not:
204                              format == Qt::TextDate ? "" : ":",
205                              (qAbs(offset) / 60) % 60);
206 }
207 
208 #if QT_CONFIG(datestring)
209 // Parse offset in [+-]HH[[:]mm] format
fromOffsetString(QStringView offsetString,bool * valid)210 static int fromOffsetString(QStringView offsetString, bool *valid) noexcept
211 {
212     *valid = false;
213 
214     const int size = offsetString.size();
215     if (size < 2 || size > 6)
216         return 0;
217 
218     // sign will be +1 for a positive and -1 for a negative offset
219     int sign;
220 
221     // First char must be + or -
222     const QChar signChar = offsetString.at(0);
223     if (signChar == QLatin1Char('+'))
224         sign = 1;
225     else if (signChar == QLatin1Char('-'))
226         sign = -1;
227     else
228         return 0;
229 
230     // Split the hour and minute parts
231     const QStringView time = offsetString.mid(1);
232     qsizetype hhLen = time.indexOf(QLatin1Char(':'));
233     qsizetype mmIndex;
234     if (hhLen == -1)
235         mmIndex = hhLen = 2; // [+-]HHmm or [+-]HH format
236     else
237         mmIndex = hhLen + 1;
238 
239     const QLocale C = QLocale::c();
240     const QStringView hhRef = time.left(qMin(hhLen, time.size()));
241     bool ok = false;
242     const int hour = C.toInt(hhRef, &ok);
243     if (!ok || hour > 23) // More generous than QTimeZone::MaxUtcOffsetSecs
244         return 0;
245 
246     const QStringView mmRef = time.mid(qMin(mmIndex, time.size()));
247     const int minute = mmRef.isEmpty() ? 0 : C.toInt(mmRef, &ok);
248     if (!ok || minute < 0 || minute > 59)
249         return 0;
250 
251     *valid = true;
252     return sign * ((hour * 60) + minute) * 60;
253 }
254 #endif // datestring
255 
256 /*****************************************************************************
257   QDate member functions
258  *****************************************************************************/
259 
260 /*!
261     \since 4.5
262 
263     \enum QDate::MonthNameType
264 
265     This enum describes the types of the string representation used
266     for the month name.
267 
268     \value DateFormat This type of name can be used for date-to-string formatting.
269     \value StandaloneFormat This type is used when you need to enumerate months or weekdays.
270            Usually standalone names are represented in singular forms with
271            capitalized first letter.
272 */
273 
274 /*!
275     \class QDate
276     \inmodule QtCore
277     \reentrant
278     \brief The QDate class provides date functions.
279 
280     A QDate object represents a particular day, regardless of calendar,
281     locale or other settings used when creating it or supplied by the system.
282     It can report the year, month and day of the month that represent the
283     day with respect to the proleptic Gregorian calendar or any calendar supplied
284     as a QCalendar object.
285 
286     A QDate object is typically created by giving the year, month, and day
287     numbers explicitly. Note that QDate interprets year numbers less than 100 as
288     presented, i.e., as years 1 through 99, without adding any offset. The
289     static function currentDate() creates a QDate object containing the date
290     read from the system clock. An explicit date can also be set using
291     setDate(). The fromString() function returns a QDate given a string and a
292     date format which is used to interpret the date within the string.
293 
294     The year(), month(), and day() functions provide access to the year, month,
295     and day numbers. When more than one of these values is needed, it is more
296     efficient to call QCalendar::partsFromDate(), to save repeating (potentially
297     expensive) calendrical calculations.
298 
299     Also, dayOfWeek() and dayOfYear() functions are provided. The same
300     information is provided in textual format by toString(). QLocale can map the
301     day numbers to names, QCalendar can map month numbers to names.
302 
303     QDate provides a full set of operators to compare two QDate
304     objects where smaller means earlier, and larger means later.
305 
306     You can increment (or decrement) a date by a given number of days
307     using addDays(). Similarly you can use addMonths() and addYears().
308     The daysTo() function returns the number of days between two
309     dates.
310 
311     The daysInMonth() and daysInYear() functions return how many days there are
312     in this date's month and year, respectively. The isLeapYear() function
313     indicates whether a date is in a leap year. QCalendar can also supply this
314     information, in some cases more conveniently.
315 
316     \section1 Remarks
317 
318     \section2 No Year 0
319 
320     In the Gregorian calendar, there is no year 0. Dates in that year are
321     considered invalid. The year -1 is the year "1 before Christ" or "1 before
322     common era." The day before 1 January 1 CE, QDate(1, 1, 1), is 31 December
323     1 BCE, QDate(-1, 12, 31). Various other calendars behave similarly; see
324     QCalendar::hasYearZero().
325 
326     \section2 Range of Valid Dates
327 
328     Dates are stored internally as a Julian Day number, an integer count of
329     every day in a contiguous range, with 24 November 4714 BCE in the Gregorian
330     calendar being Julian Day 0 (1 January 4713 BCE in the Julian calendar).
331     As well as being an efficient and accurate way of storing an absolute date,
332     it is suitable for converting a date into other calendar systems such as
333     Hebrew, Islamic or Chinese. The Julian Day number can be obtained using
334     QDate::toJulianDay() and can be set using QDate::fromJulianDay().
335 
336     The range of Julian Day numbers that QDate can represent is, for technical
337     reasons, limited to between -784350574879 and 784354017364, which means from
338     before 2 billion BCE to after 2 billion CE. This is more than seven times as
339     wide as the range of dates a QDateTime can represent.
340 
341     \sa QTime, QDateTime, QCalendar, QDateTime::YearRange, QDateEdit, QDateTimeEdit, QCalendarWidget
342 */
343 
344 /*!
345     \fn QDate::QDate()
346 
347     Constructs a null date. Null dates are invalid.
348 
349     \sa isNull(), isValid()
350 */
351 
352 /*!
353     Constructs a date with year \a y, month \a m and day \a d.
354 
355     The date is understood in terms of the Gregorian calendar. If the specified
356     date is invalid, the date is not set and isValid() returns \c false.
357 
358     \warning Years 1 to 99 are interpreted as is. Year 0 is invalid.
359 
360     \sa isValid(), QCalendar::dateFromParts()
361 */
362 
QDate(int y,int m,int d)363 QDate::QDate(int y, int m, int d)
364 {
365     if (!QGregorianCalendar::julianFromParts(y, m, d, &jd))
366         jd = nullJd();
367 }
368 
QDate(int y,int m,int d,QCalendar cal)369 QDate::QDate(int y, int m, int d, QCalendar cal)
370 {
371     *this = cal.dateFromParts(y, m, d);
372 }
373 
374 /*!
375     \fn bool QDate::isNull() const
376 
377     Returns \c true if the date is null; otherwise returns \c false. A null
378     date is invalid.
379 
380     \note The behavior of this function is equivalent to isValid().
381 
382     \sa isValid()
383 */
384 
385 /*!
386     \fn bool QDate::isValid() const
387 
388     Returns \c true if this date is valid; otherwise returns \c false.
389 
390     \sa isNull(), QCalendar::isDateValid()
391 */
392 
393 /*!
394     Returns the year of this date.
395 
396     Uses \a cal as calendar, if supplied, else the Gregorian calendar.
397 
398     Returns 0 if the date is invalid. For some calendars, dates before their
399     first year may all be invalid.
400 
401     If using a calendar which has a year 0, check using isValid() if the return
402     is 0. Such calendars use negative year numbers in the obvious way, with
403     year 1 preceded by year 0, in turn preceded by year -1 and so on.
404 
405     Some calendars, despite having no year 0, have a conventional numbering of
406     the years before their first year, counting backwards from 1. For example,
407     in the proleptic Gregorian calendar, successive years before 1 CE (the first
408     year) are identified as 1 BCE, 2 BCE, 3 BCE and so on. For such calendars,
409     negative year numbers are used to indicate these years before year 1, with
410     -1 indicating the year before 1.
411 
412     \sa month(), day(), QCalendar::hasYearZero(), QCalendar::isProleptic(), QCalendar::partsFromDate()
413 */
414 
year(QCalendar cal) const415 int QDate::year(QCalendar cal) const
416 {
417     if (isValid()) {
418         const auto parts = cal.partsFromDate(*this);
419         if (parts.isValid())
420             return parts.year;
421     }
422     return 0;
423 }
424 
425 /*!
426   \overload
427  */
428 
year() const429 int QDate::year() const
430 {
431     if (isValid()) {
432         const auto parts = QGregorianCalendar::partsFromJulian(jd);
433         if (parts.isValid())
434             return parts.year;
435     }
436     return 0;
437 }
438 
439 /*!
440     Returns the month-number for the date.
441 
442     Numbers the months of the year starting with 1 for the first. Uses \a cal
443     as calendar if supplied, else the Gregorian calendar, for which the month
444     numbering is as follows:
445 
446     \list
447     \li 1 = "January"
448     \li 2 = "February"
449     \li 3 = "March"
450     \li 4 = "April"
451     \li 5 = "May"
452     \li 6 = "June"
453     \li 7 = "July"
454     \li 8 = "August"
455     \li 9 = "September"
456     \li 10 = "October"
457     \li 11 = "November"
458     \li 12 = "December"
459     \endlist
460 
461     Returns 0 if the date is invalid. Note that some calendars may have more
462     than 12 months in some years.
463 
464     \sa year(), day(), QCalendar::partsFromDate()
465 */
466 
month(QCalendar cal) const467 int QDate::month(QCalendar cal) const
468 {
469     if (isValid()) {
470         const auto parts = cal.partsFromDate(*this);
471         if (parts.isValid())
472             return parts.month;
473     }
474     return 0;
475 }
476 
477 /*!
478   \overload
479  */
480 
month() const481 int QDate::month() const
482 {
483     if (isValid()) {
484         const auto parts = QGregorianCalendar::partsFromJulian(jd);
485         if (parts.isValid())
486             return parts.month;
487     }
488     return 0;
489 }
490 
491 /*!
492     Returns the day of the month for this date.
493 
494     Uses \a cal as calendar if supplied, else the Gregorian calendar (for which
495     the return ranges from 1 to 31). Returns 0 if the date is invalid.
496 
497     \sa year(), month(), dayOfWeek(), QCalendar::partsFromDate()
498 */
499 
day(QCalendar cal) const500 int QDate::day(QCalendar cal) const
501 {
502     if (isValid()) {
503         const auto parts = cal.partsFromDate(*this);
504         if (parts.isValid())
505             return parts.day;
506     }
507     return 0;
508 }
509 
510 /*!
511   \overload
512  */
513 
day() const514 int QDate::day() const
515 {
516     if (isValid()) {
517         const auto parts = QGregorianCalendar::partsFromJulian(jd);
518         if (parts.isValid())
519             return parts.day;
520     }
521     return 0;
522 }
523 
524 /*!
525     Returns the weekday (1 = Monday to 7 = Sunday) for this date.
526 
527     Uses \a cal as calendar if supplied, else the Gregorian calendar. Returns 0
528     if the date is invalid. Some calendars may give special meaning
529     (e.g. intercallary days) to values greater than 7.
530 
531     \sa day(), dayOfYear(), QCalendar::dayOfWeek(), Qt::DayOfWeek
532 */
533 
dayOfWeek(QCalendar cal) const534 int QDate::dayOfWeek(QCalendar cal) const
535 {
536     if (isNull())
537         return 0;
538 
539     return cal.dayOfWeek(*this);
540 }
541 
542 /*!
543   \overload
544  */
545 
dayOfWeek() const546 int QDate::dayOfWeek() const
547 {
548     return isValid() ? QGregorianCalendar::weekDayOfJulian(jd) : 0;
549 }
550 
551 /*!
552     Returns the day of the year (1 for the first day) for this date.
553 
554     Uses \a cal as calendar if supplied, else the Gregorian calendar.
555     Returns 0 if either the date or the first day of its year is invalid.
556 
557     \sa day(), dayOfWeek(), QCalendar::daysInYear()
558 */
559 
dayOfYear(QCalendar cal) const560 int QDate::dayOfYear(QCalendar cal) const
561 {
562     if (isValid()) {
563         QDate firstDay = cal.dateFromParts(year(cal), 1, 1);
564         if (firstDay.isValid())
565             return firstDay.daysTo(*this) + 1;
566     }
567     return 0;
568 }
569 
570 /*!
571   \overload
572  */
573 
dayOfYear() const574 int QDate::dayOfYear() const
575 {
576     if (isValid()) {
577         qint64 first;
578         if (QGregorianCalendar::julianFromParts(year(), 1, 1, &first))
579             return jd - first + 1;
580     }
581     return 0;
582 }
583 
584 /*!
585     Returns the number of days in the month for this date.
586 
587     Uses \a cal as calendar if supplied, else the Gregorian calendar (for which
588     the result ranges from 28 to 31). Returns 0 if the date is invalid.
589 
590     \sa day(), daysInYear(), QCalendar::daysInMonth(),
591         QCalendar::maximumDaysInMonth(), QCalendar::minimumDaysInMonth()
592 */
593 
daysInMonth(QCalendar cal) const594 int QDate::daysInMonth(QCalendar cal) const
595 {
596     if (isValid()) {
597         const auto parts = cal.partsFromDate(*this);
598         if (parts.isValid())
599             return cal.daysInMonth(parts.month, parts.year);
600     }
601     return 0;
602 }
603 
604 /*!
605   \overload
606  */
607 
daysInMonth() const608 int QDate::daysInMonth() const
609 {
610     if (isValid()) {
611         const auto parts = QGregorianCalendar::partsFromJulian(jd);
612         if (parts.isValid())
613             return QGregorianCalendar::monthLength(parts.month, parts.year);
614     }
615     return 0;
616 }
617 
618 /*!
619     Returns the number of days in the year for this date.
620 
621     Uses \a cal as calendar if supplied, else the Gregorian calendar (for which
622     the result is 365 or 366). Returns 0 if the date is invalid.
623 
624     \sa day(), daysInMonth(), QCalendar::daysInYear(), QCalendar::maximumMonthsInYear()
625 */
626 
daysInYear(QCalendar cal) const627 int QDate::daysInYear(QCalendar cal) const
628 {
629     if (isNull())
630         return 0;
631 
632     return cal.daysInYear(year(cal));
633 }
634 
635 /*!
636   \overload
637  */
638 
daysInYear() const639 int QDate::daysInYear() const
640 {
641     return isValid() ? QGregorianCalendar::leapTest(year()) ? 366 : 365 : 0;
642 }
643 
644 /*!
645     Returns the ISO 8601 week number (1 to 53).
646 
647     Returns 0 if the date is invalid. Otherwise, returns the week number for the
648     date. If \a yearNumber is not \nullptr (its default), stores the year as
649     *\a{yearNumber}.
650 
651     In accordance with ISO 8601, each week falls in the year to which most of
652     its days belong, in the Gregorian calendar. As ISO 8601's week starts on
653     Monday, this is the year in which the week's Thursday falls. Most years have
654     52 weeks, but some have 53.
655 
656     \note *\a{yearNumber} is not always the same as year(). For example, 1
657     January 2000 has week number 52 in the year 1999, and 31 December
658     2002 has week number 1 in the year 2003.
659 
660     \sa isValid()
661 */
662 
weekNumber(int * yearNumber) const663 int QDate::weekNumber(int *yearNumber) const
664 {
665     if (!isValid())
666         return 0;
667 
668     // This could be replaced by use of QIso8601Calendar, once we implement it.
669     // The Thursday of the same week determines our answer:
670     QDate thursday(addDays(4 - dayOfWeek()));
671     int year = thursday.year();
672     // Week n's Thurs's DOY has 1 <= DOY - 7*(n-1) < 8, so 0 <= DOY + 6 - 7*n < 7:
673     int week = (thursday.dayOfYear() + 6) / 7;
674 
675     if (yearNumber)
676         *yearNumber = year;
677     return week;
678 }
679 
inDateTimeRange(qint64 jd,bool start)680 static bool inDateTimeRange(qint64 jd, bool start)
681 {
682     using Bounds = std::numeric_limits<qint64>;
683     if (jd < Bounds::min() + JULIAN_DAY_FOR_EPOCH)
684         return false;
685     jd -= JULIAN_DAY_FOR_EPOCH;
686     const qint64 maxDay = Bounds::max() / MSECS_PER_DAY;
687     const qint64 minDay = Bounds::min() / MSECS_PER_DAY - 1;
688     // (Divisions rounded towards zero, as MSECS_PER_DAY has factors other than two.)
689     // Range includes start of last day and end of first:
690     if (start)
691         return jd > minDay && jd <= maxDay;
692     return jd >= minDay && jd < maxDay;
693 }
694 
toEarliest(QDate day,const QDateTime & form)695 static QDateTime toEarliest(QDate day, const QDateTime &form)
696 {
697     const Qt::TimeSpec spec = form.timeSpec();
698     const int offset = (spec == Qt::OffsetFromUTC) ? form.offsetFromUtc() : 0;
699 #if QT_CONFIG(timezone)
700     QTimeZone zone;
701     if (spec == Qt::TimeZone)
702         zone = form.timeZone();
703 #endif
704     auto moment = [=](QTime time) {
705         switch (spec) {
706         case Qt::OffsetFromUTC: return QDateTime(day, time, spec, offset);
707 #if QT_CONFIG(timezone)
708         case Qt::TimeZone: return QDateTime(day, time, zone);
709 #endif
710         default: return QDateTime(day, time, spec);
711         }
712     };
713     // Longest routine time-zone transition is 2 hours:
714     QDateTime when = moment(QTime(2, 0));
715     if (!when.isValid()) {
716         // Noon should be safe ...
717         when = moment(QTime(12, 0));
718         if (!when.isValid()) {
719             // ... unless it's a 24-hour jump (moving the date-line)
720             when = moment(QTime(23, 59, 59, 999));
721             if (!when.isValid())
722                 return QDateTime();
723         }
724     }
725     int high = when.time().msecsSinceStartOfDay() / 60000;
726     int low = 0;
727     // Binary chop to the right minute
728     while (high > low + 1) {
729         int mid = (high + low) / 2;
730         QDateTime probe = moment(QTime(mid / 60, mid % 60));
731         if (probe.isValid() && probe.date() == day) {
732             high = mid;
733             when = probe;
734         } else {
735             low = mid;
736         }
737     }
738     return when;
739 }
740 
741 /*!
742     \since 5.14
743     \fn QDateTime QDate::startOfDay(Qt::TimeSpec spec, int offsetSeconds) const
744     \fn QDateTime QDate::startOfDay(const QTimeZone &zone) const
745 
746     Returns the start-moment of the day.  Usually, this shall be midnight at the
747     start of the day: however, if a time-zone transition causes the given date
748     to skip over that midnight (e.g. a DST spring-forward skipping from the end
749     of the previous day to 01:00 of the new day), the actual earliest time in
750     the day is returned.  This can only arise when the start-moment is specified
751     in terms of a time-zone (by passing its QTimeZone as \a zone) or in terms of
752     local time (by passing Qt::LocalTime as \a spec; this is its default).
753 
754     The \a offsetSeconds is ignored unless \a spec is Qt::OffsetFromUTC, when it
755     gives the implied zone's offset from UTC.  As UTC and such zones have no
756     transitions, the start of the day is QTime(0, 0) in these cases.
757 
758     In the rare case of a date that was entirely skipped (this happens when a
759     zone east of the international date-line switches to being west of it), the
760     return shall be invalid.  Passing Qt::TimeZone as \a spec (instead of
761     passing a QTimeZone) or passing an invalid time-zone as \a zone will also
762     produce an invalid result, as shall dates that start outside the range
763     representable by QDateTime.
764 
765     \sa endOfDay()
766 */
startOfDay(Qt::TimeSpec spec,int offsetSeconds) const767 QDateTime QDate::startOfDay(Qt::TimeSpec spec, int offsetSeconds) const
768 {
769     if (!inDateTimeRange(jd, true))
770         return QDateTime();
771 
772     switch (spec) {
773     case Qt::TimeZone: // should pass a QTimeZone instead of Qt::TimeZone
774         qWarning() << "Called QDate::startOfDay(Qt::TimeZone) on" << *this;
775         return QDateTime();
776     case Qt::OffsetFromUTC:
777     case Qt::UTC:
778         return QDateTime(*this, QTime(0, 0), spec, offsetSeconds);
779 
780     case Qt::LocalTime:
781         if (offsetSeconds)
782             qWarning("Ignoring offset (%d seconds) passed with Qt::LocalTime", offsetSeconds);
783         break;
784     }
785     QDateTime when(*this, QTime(0, 0), spec);
786     if (!when.isValid())
787         when = toEarliest(*this, when);
788 
789     return when.isValid() ? when : QDateTime();
790 }
791 
792 #if QT_CONFIG(timezone)
793 /*!
794   \overload
795   \since 5.14
796 */
startOfDay(const QTimeZone & zone) const797 QDateTime QDate::startOfDay(const QTimeZone &zone) const
798 {
799     if (!inDateTimeRange(jd, true) || !zone.isValid())
800         return QDateTime();
801 
802     QDateTime when(*this, QTime(0, 0), zone);
803     if (when.isValid())
804         return when;
805 
806     // The start of the day must have fallen in a spring-forward's gap; find the spring-forward:
807     if (zone.hasTransitions()) {
808         QTimeZone::OffsetData tran = zone.previousTransition(QDateTime(*this, QTime(23, 59, 59, 999), zone));
809         const QDateTime &at = tran.atUtc.toTimeZone(zone);
810         if (at.isValid() && at.date() == *this)
811             return at;
812     }
813 
814     when = toEarliest(*this, when);
815     return when.isValid() ? when : QDateTime();
816 }
817 #endif // timezone
818 
toLatest(QDate day,const QDateTime & form)819 static QDateTime toLatest(QDate day, const QDateTime &form)
820 {
821     const Qt::TimeSpec spec = form.timeSpec();
822     const int offset = (spec == Qt::OffsetFromUTC) ? form.offsetFromUtc() : 0;
823 #if QT_CONFIG(timezone)
824     QTimeZone zone;
825     if (spec == Qt::TimeZone)
826         zone = form.timeZone();
827 #endif
828     auto moment = [=](QTime time) {
829         switch (spec) {
830         case Qt::OffsetFromUTC: return QDateTime(day, time, spec, offset);
831 #if QT_CONFIG(timezone)
832         case Qt::TimeZone: return QDateTime(day, time, zone);
833 #endif
834         default: return QDateTime(day, time, spec);
835         }
836     };
837     // Longest routine time-zone transition is 2 hours:
838     QDateTime when = moment(QTime(21, 59, 59, 999));
839     if (!when.isValid()) {
840         // Noon should be safe ...
841         when = moment(QTime(12, 0));
842         if (!when.isValid()) {
843             // ... unless it's a 24-hour jump (moving the date-line)
844             when = moment(QTime(0, 0));
845             if (!when.isValid())
846                 return QDateTime();
847         }
848     }
849     int high = 24 * 60;
850     int low = when.time().msecsSinceStartOfDay() / 60000;
851     // Binary chop to the right minute
852     while (high > low + 1) {
853         int mid = (high + low) / 2;
854         QDateTime probe = moment(QTime(mid / 60, mid % 60, 59, 999));
855         if (probe.isValid() && probe.date() == day) {
856             low = mid;
857             when = probe;
858         } else {
859             high = mid;
860         }
861     }
862     return when;
863 }
864 
865 /*!
866     \since 5.14
867     \fn QDateTime QDate::endOfDay(Qt::TimeSpec spec, int offsetSeconds) const
868     \fn QDateTime QDate::endOfDay(const QTimeZone &zone) const
869 
870     Returns the end-moment of the day.  Usually, this is one millisecond before
871     the midnight at the end of the day: however, if a time-zone transition
872     causes the given date to skip over that midnight (e.g. a DST spring-forward
873     skipping from just before 23:00 to the start of the next day), the actual
874     latest time in the day is returned.  This can only arise when the
875     start-moment is specified in terms of a time-zone (by passing its QTimeZone
876     as \a zone) or in terms of local time (by passing Qt::LocalTime as \a spec;
877     this is its default).
878 
879     The \a offsetSeconds is ignored unless \a spec is Qt::OffsetFromUTC, when it
880     gives the implied zone's offset from UTC.  As UTC and such zones have no
881     transitions, the end of the day is QTime(23, 59, 59, 999) in these cases.
882 
883     In the rare case of a date that was entirely skipped (this happens when a
884     zone east of the international date-line switches to being west of it), the
885     return shall be invalid.  Passing Qt::TimeZone as \a spec (instead of
886     passing a QTimeZone) will also produce an invalid result, as shall dates
887     that end outside the range representable by QDateTime.
888 
889     \sa startOfDay()
890 */
endOfDay(Qt::TimeSpec spec,int offsetSeconds) const891 QDateTime QDate::endOfDay(Qt::TimeSpec spec, int offsetSeconds) const
892 {
893     if (!inDateTimeRange(jd, false))
894         return QDateTime();
895 
896     switch (spec) {
897     case Qt::TimeZone: // should pass a QTimeZone instead of Qt::TimeZone
898         qWarning() << "Called QDate::endOfDay(Qt::TimeZone) on" << *this;
899         return QDateTime();
900     case Qt::UTC:
901     case Qt::OffsetFromUTC:
902         return QDateTime(*this, QTime(23, 59, 59, 999), spec, offsetSeconds);
903 
904     case Qt::LocalTime:
905         if (offsetSeconds)
906             qWarning("Ignoring offset (%d seconds) passed with Qt::LocalTime", offsetSeconds);
907         break;
908     }
909     QDateTime when(*this, QTime(23, 59, 59, 999), spec);
910     if (!when.isValid())
911         when = toLatest(*this, when);
912     return when.isValid() ? when : QDateTime();
913 }
914 
915 #if QT_CONFIG(timezone)
916 /*!
917   \overload
918   \since 5.14
919 */
endOfDay(const QTimeZone & zone) const920 QDateTime QDate::endOfDay(const QTimeZone &zone) const
921 {
922     if (!inDateTimeRange(jd, false) || !zone.isValid())
923         return QDateTime();
924 
925     QDateTime when(*this, QTime(23, 59, 59, 999), zone);
926     if (when.isValid())
927         return when;
928 
929     // The end of the day must have fallen in a spring-forward's gap; find the spring-forward:
930     if (zone.hasTransitions()) {
931         QTimeZone::OffsetData tran = zone.nextTransition(QDateTime(*this, QTime(0, 0), zone));
932         const QDateTime &at = tran.atUtc.toTimeZone(zone);
933         if (at.isValid() && at.date() == *this)
934             return at;
935     }
936 
937     when = toLatest(*this, when);
938     return when.isValid() ? when : QDateTime();
939 }
940 #endif // timezone
941 
942 #if QT_DEPRECATED_SINCE(5, 11) && QT_CONFIG(textdate)
943 
944 /*!
945     \since 4.5
946     \deprecated
947 
948     Returns the short name of the \a month for the representation specified
949     by \a type.
950 
951     The months are enumerated using the following convention:
952 
953     \list
954     \li 1 = "Jan"
955     \li 2 = "Feb"
956     \li 3 = "Mar"
957     \li 4 = "Apr"
958     \li 5 = "May"
959     \li 6 = "Jun"
960     \li 7 = "Jul"
961     \li 8 = "Aug"
962     \li 9 = "Sep"
963     \li 10 = "Oct"
964     \li 11 = "Nov"
965     \li 12 = "Dec"
966     \endlist
967 
968     The month names will be localized according to the system's
969     locale settings, i.e. using QLocale::system().
970 
971     Returns an empty string if the date is invalid.
972 
973     \sa toString(), longMonthName(), shortDayName(), longDayName()
974 */
975 
shortMonthName(int month,QDate::MonthNameType type)976 QString QDate::shortMonthName(int month, QDate::MonthNameType type)
977 {
978     switch (type) {
979     case QDate::DateFormat:
980         return QCalendar().monthName(QLocale::system(), month,
981                                      QCalendar::Unspecified, QLocale::ShortFormat);
982     case QDate::StandaloneFormat:
983         return QCalendar().standaloneMonthName(QLocale::system(), month,
984                                                QCalendar::Unspecified, QLocale::ShortFormat);
985     }
986     return QString();
987 }
988 
989 /*!
990     \since 4.5
991     \deprecated
992 
993     Returns the long name of the \a month for the representation specified
994     by \a type.
995 
996     The months are enumerated using the following convention:
997 
998     \list
999     \li 1 = "January"
1000     \li 2 = "February"
1001     \li 3 = "March"
1002     \li 4 = "April"
1003     \li 5 = "May"
1004     \li 6 = "June"
1005     \li 7 = "July"
1006     \li 8 = "August"
1007     \li 9 = "September"
1008     \li 10 = "October"
1009     \li 11 = "November"
1010     \li 12 = "December"
1011     \endlist
1012 
1013     The month names will be localized according to the system's
1014     locale settings, i.e. using QLocale::system().
1015 
1016     Returns an empty string if the date is invalid.
1017 
1018     \sa toString(), shortMonthName(), shortDayName(), longDayName()
1019 */
1020 
longMonthName(int month,MonthNameType type)1021 QString QDate::longMonthName(int month, MonthNameType type)
1022 {
1023     switch (type) {
1024     case QDate::DateFormat:
1025         return QCalendar().monthName(QLocale::system(), month,
1026                                      QCalendar::Unspecified, QLocale::LongFormat);
1027     case QDate::StandaloneFormat:
1028         return QCalendar().standaloneMonthName(QLocale::system(), month,
1029                                                QCalendar::Unspecified, QLocale::LongFormat);
1030     }
1031     return QString();
1032 }
1033 
1034 /*!
1035     \since 4.5
1036     \deprecated
1037 
1038     Returns the short name of the \a weekday for the representation specified
1039     by \a type.
1040 
1041     The days are enumerated using the following convention:
1042 
1043     \list
1044     \li 1 = "Mon"
1045     \li 2 = "Tue"
1046     \li 3 = "Wed"
1047     \li 4 = "Thu"
1048     \li 5 = "Fri"
1049     \li 6 = "Sat"
1050     \li 7 = "Sun"
1051     \endlist
1052 
1053     The day names will be localized according to the system's
1054     locale settings, i.e. using QLocale::system().
1055 
1056     Returns an empty string if the date is invalid.
1057 
1058     \sa toString(), shortMonthName(), longMonthName(), longDayName()
1059 */
1060 
shortDayName(int weekday,MonthNameType type)1061 QString QDate::shortDayName(int weekday, MonthNameType type)
1062 {
1063     switch (type) {
1064     case QDate::DateFormat:
1065         return QLocale::system().dayName(weekday, QLocale::ShortFormat);
1066     case QDate::StandaloneFormat:
1067         return QLocale::system().standaloneDayName(weekday, QLocale::ShortFormat);
1068     }
1069     return QString();
1070 }
1071 
1072 /*!
1073     \since 4.5
1074     \deprecated
1075 
1076     Returns the long name of the \a weekday for the representation specified
1077     by \a type.
1078 
1079     The days are enumerated using the following convention:
1080 
1081     \list
1082     \li 1 = "Monday"
1083     \li 2 = "Tuesday"
1084     \li 3 = "Wednesday"
1085     \li 4 = "Thursday"
1086     \li 5 = "Friday"
1087     \li 6 = "Saturday"
1088     \li 7 = "Sunday"
1089     \endlist
1090 
1091     The day names will be localized according to the system's
1092     locale settings, i.e. using QLocale::system().
1093 
1094     Returns an empty string if the date is invalid.
1095 
1096     \sa toString(), shortDayName(), shortMonthName(), longMonthName()
1097 */
1098 
longDayName(int weekday,MonthNameType type)1099 QString QDate::longDayName(int weekday, MonthNameType type)
1100 {
1101     switch (type) {
1102     case QDate::DateFormat:
1103         return QLocale::system().dayName(weekday, QLocale::LongFormat);
1104     case QDate::StandaloneFormat:
1105         return QLocale::system().standaloneDayName(weekday, QLocale::LongFormat);
1106     }
1107     return QString();
1108 }
1109 #endif // textdate && deprecated
1110 
1111 #if QT_CONFIG(datestring) // depends on, so implies, textdate
1112 
toStringTextDate(QDate date)1113 static QString toStringTextDate(QDate date)
1114 {
1115     if (date.isValid()) {
1116         QCalendar cal; // Always Gregorian
1117         const auto parts = cal.partsFromDate(date);
1118         if (parts.isValid()) {
1119             const QLatin1Char sp(' ');
1120             return QLocale::system().dayName(cal.dayOfWeek(date), QLocale::ShortFormat) + sp
1121                 + cal.monthName(QLocale::system(), parts.month, parts.year, QLocale::ShortFormat)
1122                 + sp + QString::number(parts.day) + sp + QString::number(parts.year);
1123         }
1124     }
1125     return QString();
1126 }
1127 
toStringIsoDate(QDate date)1128 static QString toStringIsoDate(QDate date)
1129 {
1130     const auto parts = QCalendar().partsFromDate(date);
1131     if (parts.isValid() && parts.year >= 0 && parts.year <= 9999)
1132         return QString::asprintf("%04d-%02d-%02d", parts.year, parts.month, parts.day);
1133     return QString();
1134 }
1135 
1136 /*!
1137     \overload
1138 
1139     Returns the date as a string. The \a format parameter determines the format
1140     of the string.
1141 
1142     If the \a format is Qt::TextDate, the string is formatted in the default
1143     way. The day and month names will be localized names using the system
1144     locale, i.e. QLocale::system(). An example of this formatting
1145     is "Sat May 20 1995".
1146 
1147     If the \a format is Qt::ISODate, the string format corresponds
1148     to the ISO 8601 extended specification for representations of
1149     dates and times, taking the form yyyy-MM-dd, where yyyy is the
1150     year, MM is the month of the year (between 01 and 12), and dd is
1151     the day of the month between 01 and 31.
1152 
1153     The \a format options Qt::SystemLocaleDate, Qt::SystemLocaleShortDate and
1154     Qt::SystemLocaleLongDate shall be removed in Qt 6. Their use should be
1155     replaced with
1156     \l {QLocale::toString()}{QLocale::system().toString(date, QLocale::ShortFormat)} or
1157     \l {QLocale::toString()}{QLocale::system().toString(date, QLocale::LongFormat)}.
1158 
1159     The \a format options Qt::LocaleDate, Qt::DefaultLocaleShortDate and
1160     Qt::DefaultLocaleLongDate shall be removed in Qt 6. Their use should be
1161     replaced with
1162     \l {QLocale::toString()}{QLocale().toString(date, QLocale::ShortFormat)} or
1163     \l {QLocale::toString()}{QLocale().toString(date, QLocale::LongFormat)}.
1164 
1165     If the \a format is Qt::RFC2822Date, the string is formatted in
1166     an \l{RFC 2822} compatible way. An example of this formatting is
1167     "20 May 1995".
1168 
1169     If the date is invalid, an empty string will be returned.
1170 
1171     \warning The Qt::ISODate format is only valid for years in the
1172     range 0 to 9999.
1173 
1174     \sa fromString(), QLocale::toString()
1175 */
toString(Qt::DateFormat format) const1176 QString QDate::toString(Qt::DateFormat format) const
1177 {
1178     if (!isValid())
1179         return QString();
1180 
1181     switch (format) {
1182 #if QT_DEPRECATED_SINCE(5, 15)
1183 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
1184     case Qt::SystemLocaleDate:
1185     case Qt::SystemLocaleShortDate:
1186         return QLocale::system().toString(*this, QLocale::ShortFormat);
1187     case Qt::SystemLocaleLongDate:
1188         return QLocale::system().toString(*this, QLocale::LongFormat);
1189     case Qt::LocaleDate:
1190     case Qt::DefaultLocaleShortDate:
1191         return QLocale().toString(*this, QLocale::ShortFormat);
1192     case Qt::DefaultLocaleLongDate:
1193         return QLocale().toString(*this, QLocale::LongFormat);
1194 QT_WARNING_POP
1195 #endif // 5.15
1196     case Qt::RFC2822Date:
1197         return QLocale::c().toString(*this, QStringView(u"dd MMM yyyy"));
1198     default:
1199     case Qt::TextDate:
1200         return toStringTextDate(*this);
1201     case Qt::ISODate:
1202     case Qt::ISODateWithMs:
1203         // No calendar dependence
1204         return toStringIsoDate(*this);
1205     }
1206 }
1207 
1208 #if QT_DEPRECATED_SINCE(5, 15)
toString(Qt::DateFormat format,QCalendar cal) const1209 QString QDate::toString(Qt::DateFormat format, QCalendar cal) const
1210 {
1211     if (!isValid())
1212         return QString();
1213 
1214     switch (format) {
1215 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
1216     case Qt::SystemLocaleDate:
1217     case Qt::SystemLocaleShortDate:
1218         return QLocale::system().toString(*this, QLocale::ShortFormat, cal);
1219     case Qt::SystemLocaleLongDate:
1220         return QLocale::system().toString(*this, QLocale::LongFormat, cal);
1221     case Qt::LocaleDate:
1222     case Qt::DefaultLocaleShortDate:
1223         return QLocale().toString(*this, QLocale::ShortFormat, cal);
1224     case Qt::DefaultLocaleLongDate:
1225         return QLocale().toString(*this, QLocale::LongFormat, cal);
1226 QT_WARNING_POP
1227     case Qt::RFC2822Date:
1228         return QLocale::c().toString(*this, QStringView(u"dd MMM yyyy"), cal);
1229     default:
1230     case Qt::TextDate:
1231         return toStringTextDate(*this);
1232     case Qt::ISODate:
1233     case Qt::ISODateWithMs:
1234         // No calendar dependence
1235         return toStringIsoDate(*this);
1236     }
1237 }
1238 #endif // 5.15
1239 
1240 /*!
1241     \fn QString QDate::toString(const QString &format) const
1242     \fn QString QDate::toString(const QString &format, QCalendar cal) const
1243     \fn QString QDate::toString(QStringView format) const
1244     \fn QString QDate::toString(QStringView format, QCalendar cal) const
1245 
1246     Returns the date as a string. The \a format parameter determines the format
1247     of the result string. If \a cal is supplied, it determines the calendar used
1248     to represent the date; it defaults to Gregorian.
1249 
1250     These expressions may be used:
1251 
1252     \table
1253     \header \li Expression \li Output
1254     \row \li d \li The day as a number without a leading zero (1 to 31)
1255     \row \li dd \li The day as a number with a leading zero (01 to 31)
1256     \row \li ddd
1257          \li The abbreviated localized day name (e.g. 'Mon' to 'Sun').
1258              Uses the system locale to localize the name, i.e. QLocale::system().
1259     \row \li dddd
1260          \li The long localized day name (e.g. 'Monday' to 'Sunday').
1261              Uses the system locale to localize the name, i.e. QLocale::system().
1262     \row \li M \li The month as a number without a leading zero (1 to 12)
1263     \row \li MM \li The month as a number with a leading zero (01 to 12)
1264     \row \li MMM
1265          \li The abbreviated localized month name (e.g. 'Jan' to 'Dec').
1266              Uses the system locale to localize the name, i.e. QLocale::system().
1267     \row \li MMMM
1268          \li The long localized month name (e.g. 'January' to 'December').
1269              Uses the system locale to localize the name, i.e. QLocale::system().
1270     \row \li yy \li The year as a two digit number (00 to 99)
1271     \row \li yyyy \li The year as a four digit number. If the year is negative,
1272             a minus sign is prepended, making five characters.
1273     \endtable
1274 
1275     Any sequence of characters enclosed in single quotes will be included
1276     verbatim in the output string (stripped of the quotes), even if it contains
1277     formatting characters. Two consecutive single quotes ("''") are replaced by
1278     a single quote in the output. All other characters in the format string are
1279     included verbatim in the output string.
1280 
1281     Formats without separators (e.g. "ddMM") are supported but must be used with
1282     care, as the resulting strings aren't always reliably readable (e.g. if "dM"
1283     produces "212" it could mean either the 2nd of December or the 21st of
1284     February).
1285 
1286     Example format strings (assuming that the QDate is the 20 July
1287     1969):
1288 
1289     \table
1290     \header \li Format            \li Result
1291     \row    \li dd.MM.yyyy        \li 20.07.1969
1292     \row    \li ddd MMMM d yy     \li Sun July 20 69
1293     \row    \li 'The day is' dddd \li The day is Sunday
1294     \endtable
1295 
1296     If the datetime is invalid, an empty string will be returned.
1297 
1298     \note If localized month and day names are desired, please switch to using
1299     QLocale::system().toString() as QDate methods shall change to use English (C
1300     locale) names at Qt 6.
1301 
1302     \sa fromString(), QDateTime::toString(), QTime::toString(), QLocale::toString()
1303 
1304 */
toString(QStringView format) const1305 QString QDate::toString(QStringView format) const
1306 {
1307     return toString(format, QCalendar());
1308 }
1309 
toString(QStringView format,QCalendar cal) const1310 QString QDate::toString(QStringView format, QCalendar cal) const
1311 {
1312     return QLocale::system().toString(*this, format, cal); // QLocale::c() ### Qt6
1313 }
1314 
1315 #if QT_STRINGVIEW_LEVEL < 2
toString(const QString & format) const1316 QString QDate::toString(const QString &format) const
1317 {
1318     return toString(qToStringViewIgnoringNull(format), QCalendar());
1319 }
1320 
toString(const QString & format,QCalendar cal) const1321 QString QDate::toString(const QString &format, QCalendar cal) const
1322 {
1323     return toString(qToStringViewIgnoringNull(format), cal);
1324 }
1325 #endif
1326 
1327 #endif // datestring
1328 
1329 /*!
1330     \fn bool QDate::setYMD(int y, int m, int d)
1331 
1332     \deprecated in 5.0, use setDate() instead.
1333 
1334     Sets the date's year \a y, month \a m, and day \a d.
1335 
1336     If \a y is in the range 0 to 99, it is interpreted as 1900 to
1337     1999.
1338     Returns \c false if the date is invalid.
1339 
1340     Use setDate() instead.
1341 */
1342 
1343 /*!
1344     \since 4.2
1345 
1346     Sets this to represent the date, in the Gregorian calendar, with the given
1347     \a year, \a month and \a day numbers. Returns true if the resulting date is
1348     valid, otherwise it sets this to represent an invalid date and returns
1349     false.
1350 
1351     \sa isValid(), QCalendar::dateFromParts()
1352 */
setDate(int year,int month,int day)1353 bool QDate::setDate(int year, int month, int day)
1354 {
1355     if (QGregorianCalendar::julianFromParts(year, month, day, &jd))
1356         return true;
1357 
1358     jd = nullJd();
1359     return false;
1360 }
1361 
1362 /*!
1363     \since 5.14
1364 
1365     Sets this to represent the date, in the given calendar \a cal, with the
1366     given \a year, \a month and \a day numbers. Returns true if the resulting
1367     date is valid, otherwise it sets this to represent an invalid date and
1368     returns false.
1369 
1370     \sa isValid(), QCalendar::dateFromParts()
1371 */
1372 
setDate(int year,int month,int day,QCalendar cal)1373 bool QDate::setDate(int year, int month, int day, QCalendar cal)
1374 {
1375     *this = QDate(year, month, day, cal);
1376     return isValid();
1377 }
1378 
1379 /*!
1380     \since 4.5
1381 
1382     Extracts the date's year, month, and day, and assigns them to
1383     *\a year, *\a month, and *\a day. The pointers may be null.
1384 
1385     Returns 0 if the date is invalid.
1386 
1387     \note In Qt versions prior to 5.7, this function is marked as non-\c{const}.
1388 
1389     \sa year(), month(), day(), isValid(), QCalendar::partsFromDate()
1390 */
getDate(int * year,int * month,int * day) const1391 void QDate::getDate(int *year, int *month, int *day) const
1392 {
1393     QCalendar::YearMonthDay parts; // invalid by default
1394     if (isValid())
1395         parts = QGregorianCalendar::partsFromJulian(jd);
1396 
1397     const bool ok = parts.isValid();
1398     if (year)
1399         *year = ok ? parts.year : 0;
1400     if (month)
1401         *month = ok ? parts.month : 0;
1402     if (day)
1403         *day = ok ? parts.day : 0;
1404 }
1405 
1406 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1407 /*!
1408     \overload
1409     \internal
1410 */
getDate(int * year,int * month,int * day)1411 void QDate::getDate(int *year, int *month, int *day)
1412 {
1413     qAsConst(*this).getDate(year, month, day);
1414 }
1415 #endif // < Qt 6
1416 
1417 /*!
1418     Returns a QDate object containing a date \a ndays later than the
1419     date of this object (or earlier if \a ndays is negative).
1420 
1421     Returns a null date if the current date is invalid or the new date is
1422     out of range.
1423 
1424     \sa addMonths(), addYears(), daysTo()
1425 */
1426 
addDays(qint64 ndays) const1427 QDate QDate::addDays(qint64 ndays) const
1428 {
1429     if (isNull())
1430         return QDate();
1431 
1432     // Due to limits on minJd() and maxJd() we know that any overflow
1433     // will be invalid and caught by fromJulianDay().
1434     return fromJulianDay(jd + ndays);
1435 }
1436 
1437 /*!
1438     Returns a QDate object containing a date \a nmonths later than the
1439     date of this object (or earlier if \a nmonths is negative).
1440 
1441     Uses \a cal as calendar, if supplied, else the Gregorian calendar.
1442 
1443     \note If the ending day/month combination does not exist in the resulting
1444     month/year, this function will return a date that is the latest valid date
1445     in the selected month.
1446 
1447     \sa addDays(), addYears()
1448 */
1449 
addMonths(int nmonths,QCalendar cal) const1450 QDate QDate::addMonths(int nmonths, QCalendar cal) const
1451 {
1452     if (!isValid())
1453         return QDate();
1454 
1455     if (nmonths == 0)
1456         return *this;
1457 
1458     auto parts = cal.partsFromDate(*this);
1459 
1460     if (!parts.isValid())
1461         return QDate();
1462     Q_ASSERT(parts.year || cal.hasYearZero());
1463 
1464     parts.month += nmonths;
1465     while (parts.month <= 0) {
1466         if (--parts.year || cal.hasYearZero())
1467             parts.month += cal.monthsInYear(parts.year);
1468     }
1469     int count = cal.monthsInYear(parts.year);
1470     while (parts.month > count) {
1471         parts.month -= count;
1472         count = (++parts.year || cal.hasYearZero()) ? cal.monthsInYear(parts.year) : 0;
1473     }
1474 
1475     return fixedDate(std::move(parts), cal);
1476 }
1477 
1478 /*!
1479   \overload
1480 */
1481 
addMonths(int nmonths) const1482 QDate QDate::addMonths(int nmonths) const
1483 {
1484     if (isNull())
1485         return QDate();
1486 
1487     if (nmonths == 0)
1488         return *this;
1489 
1490     auto parts = QGregorianCalendar::partsFromJulian(jd);
1491 
1492     if (!parts.isValid())
1493         return QDate();
1494     Q_ASSERT(parts.year);
1495 
1496     parts.month += nmonths;
1497     while (parts.month <= 0) {
1498         if (--parts.year) // skip over year 0
1499             parts.month += 12;
1500     }
1501     while (parts.month > 12) {
1502         parts.month -= 12;
1503         if (!++parts.year) // skip over year 0
1504             ++parts.year;
1505     }
1506 
1507     return fixedDate(std::move(parts));
1508 }
1509 
1510 /*!
1511     Returns a QDate object containing a date \a nyears later than the
1512     date of this object (or earlier if \a nyears is negative).
1513 
1514     Uses \a cal as calendar, if supplied, else the Gregorian calendar.
1515 
1516     \note If the ending day/month combination does not exist in the resulting
1517     year (e.g., for the Gregorian calendar, if the date was Feb 29 and the final
1518     year is not a leap year), this function will return a date that is the
1519     latest valid date in the given month (in the example, Feb 28).
1520 
1521     \sa addDays(), addMonths()
1522 */
1523 
addYears(int nyears,QCalendar cal) const1524 QDate QDate::addYears(int nyears, QCalendar cal) const
1525 {
1526     if (!isValid())
1527         return QDate();
1528 
1529     auto parts = cal.partsFromDate(*this);
1530     if (!parts.isValid())
1531         return QDate();
1532 
1533     int old_y = parts.year;
1534     parts.year += nyears;
1535 
1536     // If we just crossed (or hit) a missing year zero, adjust year by +/- 1:
1537     if (!cal.hasYearZero() && ((old_y > 0) != (parts.year > 0) || !parts.year))
1538         parts.year += nyears > 0 ? +1 : -1;
1539 
1540     return fixedDate(std::move(parts), cal);
1541 }
1542 
1543 /*!
1544     \overload
1545 */
1546 
addYears(int nyears) const1547 QDate QDate::addYears(int nyears) const
1548 {
1549     if (isNull())
1550         return QDate();
1551 
1552     auto parts = QGregorianCalendar::partsFromJulian(jd);
1553     if (!parts.isValid())
1554         return QDate();
1555 
1556     int old_y = parts.year;
1557     parts.year += nyears;
1558 
1559     // If we just crossed (or hit) a missing year zero, adjust year by +/- 1:
1560     if ((old_y > 0) != (parts.year > 0) || !parts.year)
1561         parts.year += nyears > 0 ? +1 : -1;
1562 
1563     return fixedDate(std::move(parts));
1564 }
1565 
1566 /*!
1567     Returns the number of days from this date to \a d (which is
1568     negative if \a d is earlier than this date).
1569 
1570     Returns 0 if either date is invalid.
1571 
1572     Example:
1573     \snippet code/src_corelib_tools_qdatetime.cpp 0
1574 
1575     \sa addDays()
1576 */
1577 
daysTo(const QDate & d) const1578 qint64 QDate::daysTo(const QDate &d) const
1579 {
1580     if (isNull() || d.isNull())
1581         return 0;
1582 
1583     // Due to limits on minJd() and maxJd() we know this will never overflow
1584     return d.jd - jd;
1585 }
1586 
1587 
1588 /*!
1589     \fn bool QDate::operator==(const QDate &d) const
1590 
1591     Returns \c true if this date and \a d represent the same day, otherwise
1592     \c false.
1593 */
1594 
1595 /*!
1596     \fn bool QDate::operator!=(const QDate &d) const
1597 
1598     Returns \c true if this date is different from \a d; otherwise
1599     returns \c false.
1600 
1601     \sa operator==()
1602 */
1603 
1604 /*!
1605     \fn bool QDate::operator<(const QDate &d) const
1606 
1607     Returns \c true if this date is earlier than \a d; otherwise returns
1608     false.
1609 */
1610 
1611 /*!
1612     \fn bool QDate::operator<=(const QDate &d) const
1613 
1614     Returns \c true if this date is earlier than or equal to \a d;
1615     otherwise returns \c false.
1616 */
1617 
1618 /*!
1619     \fn bool QDate::operator>(const QDate &d) const
1620 
1621     Returns \c true if this date is later than \a d; otherwise returns
1622     false.
1623 */
1624 
1625 /*!
1626     \fn bool QDate::operator>=(const QDate &d) const
1627 
1628     Returns \c true if this date is later than or equal to \a d;
1629     otherwise returns \c false.
1630 */
1631 
1632 /*!
1633     \fn QDate::currentDate()
1634     Returns the current date, as reported by the system clock.
1635 
1636     \sa QTime::currentTime(), QDateTime::currentDateTime()
1637 */
1638 
1639 #if QT_CONFIG(datestring) // depends on, so implies, textdate
1640 namespace {
1641 
1642 struct ParsedInt { int value = 0; bool ok = false; };
1643 
1644 /*
1645     /internal
1646 
1647     Read an int that must be the whole text.  QStringRef::toInt() will ignore
1648     spaces happily; but ISO date format should not.
1649 */
readInt(QStringView text)1650 ParsedInt readInt(QStringView text)
1651 {
1652     ParsedInt result;
1653     for (const auto &ch : text) {
1654         if (ch.isSpace())
1655             return result;
1656     }
1657     result.value = QLocale::c().toInt(text, &result.ok);
1658     return result;
1659 }
1660 
1661 }
1662 
1663 /*!
1664     Returns the QDate represented by the \a string, using the
1665     \a format given, or an invalid date if the string cannot be
1666     parsed.
1667 
1668     Note for Qt::TextDate: It is recommended that you use the English short
1669     month names (e.g. "Jan"). Although localized month names can also be used in
1670     Qt 5, they depend on the user's locale settings.
1671 
1672     \note Support for localized dates, including the format options
1673     Qt::SystemLocaleDate, Qt::SystemLocaleShortDate, Qt::SystemLocaleLongDate,
1674     Qt::LocaleDate, Qt::DefaultLocaleShortDate, and Qt::DefaultLocaleLongDate,
1675     shall be removed in Qt 6. Use QLocale::toDate() instead.
1676 
1677     \sa toString(), QLocale::toDate()
1678 */
1679 
fromString(const QString & string,Qt::DateFormat format)1680 QDate QDate::fromString(const QString &string, Qt::DateFormat format)
1681 {
1682     if (string.isEmpty())
1683         return QDate();
1684 
1685     switch (format) {
1686 #if QT_DEPRECATED_SINCE(5, 15)
1687 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
1688     case Qt::SystemLocaleDate:
1689     case Qt::SystemLocaleShortDate:
1690         return QLocale::system().toDate(string, QLocale::ShortFormat);
1691     case Qt::SystemLocaleLongDate:
1692         return QLocale::system().toDate(string, QLocale::LongFormat);
1693     case Qt::LocaleDate:
1694     case Qt::DefaultLocaleShortDate:
1695         return QLocale().toDate(string, QLocale::ShortFormat);
1696     case Qt::DefaultLocaleLongDate:
1697         return QLocale().toDate(string, QLocale::LongFormat);
1698 QT_WARNING_POP
1699 #endif // 5.15
1700     case Qt::RFC2822Date:
1701         return rfcDateImpl(string).date;
1702     default:
1703     case Qt::TextDate: {
1704         QVector<QStringRef> parts = string.splitRef(QLatin1Char(' '), Qt::SkipEmptyParts);
1705 
1706         if (parts.count() != 4)
1707             return QDate();
1708 
1709         bool ok = false;
1710         int year = parts.at(3).toInt(&ok);
1711         int day = ok ? parts.at(2).toInt(&ok) : 0;
1712         if (!ok || !day)
1713             return QDate();
1714 
1715         const int month = fromShortMonthName(parts.at(1), year);
1716         if (month == -1) // Month name matches no English or localised name.
1717             return QDate();
1718 
1719         return QDate(year, month, day);
1720         }
1721     case Qt::ISODate:
1722         // Semi-strict parsing, must be long enough and have punctuators as separators
1723         if (string.size() >= 10 && string.at(4).isPunct() && string.at(7).isPunct()
1724                 && (string.size() == 10 || !string.at(10).isDigit())) {
1725             QStringView view(string);
1726             const ParsedInt year = readInt(view.mid(0, 4));
1727             const ParsedInt month = readInt(view.mid(5, 2));
1728             const ParsedInt day = readInt(view.mid(8, 2));
1729             if (year.ok && year.value > 0 && year.value <= 9999 && month.ok && day.ok)
1730                 return QDate(year.value, month.value, day.value);
1731         }
1732         break;
1733     }
1734     return QDate();
1735 }
1736 
1737 /*!
1738     Returns the QDate represented by the \a string, using the \a
1739     format given, or an invalid date if the string cannot be parsed.
1740 
1741     Uses \a cal as calendar if supplied, else the Gregorian calendar. Ranges of
1742     values in the format descriptions below are for the latter; they may be
1743     different for other calendars.
1744 
1745     These expressions may be used for the format:
1746 
1747     \table
1748     \header \li Expression \li Output
1749     \row \li d \li The day as a number without a leading zero (1 to 31)
1750     \row \li dd \li The day as a number with a leading zero (01 to 31)
1751     \row \li ddd
1752          \li The abbreviated localized day name (e.g. 'Mon' to 'Sun').
1753              Uses the system locale to localize the name, i.e. QLocale::system().
1754     \row \li dddd
1755          \li The long localized day name (e.g. 'Monday' to 'Sunday').
1756              Uses the system locale to localize the name, i.e. QLocale::system().
1757     \row \li M \li The month as a number without a leading zero (1 to 12)
1758     \row \li MM \li The month as a number with a leading zero (01 to 12)
1759     \row \li MMM
1760          \li The abbreviated localized month name (e.g. 'Jan' to 'Dec').
1761              Uses the system locale to localize the name, i.e. QLocale::system().
1762     \row \li MMMM
1763          \li The long localized month name (e.g. 'January' to 'December').
1764              Uses the system locale to localize the name, i.e. QLocale::system().
1765     \row \li yy \li The year as a two digit number (00 to 99)
1766     \row \li yyyy \li The year as a four digit number, possibly plus a leading
1767              minus sign for negative years.
1768     \endtable
1769 
1770     \note Unlike the other version of this function, day and month names must
1771     be given in the user's local language. It is only possible to use the English
1772     names if the user's language is English.
1773 
1774     All other input characters will be treated as text. Any non-empty sequence
1775     of characters enclosed in single quotes will also be treated (stripped of
1776     the quotes) as text and not be interpreted as expressions. For example:
1777 
1778     \snippet code/src_corelib_tools_qdatetime.cpp 1
1779 
1780     If the format is not satisfied, an invalid QDate is returned. The
1781     expressions that don't expect leading zeroes (d, M) will be
1782     greedy. This means that they will use two digits even if this
1783     will put them outside the accepted range of values and leaves too
1784     few digits for other sections. For example, the following format
1785     string could have meant January 30 but the M will grab two
1786     digits, resulting in an invalid date:
1787 
1788     \snippet code/src_corelib_tools_qdatetime.cpp 2
1789 
1790     For any field that is not represented in the format the following
1791     defaults are used:
1792 
1793     \table
1794     \header \li Field  \li Default value
1795     \row    \li Year   \li 1900
1796     \row    \li Month  \li 1
1797     \row    \li Day    \li 1
1798     \endtable
1799 
1800     The following examples demonstrate the default values:
1801 
1802     \snippet code/src_corelib_tools_qdatetime.cpp 3
1803 
1804     \note If localized month and day names are used, please switch to using
1805     QLocale::system().toDate() as QDate methods shall change to only recognize
1806     English (C locale) names at Qt 6.
1807 
1808     \sa toString(), QDateTime::fromString(), QTime::fromString(),
1809         QLocale::toDate()
1810 */
1811 
fromString(const QString & string,const QString & format,QCalendar cal)1812 QDate QDate::fromString(const QString &string, const QString &format, QCalendar cal)
1813 {
1814     QDate date;
1815 #if QT_CONFIG(datetimeparser)
1816     QDateTimeParser dt(QMetaType::QDate, QDateTimeParser::FromString, cal);
1817     // dt.setDefaultLocale(QLocale::c()); ### Qt 6
1818     if (dt.parseFormat(format))
1819         dt.fromString(string, &date, nullptr);
1820 #else
1821     Q_UNUSED(string);
1822     Q_UNUSED(format);
1823     Q_UNUSED(cal);
1824 #endif
1825     return date;
1826 }
1827 
1828 /*!
1829   \overload
1830 */
1831 
fromString(const QString & string,const QString & format)1832 QDate QDate::fromString(const QString &string, const QString &format)
1833 {
1834     return fromString(string, format, QCalendar());
1835 }
1836 #endif // datestring
1837 
1838 /*!
1839     \overload
1840 
1841     Returns \c true if the specified date (\a year, \a month, and \a day) is
1842     valid in the Gregorian calendar; otherwise returns \c false.
1843 
1844     Example:
1845     \snippet code/src_corelib_tools_qdatetime.cpp 4
1846 
1847     \sa isNull(), setDate(), QCalendar::isDateValid()
1848 */
1849 
isValid(int year,int month,int day)1850 bool QDate::isValid(int year, int month, int day)
1851 {
1852     return QGregorianCalendar::validParts(year, month, day);
1853 }
1854 
1855 /*!
1856     \fn bool QDate::isLeapYear(int year)
1857 
1858     Returns \c true if the specified \a year is a leap year in the Gregorian
1859     calendar; otherwise returns \c false.
1860 
1861     \sa QCalendar::isLeapYear()
1862 */
1863 
isLeapYear(int y)1864 bool QDate::isLeapYear(int y)
1865 {
1866     return QGregorianCalendar::leapTest(y);
1867 }
1868 
1869 /*! \fn static QDate QDate::fromJulianDay(qint64 jd)
1870 
1871     Converts the Julian day \a jd to a QDate.
1872 
1873     \sa toJulianDay()
1874 */
1875 
1876 /*! \fn int QDate::toJulianDay() const
1877 
1878     Converts the date to a Julian day.
1879 
1880     \sa fromJulianDay()
1881 */
1882 
1883 /*****************************************************************************
1884   QTime member functions
1885  *****************************************************************************/
1886 
1887 /*!
1888     \class QTime
1889     \inmodule QtCore
1890     \reentrant
1891 
1892     \brief The QTime class provides clock time functions.
1893 
1894 
1895     A QTime object contains a clock time, which it can express as the numbers of
1896     hours, minutes, seconds, and milliseconds since midnight. It provides
1897     functions for comparing times and for manipulating a time by adding a number
1898     of milliseconds.
1899 
1900     QTime uses the 24-hour clock format; it has no concept of AM/PM.
1901     Unlike QDateTime, QTime knows nothing about time zones or
1902     daylight-saving time (DST).
1903 
1904     A QTime object is typically created either by giving the number of hours,
1905     minutes, seconds, and milliseconds explicitly, or by using the static
1906     function currentTime(), which creates a QTime object that represents the
1907     system's local time.
1908 
1909     The hour(), minute(), second(), and msec() functions provide
1910     access to the number of hours, minutes, seconds, and milliseconds
1911     of the time. The same information is provided in textual format by
1912     the toString() function.
1913 
1914     The addSecs() and addMSecs() functions provide the time a given
1915     number of seconds or milliseconds later than a given time.
1916     Correspondingly, the number of seconds or milliseconds
1917     between two times can be found using secsTo() or msecsTo().
1918 
1919     QTime provides a full set of operators to compare two QTime
1920     objects; an earlier time is considered smaller than a later one;
1921     if A.msecsTo(B) is positive, then A < B.
1922 
1923     \sa QDate, QDateTime
1924 */
1925 
1926 /*!
1927     \fn QTime::QTime()
1928 
1929     Constructs a null time object. For a null time, isNull() returns \c true and
1930     isValid() returns \c false. If you need a zero time, use QTime(0, 0).  For
1931     the start of a day, see QDate::startOfDay().
1932 
1933     \sa isNull(), isValid()
1934 */
1935 
1936 /*!
1937     Constructs a time with hour \a h, minute \a m, seconds \a s and
1938     milliseconds \a ms.
1939 
1940     \a h must be in the range 0 to 23, \a m and \a s must be in the
1941     range 0 to 59, and \a ms must be in the range 0 to 999.
1942 
1943     \sa isValid()
1944 */
1945 
QTime(int h,int m,int s,int ms)1946 QTime::QTime(int h, int m, int s, int ms)
1947 {
1948     setHMS(h, m, s, ms);
1949 }
1950 
1951 
1952 /*!
1953     \fn bool QTime::isNull() const
1954 
1955     Returns \c true if the time is null (i.e., the QTime object was
1956     constructed using the default constructor); otherwise returns
1957     false. A null time is also an invalid time.
1958 
1959     \sa isValid()
1960 */
1961 
1962 /*!
1963     Returns \c true if the time is valid; otherwise returns \c false. For example,
1964     the time 23:30:55.746 is valid, but 24:12:30 is invalid.
1965 
1966     \sa isNull()
1967 */
1968 
isValid() const1969 bool QTime::isValid() const
1970 {
1971     return mds > NullTime && mds < MSECS_PER_DAY;
1972 }
1973 
1974 
1975 /*!
1976     Returns the hour part (0 to 23) of the time.
1977 
1978     Returns -1 if the time is invalid.
1979 
1980     \sa minute(), second(), msec()
1981 */
1982 
hour() const1983 int QTime::hour() const
1984 {
1985     if (!isValid())
1986         return -1;
1987 
1988     return ds() / MSECS_PER_HOUR;
1989 }
1990 
1991 /*!
1992     Returns the minute part (0 to 59) of the time.
1993 
1994     Returns -1 if the time is invalid.
1995 
1996     \sa hour(), second(), msec()
1997 */
1998 
minute() const1999 int QTime::minute() const
2000 {
2001     if (!isValid())
2002         return -1;
2003 
2004     return (ds() % MSECS_PER_HOUR) / MSECS_PER_MIN;
2005 }
2006 
2007 /*!
2008     Returns the second part (0 to 59) of the time.
2009 
2010     Returns -1 if the time is invalid.
2011 
2012     \sa hour(), minute(), msec()
2013 */
2014 
second() const2015 int QTime::second() const
2016 {
2017     if (!isValid())
2018         return -1;
2019 
2020     return (ds() / 1000)%SECS_PER_MIN;
2021 }
2022 
2023 /*!
2024     Returns the millisecond part (0 to 999) of the time.
2025 
2026     Returns -1 if the time is invalid.
2027 
2028     \sa hour(), minute(), second()
2029 */
2030 
msec() const2031 int QTime::msec() const
2032 {
2033     if (!isValid())
2034         return -1;
2035 
2036     return ds() % 1000;
2037 }
2038 
2039 #if QT_CONFIG(datestring) // depends on, so implies, textdate
2040 /*!
2041     \overload
2042 
2043     Returns the time as a string. The \a format parameter determines
2044     the format of the string.
2045 
2046     If \a format is Qt::TextDate, the string format is HH:mm:ss;
2047     e.g. 1 second before midnight would be "23:59:59".
2048 
2049     If \a format is Qt::ISODate, the string format corresponds to the
2050     ISO 8601 extended specification for representations of dates,
2051     represented by HH:mm:ss. To include milliseconds in the ISO 8601
2052     date, use the \a format Qt::ISODateWithMs, which corresponds to
2053     HH:mm:ss.zzz.
2054 
2055     The \a format options Qt::SystemLocaleDate:, Qt::SystemLocaleShortDate and
2056     Qt::SystemLocaleLongDate shall be removed in Qt 6. Their use should be
2057     replaced with:
2058     \l {QLocale::toString()}{QLocale::system().toString(time, QLocale::ShortFormat)} or
2059     \l {QLocale::toString()}{QLocale::system().toString(time, QLocale::LongFormat)}.
2060 
2061     The \a format options Qt::LocaleDate, Qt::DefaultLocaleShortDate and
2062     Qt::DefaultLocaleLongDate shall be removed in Qt 6. Their use should be
2063     replaced with:
2064     \l {QLocale::toString()}{QLocale().toString(time, QLocale::ShortFormat)} or
2065     \l {QLocale::toString()}{QLocale().toString(time, QLocale::LongFormat)}.
2066 
2067     If the \a format is Qt::RFC2822Date, the string is formatted in
2068     an \l{RFC 2822} compatible way. An example of this formatting is
2069     "23:59:20".
2070 
2071     If the time is invalid, an empty string will be returned.
2072 
2073     \sa fromString(), QDate::toString(), QDateTime::toString(), QLocale::toString()
2074 */
2075 
toString(Qt::DateFormat format) const2076 QString QTime::toString(Qt::DateFormat format) const
2077 {
2078     if (!isValid())
2079         return QString();
2080 
2081     switch (format) {
2082 #if QT_DEPRECATED_SINCE(5, 15)
2083 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
2084     case Qt::SystemLocaleDate:
2085     case Qt::SystemLocaleShortDate:
2086         return QLocale::system().toString(*this, QLocale::ShortFormat);
2087     case Qt::SystemLocaleLongDate:
2088         return QLocale::system().toString(*this, QLocale::LongFormat);
2089     case Qt::LocaleDate:
2090     case Qt::DefaultLocaleShortDate:
2091         return QLocale().toString(*this, QLocale::ShortFormat);
2092     case Qt::DefaultLocaleLongDate:
2093         return QLocale().toString(*this, QLocale::LongFormat);
2094 QT_WARNING_POP
2095 #endif // 5.15
2096     case Qt::ISODateWithMs:
2097         return QString::asprintf("%02d:%02d:%02d.%03d", hour(), minute(), second(), msec());
2098     case Qt::RFC2822Date:
2099     case Qt::ISODate:
2100     case Qt::TextDate:
2101     default:
2102         return QString::asprintf("%02d:%02d:%02d", hour(), minute(), second());
2103     }
2104 }
2105 
2106 /*!
2107     \fn QString QTime::toString(const QString &format) const
2108     \fn QString QTime::toString(QStringView format) const
2109 
2110     Returns the time as a string. The \a format parameter determines
2111     the format of the result string.
2112 
2113     These expressions may be used:
2114 
2115     \table
2116     \header \li Expression \li Output
2117     \row \li h
2118          \li The hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
2119     \row \li hh
2120          \li The hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
2121     \row \li H
2122          \li The hour without a leading zero (0 to 23, even with AM/PM display)
2123     \row \li HH
2124          \li The hour with a leading zero (00 to 23, even with AM/PM display)
2125     \row \li m \li The minute without a leading zero (0 to 59)
2126     \row \li mm \li The minute with a leading zero (00 to 59)
2127     \row \li s \li The whole second, without any leading zero (0 to 59)
2128     \row \li ss \li The whole second, with a leading zero where applicable (00 to 59)
2129     \row \li z \li The fractional part of the second, to go after a decimal
2130                 point, without trailing zeroes (0 to 999).  Thus "\c{s.z}"
2131                 reports the seconds to full available (millisecond) precision
2132                 without trailing zeroes.
2133     \row \li zzz \li The fractional part of the second, to millisecond
2134                 precision, including trailing zeroes where applicable (000 to 999).
2135     \row \li AP or A
2136          \li Use AM/PM display. \e A/AP will be replaced by an upper-case
2137              version of either QLocale::amText() or QLocale::pmText().
2138     \row \li ap or a
2139          \li Use am/pm display. \e a/ap will be replaced by a lower-case version
2140              of either QLocale::amText() or QLocale::pmText().
2141     \row \li t \li The timezone (for example "CEST")
2142     \endtable
2143 
2144     Any non-empty sequence of characters enclosed in single quotes will be
2145     included verbatim in the output string (stripped of the quotes), even if it
2146     contains formatting characters. Two consecutive single quotes ("''") are
2147     replaced by a single quote in the output. All other characters in the format
2148     string are included verbatim in the output string.
2149 
2150     Formats without separators (e.g. "ddMM") are supported but must be used with
2151     care, as the resulting strings aren't always reliably readable (e.g. if "dM"
2152     produces "212" it could mean either the 2nd of December or the 21st of
2153     February).
2154 
2155     Example format strings (assuming that the QTime is 14:13:09.042 and the system
2156     locale is \c{en_US})
2157 
2158     \table
2159     \header \li Format \li Result
2160     \row \li hh:mm:ss.zzz \li 14:13:09.042
2161     \row \li h:m:s ap     \li 2:13:9 pm
2162     \row \li H:m:s a      \li 14:13:9 pm
2163     \endtable
2164 
2165     If the time is invalid, an empty string will be returned.
2166     If \a format is empty, the default format "hh:mm:ss" is used.
2167 
2168     \note If localized forms of am or pm (the AP, ap, A or a formats) are
2169     desired, please switch to using QLocale::system().toString() as QTime
2170     methods shall change to use English (C locale) at Qt 6.
2171 
2172     \sa fromString(), QDate::toString(), QDateTime::toString(), QLocale::toString()
2173 */
toString(QStringView format) const2174 QString QTime::toString(QStringView format) const
2175 {
2176     return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
2177 }
2178 
2179 #if QT_STRINGVIEW_VERSION < 2
toString(const QString & format) const2180 QString QTime::toString(const QString &format) const
2181 {
2182     return toString(qToStringViewIgnoringNull(format));
2183 }
2184 #endif
2185 
2186 #endif // datestring
2187 
2188 /*!
2189     Sets the time to hour \a h, minute \a m, seconds \a s and
2190     milliseconds \a ms.
2191 
2192     \a h must be in the range 0 to 23, \a m and \a s must be in the
2193     range 0 to 59, and \a ms must be in the range 0 to 999.
2194     Returns \c true if the set time is valid; otherwise returns \c false.
2195 
2196     \sa isValid()
2197 */
2198 
setHMS(int h,int m,int s,int ms)2199 bool QTime::setHMS(int h, int m, int s, int ms)
2200 {
2201     if (!isValid(h,m,s,ms)) {
2202         mds = NullTime;                // make this invalid
2203         return false;
2204     }
2205     mds = (h*SECS_PER_HOUR + m*SECS_PER_MIN + s)*1000 + ms;
2206     return true;
2207 }
2208 
2209 /*!
2210     Returns a QTime object containing a time \a s seconds later
2211     than the time of this object (or earlier if \a s is negative).
2212 
2213     Note that the time will wrap if it passes midnight.
2214 
2215     Returns a null time if this time is invalid.
2216 
2217     Example:
2218 
2219     \snippet code/src_corelib_tools_qdatetime.cpp 5
2220 
2221     \sa addMSecs(), secsTo(), QDateTime::addSecs()
2222 */
2223 
addSecs(int s) const2224 QTime QTime::addSecs(int s) const
2225 {
2226     s %= SECS_PER_DAY;
2227     return addMSecs(s * 1000);
2228 }
2229 
2230 /*!
2231     Returns the number of seconds from this time to \a t.
2232     If \a t is earlier than this time, the number of seconds returned
2233     is negative.
2234 
2235     Because QTime measures time within a day and there are 86400
2236     seconds in a day, the result is always between -86400 and 86400.
2237 
2238     secsTo() does not take into account any milliseconds.
2239 
2240     Returns 0 if either time is invalid.
2241 
2242     \sa addSecs(), QDateTime::secsTo()
2243 */
2244 
secsTo(const QTime & t) const2245 int QTime::secsTo(const QTime &t) const
2246 {
2247     if (!isValid() || !t.isValid())
2248         return 0;
2249 
2250     // Truncate milliseconds as we do not want to consider them.
2251     int ourSeconds = ds() / 1000;
2252     int theirSeconds = t.ds() / 1000;
2253     return theirSeconds - ourSeconds;
2254 }
2255 
2256 /*!
2257     Returns a QTime object containing a time \a ms milliseconds later
2258     than the time of this object (or earlier if \a ms is negative).
2259 
2260     Note that the time will wrap if it passes midnight. See addSecs()
2261     for an example.
2262 
2263     Returns a null time if this time is invalid.
2264 
2265     \sa addSecs(), msecsTo(), QDateTime::addMSecs()
2266 */
2267 
addMSecs(int ms) const2268 QTime QTime::addMSecs(int ms) const
2269 {
2270     QTime t;
2271     if (isValid()) {
2272         if (ms < 0) {
2273             // %,/ not well-defined for -ve, so always work with +ve.
2274             int negdays = (MSECS_PER_DAY - ms) / MSECS_PER_DAY;
2275             t.mds = (ds() + ms + negdays * MSECS_PER_DAY) % MSECS_PER_DAY;
2276         } else {
2277             t.mds = (ds() + ms) % MSECS_PER_DAY;
2278         }
2279     }
2280     return t;
2281 }
2282 
2283 /*!
2284     Returns the number of milliseconds from this time to \a t.
2285     If \a t is earlier than this time, the number of milliseconds returned
2286     is negative.
2287 
2288     Because QTime measures time within a day and there are 86400
2289     seconds in a day, the result is always between -86400000 and
2290     86400000 ms.
2291 
2292     Returns 0 if either time is invalid.
2293 
2294     \sa secsTo(), addMSecs(), QDateTime::msecsTo()
2295 */
2296 
msecsTo(const QTime & t) const2297 int QTime::msecsTo(const QTime &t) const
2298 {
2299     if (!isValid() || !t.isValid())
2300         return 0;
2301     return t.ds() - ds();
2302 }
2303 
2304 
2305 /*!
2306     \fn bool QTime::operator==(const QTime &t) const
2307 
2308     Returns \c true if this time is equal to \a t; otherwise returns \c false.
2309 */
2310 
2311 /*!
2312     \fn bool QTime::operator!=(const QTime &t) const
2313 
2314     Returns \c true if this time is different from \a t; otherwise returns \c false.
2315 */
2316 
2317 /*!
2318     \fn bool QTime::operator<(const QTime &t) const
2319 
2320     Returns \c true if this time is earlier than \a t; otherwise returns \c false.
2321 */
2322 
2323 /*!
2324     \fn bool QTime::operator<=(const QTime &t) const
2325 
2326     Returns \c true if this time is earlier than or equal to \a t;
2327     otherwise returns \c false.
2328 */
2329 
2330 /*!
2331     \fn bool QTime::operator>(const QTime &t) const
2332 
2333     Returns \c true if this time is later than \a t; otherwise returns \c false.
2334 */
2335 
2336 /*!
2337     \fn bool QTime::operator>=(const QTime &t) const
2338 
2339     Returns \c true if this time is later than or equal to \a t;
2340     otherwise returns \c false.
2341 */
2342 
2343 /*!
2344     \fn QTime QTime::fromMSecsSinceStartOfDay(int msecs)
2345 
2346     Returns a new QTime instance with the time set to the number of \a msecs
2347     since the start of the day, i.e. since 00:00:00.
2348 
2349     If \a msecs falls outside the valid range an invalid QTime will be returned.
2350 
2351     \sa msecsSinceStartOfDay()
2352 */
2353 
2354 /*!
2355     \fn int QTime::msecsSinceStartOfDay() const
2356 
2357     Returns the number of msecs since the start of the day, i.e. since 00:00:00.
2358 
2359     \sa fromMSecsSinceStartOfDay()
2360 */
2361 
2362 /*!
2363     \fn QTime::currentTime()
2364 
2365     Returns the current time as reported by the system clock.
2366 
2367     Note that the accuracy depends on the accuracy of the underlying
2368     operating system; not all systems provide 1-millisecond accuracy.
2369 
2370     Furthermore, currentTime() only increases within each day; it shall drop by
2371     24 hours each time midnight passes; and, beside this, changes in it may not
2372     correspond to elapsed time, if a daylight-saving transition intervenes.
2373 
2374     \sa QDateTime::currentDateTime(), QDateTime::currentDateTimeUtc()
2375 */
2376 
2377 #if QT_CONFIG(datestring) // depends on, so implies, textdate
2378 
fromIsoTimeString(QStringView string,Qt::DateFormat format,bool * isMidnight24)2379 static QTime fromIsoTimeString(QStringView string, Qt::DateFormat format, bool *isMidnight24)
2380 {
2381     if (isMidnight24)
2382         *isMidnight24 = false;
2383 
2384     const int size = string.size();
2385     if (size < 5 || string.at(2) != QLatin1Char(':'))
2386         return QTime();
2387 
2388     ParsedInt hour = readInt(string.mid(0, 2));
2389     ParsedInt minute = readInt(string.mid(3, 2));
2390     if (!hour.ok || !minute.ok)
2391         return QTime();
2392     // FIXME: ISO 8601 allows [,.]\d+ after hour, just as it does after minute
2393 
2394     int second = 0;
2395     int msec = 0;
2396 
2397     if (size == 5) {
2398         // HH:mm format
2399         second = 0;
2400         msec = 0;
2401     } else if (string.at(5) == QLatin1Char(',') || string.at(5) == QLatin1Char('.')) {
2402         if (format == Qt::TextDate)
2403             return QTime();
2404         // ISODate HH:mm.ssssss format
2405         // We only want 5 digits worth of fraction of minute. This follows the existing
2406         // behavior that determines how milliseconds are read; 4 millisecond digits are
2407         // read and then rounded to 3. If we read at most 5 digits for fraction of minute,
2408         // the maximum amount of millisecond digits it will expand to once converted to
2409         // seconds is 4. E.g. 12:34,99999 will expand to 12:34:59.9994. The milliseconds
2410         // will then be rounded up AND clamped to 999.
2411 
2412         const QStringView minuteFractionStr = string.mid(6, qMin(qsizetype(5), string.size() - 6));
2413         const ParsedInt parsed = readInt(minuteFractionStr);
2414         if (!parsed.ok)
2415             return QTime();
2416         const float secondWithMs
2417             = double(parsed.value) * 60 / (std::pow(double(10), minuteFractionStr.size()));
2418 
2419         second = std::floor(secondWithMs);
2420         const float secondFraction = secondWithMs - second;
2421         msec = qMin(qRound(secondFraction * 1000.0), 999);
2422     } else if (string.at(5) == QLatin1Char(':')) {
2423         // HH:mm:ss or HH:mm:ss.zzz
2424         const ParsedInt parsed = readInt(string.mid(6, qMin(qsizetype(2), string.size() - 6)));
2425         if (!parsed.ok)
2426             return QTime();
2427         second = parsed.value;
2428         if (size <= 8) {
2429             // No fractional part to read
2430         } else if (string.at(8) == QLatin1Char(',') || string.at(8) == QLatin1Char('.')) {
2431             QStringView msecStr(string.mid(9, qMin(qsizetype(4), string.size() - 9)));
2432             bool ok = true;
2433             // Can't use readInt() here, as we *do* allow trailing space - but not leading:
2434             if (!msecStr.isEmpty() && !msecStr.at(0).isDigit())
2435                 return QTime();
2436             msecStr = msecStr.trimmed();
2437             int msecInt = msecStr.isEmpty() ? 0 : QLocale::c().toInt(msecStr, &ok);
2438             if (!ok)
2439                 return QTime();
2440             const double secondFraction(msecInt / (std::pow(double(10), msecStr.size())));
2441             msec = qMin(qRound(secondFraction * 1000.0), 999);
2442         } else {
2443 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0) // behavior change
2444             // Stray cruft after date-time: tolerate trailing space, but nothing else.
2445             for (const auto &ch : string.mid(8)) {
2446                 if (!ch.isSpace())
2447                     return QTime();
2448             }
2449 #endif
2450         }
2451     } else {
2452         return QTime();
2453     }
2454 
2455     const bool isISODate = format == Qt::ISODate || format == Qt::ISODateWithMs;
2456     if (isISODate && hour.value == 24 && minute.value == 0 && second == 0 && msec == 0) {
2457         if (isMidnight24)
2458             *isMidnight24 = true;
2459         hour.value = 0;
2460     }
2461 
2462     return QTime(hour.value, minute.value, second, msec);
2463 }
2464 
2465 /*!
2466     Returns the time represented in the \a string as a QTime using the
2467     \a format given, or an invalid time if this is not possible.
2468 
2469     Note that fromString() uses a "C" locale encoded string to convert
2470     milliseconds to a float value. If the default locale is not "C",
2471     this may result in two conversion attempts (if the conversion
2472     fails for the default locale). This should be considered an
2473     implementation detail.
2474 
2475 
2476     \note Support for localized dates, including the format options
2477     Qt::SystemLocaleDate, Qt::SystemLocaleShortDate, Qt::SystemLocaleLongDate,
2478     Qt::LocaleDate, Qt::DefaultLocaleShortDate, and Qt::DefaultLocaleLongDate,
2479     shall be removed in Qt 6. Use QLocale::toTime() instead.
2480 
2481     \sa toString(), QLocale::toTime()
2482 */
fromString(const QString & string,Qt::DateFormat format)2483 QTime QTime::fromString(const QString &string, Qt::DateFormat format)
2484 {
2485     if (string.isEmpty())
2486         return QTime();
2487 
2488     switch (format) {
2489 #if QT_DEPRECATED_SINCE(5, 15)
2490 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
2491     case Qt::SystemLocaleDate:
2492     case Qt::SystemLocaleShortDate:
2493         return QLocale::system().toTime(string, QLocale::ShortFormat);
2494     case Qt::SystemLocaleLongDate:
2495         return QLocale::system().toTime(string, QLocale::LongFormat);
2496     case Qt::LocaleDate:
2497     case Qt::DefaultLocaleShortDate:
2498         return QLocale().toTime(string, QLocale::ShortFormat);
2499     case Qt::DefaultLocaleLongDate:
2500         return QLocale().toTime(string, QLocale::LongFormat);
2501 QT_WARNING_POP
2502 #endif // 5.15
2503     case Qt::RFC2822Date:
2504         return rfcDateImpl(string).time;
2505     case Qt::ISODate:
2506     case Qt::ISODateWithMs:
2507     case Qt::TextDate:
2508     default:
2509         return fromIsoTimeString(QStringView(string), format, nullptr);
2510     }
2511 }
2512 
2513 /*!
2514     Returns the QTime represented by the \a string, using the \a
2515     format given, or an invalid time if the string cannot be parsed.
2516 
2517     These expressions may be used for the format:
2518 
2519     \table
2520     \header \li Expression \li Output
2521     \row \li h
2522          \li The hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
2523     \row \li hh
2524          \li The hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
2525     \row \li H
2526          \li The hour without a leading zero (0 to 23, even with AM/PM display)
2527     \row \li HH
2528          \li The hour with a leading zero (00 to 23, even with AM/PM display)
2529     \row \li m \li The minute without a leading zero (0 to 59)
2530     \row \li mm \li The minute with a leading zero (00 to 59)
2531     \row \li s \li The whole second, without any leading zero (0 to 59)
2532     \row \li ss \li The whole second, with a leading zero where applicable (00 to 59)
2533     \row \li z \li The fractional part of the second, to go after a decimal
2534                 point, without trailing zeroes (0 to 999).  Thus "\c{s.z}"
2535                 reports the seconds to full available (millisecond) precision
2536                 without trailing zeroes.
2537     \row \li zzz \li The fractional part of the second, to millisecond
2538                 precision, including trailing zeroes where applicable (000 to 999).
2539     \row \li AP or A
2540          \li Interpret as an AM/PM time. \e A/AP will match an upper-case
2541              version of either QLocale::amText() or QLocale::pmText().
2542     \row \li ap or a
2543          \li Interpret as an am/pm time. \e a/ap will match a lower-case version
2544              of either QLocale::amText() or QLocale::pmText().
2545     \endtable
2546 
2547     All other input characters will be treated as text. Any non-empty sequence
2548     of characters enclosed in single quotes will also be treated (stripped of
2549     the quotes) as text and not be interpreted as expressions.
2550 
2551     \snippet code/src_corelib_tools_qdatetime.cpp 6
2552 
2553     If the format is not satisfied, an invalid QTime is returned.
2554     Expressions that do not expect leading zeroes to be given (h, m, s
2555     and z) are greedy. This means that they will use two digits even if
2556     this puts them outside the range of accepted values and leaves too
2557     few digits for other sections. For example, the following string
2558     could have meant 00:07:10, but the m will grab two digits, resulting
2559     in an invalid time:
2560 
2561     \snippet code/src_corelib_tools_qdatetime.cpp 7
2562 
2563     Any field that is not represented in the format will be set to zero.
2564     For example:
2565 
2566     \snippet code/src_corelib_tools_qdatetime.cpp 8
2567 
2568     \note If localized forms of am or pm (the AP, ap, A or a formats) are used,
2569     please switch to using QLocale::system().toTime() as QTime methods shall
2570     change to only recognize English (C locale) at Qt 6.
2571 
2572     \sa toString(), QDateTime::fromString(), QDate::fromString(),
2573     QLocale::toTime()
2574 */
2575 
fromString(const QString & string,const QString & format)2576 QTime QTime::fromString(const QString &string, const QString &format)
2577 {
2578     QTime time;
2579 #if QT_CONFIG(datetimeparser)
2580     QDateTimeParser dt(QMetaType::QTime, QDateTimeParser::FromString, QCalendar());
2581     // dt.setDefaultLocale(QLocale::c()); ### Qt 6
2582     if (dt.parseFormat(format))
2583         dt.fromString(string, nullptr, &time);
2584 #else
2585     Q_UNUSED(string);
2586     Q_UNUSED(format);
2587 #endif
2588     return time;
2589 }
2590 
2591 #endif // datestring
2592 
2593 
2594 /*!
2595     \overload
2596 
2597     Returns \c true if the specified time is valid; otherwise returns
2598     false.
2599 
2600     The time is valid if \a h is in the range 0 to 23, \a m and
2601     \a s are in the range 0 to 59, and \a ms is in the range 0 to 999.
2602 
2603     Example:
2604 
2605     \snippet code/src_corelib_tools_qdatetime.cpp 9
2606 */
2607 
isValid(int h,int m,int s,int ms)2608 bool QTime::isValid(int h, int m, int s, int ms)
2609 {
2610     return (uint)h < 24 && (uint)m < 60 && (uint)s < 60 && (uint)ms < 1000;
2611 }
2612 
2613 #if QT_DEPRECATED_SINCE(5, 14) // ### Qt 6: remove
2614 /*!
2615     Sets this time to the current time. This is practical for timing:
2616 
2617     \snippet code/src_corelib_tools_qdatetime.cpp 10
2618 
2619     \sa restart(), elapsed(), currentTime()
2620 */
2621 
start()2622 void QTime::start()
2623 {
2624     *this = currentTime();
2625 }
2626 
2627 /*!
2628     Sets this time to the current time and returns the number of
2629     milliseconds that have elapsed since the last time start() or
2630     restart() was called.
2631 
2632     This function is guaranteed to be atomic and is thus very handy
2633     for repeated measurements. Call start() to start the first
2634     measurement, and restart() for each later measurement.
2635 
2636     Note that the counter wraps to zero 24 hours after the last call
2637     to start() or restart().
2638 
2639     \warning If the system's clock setting has been changed since the
2640     last time start() or restart() was called, the result is
2641     undefined. This can happen when daylight-saving time is turned on
2642     or off.
2643 
2644     \sa start(), elapsed(), currentTime()
2645 */
2646 
restart()2647 int QTime::restart()
2648 {
2649     QTime t = currentTime();
2650     int n = msecsTo(t);
2651     if (n < 0)                                // passed midnight
2652         n += 86400*1000;
2653     *this = t;
2654     return n;
2655 }
2656 
2657 /*!
2658     Returns the number of milliseconds that have elapsed since the
2659     last time start() or restart() was called.
2660 
2661     Note that the counter wraps to zero 24 hours after the last call
2662     to start() or restart.
2663 
2664     Note that the accuracy depends on the accuracy of the underlying
2665     operating system; not all systems provide 1-millisecond accuracy.
2666 
2667     \warning If the system's clock setting has been changed since the
2668     last time start() or restart() was called, the result is
2669     undefined. This can happen when daylight-saving time is turned on
2670     or off.
2671 
2672     \sa start(), restart()
2673 */
2674 
elapsed() const2675 int QTime::elapsed() const
2676 {
2677     int n = msecsTo(currentTime());
2678     if (n < 0)                                // passed midnight
2679         n += 86400 * 1000;
2680     return n;
2681 }
2682 #endif // Use QElapsedTimer instead !
2683 
2684 /*****************************************************************************
2685   QDateTime static helper functions
2686  *****************************************************************************/
2687 
2688 // get the types from QDateTime (through QDateTimePrivate)
2689 typedef QDateTimePrivate::QDateTimeShortData ShortData;
2690 typedef QDateTimePrivate::QDateTimeData QDateTimeData;
2691 
2692 // Returns the platform variant of timezone, i.e. the standard time offset
2693 // The timezone external variable is documented as always holding the
2694 // Standard Time offset as seconds west of Greenwich, i.e. UTC+01:00 is -3600
2695 // Note this may not be historicaly accurate.
2696 // Relies on tzset, mktime, or localtime having been called to populate timezone
qt_timezone()2697 static int qt_timezone()
2698 {
2699 #if defined(_MSC_VER)
2700         long offset;
2701         _get_timezone(&offset);
2702         return offset;
2703 #elif defined(Q_OS_BSD4) && !defined(Q_OS_DARWIN)
2704         time_t clock = time(NULL);
2705         struct tm t;
2706         localtime_r(&clock, &t);
2707         // QTBUG-36080 Workaround for systems without the POSIX timezone
2708         // variable. This solution is not very efficient but fixing it is up to
2709         // the libc implementations.
2710         //
2711         // tm_gmtoff has some important differences compared to the timezone
2712         // variable:
2713         // - It returns the number of seconds east of UTC, and we want the
2714         //   number of seconds west of UTC.
2715         // - It also takes DST into account, so we need to adjust it to always
2716         //   get the Standard Time offset.
2717         return -t.tm_gmtoff + (t.tm_isdst ? (long)SECS_PER_HOUR : 0L);
2718 #elif defined(Q_OS_INTEGRITY) || defined(Q_OS_RTEMS)
2719         return 0;
2720 #else
2721         return timezone;
2722 #endif // Q_OS_WIN
2723 }
2724 
2725 // Returns the tzname, assume tzset has been called already
qt_tzname(QDateTimePrivate::DaylightStatus daylightStatus)2726 static QString qt_tzname(QDateTimePrivate::DaylightStatus daylightStatus)
2727 {
2728     int isDst = (daylightStatus == QDateTimePrivate::DaylightTime) ? 1 : 0;
2729 #if defined(Q_CC_MSVC)
2730     size_t s = 0;
2731     char name[512];
2732     if (_get_tzname(&s, name, 512, isDst))
2733         return QString();
2734     return QString::fromLocal8Bit(name);
2735 #else
2736     return QString::fromLocal8Bit(tzname[isDst]);
2737 #endif // Q_OS_WIN
2738 }
2739 
2740 #if QT_CONFIG(datetimeparser)
2741 /*
2742   \internal
2743   Implemented here to share qt_tzname()
2744 */
startsWithLocalTimeZone(const QStringRef name)2745 int QDateTimeParser::startsWithLocalTimeZone(const QStringRef name)
2746 {
2747     QDateTimePrivate::DaylightStatus zones[2] = {
2748         QDateTimePrivate::StandardTime,
2749         QDateTimePrivate::DaylightTime
2750     };
2751     for (const auto z : zones) {
2752         QString zone(qt_tzname(z));
2753         if (name.startsWith(zone))
2754             return zone.size();
2755     }
2756     return 0;
2757 }
2758 #endif // datetimeparser
2759 
2760 // Calls the platform variant of mktime for the given date, time and daylightStatus,
2761 // and updates the date, time, daylightStatus and abbreviation with the returned values
2762 // If the date falls outside the 1970 to 2037 range supported by mktime / time_t
2763 // then null date/time will be returned, you should adjust the date first if
2764 // you need a guaranteed result.
qt_mktime(QDate * date,QTime * time,QDateTimePrivate::DaylightStatus * daylightStatus,QString * abbreviation,bool * ok=nullptr)2765 static qint64 qt_mktime(QDate *date, QTime *time, QDateTimePrivate::DaylightStatus *daylightStatus,
2766                         QString *abbreviation, bool *ok = nullptr)
2767 {
2768     const qint64 msec = time->msec();
2769     int yy, mm, dd;
2770     date->getDate(&yy, &mm, &dd);
2771 
2772     // All other platforms provide standard C library time functions
2773     tm local;
2774     memset(&local, 0, sizeof(local)); // tm_[wy]day plus any non-standard fields
2775     local.tm_sec = time->second();
2776     local.tm_min = time->minute();
2777     local.tm_hour = time->hour();
2778     local.tm_mday = dd;
2779     local.tm_mon = mm - 1;
2780     local.tm_year = yy - 1900;
2781     if (daylightStatus)
2782         local.tm_isdst = int(*daylightStatus);
2783     else
2784         local.tm_isdst = -1;
2785 
2786 #if defined(Q_OS_WIN)
2787     int hh = local.tm_hour;
2788 #endif // Q_OS_WIN
2789     time_t secsSinceEpoch = qMkTime(&local);
2790     if (secsSinceEpoch != time_t(-1)) {
2791         *date = QDate(local.tm_year + 1900, local.tm_mon + 1, local.tm_mday);
2792         *time = QTime(local.tm_hour, local.tm_min, local.tm_sec, msec);
2793 #if defined(Q_OS_WIN)
2794         // Windows mktime for the missing hour subtracts 1 hour from the time
2795         // instead of adding 1 hour.  If time differs and is standard time then
2796         // this has happened, so add 2 hours to the time and 1 hour to the msecs
2797         if (local.tm_isdst == 0 && local.tm_hour != hh) {
2798             if (time->hour() >= 22)
2799                 *date = date->addDays(1);
2800             *time = time->addSecs(2 * SECS_PER_HOUR);
2801             secsSinceEpoch += SECS_PER_HOUR;
2802             local.tm_isdst = 1;
2803         }
2804 #endif // Q_OS_WIN
2805         if (local.tm_isdst >= 1) {
2806             if (daylightStatus)
2807                 *daylightStatus = QDateTimePrivate::DaylightTime;
2808             if (abbreviation)
2809                 *abbreviation = qt_tzname(QDateTimePrivate::DaylightTime);
2810         } else if (local.tm_isdst == 0) {
2811             if (daylightStatus)
2812                 *daylightStatus = QDateTimePrivate::StandardTime;
2813             if (abbreviation)
2814                 *abbreviation = qt_tzname(QDateTimePrivate::StandardTime);
2815         } else {
2816             if (daylightStatus)
2817                 *daylightStatus = QDateTimePrivate::UnknownDaylightTime;
2818             if (abbreviation)
2819                 *abbreviation = qt_tzname(QDateTimePrivate::StandardTime);
2820         }
2821         if (ok)
2822             *ok = true;
2823     } else {
2824         *date = QDate();
2825         *time = QTime();
2826         if (daylightStatus)
2827             *daylightStatus = QDateTimePrivate::UnknownDaylightTime;
2828         if (abbreviation)
2829             *abbreviation = QString();
2830         if (ok)
2831             *ok = false;
2832     }
2833 
2834     return ((qint64)secsSinceEpoch * 1000) + msec;
2835 }
2836 
2837 // Calls the platform variant of localtime for the given msecs, and updates
2838 // the date, time, and DST status with the returned values.
qt_localtime(qint64 msecsSinceEpoch,QDate * localDate,QTime * localTime,QDateTimePrivate::DaylightStatus * daylightStatus)2839 static bool qt_localtime(qint64 msecsSinceEpoch, QDate *localDate, QTime *localTime,
2840                          QDateTimePrivate::DaylightStatus *daylightStatus)
2841 {
2842     const time_t secsSinceEpoch = msecsSinceEpoch / 1000;
2843     const int msec = msecsSinceEpoch % 1000;
2844 
2845     tm local;
2846     bool valid = false;
2847 
2848     // localtime() is specified to work as if it called tzset().
2849     // localtime_r() does not have this constraint, so make an explicit call.
2850     // The explicit call should also request the timezone info be re-parsed.
2851     qTzSet();
2852 #if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
2853     // Use the reentrant version of localtime() where available
2854     // as is thread-safe and doesn't use a shared static data area
2855     tm *res = nullptr;
2856     res = localtime_r(&secsSinceEpoch, &local);
2857     if (res)
2858         valid = true;
2859 #elif defined(Q_CC_MSVC)
2860     if (!_localtime64_s(&local, &secsSinceEpoch))
2861         valid = true;
2862 #else
2863     // Returns shared static data which may be overwritten at any time
2864     // So copy the result asap
2865     tm *res = nullptr;
2866     res = localtime(&secsSinceEpoch);
2867     if (res) {
2868         local = *res;
2869         valid = true;
2870     }
2871 #endif
2872     if (valid) {
2873         *localDate = QDate(local.tm_year + 1900, local.tm_mon + 1, local.tm_mday);
2874         *localTime = QTime(local.tm_hour, local.tm_min, local.tm_sec, msec);
2875         if (daylightStatus) {
2876             if (local.tm_isdst > 0)
2877                 *daylightStatus = QDateTimePrivate::DaylightTime;
2878             else if (local.tm_isdst < 0)
2879                 *daylightStatus = QDateTimePrivate::UnknownDaylightTime;
2880             else
2881                 *daylightStatus = QDateTimePrivate::StandardTime;
2882         }
2883         return true;
2884     } else {
2885         *localDate = QDate();
2886         *localTime = QTime();
2887         if (daylightStatus)
2888             *daylightStatus = QDateTimePrivate::UnknownDaylightTime;
2889         return false;
2890     }
2891 }
2892 
2893 // Converts an msecs value into a date and time
msecsToTime(qint64 msecs,QDate * date,QTime * time)2894 static void msecsToTime(qint64 msecs, QDate *date, QTime *time)
2895 {
2896     qint64 jd = JULIAN_DAY_FOR_EPOCH;
2897     qint64 ds = 0;
2898 
2899     if (msecs >= MSECS_PER_DAY || msecs <= -MSECS_PER_DAY) {
2900         jd += msecs / MSECS_PER_DAY;
2901         msecs %= MSECS_PER_DAY;
2902     }
2903 
2904     if (msecs < 0) {
2905         ds = MSECS_PER_DAY - msecs - 1;
2906         jd -= ds / MSECS_PER_DAY;
2907         ds = ds % MSECS_PER_DAY;
2908         ds = MSECS_PER_DAY - ds - 1;
2909     } else {
2910         ds = msecs;
2911     }
2912 
2913     if (date)
2914         *date = QDate::fromJulianDay(jd);
2915     if (time)
2916         *time = QTime::fromMSecsSinceStartOfDay(ds);
2917 }
2918 
2919 // Converts a date/time value into msecs
timeToMSecs(QDate date,QTime time)2920 static qint64 timeToMSecs(QDate date, QTime time)
2921 {
2922     return ((date.toJulianDay() - JULIAN_DAY_FOR_EPOCH) * MSECS_PER_DAY)
2923            + time.msecsSinceStartOfDay();
2924 }
2925 
2926 // Convert an MSecs Since Epoch into Local Time
epochMSecsToLocalTime(qint64 msecs,QDate * localDate,QTime * localTime,QDateTimePrivate::DaylightStatus * daylightStatus=nullptr)2927 static bool epochMSecsToLocalTime(qint64 msecs, QDate *localDate, QTime *localTime,
2928                                   QDateTimePrivate::DaylightStatus *daylightStatus = nullptr)
2929 {
2930     if (msecs < 0) {
2931         // Docs state any LocalTime before 1970-01-01 will *not* have any Daylight Time applied
2932         // Instead just use the standard offset from UTC to convert to UTC time
2933         qTzSet();
2934         msecsToTime(msecs - qt_timezone() * 1000, localDate, localTime);
2935         if (daylightStatus)
2936             *daylightStatus = QDateTimePrivate::StandardTime;
2937         return true;
2938     } else if (msecs > (qint64(TIME_T_MAX) * 1000)) {
2939         // Docs state any LocalTime after 2037-12-31 *will* have any DST applied
2940         // but this may fall outside the supported time_t range, so need to fake it.
2941         // Use existing method to fake the conversion, but this is deeply flawed as it may
2942         // apply the conversion from the wrong day number, e.g. if rule is last Sunday of month
2943         // TODO Use QTimeZone when available to apply the future rule correctly
2944         QDate utcDate;
2945         QTime utcTime;
2946         msecsToTime(msecs, &utcDate, &utcTime);
2947         int year, month, day;
2948         utcDate.getDate(&year, &month, &day);
2949         // 2037 is not a leap year, so make sure date isn't Feb 29
2950         if (month == 2 && day == 29)
2951             --day;
2952         QDate fakeDate(2037, month, day);
2953         qint64 fakeMsecs = QDateTime(fakeDate, utcTime, Qt::UTC).toMSecsSinceEpoch();
2954         bool res = qt_localtime(fakeMsecs, localDate, localTime, daylightStatus);
2955         *localDate = localDate->addDays(fakeDate.daysTo(utcDate));
2956         return res;
2957     } else {
2958         // Falls inside time_t suported range so can use localtime
2959         return qt_localtime(msecs, localDate, localTime, daylightStatus);
2960     }
2961 }
2962 
2963 // Convert a LocalTime expressed in local msecs encoding and the corresponding
2964 // DST status into a UTC epoch msecs. Optionally populate the returned
2965 // values from mktime for the adjusted local date and time.
localMSecsToEpochMSecs(qint64 localMsecs,QDateTimePrivate::DaylightStatus * daylightStatus,QDate * localDate=nullptr,QTime * localTime=nullptr,QString * abbreviation=nullptr)2966 static qint64 localMSecsToEpochMSecs(qint64 localMsecs,
2967                                      QDateTimePrivate::DaylightStatus *daylightStatus,
2968                                      QDate *localDate = nullptr, QTime *localTime = nullptr,
2969                                      QString *abbreviation = nullptr)
2970 {
2971     QDate dt;
2972     QTime tm;
2973     msecsToTime(localMsecs, &dt, &tm);
2974 
2975     const qint64 msecsMax = qint64(TIME_T_MAX) * 1000;
2976 
2977     if (localMsecs <= qint64(MSECS_PER_DAY)) {
2978 
2979         // Docs state any LocalTime before 1970-01-01 will *not* have any DST applied
2980 
2981         // First, if localMsecs is within +/- 1 day of minimum time_t try mktime in case it does
2982         // fall after minimum and needs proper DST conversion
2983         if (localMsecs >= -qint64(MSECS_PER_DAY)) {
2984             bool valid;
2985             qint64 utcMsecs = qt_mktime(&dt, &tm, daylightStatus, abbreviation, &valid);
2986             if (valid && utcMsecs >= 0) {
2987                 // mktime worked and falls in valid range, so use it
2988                 if (localDate)
2989                     *localDate = dt;
2990                 if (localTime)
2991                     *localTime = tm;
2992                 return utcMsecs;
2993             }
2994         } else {
2995             // If we don't call mktime then need to call tzset to get offset
2996             qTzSet();
2997         }
2998         // Time is clearly before 1970-01-01 so just use standard offset to convert
2999         qint64 utcMsecs = localMsecs + qt_timezone() * 1000;
3000         if (localDate || localTime)
3001             msecsToTime(localMsecs, localDate, localTime);
3002         if (daylightStatus)
3003             *daylightStatus = QDateTimePrivate::StandardTime;
3004         if (abbreviation)
3005             *abbreviation = qt_tzname(QDateTimePrivate::StandardTime);
3006         return utcMsecs;
3007 
3008     } else if (localMsecs >= msecsMax - MSECS_PER_DAY) {
3009 
3010         // Docs state any LocalTime after 2037-12-31 *will* have any DST applied
3011         // but this may fall outside the supported time_t range, so need to fake it.
3012 
3013         // First, if localMsecs is within +/- 1 day of maximum time_t try mktime in case it does
3014         // fall before maximum and can use proper DST conversion
3015         if (localMsecs <= msecsMax + MSECS_PER_DAY) {
3016             bool valid;
3017             qint64 utcMsecs = qt_mktime(&dt, &tm, daylightStatus, abbreviation, &valid);
3018             if (valid && utcMsecs <= msecsMax) {
3019                 // mktime worked and falls in valid range, so use it
3020                 if (localDate)
3021                     *localDate = dt;
3022                 if (localTime)
3023                     *localTime = tm;
3024                 return utcMsecs;
3025             }
3026         }
3027         // Use existing method to fake the conversion, but this is deeply flawed as it may
3028         // apply the conversion from the wrong day number, e.g. if rule is last Sunday of month
3029         // TODO Use QTimeZone when available to apply the future rule correctly
3030         int year, month, day;
3031         dt.getDate(&year, &month, &day);
3032         // 2037 is not a leap year, so make sure date isn't Feb 29
3033         if (month == 2 && day == 29)
3034             --day;
3035         QDate fakeDate(2037, month, day);
3036         qint64 fakeDiff = fakeDate.daysTo(dt);
3037         qint64 utcMsecs = qt_mktime(&fakeDate, &tm, daylightStatus, abbreviation);
3038         if (localDate)
3039             *localDate = fakeDate.addDays(fakeDiff);
3040         if (localTime)
3041             *localTime = tm;
3042         QDate utcDate;
3043         QTime utcTime;
3044         msecsToTime(utcMsecs, &utcDate, &utcTime);
3045         utcDate = utcDate.addDays(fakeDiff);
3046         utcMsecs = timeToMSecs(utcDate, utcTime);
3047         return utcMsecs;
3048 
3049     } else {
3050 
3051         // Clearly falls inside 1970-2037 suported range so can use mktime
3052         qint64 utcMsecs = qt_mktime(&dt, &tm, daylightStatus, abbreviation);
3053         if (localDate)
3054             *localDate = dt;
3055         if (localTime)
3056             *localTime = tm;
3057         return utcMsecs;
3058 
3059     }
3060 }
3061 
specCanBeSmall(Qt::TimeSpec spec)3062 static inline bool specCanBeSmall(Qt::TimeSpec spec)
3063 {
3064     return spec == Qt::LocalTime || spec == Qt::UTC;
3065 }
3066 
msecsCanBeSmall(qint64 msecs)3067 static inline bool msecsCanBeSmall(qint64 msecs)
3068 {
3069     if (!QDateTimeData::CanBeSmall)
3070         return false;
3071 
3072     ShortData sd;
3073     sd.msecs = qintptr(msecs);
3074     return sd.msecs == msecs;
3075 }
3076 
3077 static Q_DECL_CONSTEXPR inline
mergeSpec(QDateTimePrivate::StatusFlags status,Qt::TimeSpec spec)3078 QDateTimePrivate::StatusFlags mergeSpec(QDateTimePrivate::StatusFlags status, Qt::TimeSpec spec)
3079 {
3080     return QDateTimePrivate::StatusFlags((status & ~QDateTimePrivate::TimeSpecMask) |
3081                                          (int(spec) << QDateTimePrivate::TimeSpecShift));
3082 }
3083 
extractSpec(QDateTimePrivate::StatusFlags status)3084 static Q_DECL_CONSTEXPR inline Qt::TimeSpec extractSpec(QDateTimePrivate::StatusFlags status)
3085 {
3086     return Qt::TimeSpec((status & QDateTimePrivate::TimeSpecMask) >> QDateTimePrivate::TimeSpecShift);
3087 }
3088 
3089 // Set the Daylight Status if LocalTime set via msecs
3090 static Q_DECL_RELAXED_CONSTEXPR inline QDateTimePrivate::StatusFlags
mergeDaylightStatus(QDateTimePrivate::StatusFlags sf,QDateTimePrivate::DaylightStatus status)3091 mergeDaylightStatus(QDateTimePrivate::StatusFlags sf, QDateTimePrivate::DaylightStatus status)
3092 {
3093     sf &= ~QDateTimePrivate::DaylightMask;
3094     if (status == QDateTimePrivate::DaylightTime) {
3095         sf |= QDateTimePrivate::SetToDaylightTime;
3096     } else if (status == QDateTimePrivate::StandardTime) {
3097         sf |= QDateTimePrivate::SetToStandardTime;
3098     }
3099     return sf;
3100 }
3101 
3102 // Get the DST Status if LocalTime set via msecs
3103 static Q_DECL_RELAXED_CONSTEXPR inline
extractDaylightStatus(QDateTimePrivate::StatusFlags status)3104 QDateTimePrivate::DaylightStatus extractDaylightStatus(QDateTimePrivate::StatusFlags status)
3105 {
3106     if (status & QDateTimePrivate::SetToDaylightTime)
3107         return QDateTimePrivate::DaylightTime;
3108     if (status & QDateTimePrivate::SetToStandardTime)
3109         return QDateTimePrivate::StandardTime;
3110     return QDateTimePrivate::UnknownDaylightTime;
3111 }
3112 
getMSecs(const QDateTimeData & d)3113 static inline qint64 getMSecs(const QDateTimeData &d)
3114 {
3115     if (d.isShort()) {
3116         // same as, but producing better code
3117         //return d.data.msecs;
3118         return qintptr(d.d) >> 8;
3119     }
3120     return d->m_msecs;
3121 }
3122 
getStatus(const QDateTimeData & d)3123 static inline QDateTimePrivate::StatusFlags getStatus(const QDateTimeData &d)
3124 {
3125     if (d.isShort()) {
3126         // same as, but producing better code
3127         //return StatusFlag(d.data.status);
3128         return QDateTimePrivate::StatusFlag(qintptr(d.d) & 0xFF);
3129     }
3130     return d->m_status;
3131 }
3132 
getSpec(const QDateTimeData & d)3133 static inline Qt::TimeSpec getSpec(const QDateTimeData &d)
3134 {
3135     return extractSpec(getStatus(d));
3136 }
3137 
3138 #if QT_CONFIG(timezone)
setUtcOffsetByTZ(qint64 atMSecsSinceEpoch)3139 void QDateTimePrivate::setUtcOffsetByTZ(qint64 atMSecsSinceEpoch)
3140 {
3141     m_offsetFromUtc = m_timeZone.d->offsetFromUtc(atMSecsSinceEpoch);
3142 }
3143 #endif
3144 
3145 // Refresh the LocalTime validity and offset
refreshDateTime(QDateTimeData & d)3146 static void refreshDateTime(QDateTimeData &d)
3147 {
3148     auto status = getStatus(d);
3149     const auto spec = extractSpec(status);
3150     const qint64 msecs = getMSecs(d);
3151     qint64 epochMSecs = 0;
3152     int offsetFromUtc = 0;
3153     QDate testDate;
3154     QTime testTime;
3155     Q_ASSERT(spec == Qt::TimeZone || spec == Qt::LocalTime);
3156 
3157 #if QT_CONFIG(timezone)
3158     // If not valid time zone then is invalid
3159     if (spec == Qt::TimeZone) {
3160         if (!d->m_timeZone.isValid()) {
3161             status &= ~QDateTimePrivate::ValidDateTime;
3162         } else {
3163             epochMSecs = QDateTimePrivate::zoneMSecsToEpochMSecs(msecs, d->m_timeZone, extractDaylightStatus(status), &testDate, &testTime);
3164             d->setUtcOffsetByTZ(epochMSecs);
3165         }
3166     }
3167 #endif // timezone
3168 
3169     // If not valid date and time then is invalid
3170     if (!(status & QDateTimePrivate::ValidDate) || !(status & QDateTimePrivate::ValidTime)) {
3171         status &= ~QDateTimePrivate::ValidDateTime;
3172         if (status & QDateTimePrivate::ShortData) {
3173             d.data.status = status;
3174         } else {
3175             d->m_status = status;
3176             d->m_offsetFromUtc = 0;
3177         }
3178         return;
3179     }
3180 
3181     // We have a valid date and time and a Qt::LocalTime or Qt::TimeZone that needs calculating
3182     // LocalTime and TimeZone might fall into a "missing" DST transition hour
3183     // Calling toEpochMSecs will adjust the returned date/time if it does
3184     if (spec == Qt::LocalTime) {
3185         auto dstStatus = extractDaylightStatus(status);
3186         epochMSecs = localMSecsToEpochMSecs(msecs, &dstStatus, &testDate, &testTime);
3187         status = mergeDaylightStatus(status, dstStatus);
3188     }
3189     if (timeToMSecs(testDate, testTime) == msecs) {
3190         status |= QDateTimePrivate::ValidDateTime;
3191         // Cache the offset to use in offsetFromUtc()
3192         offsetFromUtc = (msecs - epochMSecs) / 1000;
3193     } else {
3194         status &= ~QDateTimePrivate::ValidDateTime;
3195     }
3196 
3197     if (status & QDateTimePrivate::ShortData) {
3198         d.data.status = status;
3199     } else {
3200         d->m_status = status;
3201         d->m_offsetFromUtc = offsetFromUtc;
3202     }
3203 }
3204 
3205 // Check the UTC / offsetFromUTC validity
checkValidDateTime(QDateTimeData & d)3206 static void checkValidDateTime(QDateTimeData &d)
3207 {
3208     auto status = getStatus(d);
3209     auto spec = extractSpec(status);
3210     switch (spec) {
3211     case Qt::OffsetFromUTC:
3212     case Qt::UTC:
3213         // for these, a valid date and a valid time imply a valid QDateTime
3214         if ((status & QDateTimePrivate::ValidDate) && (status & QDateTimePrivate::ValidTime))
3215             status |= QDateTimePrivate::ValidDateTime;
3216         else
3217             status &= ~QDateTimePrivate::ValidDateTime;
3218         if (status & QDateTimePrivate::ShortData)
3219             d.data.status = status;
3220         else
3221             d->m_status = status;
3222         break;
3223     case Qt::TimeZone:
3224     case Qt::LocalTime:
3225         // for these, we need to check whether the timezone is valid and whether
3226         // the time is valid in that timezone. Expensive, but no other option.
3227         refreshDateTime(d);
3228         break;
3229     }
3230 }
3231 
setTimeSpec(QDateTimeData & d,Qt::TimeSpec spec,int offsetSeconds)3232 static void setTimeSpec(QDateTimeData &d, Qt::TimeSpec spec, int offsetSeconds)
3233 {
3234     auto status = getStatus(d);
3235     status &= ~(QDateTimePrivate::ValidDateTime | QDateTimePrivate::DaylightMask |
3236                 QDateTimePrivate::TimeSpecMask);
3237 
3238     switch (spec) {
3239     case Qt::OffsetFromUTC:
3240         if (offsetSeconds == 0)
3241             spec = Qt::UTC;
3242         break;
3243     case Qt::TimeZone:
3244         // Use system time zone instead
3245         spec = Qt::LocalTime;
3246         Q_FALLTHROUGH();
3247     case Qt::UTC:
3248     case Qt::LocalTime:
3249         offsetSeconds = 0;
3250         break;
3251     }
3252 
3253     status = mergeSpec(status, spec);
3254     if (d.isShort() && offsetSeconds == 0) {
3255         d.data.status = status;
3256     } else {
3257         d.detach();
3258         d->m_status = status & ~QDateTimePrivate::ShortData;
3259         d->m_offsetFromUtc = offsetSeconds;
3260 #if QT_CONFIG(timezone)
3261         d->m_timeZone = QTimeZone();
3262 #endif // timezone
3263     }
3264 }
3265 
setDateTime(QDateTimeData & d,QDate date,QTime time)3266 static void setDateTime(QDateTimeData &d, QDate date, QTime time)
3267 {
3268     // If the date is valid and the time is not we set time to 00:00:00
3269     QTime useTime = time;
3270     if (!useTime.isValid() && date.isValid())
3271         useTime = QTime::fromMSecsSinceStartOfDay(0);
3272 
3273     QDateTimePrivate::StatusFlags newStatus = { };
3274 
3275     // Set date value and status
3276     qint64 days = 0;
3277     if (date.isValid()) {
3278         days = date.toJulianDay() - JULIAN_DAY_FOR_EPOCH;
3279         newStatus = QDateTimePrivate::ValidDate;
3280     }
3281 
3282     // Set time value and status
3283     int ds = 0;
3284     if (useTime.isValid()) {
3285         ds = useTime.msecsSinceStartOfDay();
3286         newStatus |= QDateTimePrivate::ValidTime;
3287     }
3288 
3289     // Set msecs serial value
3290     qint64 msecs = (days * MSECS_PER_DAY) + ds;
3291     if (d.isShort()) {
3292         // let's see if we can keep this short
3293         if (msecsCanBeSmall(msecs)) {
3294             // yes, we can
3295             d.data.msecs = qintptr(msecs);
3296             d.data.status &= ~(QDateTimePrivate::ValidityMask | QDateTimePrivate::DaylightMask);
3297             d.data.status |= newStatus;
3298         } else {
3299             // nope...
3300             d.detach();
3301         }
3302     }
3303     if (!d.isShort()) {
3304         d.detach();
3305         d->m_msecs = msecs;
3306         d->m_status &= ~(QDateTimePrivate::ValidityMask | QDateTimePrivate::DaylightMask);
3307         d->m_status |= newStatus;
3308     }
3309 
3310     // Set if date and time are valid
3311     checkValidDateTime(d);
3312 }
3313 
getDateTime(const QDateTimeData & d)3314 static QPair<QDate, QTime> getDateTime(const QDateTimeData &d)
3315 {
3316     QPair<QDate, QTime> result;
3317     qint64 msecs = getMSecs(d);
3318     auto status = getStatus(d);
3319     msecsToTime(msecs, &result.first, &result.second);
3320 
3321     if (!status.testFlag(QDateTimePrivate::ValidDate))
3322         result.first = QDate();
3323 
3324     if (!status.testFlag(QDateTimePrivate::ValidTime))
3325         result.second = QTime();
3326 
3327     return result;
3328 }
3329 
3330 /*****************************************************************************
3331   QDateTime::Data member functions
3332  *****************************************************************************/
3333 
Data()3334 inline QDateTime::Data::Data()
3335 {
3336     // default-constructed data has a special exception:
3337     // it can be small even if CanBeSmall == false
3338     // (optimization so we don't allocate memory in the default constructor)
3339     quintptr value = quintptr(mergeSpec(QDateTimePrivate::ShortData, Qt::LocalTime));
3340     d = reinterpret_cast<QDateTimePrivate *>(value);
3341 }
3342 
Data(Qt::TimeSpec spec)3343 inline QDateTime::Data::Data(Qt::TimeSpec spec)
3344 {
3345     if (CanBeSmall && Q_LIKELY(specCanBeSmall(spec))) {
3346         d = reinterpret_cast<QDateTimePrivate *>(quintptr(mergeSpec(QDateTimePrivate::ShortData, spec)));
3347     } else {
3348         // the structure is too small, we need to detach
3349         d = new QDateTimePrivate;
3350         d->ref.ref();
3351         d->m_status = mergeSpec({}, spec);
3352     }
3353 }
3354 
Data(const Data & other)3355 inline QDateTime::Data::Data(const Data &other)
3356     : d(other.d)
3357 {
3358     if (!isShort()) {
3359         // check if we could shrink
3360         if (specCanBeSmall(extractSpec(d->m_status)) && msecsCanBeSmall(d->m_msecs)) {
3361             ShortData sd;
3362             sd.msecs = qintptr(d->m_msecs);
3363             sd.status = d->m_status | QDateTimePrivate::ShortData;
3364             data = sd;
3365         } else {
3366             // no, have to keep it big
3367             d->ref.ref();
3368         }
3369     }
3370 }
3371 
Data(Data && other)3372 inline QDateTime::Data::Data(Data &&other)
3373     : d(other.d)
3374 {
3375     // reset the other to a short state
3376     Data dummy;
3377     Q_ASSERT(dummy.isShort());
3378     other.d = dummy.d;
3379 }
3380 
operator =(const Data & other)3381 inline QDateTime::Data &QDateTime::Data::operator=(const Data &other)
3382 {
3383     if (d == other.d)
3384         return *this;
3385 
3386     auto x = d;
3387     d = other.d;
3388     if (!other.isShort()) {
3389         // check if we could shrink
3390         if (specCanBeSmall(extractSpec(other.d->m_status)) && msecsCanBeSmall(other.d->m_msecs)) {
3391             ShortData sd;
3392             sd.msecs = qintptr(other.d->m_msecs);
3393             sd.status = other.d->m_status | QDateTimePrivate::ShortData;
3394             data = sd;
3395         } else {
3396             // no, have to keep it big
3397             other.d->ref.ref();
3398         }
3399     }
3400 
3401     if (!(quintptr(x) & QDateTimePrivate::ShortData) && !x->ref.deref())
3402         delete x;
3403     return *this;
3404 }
3405 
~Data()3406 inline QDateTime::Data::~Data()
3407 {
3408     if (!isShort() && !d->ref.deref())
3409         delete d;
3410 }
3411 
isShort() const3412 inline bool QDateTime::Data::isShort() const
3413 {
3414     bool b = quintptr(d) & QDateTimePrivate::ShortData;
3415 
3416     // sanity check:
3417     Q_ASSERT(b || (d->m_status & QDateTimePrivate::ShortData) == 0);
3418 
3419     // even if CanBeSmall = false, we have short data for a default-constructed
3420     // QDateTime object. But it's unlikely.
3421     if (CanBeSmall)
3422         return Q_LIKELY(b);
3423     return Q_UNLIKELY(b);
3424 }
3425 
detach()3426 inline void QDateTime::Data::detach()
3427 {
3428     QDateTimePrivate *x;
3429     bool wasShort = isShort();
3430     if (wasShort) {
3431         // force enlarging
3432         x = new QDateTimePrivate;
3433         x->m_status = QDateTimePrivate::StatusFlag(data.status & ~QDateTimePrivate::ShortData);
3434         x->m_msecs = data.msecs;
3435     } else {
3436         if (d->ref.loadRelaxed() == 1)
3437             return;
3438 
3439         x = new QDateTimePrivate(*d);
3440     }
3441 
3442     x->ref.storeRelaxed(1);
3443     if (!wasShort && !d->ref.deref())
3444         delete d;
3445     d = x;
3446 }
3447 
operator ->() const3448 inline const QDateTimePrivate *QDateTime::Data::operator->() const
3449 {
3450     Q_ASSERT(!isShort());
3451     return d;
3452 }
3453 
operator ->()3454 inline QDateTimePrivate *QDateTime::Data::operator->()
3455 {
3456     // should we attempt to detach here?
3457     Q_ASSERT(!isShort());
3458     Q_ASSERT(d->ref.loadRelaxed() == 1);
3459     return d;
3460 }
3461 
3462 /*****************************************************************************
3463   QDateTimePrivate member functions
3464  *****************************************************************************/
3465 
3466 Q_NEVER_INLINE
create(const QDate & toDate,const QTime & toTime,Qt::TimeSpec toSpec,int offsetSeconds)3467 QDateTime::Data QDateTimePrivate::create(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec,
3468                                          int offsetSeconds)
3469 {
3470     QDateTime::Data result(toSpec);
3471     setTimeSpec(result, toSpec, offsetSeconds);
3472     setDateTime(result, toDate, toTime);
3473     return result;
3474 }
3475 
3476 #if QT_CONFIG(timezone)
create(const QDate & toDate,const QTime & toTime,const QTimeZone & toTimeZone)3477 inline QDateTime::Data QDateTimePrivate::create(const QDate &toDate, const QTime &toTime,
3478                                                 const QTimeZone &toTimeZone)
3479 {
3480     QDateTime::Data result(Qt::TimeZone);
3481     Q_ASSERT(!result.isShort());
3482 
3483     result.d->m_status = mergeSpec(result.d->m_status, Qt::TimeZone);
3484     result.d->m_timeZone = toTimeZone;
3485     setDateTime(result, toDate, toTime);
3486     return result;
3487 }
3488 
3489 // Convert a TimeZone time expressed in zone msecs encoding into a UTC epoch msecs
3490 // DST transitions are disambiguated by hint.
zoneMSecsToEpochMSecs(qint64 zoneMSecs,const QTimeZone & zone,DaylightStatus hint,QDate * zoneDate,QTime * zoneTime)3491 inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QTimeZone &zone,
3492                                                       DaylightStatus hint,
3493                                                       QDate *zoneDate, QTime *zoneTime)
3494 {
3495     Q_ASSERT(zone.isValid());
3496     // Get the effective data from QTimeZone
3497     QTimeZonePrivate::Data data = zone.d->dataForLocalTime(zoneMSecs, int(hint));
3498     // Docs state any time before 1970-01-01 will *not* have any DST applied
3499     // but all affected times afterwards will have DST applied.
3500     if (data.atMSecsSinceEpoch < 0) {
3501         msecsToTime(zoneMSecs, zoneDate, zoneTime);
3502         return zoneMSecs - data.standardTimeOffset * 1000;
3503     } else {
3504         msecsToTime(data.atMSecsSinceEpoch + data.offsetFromUtc * 1000, zoneDate, zoneTime);
3505         return data.atMSecsSinceEpoch;
3506     }
3507 }
3508 #endif // timezone
3509 
3510 /*****************************************************************************
3511   QDateTime member functions
3512  *****************************************************************************/
3513 
3514 /*!
3515     \class QDateTime
3516     \inmodule QtCore
3517     \ingroup shared
3518     \reentrant
3519     \brief The QDateTime class provides date and time functions.
3520 
3521 
3522     A QDateTime object encodes a calendar date and a clock time (a
3523     "datetime"). It combines features of the QDate and QTime classes.
3524     It can read the current datetime from the system clock. It
3525     provides functions for comparing datetimes and for manipulating a
3526     datetime by adding a number of seconds, days, months, or years.
3527 
3528     QDateTime can describe datetimes with respect to \l{Qt::LocalTime}{local
3529     time}, to \l{Qt::UTC}{UTC}, to a specified \l{Qt::OffsetFromUTC}{offset from
3530     UTC} or to a specified \l{Qt::TimeZone}{time zone}, in conjunction with the
3531     QTimeZone class. For example, a time zone of "Europe/Berlin" will apply the
3532     daylight-saving rules as used in Germany since 1970. In contrast, an offset
3533     from UTC of +3600 seconds is one hour ahead of UTC (usually written in ISO
3534     standard notation as "UTC+01:00"), with no daylight-saving offset or
3535     changes. When using either local time or a specified time zone, time-zone
3536     transitions such as the starts and ends of daylight-saving time (DST; but
3537     see below) are taken into account. The choice of system used to represent a
3538     datetime is described as its "timespec".
3539 
3540     A QDateTime object is typically created either by giving a date and time
3541     explicitly in the constructor, or by using a static function such as
3542     currentDateTime() or fromMSecsSinceEpoch(). The date and time can be changed
3543     with setDate() and setTime(). A datetime can also be set using the
3544     setMSecsSinceEpoch() function that takes the time, in milliseconds, since
3545     00:00:00 on January 1, 1970. The fromString() function returns a QDateTime,
3546     given a string and a date format used to interpret the date within the
3547     string.
3548 
3549     QDateTime::currentDateTime() returns a QDateTime that expresses the current
3550     time with respect to local time. QDateTime::currentDateTimeUtc() returns a
3551     QDateTime that expresses the current time with respect to UTC.
3552 
3553     The date() and time() functions provide access to the date and
3554     time parts of the datetime. The same information is provided in
3555     textual format by the toString() function.
3556 
3557     QDateTime provides a full set of operators to compare two
3558     QDateTime objects, where smaller means earlier and larger means
3559     later.
3560 
3561     You can increment (or decrement) a datetime by a given number of
3562     milliseconds using addMSecs(), seconds using addSecs(), or days using
3563     addDays(). Similarly, you can use addMonths() and addYears(). The daysTo()
3564     function returns the number of days between two datetimes, secsTo() returns
3565     the number of seconds between two datetimes, and msecsTo() returns the
3566     number of milliseconds between two datetimes. These operations are aware of
3567     daylight-saving time (DST) and other time-zone transitions, where
3568     applicable.
3569 
3570     Use toTimeSpec() to express a datetime in local time or UTC,
3571     toOffsetFromUtc() to express in terms of an offset from UTC, or toTimeZone()
3572     to express it with respect to a general time zone. You can use timeSpec() to
3573     find out what time-spec a QDateTime object stores its time relative to. When
3574     that is Qt::TimeZone, you can use timeZone() to find out which zone it is
3575     using.
3576 
3577     \note QDateTime does not account for leap seconds.
3578 
3579     \section1 Remarks
3580 
3581     \section2 No Year 0
3582 
3583     There is no year 0. Dates in that year are considered invalid. The
3584     year -1 is the year "1 before Christ" or "1 before current era."
3585     The day before 1 January 1 CE is 31 December 1 BCE.
3586 
3587     \section2 Range of Valid Dates
3588 
3589     The range of values that QDateTime can represent is dependent on the
3590     internal storage implementation. QDateTime is currently stored in a qint64
3591     as a serial msecs value encoding the date and time. This restricts the date
3592     range to about +/- 292 million years, compared to the QDate range of +/- 2
3593     billion years. Care must be taken when creating a QDateTime with extreme
3594     values that you do not overflow the storage. The exact range of supported
3595     values varies depending on the Qt::TimeSpec and time zone.
3596 
3597     \section2 Use of Timezones
3598 
3599     QDateTime uses the system's time zone information to determine the current
3600     local time zone and its offset from UTC. If the system is not configured
3601     correctly or not up-to-date, QDateTime will give wrong results.
3602 
3603     QDateTime likewise uses system-provided information to determine the offsets
3604     of other timezones from UTC. If this information is incomplete or out of
3605     date, QDateTime will give wrong results. See the QTimeZone documentation for
3606     more details.
3607 
3608     On modern Unix systems, this means QDateTime usually has accurate
3609     information about historical transitions (including DST, see below) whenever
3610     possible. On Windows, where the system doesn't support historical timezone
3611     data, historical accuracy is not maintained with respect to timezone
3612     transitions, notably including DST.
3613 
3614     \section2 Daylight-Saving Time (DST)
3615 
3616     QDateTime takes into account transitions between Standard Time and
3617     Daylight-Saving Time. For example, if the transition is at 2am and the clock
3618     goes forward to 3am, then there is a "missing" hour from 02:00:00 to
3619     02:59:59.999 which QDateTime considers to be invalid. Any date arithmetic
3620     performed will take this missing hour into account and return a valid
3621     result. For example, adding one minute to 01:59:59 will get 03:00:00.
3622 
3623     The range of valid dates taking DST into account is 1970-01-01 to the
3624     present, and rules are in place for handling DST correctly until 2037-12-31,
3625     but these could change. For dates after 2037, QDateTime makes a \e{best
3626     guess} using the rules for year 2037, but we can't guarantee accuracy;
3627     indeed, for \e{any} future date, the time-zone may change its rules before
3628     that date comes around. For dates before 1970, QDateTime doesn't take DST
3629     changes into account, even if the system's time zone database provides that
3630     information, although it does take into account changes to the time-zone's
3631     standard offset, where this information is available.
3632 
3633     \section2 Offsets From UTC
3634 
3635     There is no explicit size restriction on an offset from UTC, but there is an
3636     implicit limit imposed when using the toString() and fromString() methods
3637     which use a [+|-]hh:mm format, effectively limiting the range to +/- 99
3638     hours and 59 minutes and whole minutes only. Note that currently no time
3639     zone lies outside the range of +/- 14 hours.
3640 
3641     \sa QDate, QTime, QDateTimeEdit, QTimeZone
3642 */
3643 
3644 /*!
3645     \since 5.14
3646     \enum QDateTime::YearRange
3647 
3648     This enumerated type describes the range of years (in the Gregorian
3649     calendar) representable by QDateTime:
3650 
3651     \value First The later parts of this year are representable
3652     \value Last The earlier parts of this year are representable
3653 
3654     All dates strictly between these two years are also representable.
3655     Note, however, that the Gregorian Calendar has no year zero.
3656 
3657     \note QDate can describe dates in a wider range of years.  For most
3658     purposes, this makes little difference, as the range of years that QDateTime
3659     can support reaches 292 million years either side of 1970.
3660 
3661     \sa isValid(), QDate
3662 */
3663 
3664 /*!
3665     Constructs a null datetime (i.e. null date and null time). A null
3666     datetime is invalid, since the date is invalid.
3667 
3668     \sa isValid()
3669 */
QDateTime()3670 QDateTime::QDateTime() noexcept(Data::CanBeSmall)
3671 {
3672 }
3673 
3674 
3675 #if QT_DEPRECATED_SINCE(5, 17) // ### Qt 6: remove
3676 /*!
3677     Constructs a datetime with the given \a date, using Qt::LocalTime as the
3678     timeSpec() and the time at the start of that date.
3679 
3680     \sa QDate::startOfDay()
3681 */
QDateTime(const QDate & date)3682 QDateTime::QDateTime(const QDate &date)
3683     : QDateTime(date.startOfDay(Qt::LocalTime, 0))
3684 {
3685 }
3686 #endif
3687 
3688 /*!
3689     Constructs a datetime with the given \a date and \a time, using
3690     the time specification defined by \a spec.
3691 
3692     If \a date is valid and \a time is not, the time will be set to midnight.
3693 
3694     If \a spec is Qt::OffsetFromUTC then it will be set to Qt::UTC, i.e. an
3695     offset of 0 seconds. To create a Qt::OffsetFromUTC datetime use the
3696     correct constructor.
3697 
3698     If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
3699     i.e. the current system time zone.  To create a Qt::TimeZone datetime
3700     use the correct constructor.
3701 */
3702 
QDateTime(const QDate & date,const QTime & time,Qt::TimeSpec spec)3703 QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec)
3704     : d(QDateTimePrivate::create(date, time, spec, 0))
3705 {
3706 }
3707 
3708 /*!
3709     \since 5.2
3710 
3711     Constructs a datetime with the given \a date and \a time, using
3712     the time specification defined by \a spec and \a offsetSeconds seconds.
3713 
3714     If \a date is valid and \a time is not, the time will be set to midnight.
3715 
3716     If the \a spec is not Qt::OffsetFromUTC then \a offsetSeconds will be ignored.
3717 
3718     If the \a spec is Qt::OffsetFromUTC and \a offsetSeconds is 0 then the
3719     timeSpec() will be set to Qt::UTC, i.e. an offset of 0 seconds.
3720 
3721     If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
3722     i.e. the current system time zone.  To create a Qt::TimeZone datetime
3723     use the correct constructor.
3724 */
3725 
QDateTime(const QDate & date,const QTime & time,Qt::TimeSpec spec,int offsetSeconds)3726 QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec, int offsetSeconds)
3727          : d(QDateTimePrivate::create(date, time, spec, offsetSeconds))
3728 {
3729 }
3730 
3731 #if QT_CONFIG(timezone)
3732 /*!
3733     \since 5.2
3734 
3735     Constructs a datetime with the given \a date and \a time, using
3736     the Time Zone specified by \a timeZone.
3737 
3738     If \a date is valid and \a time is not, the time will be set to 00:00:00.
3739 
3740     If \a timeZone is invalid then the datetime will be invalid.
3741 */
3742 
QDateTime(const QDate & date,const QTime & time,const QTimeZone & timeZone)3743 QDateTime::QDateTime(const QDate &date, const QTime &time, const QTimeZone &timeZone)
3744     : d(QDateTimePrivate::create(date, time, timeZone))
3745 {
3746 }
3747 #endif // timezone
3748 
3749 /*!
3750     Constructs a copy of the \a other datetime.
3751 */
QDateTime(const QDateTime & other)3752 QDateTime::QDateTime(const QDateTime &other) noexcept
3753     : d(other.d)
3754 {
3755 }
3756 
3757 /*!
3758     \since 5.8
3759     Moves the content of the temporary \a other datetime to this object and
3760     leaves \a other in an unspecified (but proper) state.
3761 */
QDateTime(QDateTime && other)3762 QDateTime::QDateTime(QDateTime &&other) noexcept
3763     : d(std::move(other.d))
3764 {
3765 }
3766 
3767 /*!
3768     Destroys the datetime.
3769 */
~QDateTime()3770 QDateTime::~QDateTime()
3771 {
3772 }
3773 
3774 /*!
3775     Makes a copy of the \a other datetime and returns a reference to the
3776     copy.
3777 */
3778 
operator =(const QDateTime & other)3779 QDateTime &QDateTime::operator=(const QDateTime &other) noexcept
3780 {
3781     d = other.d;
3782     return *this;
3783 }
3784 /*!
3785     \fn void QDateTime::swap(QDateTime &other)
3786     \since 5.0
3787 
3788     Swaps this datetime with \a other. This operation is very fast
3789     and never fails.
3790 */
3791 
3792 /*!
3793     Returns \c true if both the date and the time are null; otherwise
3794     returns \c false. A null datetime is invalid.
3795 
3796     \sa QDate::isNull(), QTime::isNull(), isValid()
3797 */
3798 
isNull() const3799 bool QDateTime::isNull() const
3800 {
3801     auto status = getStatus(d);
3802     return !status.testFlag(QDateTimePrivate::ValidDate) &&
3803             !status.testFlag(QDateTimePrivate::ValidTime);
3804 }
3805 
3806 /*!
3807     Returns \c true if both the date and the time are valid and they are valid in
3808     the current Qt::TimeSpec, otherwise returns \c false.
3809 
3810     If the timeSpec() is Qt::LocalTime or Qt::TimeZone then the date and time are
3811     checked to see if they fall in the Standard Time to Daylight-Saving Time transition
3812     hour, i.e. if the transition is at 2am and the clock goes forward to 3am
3813     then the time from 02:00:00 to 02:59:59.999 is considered to be invalid.
3814 
3815     \sa QDateTime::YearRange, QDate::isValid(), QTime::isValid()
3816 */
3817 
isValid() const3818 bool QDateTime::isValid() const
3819 {
3820     auto status = getStatus(d);
3821     return status & QDateTimePrivate::ValidDateTime;
3822 }
3823 
3824 /*!
3825     Returns the date part of the datetime.
3826 
3827     \sa setDate(), time(), timeSpec()
3828 */
3829 
date() const3830 QDate QDateTime::date() const
3831 {
3832     auto status = getStatus(d);
3833     if (!status.testFlag(QDateTimePrivate::ValidDate))
3834         return QDate();
3835     QDate dt;
3836     msecsToTime(getMSecs(d), &dt, nullptr);
3837     return dt;
3838 }
3839 
3840 /*!
3841     Returns the time part of the datetime.
3842 
3843     \sa setTime(), date(), timeSpec()
3844 */
3845 
time() const3846 QTime QDateTime::time() const
3847 {
3848     auto status = getStatus(d);
3849     if (!status.testFlag(QDateTimePrivate::ValidTime))
3850         return QTime();
3851     QTime tm;
3852     msecsToTime(getMSecs(d), nullptr, &tm);
3853     return tm;
3854 }
3855 
3856 /*!
3857     Returns the time specification of the datetime.
3858 
3859     \sa setTimeSpec(), date(), time(), Qt::TimeSpec
3860 */
3861 
timeSpec() const3862 Qt::TimeSpec QDateTime::timeSpec() const
3863 {
3864     return getSpec(d);
3865 }
3866 
3867 #if QT_CONFIG(timezone)
3868 /*!
3869     \since 5.2
3870 
3871     Returns the time zone of the datetime.
3872 
3873     If the timeSpec() is Qt::LocalTime then an instance of the current system
3874     time zone will be returned. Note however that if you copy this time zone
3875     the instance will not remain in sync if the system time zone changes.
3876 
3877     \sa setTimeZone(), Qt::TimeSpec
3878 */
3879 
timeZone() const3880 QTimeZone QDateTime::timeZone() const
3881 {
3882     switch (getSpec(d)) {
3883     case Qt::UTC:
3884         return QTimeZone::utc();
3885     case Qt::OffsetFromUTC:
3886         return QTimeZone(d->m_offsetFromUtc);
3887     case Qt::TimeZone:
3888         if (d->m_timeZone.isValid())
3889             return d->m_timeZone;
3890         break;
3891     case Qt::LocalTime:
3892         return QTimeZone::systemTimeZone();
3893     }
3894     return QTimeZone();
3895 }
3896 #endif // timezone
3897 
3898 /*!
3899     \since 5.2
3900 
3901     Returns this date-time's Offset From UTC in seconds.
3902 
3903     The result depends on timeSpec():
3904     \list
3905     \li \c Qt::UTC The offset is 0.
3906     \li \c Qt::OffsetFromUTC The offset is the value originally set.
3907     \li \c Qt::LocalTime The local time's offset from UTC is returned.
3908     \li \c Qt::TimeZone The offset used by the time-zone is returned.
3909     \endlist
3910 
3911     For the last two, the offset at this date and time will be returned, taking
3912     account of Daylight-Saving Offset unless the date precedes the start of
3913     1970. The offset is the difference between the local time or time in the
3914     given time-zone and UTC time; it is positive in time-zones ahead of UTC
3915     (East of The Prime Meridian), negative for those behind UTC (West of The
3916     Prime Meridian).
3917 
3918     \sa setOffsetFromUtc()
3919 */
3920 
offsetFromUtc() const3921 int QDateTime::offsetFromUtc() const
3922 {
3923     if (!d.isShort())
3924         return d->m_offsetFromUtc;
3925     if (!isValid())
3926         return 0;
3927 
3928     auto spec = getSpec(d);
3929     if (spec == Qt::LocalTime) {
3930         // we didn't cache the value, so we need to calculate it now...
3931         qint64 msecs = getMSecs(d);
3932         return (msecs - toMSecsSinceEpoch()) / 1000;
3933     }
3934 
3935     Q_ASSERT(spec == Qt::UTC);
3936     return 0;
3937 }
3938 
3939 /*!
3940     \since 5.2
3941 
3942     Returns the Time Zone Abbreviation for the datetime.
3943 
3944     If the timeSpec() is Qt::UTC this will be "UTC".
3945 
3946     If the timeSpec() is Qt::OffsetFromUTC this will be in the format
3947     "UTC[+-]00:00".
3948 
3949     If the timeSpec() is Qt::LocalTime then the host system is queried for the
3950     correct abbreviation.
3951 
3952     Note that abbreviations may or may not be localized.
3953 
3954     Note too that the abbreviation is not guaranteed to be a unique value,
3955     i.e. different time zones may have the same abbreviation.
3956 
3957     \sa timeSpec()
3958 */
3959 
timeZoneAbbreviation() const3960 QString QDateTime::timeZoneAbbreviation() const
3961 {
3962     if (!isValid())
3963         return QString();
3964 
3965     switch (getSpec(d)) {
3966     case Qt::UTC:
3967         return QLatin1String("UTC");
3968     case Qt::OffsetFromUTC:
3969         return QLatin1String("UTC") + toOffsetString(Qt::ISODate, d->m_offsetFromUtc);
3970     case Qt::TimeZone:
3971 #if !QT_CONFIG(timezone)
3972         break;
3973 #else
3974         Q_ASSERT(d->m_timeZone.isValid());
3975         return d->m_timeZone.d->abbreviation(toMSecsSinceEpoch());
3976 #endif // timezone
3977     case Qt::LocalTime:  {
3978         QString abbrev;
3979         auto status = extractDaylightStatus(getStatus(d));
3980         localMSecsToEpochMSecs(getMSecs(d), &status, nullptr, nullptr, &abbrev);
3981         return abbrev;
3982         }
3983     }
3984     return QString();
3985 }
3986 
3987 /*!
3988     \since 5.2
3989 
3990     Returns if this datetime falls in Daylight-Saving Time.
3991 
3992     If the Qt::TimeSpec is not Qt::LocalTime or Qt::TimeZone then will always
3993     return false.
3994 
3995     \sa timeSpec()
3996 */
3997 
isDaylightTime() const3998 bool QDateTime::isDaylightTime() const
3999 {
4000     if (!isValid())
4001         return false;
4002 
4003     switch (getSpec(d)) {
4004     case Qt::UTC:
4005     case Qt::OffsetFromUTC:
4006         return false;
4007     case Qt::TimeZone:
4008 #if !QT_CONFIG(timezone)
4009         break;
4010 #else
4011         Q_ASSERT(d->m_timeZone.isValid());
4012         return d->m_timeZone.d->isDaylightTime(toMSecsSinceEpoch());
4013 #endif // timezone
4014     case Qt::LocalTime: {
4015         auto status = extractDaylightStatus(getStatus(d));
4016         if (status == QDateTimePrivate::UnknownDaylightTime)
4017             localMSecsToEpochMSecs(getMSecs(d), &status);
4018         return (status == QDateTimePrivate::DaylightTime);
4019         }
4020     }
4021     return false;
4022 }
4023 
4024 /*!
4025     Sets the date part of this datetime to \a date. If no time is set yet, it
4026     is set to midnight. If \a date is invalid, this QDateTime becomes invalid.
4027 
4028     \sa date(), setTime(), setTimeSpec()
4029 */
4030 
setDate(const QDate & date)4031 void QDateTime::setDate(const QDate &date)
4032 {
4033     setDateTime(d, date, time());
4034 }
4035 
4036 /*!
4037     Sets the time part of this datetime to \a time. If \a time is not valid,
4038     this function sets it to midnight. Therefore, it's possible to clear any
4039     set time in a QDateTime by setting it to a default QTime:
4040 
4041     \code
4042         QDateTime dt = QDateTime::currentDateTime();
4043         dt.setTime(QTime());
4044     \endcode
4045 
4046     \sa time(), setDate(), setTimeSpec()
4047 */
4048 
setTime(const QTime & time)4049 void QDateTime::setTime(const QTime &time)
4050 {
4051     setDateTime(d, date(), time);
4052 }
4053 
4054 /*!
4055     Sets the time specification used in this datetime to \a spec.
4056     The datetime will refer to a different point in time.
4057 
4058     If \a spec is Qt::OffsetFromUTC then the timeSpec() will be set
4059     to Qt::UTC, i.e. an effective offset of 0.
4060 
4061     If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
4062     i.e. the current system time zone.
4063 
4064     Example:
4065     \snippet code/src_corelib_tools_qdatetime.cpp 19
4066 
4067     \sa timeSpec(), setDate(), setTime(), setTimeZone(), Qt::TimeSpec
4068 */
4069 
setTimeSpec(Qt::TimeSpec spec)4070 void QDateTime::setTimeSpec(Qt::TimeSpec spec)
4071 {
4072     QT_PREPEND_NAMESPACE(setTimeSpec(d, spec, 0));
4073     checkValidDateTime(d);
4074 }
4075 
4076 /*!
4077     \since 5.2
4078 
4079     Sets the timeSpec() to Qt::OffsetFromUTC and the offset to \a offsetSeconds.
4080     The datetime will refer to a different point in time.
4081 
4082     The maximum and minimum offset is 14 positive or negative hours.  If
4083     \a offsetSeconds is larger or smaller than that, then the result is
4084     undefined.
4085 
4086     If \a offsetSeconds is 0 then the timeSpec() will be set to Qt::UTC.
4087 
4088     \sa isValid(), offsetFromUtc()
4089 */
4090 
setOffsetFromUtc(int offsetSeconds)4091 void QDateTime::setOffsetFromUtc(int offsetSeconds)
4092 {
4093     QT_PREPEND_NAMESPACE(setTimeSpec(d, Qt::OffsetFromUTC, offsetSeconds));
4094     checkValidDateTime(d);
4095 }
4096 
4097 #if QT_CONFIG(timezone)
4098 /*!
4099     \since 5.2
4100 
4101     Sets the time zone used in this datetime to \a toZone.
4102     The datetime will refer to a different point in time.
4103 
4104     If \a toZone is invalid then the datetime will be invalid.
4105 
4106     \sa timeZone(), Qt::TimeSpec
4107 */
4108 
setTimeZone(const QTimeZone & toZone)4109 void QDateTime::setTimeZone(const QTimeZone &toZone)
4110 {
4111     d.detach();         // always detach
4112     d->m_status = mergeSpec(d->m_status, Qt::TimeZone);
4113     d->m_offsetFromUtc = 0;
4114     d->m_timeZone = toZone;
4115     refreshDateTime(d);
4116 }
4117 #endif // timezone
4118 
4119 /*!
4120     \since 4.7
4121 
4122     Returns the datetime as the number of milliseconds that have passed
4123     since 1970-01-01T00:00:00.000, Coordinated Universal Time (Qt::UTC).
4124 
4125     On systems that do not support time zones, this function will
4126     behave as if local time were Qt::UTC.
4127 
4128     The behavior for this function is undefined if the datetime stored in
4129     this object is not valid. However, for all valid dates, this function
4130     returns a unique value.
4131 
4132     \sa toSecsSinceEpoch(), setMSecsSinceEpoch()
4133 */
toMSecsSinceEpoch() const4134 qint64 QDateTime::toMSecsSinceEpoch() const
4135 {
4136     // Note: QDateTimeParser relies on this producing a useful result, even when
4137     // !isValid(), at least when the invalidity is a time in a fall-back (that
4138     // we'll have adjusted to lie outside it, but marked invalid because it's
4139     // not what was asked for). Other things may be doing similar.
4140     switch (getSpec(d)) {
4141     case Qt::UTC:
4142         return getMSecs(d);
4143 
4144     case Qt::OffsetFromUTC:
4145         return d->m_msecs - (d->m_offsetFromUtc * 1000);
4146 
4147     case Qt::LocalTime: {
4148         // recalculate the local timezone
4149         auto status = extractDaylightStatus(getStatus(d));
4150         return localMSecsToEpochMSecs(getMSecs(d), &status);
4151     }
4152 
4153     case Qt::TimeZone:
4154 #if QT_CONFIG(timezone)
4155         if (d->m_timeZone.isValid()) {
4156             return QDateTimePrivate::zoneMSecsToEpochMSecs(d->m_msecs, d->m_timeZone,
4157                                                            extractDaylightStatus(getStatus(d)));
4158         }
4159 #endif
4160         return 0;
4161     }
4162     Q_UNREACHABLE();
4163     return 0;
4164 }
4165 
4166 /*!
4167     \since 5.8
4168 
4169     Returns the datetime as the number of seconds that have passed since
4170     1970-01-01T00:00:00.000, Coordinated Universal Time (Qt::UTC).
4171 
4172     On systems that do not support time zones, this function will
4173     behave as if local time were Qt::UTC.
4174 
4175     The behavior for this function is undefined if the datetime stored in
4176     this object is not valid. However, for all valid dates, this function
4177     returns a unique value.
4178 
4179     \sa toMSecsSinceEpoch(), setSecsSinceEpoch()
4180 */
toSecsSinceEpoch() const4181 qint64 QDateTime::toSecsSinceEpoch() const
4182 {
4183     return toMSecsSinceEpoch() / 1000;
4184 }
4185 
4186 #if QT_DEPRECATED_SINCE(5, 8)
4187 /*!
4188     \deprecated
4189 
4190     Returns the datetime as the number of seconds that have passed
4191     since 1970-01-01T00:00:00, Coordinated Universal Time (Qt::UTC).
4192 
4193     On systems that do not support time zones, this function will
4194     behave as if local time were Qt::UTC.
4195 
4196     \note This function returns a 32-bit unsigned integer and is deprecated.
4197 
4198     If the date is outside the range 1970-01-01T00:00:00 to
4199     2106-02-07T06:28:14, this function returns -1 cast to an unsigned integer
4200     (i.e., 0xFFFFFFFF).
4201 
4202     To get an extended range, use toMSecsSinceEpoch() or toSecsSinceEpoch().
4203 
4204     \sa toSecsSinceEpoch(), toMSecsSinceEpoch(), setTime_t()
4205 */
4206 
toTime_t() const4207 uint QDateTime::toTime_t() const
4208 {
4209     if (!isValid())
4210         return uint(-1);
4211     qint64 retval = toMSecsSinceEpoch() / 1000;
4212     if (quint64(retval) >= Q_UINT64_C(0xFFFFFFFF))
4213         return uint(-1);
4214     return uint(retval);
4215 }
4216 #endif
4217 
4218 /*!
4219     \since 4.7
4220 
4221     Sets the date and time given the number of milliseconds \a msecs that have
4222     passed since 1970-01-01T00:00:00.000, Coordinated Universal Time
4223     (Qt::UTC). On systems that do not support time zones this function
4224     will behave as if local time were Qt::UTC.
4225 
4226     Note that passing the minimum of \c qint64
4227     (\c{std::numeric_limits<qint64>::min()}) to \a msecs will result in
4228     undefined behavior.
4229 
4230     \sa toMSecsSinceEpoch(), setSecsSinceEpoch()
4231 */
setMSecsSinceEpoch(qint64 msecs)4232 void QDateTime::setMSecsSinceEpoch(qint64 msecs)
4233 {
4234     const auto spec = getSpec(d);
4235     auto status = getStatus(d);
4236 
4237     status &= ~QDateTimePrivate::ValidityMask;
4238     switch (spec) {
4239     case Qt::UTC:
4240         status = status
4241                     | QDateTimePrivate::ValidDate
4242                     | QDateTimePrivate::ValidTime
4243                     | QDateTimePrivate::ValidDateTime;
4244         break;
4245     case Qt::OffsetFromUTC:
4246         msecs = msecs + (d->m_offsetFromUtc * 1000);
4247         status = status
4248                     | QDateTimePrivate::ValidDate
4249                     | QDateTimePrivate::ValidTime
4250                     | QDateTimePrivate::ValidDateTime;
4251         break;
4252     case Qt::TimeZone:
4253         Q_ASSERT(!d.isShort());
4254 #if QT_CONFIG(timezone)
4255         d.detach();
4256         if (!d->m_timeZone.isValid())
4257             break;
4258         // Docs state any LocalTime before 1970-01-01 will *not* have any DST applied
4259         // but all affected times afterwards will have DST applied.
4260         if (msecs >= 0) {
4261             status = mergeDaylightStatus(status,
4262                                          d->m_timeZone.d->isDaylightTime(msecs)
4263                                          ? QDateTimePrivate::DaylightTime
4264                                          : QDateTimePrivate::StandardTime);
4265             d->m_offsetFromUtc = d->m_timeZone.d->offsetFromUtc(msecs);
4266         } else {
4267             status = mergeDaylightStatus(status, QDateTimePrivate::StandardTime);
4268             d->m_offsetFromUtc = d->m_timeZone.d->standardTimeOffset(msecs);
4269         }
4270         msecs = msecs + (d->m_offsetFromUtc * 1000);
4271         status = status
4272                     | QDateTimePrivate::ValidDate
4273                     | QDateTimePrivate::ValidTime
4274                     | QDateTimePrivate::ValidDateTime;
4275 #endif // timezone
4276         break;
4277     case Qt::LocalTime: {
4278         QDate dt;
4279         QTime tm;
4280         QDateTimePrivate::DaylightStatus dstStatus;
4281         epochMSecsToLocalTime(msecs, &dt, &tm, &dstStatus);
4282         setDateTime(d, dt, tm);
4283         msecs = getMSecs(d);
4284         status = mergeDaylightStatus(getStatus(d), dstStatus);
4285         break;
4286         }
4287     }
4288 
4289     if (msecsCanBeSmall(msecs) && d.isShort()) {
4290         // we can keep short
4291         d.data.msecs = qintptr(msecs);
4292         d.data.status = status;
4293     } else {
4294         d.detach();
4295         d->m_status = status & ~QDateTimePrivate::ShortData;
4296         d->m_msecs = msecs;
4297     }
4298 
4299     if (spec == Qt::LocalTime || spec == Qt::TimeZone)
4300         refreshDateTime(d);
4301 }
4302 
4303 /*!
4304     \since 5.8
4305 
4306     Sets the date and time given the number of seconds \a secs that have
4307     passed since 1970-01-01T00:00:00.000, Coordinated Universal Time
4308     (Qt::UTC). On systems that do not support time zones this function
4309     will behave as if local time were Qt::UTC.
4310 
4311     \sa toSecsSinceEpoch(), setMSecsSinceEpoch()
4312 */
setSecsSinceEpoch(qint64 secs)4313 void QDateTime::setSecsSinceEpoch(qint64 secs)
4314 {
4315     setMSecsSinceEpoch(secs * 1000);
4316 }
4317 
4318 #if QT_DEPRECATED_SINCE(5, 8)
4319 /*!
4320     \fn void QDateTime::setTime_t(uint seconds)
4321     \deprecated
4322 
4323     Sets the date and time given the number of \a seconds that have
4324     passed since 1970-01-01T00:00:00, Coordinated Universal Time
4325     (Qt::UTC). On systems that do not support time zones this function
4326     will behave as if local time were Qt::UTC.
4327 
4328     \note This function is deprecated. For new code, use setSecsSinceEpoch().
4329 
4330     \sa toTime_t()
4331 */
4332 
setTime_t(uint secsSince1Jan1970UTC)4333 void QDateTime::setTime_t(uint secsSince1Jan1970UTC)
4334 {
4335     setMSecsSinceEpoch((qint64)secsSince1Jan1970UTC * 1000);
4336 }
4337 #endif
4338 
4339 #if QT_CONFIG(datestring) // depends on, so implies, textdate
4340 /*!
4341     \overload
4342 
4343     Returns the datetime as a string in the \a format given.
4344 
4345     If the \a format is Qt::TextDate, the string is formatted in the default
4346     way. The day and month names will be localized names using the system
4347     locale, i.e. QLocale::system(). An example of this formatting is "Wed May 20
4348     03:40:13 1998".
4349 
4350     If the \a format is Qt::ISODate, the string format corresponds
4351     to the ISO 8601 extended specification for representations of
4352     dates and times, taking the form yyyy-MM-ddTHH:mm:ss[Z|[+|-]HH:mm],
4353     depending on the timeSpec() of the QDateTime. If the timeSpec()
4354     is Qt::UTC, Z will be appended to the string; if the timeSpec() is
4355     Qt::OffsetFromUTC, the offset in hours and minutes from UTC will
4356     be appended to the string. To include milliseconds in the ISO 8601
4357     date, use the \a format Qt::ISODateWithMs, which corresponds to
4358     yyyy-MM-ddTHH:mm:ss.zzz[Z|[+|-]HH:mm].
4359 
4360     The \a format options Qt::SystemLocaleDate, Qt::SystemLocaleShortDate and
4361     Qt::SystemLocaleLongDate shall be removed in Qt 6. Their use should be
4362     replaced with
4363     \l {QLocale::toString()}{QLocale::system().toString(datetime, QLocale::ShortFormat)} or
4364     \l {QLocale::toString()}{QLocale::system().toString(datetime, QLocale::LongFormat)}.
4365 
4366     The \a format options Qt::LocaleDate, Qt::DefaultLocaleShortDate and
4367     Qt::DefaultLocaleLongDate shall be removed in Qt 6. Their use should be
4368     replaced with
4369     \l {QLocale::toString()}{QLocale().toString(datetime, QLocale::ShortFormat)} or
4370     \l {QLocale::toString()}{QLocale().toString(datetime, QLocale::LongFormat)}.
4371 
4372     If the \a format is Qt::RFC2822Date, the string is formatted
4373     following \l{RFC 2822}.
4374 
4375     If the datetime is invalid, an empty string will be returned.
4376 
4377     \warning The Qt::ISODate format is only valid for years in the
4378     range 0 to 9999.
4379 
4380     \sa fromString(), QDate::toString(), QTime::toString(),
4381     QLocale::toString()
4382 */
4383 
toString(Qt::DateFormat format) const4384 QString QDateTime::toString(Qt::DateFormat format) const
4385 {
4386     QString buf;
4387     if (!isValid())
4388         return buf;
4389 
4390     switch (format) {
4391 #if QT_DEPRECATED_SINCE(5, 15)
4392 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
4393     case Qt::SystemLocaleDate:
4394     case Qt::SystemLocaleShortDate:
4395         return QLocale::system().toString(*this, QLocale::ShortFormat);
4396     case Qt::SystemLocaleLongDate:
4397         return QLocale::system().toString(*this, QLocale::LongFormat);
4398     case Qt::LocaleDate:
4399     case Qt::DefaultLocaleShortDate:
4400         return QLocale().toString(*this, QLocale::ShortFormat);
4401     case Qt::DefaultLocaleLongDate:
4402         return QLocale().toString(*this, QLocale::LongFormat);
4403 QT_WARNING_POP
4404 #endif // 5.15
4405     case Qt::RFC2822Date: {
4406         buf = QLocale::c().toString(*this, u"dd MMM yyyy hh:mm:ss ");
4407         buf += toOffsetString(Qt::TextDate, offsetFromUtc());
4408         return buf;
4409     }
4410     default:
4411     case Qt::TextDate: {
4412         const QPair<QDate, QTime> p = getDateTime(d);
4413         buf = toStringTextDate(p.first);
4414         // Insert time between date's day and year:
4415         buf.insert(buf.lastIndexOf(QLatin1Char(' ')),
4416                    QLatin1Char(' ') + p.second.toString(Qt::TextDate));
4417         // Append zone/offset indicator, as appropriate:
4418         switch (timeSpec()) {
4419         case Qt::LocalTime:
4420             break;
4421 #if QT_CONFIG(timezone)
4422         case Qt::TimeZone:
4423             buf += QLatin1Char(' ') + d->m_timeZone.abbreviation(*this);
4424             break;
4425 #endif
4426         default:
4427             buf += QLatin1String(" GMT");
4428             if (getSpec(d) == Qt::OffsetFromUTC)
4429                 buf += toOffsetString(Qt::TextDate, offsetFromUtc());
4430         }
4431         return buf;
4432     }
4433     case Qt::ISODate:
4434     case Qt::ISODateWithMs: {
4435         const QPair<QDate, QTime> p = getDateTime(d);
4436         buf = toStringIsoDate(p.first);
4437         if (buf.isEmpty())
4438             return QString();   // failed to convert
4439         buf += QLatin1Char('T') + p.second.toString(format);
4440         switch (getSpec(d)) {
4441         case Qt::UTC:
4442             buf += QLatin1Char('Z');
4443             break;
4444         case Qt::OffsetFromUTC:
4445 #if QT_CONFIG(timezone)
4446         case Qt::TimeZone:
4447 #endif
4448             buf += toOffsetString(Qt::ISODate, offsetFromUtc());
4449             break;
4450         default:
4451             break;
4452         }
4453         return buf;
4454     }
4455     }
4456 }
4457 
4458 /*!
4459     \fn QString QDateTime::toString(const QString &format) const
4460     \fn QString QDateTime::toString(const QString &format, QCalendar cal) const
4461     \fn QString QDateTime::toString(QStringView format) const
4462     \fn QString QDateTime::toString(QStringView format, QCalendar cal) const
4463 
4464     Returns the datetime as a string. The \a format parameter determines the
4465     format of the result string. If \a cal is supplied, it determines the calendar
4466     used to represent the date; it defaults to Gregorian. See QTime::toString()
4467     and QDate::toString() for the supported specifiers for time and date,
4468     respectively.
4469 
4470     Any sequence of characters enclosed in single quotes will be included
4471     verbatim in the output string (stripped of the quotes), even if it contains
4472     formatting characters. Two consecutive single quotes ("''") are replaced by
4473     a single quote in the output. All other characters in the format string are
4474     included verbatim in the output string.
4475 
4476     Formats without separators (e.g. "ddMM") are supported but must be used with
4477     care, as the resulting strings aren't always reliably readable (e.g. if "dM"
4478     produces "212" it could mean either the 2nd of December or the 21st of
4479     February).
4480 
4481     Example format strings (assumed that the QDateTime is 21 May 2001
4482     14:13:09.120):
4483 
4484     \table
4485     \header \li Format       \li Result
4486     \row \li dd.MM.yyyy      \li 21.05.2001
4487     \row \li ddd MMMM d yy   \li Tue May 21 01
4488     \row \li hh:mm:ss.zzz    \li 14:13:09.120
4489     \row \li hh:mm:ss.z      \li 14:13:09.12
4490     \row \li h:m:s ap        \li 2:13:9 pm
4491     \endtable
4492 
4493     If the datetime is invalid, an empty string will be returned.
4494 
4495     \note If localized month and day names are desired, please switch to using
4496     QLocale::system().toString() as QDateTime methods shall change to use
4497     English (C locale) names at Qt 6.
4498 
4499     \sa fromString(), QDate::toString(), QTime::toString(), QLocale::toString()
4500 */
toString(QStringView format) const4501 QString QDateTime::toString(QStringView format) const
4502 {
4503     return toString(format, QCalendar());
4504 }
4505 
toString(QStringView format,QCalendar cal) const4506 QString QDateTime::toString(QStringView format, QCalendar cal) const
4507 {
4508     return QLocale::system().toString(*this, format, cal); // QLocale::c() ### Qt6
4509 }
4510 
4511 #if QT_STRINGVIEW_LEVEL < 2
toString(const QString & format) const4512 QString QDateTime::toString(const QString &format) const
4513 {
4514     return toString(qToStringViewIgnoringNull(format), QCalendar());
4515 }
4516 
toString(const QString & format,QCalendar cal) const4517 QString QDateTime::toString(const QString &format, QCalendar cal) const
4518 {
4519     return toString(qToStringViewIgnoringNull(format), cal);
4520 }
4521 #endif
4522 
4523 #endif // datestring
4524 
massageAdjustedDateTime(const QDateTimeData & d,QDate * date,QTime * time)4525 static inline void massageAdjustedDateTime(const QDateTimeData &d, QDate *date, QTime *time)
4526 {
4527     /*
4528       If we have just adjusted to a day with a DST transition, our given time
4529       may lie in the transition hour (either missing or duplicated).  For any
4530       other time, telling mktime (deep in the bowels of localMSecsToEpochMSecs)
4531       we don't know its DST-ness will produce no adjustment (just a decision as
4532       to its DST-ness); but for a time in spring's missing hour it'll adjust the
4533       time while picking a DST-ness.  (Handling of autumn is trickier, as either
4534       DST-ness is valid, without adjusting the time.  We might want to propagate
4535       the daylight status in that case, but it's hard to do so without breaking
4536       (far more common) other cases; and it makes little difference, as the two
4537       answers do then differ only in DST-ness.)
4538     */
4539     auto spec = getSpec(d);
4540     if (spec == Qt::LocalTime) {
4541         QDateTimePrivate::DaylightStatus status = QDateTimePrivate::UnknownDaylightTime;
4542         localMSecsToEpochMSecs(timeToMSecs(*date, *time), &status, date, time);
4543 #if QT_CONFIG(timezone)
4544     } else if (spec == Qt::TimeZone && d->m_timeZone.isValid()) {
4545         QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time),
4546                                                 d->m_timeZone,
4547                                                 QDateTimePrivate::UnknownDaylightTime,
4548                                                 date, time);
4549 #endif // timezone
4550     }
4551 }
4552 
4553 /*!
4554     Returns a QDateTime object containing a datetime \a ndays days
4555     later than the datetime of this object (or earlier if \a ndays is
4556     negative).
4557 
4558     If the timeSpec() is Qt::LocalTime and the resulting
4559     date and time fall in the Standard Time to Daylight-Saving Time transition
4560     hour then the result will be adjusted accordingly, i.e. if the transition
4561     is at 2am and the clock goes forward to 3am and the result falls between
4562     2am and 3am then the result will be adjusted to fall after 3am.
4563 
4564     \sa daysTo(), addMonths(), addYears(), addSecs()
4565 */
4566 
addDays(qint64 ndays) const4567 QDateTime QDateTime::addDays(qint64 ndays) const
4568 {
4569     QDateTime dt(*this);
4570     QPair<QDate, QTime> p = getDateTime(d);
4571     QDate &date = p.first;
4572     QTime &time = p.second;
4573     date = date.addDays(ndays);
4574     massageAdjustedDateTime(dt.d, &date, &time);
4575     setDateTime(dt.d, date, time);
4576     return dt;
4577 }
4578 
4579 /*!
4580     Returns a QDateTime object containing a datetime \a nmonths months
4581     later than the datetime of this object (or earlier if \a nmonths
4582     is negative).
4583 
4584     If the timeSpec() is Qt::LocalTime and the resulting
4585     date and time fall in the Standard Time to Daylight-Saving Time transition
4586     hour then the result will be adjusted accordingly, i.e. if the transition
4587     is at 2am and the clock goes forward to 3am and the result falls between
4588     2am and 3am then the result will be adjusted to fall after 3am.
4589 
4590     \sa daysTo(), addDays(), addYears(), addSecs()
4591 */
4592 
addMonths(int nmonths) const4593 QDateTime QDateTime::addMonths(int nmonths) const
4594 {
4595     QDateTime dt(*this);
4596     QPair<QDate, QTime> p = getDateTime(d);
4597     QDate &date = p.first;
4598     QTime &time = p.second;
4599     date = date.addMonths(nmonths);
4600     massageAdjustedDateTime(dt.d, &date, &time);
4601     setDateTime(dt.d, date, time);
4602     return dt;
4603 }
4604 
4605 /*!
4606     Returns a QDateTime object containing a datetime \a nyears years
4607     later than the datetime of this object (or earlier if \a nyears is
4608     negative).
4609 
4610     If the timeSpec() is Qt::LocalTime and the resulting
4611     date and time fall in the Standard Time to Daylight-Saving Time transition
4612     hour then the result will be adjusted accordingly, i.e. if the transition
4613     is at 2am and the clock goes forward to 3am and the result falls between
4614     2am and 3am then the result will be adjusted to fall after 3am.
4615 
4616     \sa daysTo(), addDays(), addMonths(), addSecs()
4617 */
4618 
addYears(int nyears) const4619 QDateTime QDateTime::addYears(int nyears) const
4620 {
4621     QDateTime dt(*this);
4622     QPair<QDate, QTime> p = getDateTime(d);
4623     QDate &date = p.first;
4624     QTime &time = p.second;
4625     date = date.addYears(nyears);
4626     massageAdjustedDateTime(dt.d, &date, &time);
4627     setDateTime(dt.d, date, time);
4628     return dt;
4629 }
4630 
4631 /*!
4632     Returns a QDateTime object containing a datetime \a s seconds
4633     later than the datetime of this object (or earlier if \a s is
4634     negative).
4635 
4636     If this datetime is invalid, an invalid datetime will be returned.
4637 
4638     \sa addMSecs(), secsTo(), addDays(), addMonths(), addYears()
4639 */
4640 
addSecs(qint64 s) const4641 QDateTime QDateTime::addSecs(qint64 s) const
4642 {
4643     return addMSecs(s * 1000);
4644 }
4645 
4646 /*!
4647     Returns a QDateTime object containing a datetime \a msecs miliseconds
4648     later than the datetime of this object (or earlier if \a msecs is
4649     negative).
4650 
4651     If this datetime is invalid, an invalid datetime will be returned.
4652 
4653     \sa addSecs(), msecsTo(), addDays(), addMonths(), addYears()
4654 */
addMSecs(qint64 msecs) const4655 QDateTime QDateTime::addMSecs(qint64 msecs) const
4656 {
4657     if (!isValid())
4658         return QDateTime();
4659 
4660     QDateTime dt(*this);
4661     auto spec = getSpec(d);
4662     if (spec == Qt::LocalTime || spec == Qt::TimeZone) {
4663         // Convert to real UTC first in case crosses DST transition
4664         dt.setMSecsSinceEpoch(toMSecsSinceEpoch() + msecs);
4665     } else {
4666         // No need to convert, just add on
4667         if (d.isShort()) {
4668             // need to check if we need to enlarge first
4669             msecs += dt.d.data.msecs;
4670             if (msecsCanBeSmall(msecs)) {
4671                 dt.d.data.msecs = qintptr(msecs);
4672             } else {
4673                 dt.d.detach();
4674                 dt.d->m_msecs = msecs;
4675             }
4676         } else {
4677             dt.d.detach();
4678             dt.d->m_msecs += msecs;
4679         }
4680     }
4681     return dt;
4682 }
4683 
4684 /*!
4685     Returns the number of days from this datetime to the \a other
4686     datetime. The number of days is counted as the number of times
4687     midnight is reached between this datetime to the \a other
4688     datetime. This means that a 10 minute difference from 23:55 to
4689     0:05 the next day counts as one day.
4690 
4691     If the \a other datetime is earlier than this datetime,
4692     the value returned is negative.
4693 
4694     Example:
4695     \snippet code/src_corelib_tools_qdatetime.cpp 15
4696 
4697     \sa addDays(), secsTo(), msecsTo()
4698 */
4699 
daysTo(const QDateTime & other) const4700 qint64 QDateTime::daysTo(const QDateTime &other) const
4701 {
4702     return date().daysTo(other.date());
4703 }
4704 
4705 /*!
4706     Returns the number of seconds from this datetime to the \a other
4707     datetime. If the \a other datetime is earlier than this datetime,
4708     the value returned is negative.
4709 
4710     Before performing the comparison, the two datetimes are converted
4711     to Qt::UTC to ensure that the result is correct if daylight-saving
4712     (DST) applies to one of the two datetimes but not the other.
4713 
4714     Returns 0 if either datetime is invalid.
4715 
4716     Example:
4717     \snippet code/src_corelib_tools_qdatetime.cpp 11
4718 
4719     \sa addSecs(), daysTo(), QTime::secsTo()
4720 */
4721 
secsTo(const QDateTime & other) const4722 qint64 QDateTime::secsTo(const QDateTime &other) const
4723 {
4724     return (msecsTo(other) / 1000);
4725 }
4726 
4727 /*!
4728     Returns the number of milliseconds from this datetime to the \a other
4729     datetime. If the \a other datetime is earlier than this datetime,
4730     the value returned is negative.
4731 
4732     Before performing the comparison, the two datetimes are converted
4733     to Qt::UTC to ensure that the result is correct if daylight-saving
4734     (DST) applies to one of the two datetimes and but not the other.
4735 
4736     Returns 0 if either datetime is invalid.
4737 
4738     \sa addMSecs(), daysTo(), QTime::msecsTo()
4739 */
4740 
msecsTo(const QDateTime & other) const4741 qint64 QDateTime::msecsTo(const QDateTime &other) const
4742 {
4743     if (!isValid() || !other.isValid())
4744         return 0;
4745 
4746     return other.toMSecsSinceEpoch() - toMSecsSinceEpoch();
4747 }
4748 
4749 /*!
4750     \fn QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const
4751 
4752     Returns a copy of this datetime converted to the given time
4753     \a spec.
4754 
4755     If \a spec is Qt::OffsetFromUTC then it is set to Qt::UTC.  To set to a
4756     spec of Qt::OffsetFromUTC use toOffsetFromUtc().
4757 
4758     If \a spec is Qt::TimeZone then it is set to Qt::LocalTime,
4759     i.e. the local Time Zone.
4760 
4761     Example:
4762     \snippet code/src_corelib_tools_qdatetime.cpp 16
4763 
4764     \sa timeSpec(), toTimeZone(), toOffsetFromUtc()
4765 */
4766 
toTimeSpec(Qt::TimeSpec spec) const4767 QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const
4768 {
4769     if (getSpec(d) == spec && (spec == Qt::UTC || spec == Qt::LocalTime))
4770         return *this;
4771 
4772     if (!isValid()) {
4773         QDateTime ret = *this;
4774         ret.setTimeSpec(spec);
4775         return ret;
4776     }
4777 
4778     return fromMSecsSinceEpoch(toMSecsSinceEpoch(), spec, 0);
4779 }
4780 
4781 /*!
4782     \since 5.2
4783 
4784     \fn QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const
4785 
4786     Returns a copy of this datetime converted to a spec of Qt::OffsetFromUTC
4787     with the given \a offsetSeconds.
4788 
4789     If the \a offsetSeconds equals 0 then a UTC datetime will be returned
4790 
4791     \sa setOffsetFromUtc(), offsetFromUtc(), toTimeSpec()
4792 */
4793 
toOffsetFromUtc(int offsetSeconds) const4794 QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const
4795 {
4796     if (getSpec(d) == Qt::OffsetFromUTC
4797             && d->m_offsetFromUtc == offsetSeconds)
4798         return *this;
4799 
4800     if (!isValid()) {
4801         QDateTime ret = *this;
4802         ret.setOffsetFromUtc(offsetSeconds);
4803         return ret;
4804     }
4805 
4806     return fromMSecsSinceEpoch(toMSecsSinceEpoch(), Qt::OffsetFromUTC, offsetSeconds);
4807 }
4808 
4809 #if QT_CONFIG(timezone)
4810 /*!
4811     \since 5.2
4812 
4813     Returns a copy of this datetime converted to the given \a timeZone
4814 
4815     \sa timeZone(), toTimeSpec()
4816 */
4817 
toTimeZone(const QTimeZone & timeZone) const4818 QDateTime QDateTime::toTimeZone(const QTimeZone &timeZone) const
4819 {
4820     if (getSpec(d) == Qt::TimeZone && d->m_timeZone == timeZone)
4821         return *this;
4822 
4823     if (!isValid()) {
4824         QDateTime ret = *this;
4825         ret.setTimeZone(timeZone);
4826         return ret;
4827     }
4828 
4829     return fromMSecsSinceEpoch(toMSecsSinceEpoch(), timeZone);
4830 }
4831 #endif // timezone
4832 
4833 /*!
4834     Returns \c true if this datetime is equal to the \a other datetime;
4835     otherwise returns \c false.
4836 
4837     Since 5.14, all invalid datetimes are equal to one another and differ from
4838     all other datetimes.
4839 
4840     \sa operator!=()
4841 */
4842 
operator ==(const QDateTime & other) const4843 bool QDateTime::operator==(const QDateTime &other) const
4844 {
4845     if (!isValid())
4846         return !other.isValid();
4847     if (!other.isValid())
4848         return false;
4849 
4850     if (getSpec(d) == Qt::LocalTime && getStatus(d) == getStatus(other.d))
4851         return getMSecs(d) == getMSecs(other.d);
4852 
4853     // Convert to UTC and compare
4854     return toMSecsSinceEpoch() == other.toMSecsSinceEpoch();
4855 }
4856 
4857 /*!
4858     \fn bool QDateTime::operator!=(const QDateTime &other) const
4859 
4860     Returns \c true if this datetime is different from the \a other
4861     datetime; otherwise returns \c false.
4862 
4863     Two datetimes are different if either the date, the time, or the time zone
4864     components are different. Since 5.14, any invalid datetime is less than all
4865     valid datetimes.
4866 
4867     \sa operator==()
4868 */
4869 
4870 /*!
4871     Returns \c true if this datetime is earlier than the \a other
4872     datetime; otherwise returns \c false.
4873 */
4874 
operator <(const QDateTime & other) const4875 bool QDateTime::operator<(const QDateTime &other) const
4876 {
4877     if (!isValid())
4878         return other.isValid();
4879     if (!other.isValid())
4880         return false;
4881 
4882     if (getSpec(d) == Qt::LocalTime && getStatus(d) == getStatus(other.d))
4883         return getMSecs(d) < getMSecs(other.d);
4884 
4885     // Convert to UTC and compare
4886     return toMSecsSinceEpoch() < other.toMSecsSinceEpoch();
4887 }
4888 
4889 /*!
4890     \fn bool QDateTime::operator<=(const QDateTime &other) const
4891 
4892     Returns \c true if this datetime is earlier than or equal to the
4893     \a other datetime; otherwise returns \c false.
4894 */
4895 
4896 /*!
4897     \fn bool QDateTime::operator>(const QDateTime &other) const
4898 
4899     Returns \c true if this datetime is later than the \a other datetime;
4900     otherwise returns \c false.
4901 */
4902 
4903 /*!
4904     \fn bool QDateTime::operator>=(const QDateTime &other) const
4905 
4906     Returns \c true if this datetime is later than or equal to the
4907     \a other datetime; otherwise returns \c false.
4908 */
4909 
4910 /*!
4911     \fn QDateTime QDateTime::currentDateTime()
4912     Returns the current datetime, as reported by the system clock, in
4913     the local time zone.
4914 
4915     \sa currentDateTimeUtc(), QDate::currentDate(), QTime::currentTime(), toTimeSpec()
4916 */
4917 
4918 /*!
4919     \fn QDateTime QDateTime::currentDateTimeUtc()
4920     \since 4.7
4921     Returns the current datetime, as reported by the system clock, in
4922     UTC.
4923 
4924     \sa currentDateTime(), QDate::currentDate(), QTime::currentTime(), toTimeSpec()
4925 */
4926 
4927 /*!
4928     \fn qint64 QDateTime::currentMSecsSinceEpoch()
4929     \since 4.7
4930 
4931     Returns the number of milliseconds since 1970-01-01T00:00:00 Universal
4932     Coordinated Time. This number is like the POSIX time_t variable, but
4933     expressed in milliseconds instead.
4934 
4935     \sa currentDateTime(), currentDateTimeUtc(), toTime_t(), toTimeSpec()
4936 */
4937 
4938 /*!
4939     \fn qint64 QDateTime::currentSecsSinceEpoch()
4940     \since 5.8
4941 
4942     Returns the number of seconds since 1970-01-01T00:00:00 Universal
4943     Coordinated Time.
4944 
4945     \sa currentMSecsSinceEpoch()
4946 */
4947 
4948 #if defined(Q_OS_WIN)
msecsFromDecomposed(int hour,int minute,int sec,int msec=0)4949 static inline uint msecsFromDecomposed(int hour, int minute, int sec, int msec = 0)
4950 {
4951     return MSECS_PER_HOUR * hour + MSECS_PER_MIN * minute + 1000 * sec + msec;
4952 }
4953 
currentDate()4954 QDate QDate::currentDate()
4955 {
4956     SYSTEMTIME st;
4957     memset(&st, 0, sizeof(SYSTEMTIME));
4958     GetLocalTime(&st);
4959     return QDate(st.wYear, st.wMonth, st.wDay);
4960 }
4961 
currentTime()4962 QTime QTime::currentTime()
4963 {
4964     QTime ct;
4965     SYSTEMTIME st;
4966     memset(&st, 0, sizeof(SYSTEMTIME));
4967     GetLocalTime(&st);
4968     ct.setHMS(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
4969     return ct;
4970 }
4971 
currentDateTime()4972 QDateTime QDateTime::currentDateTime()
4973 {
4974     QTime t;
4975     SYSTEMTIME st;
4976     memset(&st, 0, sizeof(SYSTEMTIME));
4977     GetLocalTime(&st);
4978     QDate d(st.wYear, st.wMonth, st.wDay);
4979     t.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
4980     return QDateTime(d, t);
4981 }
4982 
currentDateTimeUtc()4983 QDateTime QDateTime::currentDateTimeUtc()
4984 {
4985     QTime t;
4986     SYSTEMTIME st;
4987     memset(&st, 0, sizeof(SYSTEMTIME));
4988     GetSystemTime(&st);
4989     QDate d(st.wYear, st.wMonth, st.wDay);
4990     t.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
4991     return QDateTime(d, t, Qt::UTC);
4992 }
4993 
currentMSecsSinceEpoch()4994 qint64 QDateTime::currentMSecsSinceEpoch() noexcept
4995 {
4996     SYSTEMTIME st;
4997     memset(&st, 0, sizeof(SYSTEMTIME));
4998     GetSystemTime(&st);
4999     const qint64 daysAfterEpoch = QDate(1970, 1, 1).daysTo(QDate(st.wYear, st.wMonth, st.wDay));
5000 
5001     return msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds) +
5002            daysAfterEpoch * Q_INT64_C(86400000);
5003 }
5004 
currentSecsSinceEpoch()5005 qint64 QDateTime::currentSecsSinceEpoch() noexcept
5006 {
5007     SYSTEMTIME st;
5008     memset(&st, 0, sizeof(SYSTEMTIME));
5009     GetSystemTime(&st);
5010     const qint64 daysAfterEpoch = QDate(1970, 1, 1).daysTo(QDate(st.wYear, st.wMonth, st.wDay));
5011 
5012     return st.wHour * SECS_PER_HOUR + st.wMinute * SECS_PER_MIN + st.wSecond +
5013            daysAfterEpoch * Q_INT64_C(86400);
5014 }
5015 
5016 #elif defined(Q_OS_UNIX)
currentDate()5017 QDate QDate::currentDate()
5018 {
5019     return QDateTime::currentDateTime().date();
5020 }
5021 
currentTime()5022 QTime QTime::currentTime()
5023 {
5024     return QDateTime::currentDateTime().time();
5025 }
5026 
currentDateTime()5027 QDateTime QDateTime::currentDateTime()
5028 {
5029     return fromMSecsSinceEpoch(currentMSecsSinceEpoch(), Qt::LocalTime);
5030 }
5031 
currentDateTimeUtc()5032 QDateTime QDateTime::currentDateTimeUtc()
5033 {
5034     return fromMSecsSinceEpoch(currentMSecsSinceEpoch(), Qt::UTC);
5035 }
5036 
currentMSecsSinceEpoch()5037 qint64 QDateTime::currentMSecsSinceEpoch() noexcept
5038 {
5039     // posix compliant system
5040     // we have milliseconds
5041     struct timeval tv;
5042     gettimeofday(&tv, nullptr);
5043     return qint64(tv.tv_sec) * Q_INT64_C(1000) + tv.tv_usec / 1000;
5044 }
5045 
currentSecsSinceEpoch()5046 qint64 QDateTime::currentSecsSinceEpoch() noexcept
5047 {
5048     struct timeval tv;
5049     gettimeofday(&tv, nullptr);
5050     return qint64(tv.tv_sec);
5051 }
5052 #else
5053 #error "What system is this?"
5054 #endif
5055 
5056 #if QT_DEPRECATED_SINCE(5, 8)
5057 /*!
5058   \since 4.2
5059   \deprecated
5060 
5061   Returns a datetime whose date and time are the number of \a seconds
5062   that have passed since 1970-01-01T00:00:00, Coordinated Universal
5063   Time (Qt::UTC) and converted to Qt::LocalTime.  On systems that do not
5064   support time zones, the time will be set as if local time were Qt::UTC.
5065 
5066   \note This function is deprecated. Please use fromSecsSinceEpoch() in new
5067   code.
5068 
5069   \sa toTime_t(), setTime_t()
5070 */
fromTime_t(uint seconds)5071 QDateTime QDateTime::fromTime_t(uint seconds)
5072 {
5073     return fromMSecsSinceEpoch((qint64)seconds * 1000, Qt::LocalTime);
5074 }
5075 
5076 /*!
5077   \since 5.2
5078   \deprecated
5079 
5080   Returns a datetime whose date and time are the number of \a seconds
5081   that have passed since 1970-01-01T00:00:00, Coordinated Universal
5082   Time (Qt::UTC) and converted to the given \a spec.
5083 
5084   If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be
5085   ignored.  If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0
5086   then the spec will be set to Qt::UTC, i.e. an offset of 0 seconds.
5087 
5088   \note This function is deprecated. Please use fromSecsSinceEpoch() in new
5089   code.
5090 
5091   \sa toTime_t(), setTime_t()
5092 */
fromTime_t(uint seconds,Qt::TimeSpec spec,int offsetSeconds)5093 QDateTime QDateTime::fromTime_t(uint seconds, Qt::TimeSpec spec, int offsetSeconds)
5094 {
5095     return fromMSecsSinceEpoch((qint64)seconds * 1000, spec, offsetSeconds);
5096 }
5097 
5098 #if QT_CONFIG(timezone)
5099 /*!
5100     \since 5.2
5101     \deprecated
5102 
5103     Returns a datetime whose date and time are the number of \a seconds
5104     that have passed since 1970-01-01T00:00:00, Coordinated Universal
5105     Time (Qt::UTC) and with the given \a timeZone.
5106 
5107     \note This function is deprecated. Please use fromSecsSinceEpoch() in new
5108     code.
5109 
5110     \sa toTime_t(), setTime_t()
5111 */
fromTime_t(uint seconds,const QTimeZone & timeZone)5112 QDateTime QDateTime::fromTime_t(uint seconds, const QTimeZone &timeZone)
5113 {
5114     return fromMSecsSinceEpoch((qint64)seconds * 1000, timeZone);
5115 }
5116 #endif
5117 #endif // QT_DEPRECATED_SINCE(5, 8)
5118 
5119 /*!
5120   \since 4.7
5121 
5122   Returns a datetime whose date and time are the number of milliseconds, \a msecs,
5123   that have passed since 1970-01-01T00:00:00.000, Coordinated Universal
5124   Time (Qt::UTC), and converted to Qt::LocalTime.  On systems that do not
5125   support time zones, the time will be set as if local time were Qt::UTC.
5126 
5127   Note that there are possible values for \a msecs that lie outside the valid
5128   range of QDateTime, both negative and positive. The behavior of this
5129   function is undefined for those values.
5130 
5131   \sa toMSecsSinceEpoch(), setMSecsSinceEpoch()
5132 */
fromMSecsSinceEpoch(qint64 msecs)5133 QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs)
5134 {
5135     return fromMSecsSinceEpoch(msecs, Qt::LocalTime);
5136 }
5137 
5138 /*!
5139   \since 5.2
5140 
5141   Returns a datetime whose date and time are the number of milliseconds \a msecs
5142   that have passed since 1970-01-01T00:00:00.000, Coordinated Universal
5143   Time (Qt::UTC) and converted to the given \a spec.
5144 
5145   Note that there are possible values for \a msecs that lie outside the valid
5146   range of QDateTime, both negative and positive. The behavior of this
5147   function is undefined for those values.
5148 
5149   If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be
5150   ignored.  If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0
5151   then the spec will be set to Qt::UTC, i.e. an offset of 0 seconds.
5152 
5153   If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
5154   i.e. the current system time zone.
5155 
5156   \sa toMSecsSinceEpoch(), setMSecsSinceEpoch()
5157 */
fromMSecsSinceEpoch(qint64 msecs,Qt::TimeSpec spec,int offsetSeconds)5158 QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int offsetSeconds)
5159 {
5160     QDateTime dt;
5161     QT_PREPEND_NAMESPACE(setTimeSpec(dt.d, spec, offsetSeconds));
5162     dt.setMSecsSinceEpoch(msecs);
5163     return dt;
5164 }
5165 
5166 /*!
5167   \since 5.8
5168 
5169   Returns a datetime whose date and time are the number of seconds \a secs
5170   that have passed since 1970-01-01T00:00:00.000, Coordinated Universal
5171   Time (Qt::UTC) and converted to the given \a spec.
5172 
5173   Note that there are possible values for \a secs that lie outside the valid
5174   range of QDateTime, both negative and positive. The behavior of this
5175   function is undefined for those values.
5176 
5177   If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be
5178   ignored.  If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0
5179   then the spec will be set to Qt::UTC, i.e. an offset of 0 seconds.
5180 
5181   If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
5182   i.e. the current system time zone.
5183 
5184   \sa toSecsSinceEpoch(), setSecsSinceEpoch()
5185 */
fromSecsSinceEpoch(qint64 secs,Qt::TimeSpec spec,int offsetSeconds)5186 QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec, int offsetSeconds)
5187 {
5188     return fromMSecsSinceEpoch(secs * 1000, spec, offsetSeconds);
5189 }
5190 
5191 #if QT_CONFIG(timezone)
5192 /*!
5193     \since 5.2
5194 
5195     Returns a datetime whose date and time are the number of milliseconds \a msecs
5196     that have passed since 1970-01-01T00:00:00.000, Coordinated Universal
5197     Time (Qt::UTC) and with the given \a timeZone.
5198 
5199     \sa fromSecsSinceEpoch()
5200 */
fromMSecsSinceEpoch(qint64 msecs,const QTimeZone & timeZone)5201 QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone)
5202 {
5203     QDateTime dt;
5204     dt.setTimeZone(timeZone);
5205     if (timeZone.isValid())
5206         dt.setMSecsSinceEpoch(msecs);
5207     return dt;
5208 }
5209 
5210 /*!
5211     \since 5.8
5212 
5213     Returns a datetime whose date and time are the number of seconds \a secs
5214     that have passed since 1970-01-01T00:00:00.000, Coordinated Universal
5215     Time (Qt::UTC) and with the given \a timeZone.
5216 
5217     \sa fromMSecsSinceEpoch()
5218 */
fromSecsSinceEpoch(qint64 secs,const QTimeZone & timeZone)5219 QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, const QTimeZone &timeZone)
5220 {
5221     return fromMSecsSinceEpoch(secs * 1000, timeZone);
5222 }
5223 #endif
5224 
5225 #if QT_DEPRECATED_SINCE(5, 2)
5226 /*!
5227     \since 4.4
5228     \internal
5229     \obsolete
5230 
5231     This method was added in 4.4 but never documented as public. It was replaced
5232     in 5.2 with public method setOffsetFromUtc() for consistency with QTimeZone.
5233 
5234     This method should never be made public.
5235 
5236     \sa setOffsetFromUtc()
5237  */
setUtcOffset(int seconds)5238 void QDateTime::setUtcOffset(int seconds)
5239 {
5240     setOffsetFromUtc(seconds);
5241 }
5242 
5243 /*!
5244     \since 4.4
5245     \internal
5246     \obsolete
5247 
5248     This method was added in 4.4 but never documented as public. It was replaced
5249     in 5.1 with public method offsetFromUTC() for consistency with QTimeZone.
5250 
5251     This method should never be made public.
5252 
5253     \sa offsetFromUTC()
5254 */
utcOffset() const5255 int QDateTime::utcOffset() const
5256 {
5257     return offsetFromUtc();
5258 }
5259 #endif // QT_DEPRECATED_SINCE
5260 
5261 #if QT_CONFIG(datestring) // depends on, so implies, textdate
5262 
5263 /*!
5264     Returns the QDateTime represented by the \a string, using the
5265     \a format given, or an invalid datetime if this is not possible.
5266 
5267     Note for Qt::TextDate: It is recommended that you use the English short
5268     month names (e.g. "Jan"). Although localized month names can also be used in
5269     Qt 5, they depend on the user's locale settings.
5270 
5271     \note Support for localized dates, including the format options
5272     Qt::SystemLocaleDate, Qt::SystemLocaleShortDate, Qt::SystemLocaleLongDate,
5273     Qt::LocaleDate, Qt::DefaultLocaleShortDate, and Qt::DefaultLocaleLongDate,
5274     shall be removed in Qt 6. Use QLocale::toDateTime() instead.
5275 
5276     \sa toString(), QLocale::toDateTime()
5277 */
fromString(const QString & string,Qt::DateFormat format)5278 QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format)
5279 {
5280     if (string.isEmpty())
5281         return QDateTime();
5282 
5283     switch (format) {
5284 #if QT_DEPRECATED_SINCE(5, 15)
5285 QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
5286     case Qt::SystemLocaleDate:
5287     case Qt::SystemLocaleShortDate:
5288         return QLocale::system().toDateTime(string, QLocale::ShortFormat);
5289     case Qt::SystemLocaleLongDate:
5290         return QLocale::system().toDateTime(string, QLocale::LongFormat);
5291     case Qt::LocaleDate:
5292     case Qt::DefaultLocaleShortDate:
5293         return QLocale().toDateTime(string, QLocale::ShortFormat);
5294     case Qt::DefaultLocaleLongDate:
5295         return QLocale().toDateTime(string, QLocale::LongFormat);
5296 QT_WARNING_POP
5297 #endif // 5.15
5298     case Qt::RFC2822Date: {
5299         const ParsedRfcDateTime rfc = rfcDateImpl(string);
5300 
5301         if (!rfc.date.isValid() || !rfc.time.isValid())
5302             return QDateTime();
5303 
5304         QDateTime dateTime(rfc.date, rfc.time, Qt::UTC);
5305         dateTime.setOffsetFromUtc(rfc.utcOffset);
5306         return dateTime;
5307     }
5308     case Qt::ISODate:
5309     case Qt::ISODateWithMs: {
5310         const int size = string.size();
5311         if (size < 10)
5312             return QDateTime();
5313 
5314         QDate date = QDate::fromString(string.left(10), Qt::ISODate);
5315         if (!date.isValid())
5316             return QDateTime();
5317         if (size == 10)
5318             return date.startOfDay();
5319 
5320         Qt::TimeSpec spec = Qt::LocalTime;
5321         QStringView isoString = QStringView(string).mid(10); // trim "yyyy-MM-dd"
5322 
5323         // Must be left with T (or space) and at least one digit for the hour:
5324         if (isoString.size() < 2
5325             || !(isoString.startsWith(QLatin1Char('T'), Qt::CaseInsensitive)
5326                  // RFC 3339 (section 5.6) allows a space here.  (It actually
5327                  // allows any separator one considers more readable, merely
5328                  // giving space as an example - but let's not go wild !)
5329                  || isoString.startsWith(QLatin1Char(' ')))) {
5330             return QDateTime();
5331         }
5332         isoString = isoString.mid(1); // trim 'T' (or space)
5333 
5334         int offset = 0;
5335         // Check end of string for Time Zone definition, either Z for UTC or [+-]HH:mm for Offset
5336         if (isoString.endsWith(QLatin1Char('Z'), Qt::CaseInsensitive)) {
5337             spec = Qt::UTC;
5338             isoString.chop(1); // trim 'Z'
5339         } else {
5340             // the loop below is faster but functionally equal to:
5341             // const int signIndex = isoString.indexOf(QRegExp(QStringLiteral("[+-]")));
5342             int signIndex = isoString.size() - 1;
5343             Q_ASSERT(signIndex >= 0);
5344             bool found = false;
5345             {
5346                 const QChar plus = QLatin1Char('+');
5347                 const QChar minus = QLatin1Char('-');
5348                 do {
5349                     QChar character(isoString.at(signIndex));
5350                     found = character == plus || character == minus;
5351                 } while (!found && --signIndex >= 0);
5352             }
5353 
5354             if (found) {
5355                 bool ok;
5356                 offset = fromOffsetString(isoString.mid(signIndex), &ok);
5357                 if (!ok)
5358                     return QDateTime();
5359                 isoString = isoString.left(signIndex);
5360                 spec = Qt::OffsetFromUTC;
5361             }
5362         }
5363 
5364         // Might be end of day (24:00, including variants), which QTime considers invalid.
5365         // ISO 8601 (section 4.2.3) says that 24:00 is equivalent to 00:00 the next day.
5366         bool isMidnight24 = false;
5367         QTime time = fromIsoTimeString(isoString, format, &isMidnight24);
5368         if (!time.isValid())
5369             return QDateTime();
5370         if (isMidnight24)
5371             date = date.addDays(1);
5372         return QDateTime(date, time, spec, offset);
5373     }
5374     case Qt::TextDate: {
5375         QVector<QStringRef> parts = string.splitRef(QLatin1Char(' '), Qt::SkipEmptyParts);
5376 
5377         if ((parts.count() < 5) || (parts.count() > 6))
5378             return QDateTime();
5379 
5380         // Accept "Sun Dec 1 13:02:00 1974" and "Sun 1. Dec 13:02:00 1974"
5381 
5382         // Year and time can be in either order.
5383         // Guess which by looking for ':' in the time
5384         int yearPart = 3;
5385         int timePart = 3;
5386         if (parts.at(3).contains(QLatin1Char(':')))
5387             yearPart = 4;
5388         else if (parts.at(4).contains(QLatin1Char(':')))
5389             timePart = 4;
5390         else
5391             return QDateTime();
5392 
5393         int month = 0;
5394         int day = 0;
5395         bool ok = false;
5396 
5397         int year = parts.at(yearPart).toInt(&ok);
5398         if (!ok || year == 0)
5399             return QDateTime();
5400 
5401         // Next try month then day
5402         month = fromShortMonthName(parts.at(1), year);
5403         if (month)
5404             day = parts.at(2).toInt(&ok);
5405 
5406         // If failed, try day then month
5407         if (!ok || !month || !day) {
5408             month = fromShortMonthName(parts.at(2), year);
5409             if (month) {
5410                 QStringRef dayStr = parts.at(1);
5411                 if (dayStr.endsWith(QLatin1Char('.'))) {
5412                     dayStr = dayStr.left(dayStr.size() - 1);
5413                     day = dayStr.toInt(&ok);
5414                 }
5415             }
5416         }
5417 
5418         // If both failed, give up
5419         if (!ok || !month || !day)
5420             return QDateTime();
5421 
5422         QDate date(year, month, day);
5423         if (!date.isValid())
5424             return QDateTime();
5425 
5426         QVector<QStringRef> timeParts = parts.at(timePart).split(QLatin1Char(':'));
5427         if (timeParts.count() < 2 || timeParts.count() > 3)
5428             return QDateTime();
5429 
5430         int hour = timeParts.at(0).toInt(&ok);
5431         if (!ok)
5432             return QDateTime();
5433 
5434         int minute = timeParts.at(1).toInt(&ok);
5435         if (!ok)
5436             return QDateTime();
5437 
5438         int second = 0;
5439         int millisecond = 0;
5440         if (timeParts.count() > 2) {
5441             const QVector<QStringRef> secondParts = timeParts.at(2).split(QLatin1Char('.'));
5442             if (secondParts.size() > 2) {
5443                 return QDateTime();
5444             }
5445 
5446             second = secondParts.first().toInt(&ok);
5447             if (!ok) {
5448                 return QDateTime();
5449             }
5450 
5451             if (secondParts.size() > 1) {
5452                 millisecond = secondParts.last().toInt(&ok);
5453                 if (!ok) {
5454                     return QDateTime();
5455                 }
5456             }
5457         }
5458 
5459         QTime time(hour, minute, second, millisecond);
5460         if (!time.isValid())
5461             return QDateTime();
5462 
5463         if (parts.count() == 5)
5464             return QDateTime(date, time, Qt::LocalTime);
5465 
5466         QStringView tz = parts.at(5);
5467         if (!tz.startsWith(QLatin1String("GMT"), Qt::CaseInsensitive))
5468             return QDateTime();
5469         tz = tz.mid(3);
5470         if (!tz.isEmpty()) {
5471             int offset = fromOffsetString(tz, &ok);
5472             if (!ok)
5473                 return QDateTime();
5474             return QDateTime(date, time, Qt::OffsetFromUTC, offset);
5475         } else {
5476             return QDateTime(date, time, Qt::UTC);
5477         }
5478     }
5479     }
5480 
5481     return QDateTime();
5482 }
5483 
5484 /*!
5485     Returns the QDateTime represented by the \a string, using the \a
5486     format given, or an invalid datetime if the string cannot be parsed.
5487 
5488     Uses the calendar \a cal if supplied, else Gregorian.
5489 
5490     In addition to the expressions, recognized in the format string to represent
5491     parts of the date and time, by QDate::fromString() and QTime::fromString(),
5492     this method supports:
5493 
5494     \table
5495     \header \li Expression \li Output
5496     \row \li t \li the timezone (for example "CEST")
5497     \endtable
5498 
5499     All other input characters will be treated as text. Any non-empty sequence
5500     of characters enclosed in single quotes will also be treated (stripped of
5501     the quotes) as text and not be interpreted as expressions.
5502 
5503     \snippet code/src_corelib_tools_qdatetime.cpp 12
5504 
5505     If the format is not satisfied, an invalid QDateTime is returned.  If the
5506     format is satisfied but \a string represents an invalid date-time (e.g. in a
5507     gap skipped by a time-zone transition), an invalid QDateTime is returned,
5508     whose toMSecsSinceEpoch() represents a near-by date-time that is
5509     valid. Passing that to fromMSecsSinceEpoch() will produce a valid date-time
5510     that isn't faithfully represented by the string parsed.
5511 
5512     The expressions that don't have leading zeroes (d, M, h, m, s, z) will be
5513     greedy. This means that they will use two digits even if this will
5514     put them outside the range and/or leave too few digits for other
5515     sections.
5516 
5517     \snippet code/src_corelib_tools_qdatetime.cpp 13
5518 
5519     This could have meant 1 January 00:30.00 but the M will grab
5520     two digits.
5521 
5522     Incorrectly specified fields of the \a string will cause an invalid
5523     QDateTime to be returned. For example, consider the following code,
5524     where the two digit year 12 is read as 1912 (see the table below for all
5525     field defaults); the resulting datetime is invalid because 23 April 1912
5526     was a Tuesday, not a Monday:
5527 
5528     \snippet code/src_corelib_tools_qdatetime.cpp 20
5529 
5530     The correct code is:
5531 
5532     \snippet code/src_corelib_tools_qdatetime.cpp 21
5533 
5534     For any field that is not represented in the format, the following
5535     defaults are used:
5536 
5537     \table
5538     \header \li Field  \li Default value
5539     \row    \li Year   \li 1900
5540     \row    \li Month  \li 1 (January)
5541     \row    \li Day    \li 1
5542     \row    \li Hour   \li 0
5543     \row    \li Minute \li 0
5544     \row    \li Second \li 0
5545     \endtable
5546 
5547     For example:
5548 
5549     \snippet code/src_corelib_tools_qdatetime.cpp 14
5550 
5551     \note If localized month and day names are used, please switch to using
5552     QLocale::system().toDateTime() as QDateTime methods shall change to only
5553     recognize English (C locale) names at Qt 6.
5554 
5555     \sa toString(), QDate::fromString(), QTime::fromString(),
5556     QLocale::toDateTime()
5557 */
5558 
fromString(const QString & string,const QString & format,QCalendar cal)5559 QDateTime QDateTime::fromString(const QString &string, const QString &format, QCalendar cal)
5560 {
5561 #if QT_CONFIG(datetimeparser)
5562     QDateTime datetime;
5563 
5564     QDateTimeParser dt(QMetaType::QDateTime, QDateTimeParser::FromString, cal);
5565     // dt.setDefaultLocale(QLocale::c()); ### Qt 6
5566     if (dt.parseFormat(format) && (dt.fromString(string, &datetime) || !datetime.isValid()))
5567         return datetime;
5568 #else
5569     Q_UNUSED(string);
5570     Q_UNUSED(format);
5571     Q_UNUSED(cal);
5572 #endif
5573     return QDateTime();
5574 }
5575 
5576 /*
5577   \overload
5578 */
5579 
fromString(const QString & string,const QString & format)5580 QDateTime QDateTime::fromString(const QString &string, const QString &format)
5581 {
5582     return fromString(string, format, QCalendar());
5583 }
5584 
5585 #endif // datestring
5586 /*!
5587     \fn QDateTime QDateTime::toLocalTime() const
5588 
5589     Returns a datetime containing the date and time information in
5590     this datetime, but specified using the Qt::LocalTime definition.
5591 
5592     Example:
5593 
5594     \snippet code/src_corelib_tools_qdatetime.cpp 17
5595 
5596     \sa toTimeSpec()
5597 */
5598 
5599 /*!
5600     \fn QDateTime QDateTime::toUTC() const
5601 
5602     Returns a datetime containing the date and time information in
5603     this datetime, but specified using the Qt::UTC definition.
5604 
5605     Example:
5606 
5607     \snippet code/src_corelib_tools_qdatetime.cpp 18
5608 
5609     \sa toTimeSpec()
5610 */
5611 
5612 /*****************************************************************************
5613   Date/time stream functions
5614  *****************************************************************************/
5615 
5616 #ifndef QT_NO_DATASTREAM
5617 /*!
5618     \relates QDate
5619 
5620     Writes the \a date to stream \a out.
5621 
5622     \sa {Serializing Qt Data Types}
5623 */
5624 
operator <<(QDataStream & out,const QDate & date)5625 QDataStream &operator<<(QDataStream &out, const QDate &date)
5626 {
5627     if (out.version() < QDataStream::Qt_5_0)
5628         return out << quint32(date.jd);
5629     else
5630         return out << qint64(date.jd);
5631 }
5632 
5633 /*!
5634     \relates QDate
5635 
5636     Reads a date from stream \a in into the \a date.
5637 
5638     \sa {Serializing Qt Data Types}
5639 */
5640 
operator >>(QDataStream & in,QDate & date)5641 QDataStream &operator>>(QDataStream &in, QDate &date)
5642 {
5643     if (in.version() < QDataStream::Qt_5_0) {
5644         quint32 jd;
5645         in >> jd;
5646         // Older versions consider 0 an invalid jd.
5647         date.jd = (jd != 0 ? jd : QDate::nullJd());
5648     } else {
5649         qint64 jd;
5650         in >> jd;
5651         date.jd = jd;
5652     }
5653 
5654     return in;
5655 }
5656 
5657 /*!
5658     \relates QTime
5659 
5660     Writes \a time to stream \a out.
5661 
5662     \sa {Serializing Qt Data Types}
5663 */
5664 
operator <<(QDataStream & out,const QTime & time)5665 QDataStream &operator<<(QDataStream &out, const QTime &time)
5666 {
5667     if (out.version() >= QDataStream::Qt_4_0) {
5668         return out << quint32(time.mds);
5669     } else {
5670         // Qt3 had no support for reading -1, QTime() was valid and serialized as 0
5671         return out << quint32(time.isNull() ? 0 : time.mds);
5672     }
5673 }
5674 
5675 /*!
5676     \relates QTime
5677 
5678     Reads a time from stream \a in into the given \a time.
5679 
5680     \sa {Serializing Qt Data Types}
5681 */
5682 
operator >>(QDataStream & in,QTime & time)5683 QDataStream &operator>>(QDataStream &in, QTime &time)
5684 {
5685     quint32 ds;
5686     in >> ds;
5687     if (in.version() >= QDataStream::Qt_4_0) {
5688         time.mds = int(ds);
5689     } else {
5690         // Qt3 would write 0 for a null time
5691         time.mds = (ds == 0) ? QTime::NullTime : int(ds);
5692     }
5693     return in;
5694 }
5695 
5696 /*!
5697     \relates QDateTime
5698 
5699     Writes \a dateTime to the \a out stream.
5700 
5701     \sa {Serializing Qt Data Types}
5702 */
operator <<(QDataStream & out,const QDateTime & dateTime)5703 QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime)
5704 {
5705     QPair<QDate, QTime> dateAndTime;
5706 
5707     if (out.version() >= QDataStream::Qt_5_2) {
5708 
5709         // In 5.2 we switched to using Qt::TimeSpec and added offset support
5710         dateAndTime = getDateTime(dateTime.d);
5711         out << dateAndTime << qint8(dateTime.timeSpec());
5712         if (dateTime.timeSpec() == Qt::OffsetFromUTC)
5713             out << qint32(dateTime.offsetFromUtc());
5714 #if QT_CONFIG(timezone)
5715         else if (dateTime.timeSpec() == Qt::TimeZone)
5716             out << dateTime.timeZone();
5717 #endif // timezone
5718 
5719     } else if (out.version() == QDataStream::Qt_5_0) {
5720 
5721         // In Qt 5.0 we incorrectly serialised all datetimes as UTC.
5722         // This approach is wrong and should not be used again; it breaks
5723         // the guarantee that a deserialised local datetime is the same time
5724         // of day, regardless of which timezone it was serialised in.
5725         dateAndTime = getDateTime((dateTime.isValid() ? dateTime.toUTC() : dateTime).d);
5726         out << dateAndTime << qint8(dateTime.timeSpec());
5727 
5728     } else if (out.version() >= QDataStream::Qt_4_0) {
5729 
5730         // From 4.0 to 5.1 (except 5.0) we used QDateTimePrivate::Spec
5731         dateAndTime = getDateTime(dateTime.d);
5732         out << dateAndTime;
5733         switch (dateTime.timeSpec()) {
5734         case Qt::UTC:
5735             out << (qint8)QDateTimePrivate::UTC;
5736             break;
5737         case Qt::OffsetFromUTC:
5738             out << (qint8)QDateTimePrivate::OffsetFromUTC;
5739             break;
5740         case Qt::TimeZone:
5741             out << (qint8)QDateTimePrivate::TimeZone;
5742             break;
5743         case Qt::LocalTime:
5744             out << (qint8)QDateTimePrivate::LocalUnknown;
5745             break;
5746         }
5747 
5748     } else { // version < QDataStream::Qt_4_0
5749 
5750         // Before 4.0 there was no TimeSpec, only Qt::LocalTime was supported
5751         dateAndTime = getDateTime(dateTime.d);
5752         out << dateAndTime;
5753 
5754     }
5755 
5756     return out;
5757 }
5758 
5759 /*!
5760     \relates QDateTime
5761 
5762     Reads a datetime from the stream \a in into \a dateTime.
5763 
5764     \sa {Serializing Qt Data Types}
5765 */
5766 
operator >>(QDataStream & in,QDateTime & dateTime)5767 QDataStream &operator>>(QDataStream &in, QDateTime &dateTime)
5768 {
5769     QDate dt;
5770     QTime tm;
5771     qint8 ts = 0;
5772     Qt::TimeSpec spec = Qt::LocalTime;
5773     qint32 offset = 0;
5774 #if QT_CONFIG(timezone)
5775     QTimeZone tz;
5776 #endif // timezone
5777 
5778     if (in.version() >= QDataStream::Qt_5_2) {
5779 
5780         // In 5.2 we switched to using Qt::TimeSpec and added offset support
5781         in >> dt >> tm >> ts;
5782         spec = static_cast<Qt::TimeSpec>(ts);
5783         if (spec == Qt::OffsetFromUTC) {
5784             in >> offset;
5785             dateTime = QDateTime(dt, tm, spec, offset);
5786 #if QT_CONFIG(timezone)
5787         } else if (spec == Qt::TimeZone) {
5788             in >> tz;
5789             dateTime = QDateTime(dt, tm, tz);
5790 #endif // timezone
5791         } else {
5792             dateTime = QDateTime(dt, tm, spec);
5793         }
5794 
5795     } else if (in.version() == QDataStream::Qt_5_0) {
5796 
5797         // In Qt 5.0 we incorrectly serialised all datetimes as UTC
5798         in >> dt >> tm >> ts;
5799         spec = static_cast<Qt::TimeSpec>(ts);
5800         dateTime = QDateTime(dt, tm, Qt::UTC);
5801         dateTime = dateTime.toTimeSpec(spec);
5802 
5803     } else if (in.version() >= QDataStream::Qt_4_0) {
5804 
5805         // From 4.0 to 5.1 (except 5.0) we used QDateTimePrivate::Spec
5806         in >> dt >> tm >> ts;
5807         switch ((QDateTimePrivate::Spec)ts) {
5808         case QDateTimePrivate::UTC:
5809             spec = Qt::UTC;
5810             break;
5811         case QDateTimePrivate::OffsetFromUTC:
5812             spec = Qt::OffsetFromUTC;
5813             break;
5814         case QDateTimePrivate::TimeZone:
5815             spec = Qt::TimeZone;
5816 #if QT_CONFIG(timezone)
5817             // FIXME: need to use a different constructor !
5818 #endif
5819             break;
5820         case QDateTimePrivate::LocalUnknown:
5821         case QDateTimePrivate::LocalStandard:
5822         case QDateTimePrivate::LocalDST:
5823             spec = Qt::LocalTime;
5824             break;
5825         }
5826         dateTime = QDateTime(dt, tm, spec, offset);
5827 
5828     } else { // version < QDataStream::Qt_4_0
5829 
5830         // Before 4.0 there was no TimeSpec, only Qt::LocalTime was supported
5831         in >> dt >> tm;
5832         dateTime = QDateTime(dt, tm, spec, offset);
5833 
5834     }
5835 
5836     return in;
5837 }
5838 #endif // QT_NO_DATASTREAM
5839 
5840 /*****************************************************************************
5841   Date / Time Debug Streams
5842 *****************************************************************************/
5843 
5844 #if !defined(QT_NO_DEBUG_STREAM) && QT_CONFIG(datestring)
operator <<(QDebug dbg,const QDate & date)5845 QDebug operator<<(QDebug dbg, const QDate &date)
5846 {
5847     QDebugStateSaver saver(dbg);
5848     dbg.nospace() << "QDate(";
5849     if (date.isValid())
5850         dbg.nospace() << date.toString(Qt::ISODate);
5851     else
5852         dbg.nospace() << "Invalid";
5853     dbg.nospace() << ')';
5854     return dbg;
5855 }
5856 
operator <<(QDebug dbg,const QTime & time)5857 QDebug operator<<(QDebug dbg, const QTime &time)
5858 {
5859     QDebugStateSaver saver(dbg);
5860     dbg.nospace() << "QTime(";
5861     if (time.isValid())
5862         dbg.nospace() << time.toString(u"HH:mm:ss.zzz");
5863     else
5864         dbg.nospace() << "Invalid";
5865     dbg.nospace() << ')';
5866     return dbg;
5867 }
5868 
operator <<(QDebug dbg,const QDateTime & date)5869 QDebug operator<<(QDebug dbg, const QDateTime &date)
5870 {
5871     QDebugStateSaver saver(dbg);
5872     dbg.nospace() << "QDateTime(";
5873     if (date.isValid()) {
5874         const Qt::TimeSpec ts = date.timeSpec();
5875         dbg.noquote() << date.toString(u"yyyy-MM-dd HH:mm:ss.zzz t")
5876                       << ' ' << ts;
5877         switch (ts) {
5878         case Qt::UTC:
5879             break;
5880         case Qt::OffsetFromUTC:
5881             dbg.space() << date.offsetFromUtc() << 's';
5882             break;
5883         case Qt::TimeZone:
5884 #if QT_CONFIG(timezone)
5885             dbg.space() << date.timeZone().id();
5886 #endif // timezone
5887             break;
5888         case Qt::LocalTime:
5889             break;
5890         }
5891     } else {
5892         dbg.nospace() << "Invalid";
5893     }
5894     return dbg.nospace() << ')';
5895 }
5896 #endif // debug_stream && datestring
5897 
5898 /*! \fn uint qHash(const QDateTime &key, uint seed = 0)
5899     \relates QHash
5900     \since 5.0
5901 
5902     Returns the hash value for the \a key, using \a seed to seed the calculation.
5903 */
qHash(const QDateTime & key,uint seed)5904 uint qHash(const QDateTime &key, uint seed)
5905 {
5906     // Use to toMSecsSinceEpoch instead of individual qHash functions for
5907     // QDate/QTime/spec/offset because QDateTime::operator== converts both arguments
5908     // to the same timezone. If we don't, qHash would return different hashes for
5909     // two QDateTimes that are equivalent once converted to the same timezone.
5910     return key.isValid() ? qHash(key.toMSecsSinceEpoch(), seed) : seed;
5911 }
5912 
5913 /*! \fn uint qHash(const QDate &key, uint seed = 0)
5914     \relates QHash
5915     \since 5.0
5916 
5917     Returns the hash value for the \a key, using \a seed to seed the calculation.
5918 */
qHash(const QDate & key,uint seed)5919 uint qHash(const QDate &key, uint seed) noexcept
5920 {
5921     return qHash(key.toJulianDay(), seed);
5922 }
5923 
5924 /*! \fn uint qHash(const QTime &key, uint seed = 0)
5925     \relates QHash
5926     \since 5.0
5927 
5928     Returns the hash value for the \a key, using \a seed to seed the calculation.
5929 */
qHash(const QTime & key,uint seed)5930 uint qHash(const QTime &key, uint seed) noexcept
5931 {
5932     return qHash(key.msecsSinceStartOfDay(), seed);
5933 }
5934 
5935 QT_END_NAMESPACE
5936