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