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