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

source code of qtbase/src/corelib/time/qdatetime.cpp