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(a: parts.day, b: cal.daysInMonth(month: parts.month, year: 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(a: parts.day, b: QGregorianCalendar::monthLength(month: parts.month, year: parts.year));
66 const auto jd = QGregorianCalendar::julianFromParts(year: parts.year, month: parts.month, day: parts.day);
67 if (jd)
68 return QDate::fromJulianDay(jd_: *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(c: text.front().toLatin1()))
107 return {};
108
109 QSimpleParsedNumber res = qstrntoull(nptr: text.data(), size: text.size(), base: 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(out: latin1.data(), in: text);
125 return readInt(text: 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(needle: u' ', flags: Qt::SkipEmptyParts);
155 auto it = tokens.begin();
156 for (int i = 0; i < 6 && it != tokens.end(); ++i, ++it)
157 words.emplace_back(args: *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(c: u',')) {
179 dayName = maybeDayName.chopped(n: 1);
180 words.erase(pos: words.begin());
181 } else if (!maybeDayName.front().isDigit()) {
182 dayName = maybeDayName;
183 words.erase(pos: 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(idx: 2).contains(c: colon) ? 3 : 2;
201 }
202
203 int dayOfWeek = 0;
204 if (!dayName.isEmpty()) {
205 if (!isShortName(dayName))
206 return result;
207 dayOfWeek = shortDayFromName(name: dayName);
208 if (!dayOfWeek)
209 break;
210 }
211
212 const int day = words.at(idx: dayIndex).toInt(ok: &ok);
213 if (!ok)
214 return result;
215 const int year = words.at(idx: yearIndex).toInt(ok: &ok);
216 if (!ok)
217 return result;
218 const QStringView monthName = words.at(idx: 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(i: yearIndex);
230 words.remove(i: 0, n: 2); // month and day-of-month, in some order
231
232 // Time: [hh:mm[:ss]]
233 QTime time;
234 if (words.size() && words.at(idx: 0).contains(c: colon)) {
235 const QStringView when = words.front();
236 words.erase(pos: 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(n: 2).toInt(ok: &ok);
242 if (!ok)
243 return result;
244 const int minute = when.sliced(pos: 3, n: 2).toInt(ok: &ok);
245 if (!ok)
246 return result;
247 const auto secs = when.size() == 8 ? when.last(n: 2).toInt(ok: &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(pos: 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(pos: 1, n: 2).toInt(ok: &ok);
266 if (!ok)
267 return result;
268 const auto minute = zone.size() == 5 ? zone.last(n: 2).toInt(ok: &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(format: "%c%02d%s%02d",
287 offset >= 0 ? '+' : '-',
288 qAbs(t: 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(t: 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(pos: 1);
318 qsizetype hhLen = time.indexOf(c: 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(n: qMin(a: hhLen, b: time.size()));
326 bool ok = false;
327 const int hour = hhRef.toInt(ok: &ok);
328 if (!ok || hour > 23) // More generous than QTimeZone::MaxUtcOffsetSecs
329 return 0;
330
331 const QStringView mmRef = time.sliced(pos: qMin(a: mmIndex, b: time.size()));
332 const int minute = mmRef.isEmpty() ? 0 : mmRef.toInt(ok: &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(year: y, month: m, day: d).value_or(u: nullJd());
447}
448
449QDate::QDate(int y, int m, int d, QCalendar cal)
450{
451 *this = cal.dateFromParts(year: y, month: m, day: 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(date: *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(date: *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(date: *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(date: *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: year(cal), month: 1, day: 1);
692 if (firstDay.isValid())
693 return firstDay.daysTo(d: *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: year(), month: 1, day: 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(date: *this);
725 if (parts.isValid())
726 return cal.daysInMonth(month: parts.month, year: 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(month: parts.month, year: 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: year(cal));
760}
761
762/*!
763 \overload
764 */
765
766int QDate::daysInYear() const
767{
768 return isValid() ? QGregorianCalendar::leapTest(year: 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(days: 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(msg: "%s: Pass a QTimeZone instead of Qt::TimeZone.", warner);
813 break;
814 case Qt::LocalTime:
815 if (offset) {
816 qWarning(msg: "%s: Ignoring offset (%d seconds) passed with Qt::LocalTime",
817 warner, offset);
818 }
819 break;
820 case Qt::UTC:
821 if (offset) {
822 qWarning(msg: "%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(secs: -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, side: 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(beforeDateTime: QDateTime(addDays(days: 1), QTime(12, 0), zone));
956 const QDateTime &at = tran.atUtc.toTimeZone(toZone: zone);
957 if (at.isValid() && at.date() == *this)
958 return at;
959 }
960#endif
961
962 when = toEarliest(day: *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(zone: 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, offset: offsetSeconds, warner: "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(secs: 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, side: 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(afterDateTime: QDateTime(addDays(days: -1), QTime(12, 0), zone));
1112 const QDateTime &at = tran.atUtc.toTimeZone(toZone: zone);
1113 if (at.isValid() && at.date() == *this)
1114 return at;
1115 }
1116#endif
1117
1118 when = toLatest(day: *this, zone);
1119 }
1120 return when;
1121}
1122
1123/*!
1124 \overload
1125 \since 6.5
1126*/
1127QDateTime QDate::endOfDay() const
1128{
1129 return endOfDay(zone: 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, offset: offsetSeconds, warner: "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), format: QLocale::ShortFormat) + sp
1179 + cal.monthName(locale: QLocale::c(), month: parts.month, year: parts.year, format: QLocale::ShortFormat)
1180 // Documented to use 4-digit year
1181 + sp + QString::asprintf(format: "%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(format: "%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(date: *this, format: u"dd MMM yyyy");
1231 default:
1232 case Qt::TextDate:
1233 return toStringTextDate(date: *this);
1234 case Qt::ISODate:
1235 case Qt::ISODateWithMs:
1236 // No calendar dependence
1237 return toStringIsoDate(date: *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(date: *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(date: *this, format, cal: QCalendar());
1316}
1317
1318/*!
1319 \overload
1320 \since 4.6
1321*/
1322QString QDate::toString(const QString &format) const
1323{
1324 return QLocale::c().toString(date: *this, format: qToStringViewIgnoringNull(s: format), cal: 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(u: 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(jd_: 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(date: *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(year: parts.year);
1463 }
1464 int count = cal.monthsInYear(year: parts.year);
1465 while (parts.month > count) {
1466 parts.month -= count;
1467 count = (++parts.year || cal.hasYearZero()) ? cal.monthsInYear(year: 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(date: *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(s: 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(needle: u' ', flags: Qt::SkipEmptyParts);
1664 auto it = tokens.begin();
1665 for (int i = 0; i < 4 && it != tokens.end(); ++i, ++it)
1666 parts.emplace_back(args: *it);
1667
1668 if (parts.size() != 4 || it != tokens.end())
1669 return QDate();
1670
1671 bool ok = false;
1672 int year = parts.at(idx: 3).toInt(ok: &ok);
1673 int day = ok ? parts.at(idx: 2).toInt(ok: &ok) : 0;
1674 if (!ok || !day)
1675 return QDate();
1676
1677 const int month = fromShortMonthName(monthName: parts.at(idx: 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(text: string.first(n: 4));
1688 const ParsedInt month = readInt(text: string.sliced(pos: 5, n: 2));
1689 const ParsedInt day = readInt(text: string.sliced(pos: 8, n: 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(text: string, date: &date, time: 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, cal: 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(year: 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(format: "%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(format: "%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(time: *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(ms: 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>(a: 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(c: u'.'), comma = string.indexOf(c: u',');
2461 if (dot != -1) {
2462 tail = string.sliced(pos: dot + 1);
2463 if (tail.indexOf(c: u'.') != -1) // Forbid second dot:
2464 return QTime();
2465 string = string.first(n: dot);
2466 } else if (comma != -1) {
2467 tail = string.sliced(pos: comma + 1);
2468 string = string.first(n: comma);
2469 }
2470 if (tail.indexOf(c: u',') != -1) // Forbid comma after first dot-or-comma:
2471 return QTime();
2472
2473 const ParsedInt frac = readInt(text: 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(x: 0.1, y: 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(text: string.first(n: 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(text: string.sliced(pos: 3, n: 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(text: string.sliced(pos: 6, n: 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(d: 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(s: string).time;
2574 case Qt::ISODate:
2575 case Qt::ISODateWithMs:
2576 case Qt::TextDate:
2577 default:
2578 return fromIsoTimeString(string, format, isMidnight24: 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(text: string, date: nullptr, time: &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)
2712typedef QDateTimePrivate::QDateTimeShortData ShortData;
2713typedef QDateTimePrivate::QDateTimeData QDateTimeData;
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>(a: msecs);
2719}
2720
2721static QDate msecsToDate(qint64 msecs)
2722{
2723 return QDate::fromJulianDay(jd_: msecsToJulianDay(msecs));
2724}
2725
2726static QTime msecsToTime(qint64 msecs)
2727{
2728 return QTime::fromMSecsSinceStartOfDay(msecs: QRoundingDown::qMod<MSECS_PER_DAY>(a: 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(v1: days, std::integral_constant<qint64, MSECS_PER_DAY>(), r: sumMillis)
2736 || qAddOverflow(v1: *sumMillis, v2: millisInDay, r: 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, millisInDay: dayms, sumMillis: &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(millis: utcMSecs)) {
2822 result = QLocalTime::utcToLocal(utcMillis: 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(atMSecsSinceEpoch: utcMSecs);
2832 if (qAddOverflow(v1: utcMSecs, v2: result.offset * MSECS_PER_SEC, r: &result.when))
2833 return result;
2834 result.dst = sys.d->isDaylightTime(atMSecsSinceEpoch: utcMSecs) ? DaylightTime : StandardTime;
2835 result.valid = true;
2836 return result;
2837 }
2838#endif // timezone
2839
2840 // Kludge
2841 // Do the conversion in a year with the same days of the week, so DST
2842 // dates might be right, and adjust by the number of days that was off:
2843 const qint64 jd = msecsToJulianDay(msecs: utcMSecs);
2844 const auto ymd = QGregorianCalendar::partsFromJulian(jd);
2845 qint64 diffMillis, fakeUtc;
2846 const auto fakeJd = QGregorianCalendar::julianFromParts(year: systemTimeYearMatching(year: ymd.year),
2847 month: ymd.month, day: ymd.day);
2848 if (Q_UNLIKELY(!fakeJd
2849 || qMulOverflow(jd - *fakeJd, std::integral_constant<qint64, MSECS_PER_DAY>(),
2850 &diffMillis)
2851 || qSubOverflow(utcMSecs, diffMillis, &fakeUtc))) {
2852 return result;
2853 }
2854
2855 result = QLocalTime::utcToLocal(utcMillis: fakeUtc);
2856 // Now correct result.when for the use of the fake date:
2857 if (!result.valid || qAddOverflow(v1: result.when, v2: diffMillis, r: &result.when)) {
2858 // If utcToLocal() failed, its return has the fake when; restore utcMSecs.
2859 // Fail on overflow, but preserve offset and DST-ness.
2860 result.when = utcMSecs;
2861 result.valid = false;
2862 }
2863 return result;
2864}
2865
2866static auto millisToWithinRange(qint64 millis)
2867{
2868 struct R {
2869 qint64 shifted = 0;
2870 bool good = false;
2871 } result;
2872 qint64 jd = msecsToJulianDay(msecs: millis);
2873 auto ymd = QGregorianCalendar::partsFromJulian(jd);
2874 const auto fakeJd = QGregorianCalendar::julianFromParts(year: systemTimeYearMatching(year: ymd.year),
2875 month: ymd.month, day: ymd.day);
2876 result.good = fakeJd && !daysAndMillisOverflow(days: *fakeJd - jd, millisInDay: millis, sumMillis: &result.shifted);
2877 return result;
2878}
2879
2880/*!
2881 \internal
2882 \enum QDateTimePrivate::TransitionOption
2883
2884 This enumeration is used to resolve datetime combinations which fall in \l
2885 {Timezone transitions}. The transition is described as a "gap" if there are
2886 time representations skipped over by the zone, as is common in the "spring
2887 forward" transitions in many zones on entering daylight-saving time. The
2888 transition is described as a "fold" if there are time representations
2889 repeated in the zone, as in a "fall back" transition out of daylight-saving
2890 time.
2891
2892 When the options specified do not determine a resolution for a datetime, it
2893 is marked invalid.
2894
2895 The prepared option sets above are in fact composed from low-level atomic
2896 options. For each of gap and fold you can chose between two candidate times,
2897 one before or after the transition, based on the time requested; or you can
2898 pick the moment of transition, or the start or end of the transition
2899 interval. For a gap, the start and end of the interval are the moment of the
2900 transition, but for a repeated interval the start of the first pass is the
2901 start of the transition interval, the end of the second pass is the end of
2902 the transition interval and the moment of the transition itself is both the
2903 end of the first pass and the start of the second.
2904
2905 \value GapUseBefore For a time in a gap, use a time before the transition,
2906 as if stepping back from a later time.
2907 \value GapUseAfter For a time in a gap, use a time after the transition, as
2908 if stepping forward from an earlier time.
2909 \value FoldUseBefore For a repeated time, use the first candidate, which is
2910 before the transition.
2911 \value FoldUseAfter For a repeated time, use the second candidate, which is
2912 after the transition.
2913 \value FlipForReverseDst For "reversed" DST, this reverses the preceding
2914 four options (see below).
2915
2916 The last has no effect unless the "daylight-saving" time side of the
2917 transition is known to have a lower offset from UTC than the standard time
2918 side. (This is the "reversed" DST case of \l {Timezone transitions}.) In
2919 that case, if other options would select a time after the transition, a time
2920 before is used instead, and vice versa. This effectively turns a preference
2921 for the side with lower offset into a preference for the side that is
2922 officially standard time, even if it has higher offset; and conversely a
2923 preference for higher offset into a preference for daylight-saving time,
2924 even if it has a lower offset. This option has no effect on a resolution
2925 that selects the moment of transition or the start or end of the transition
2926 interval.
2927
2928 The result of combining more than one of the \c GapUse* options is
2929 undefined; likewise for the \c FoldUse*. Each of QDateTime's
2930 TransitionResolution values, aside from Reject, maps to a combination that
2931 incorporates one from each of these sets.
2932*/
2933
2934constexpr static QDateTimePrivate::TransitionOptions
2935toTransitionOptions(QDateTime::TransitionResolution res)
2936{
2937 switch (res) {
2938 case QDateTime::TransitionResolution::RelativeToBefore:
2939 return QDateTimePrivate::GapUseAfter | QDateTimePrivate::FoldUseBefore;
2940 case QDateTime::TransitionResolution::RelativeToAfter:
2941 return QDateTimePrivate::GapUseBefore | QDateTimePrivate::FoldUseAfter;
2942 case QDateTime::TransitionResolution::PreferBefore:
2943 return QDateTimePrivate::GapUseBefore | QDateTimePrivate::FoldUseBefore;
2944 case QDateTime::TransitionResolution::PreferAfter:
2945 return QDateTimePrivate::GapUseAfter | QDateTimePrivate::FoldUseAfter;
2946 case QDateTime::TransitionResolution::PreferStandard:
2947 return QDateTimePrivate::GapUseBefore
2948 | QDateTimePrivate::FoldUseAfter
2949 | QDateTimePrivate::FlipForReverseDst;
2950 case QDateTime::TransitionResolution::PreferDaylightSaving:
2951 return QDateTimePrivate::GapUseAfter
2952 | QDateTimePrivate::FoldUseBefore
2953 | QDateTimePrivate::FlipForReverseDst;
2954 case QDateTime::TransitionResolution::Reject: break;
2955 }
2956 return {};
2957}
2958
2959constexpr static QDateTimePrivate::TransitionOptions
2960toTransitionOptions(QDateTimePrivate::DaylightStatus dst)
2961{
2962 return toTransitionOptions(res: dst == QDateTimePrivate::DaylightTime
2963 ? QDateTime::TransitionResolution::PreferDaylightSaving
2964 : QDateTime::TransitionResolution::PreferStandard);
2965}
2966
2967QString QDateTimePrivate::localNameAtMillis(qint64 millis, DaylightStatus dst)
2968{
2969 const QDateTimePrivate::TransitionOptions resolve = toTransitionOptions(dst);
2970 QString abbreviation;
2971 if (millisInSystemRange(millis, slack: MSECS_PER_DAY)) {
2972 abbreviation = QLocalTime::localTimeAbbbreviationAt(local: millis, resolve);
2973 if (!abbreviation.isEmpty())
2974 return abbreviation;
2975 }
2976
2977 // Otherwise, outside the system range.
2978#if QT_CONFIG(timezone)
2979 // Use the system zone:
2980 const auto sys = QTimeZone::systemTimeZone();
2981 if (sys.isValid()) {
2982 ZoneState state = zoneStateAtMillis(zone: sys, millis, resolve);
2983 if (state.valid)
2984 return sys.d->abbreviation(atMSecsSinceEpoch: state.when - state.offset * MSECS_PER_SEC);
2985 }
2986#endif // timezone
2987
2988 // Kludge
2989 // Use a time in the system range with the same day-of-week pattern to its year:
2990 auto fake = millisToWithinRange(millis);
2991 if (Q_LIKELY(fake.good))
2992 return QLocalTime::localTimeAbbbreviationAt(local: fake.shifted, resolve);
2993
2994 // Overflow, apparently.
2995 return {};
2996}
2997
2998// Determine the offset from UTC at the given local time as millis.
2999QDateTimePrivate::ZoneState QDateTimePrivate::localStateAtMillis(
3000 qint64 millis, QDateTimePrivate::TransitionOptions resolve)
3001{
3002 // First, if millis is within a day of the viable range, try mktime() in
3003 // case it does fall in the range and gets useful information:
3004 if (millisInSystemRange(millis, slack: MSECS_PER_DAY)) {
3005 auto result = QLocalTime::mapLocalTime(local: millis, resolve);
3006 if (result.valid)
3007 return result;
3008 }
3009
3010 // Otherwise, outside the system range.
3011#if QT_CONFIG(timezone)
3012 // Use the system zone:
3013 const auto sys = QTimeZone::systemTimeZone();
3014 if (sys.isValid())
3015 return zoneStateAtMillis(zone: sys, millis, resolve);
3016#endif // timezone
3017
3018 // Kludge
3019 // Use a time in the system range with the same day-of-week pattern to its year:
3020 auto fake = millisToWithinRange(millis);
3021 if (Q_LIKELY(fake.good)) {
3022 auto result = QLocalTime::mapLocalTime(local: fake.shifted, resolve);
3023 if (result.valid) {
3024 qint64 adjusted;
3025 if (Q_UNLIKELY(qAddOverflow(result.when, millis - fake.shifted, &adjusted))) {
3026 using Bound = std::numeric_limits<qint64>;
3027 adjusted = millis < fake.shifted ? Bound::min() : Bound::max();
3028 }
3029 result.when = adjusted;
3030 } else {
3031 result.when = millis;
3032 }
3033 return result;
3034 }
3035 // Overflow, apparently.
3036 return {millis};
3037}
3038
3039#if QT_CONFIG(timezone)
3040// For a TimeZone and a time expressed in zone msecs encoding, compute the
3041// actual DST-ness and offset, adjusting the time if needed to escape a
3042// spring-forward.
3043QDateTimePrivate::ZoneState QDateTimePrivate::zoneStateAtMillis(
3044 const QTimeZone &zone, qint64 millis, QDateTimePrivate::TransitionOptions resolve)
3045{
3046 Q_ASSERT(zone.isValid());
3047 Q_ASSERT(zone.timeSpec() == Qt::TimeZone);
3048 return zone.d->stateAtZoneTime(forLocalMSecs: millis, resolve);
3049}
3050#endif // timezone
3051
3052static inline QDateTimePrivate::ZoneState stateAtMillis(const QTimeZone &zone, qint64 millis,
3053 QDateTimePrivate::TransitionOptions resolve)
3054{
3055 if (zone.timeSpec() == Qt::LocalTime)
3056 return QDateTimePrivate::localStateAtMillis(millis, resolve);
3057#if QT_CONFIG(timezone)
3058 if (zone.timeSpec() == Qt::TimeZone && zone.isValid())
3059 return QDateTimePrivate::zoneStateAtMillis(zone, millis, resolve);
3060#endif
3061 return {millis};
3062}
3063
3064static inline bool specCanBeSmall(Qt::TimeSpec spec)
3065{
3066 return spec == Qt::LocalTime || spec == Qt::UTC;
3067}
3068
3069static inline bool msecsCanBeSmall(qint64 msecs)
3070{
3071 if constexpr (!QDateTimeData::CanBeSmall)
3072 return false;
3073
3074 ShortData sd;
3075 sd.msecs = qintptr(msecs);
3076 return sd.msecs == msecs;
3077}
3078
3079static constexpr inline
3080QDateTimePrivate::StatusFlags mergeSpec(QDateTimePrivate::StatusFlags status, Qt::TimeSpec spec)
3081{
3082 status &= ~QDateTimePrivate::TimeSpecMask;
3083 status |= QDateTimePrivate::StatusFlags::fromInt(i: int(spec) << QDateTimePrivate::TimeSpecShift);
3084 return status;
3085}
3086
3087static constexpr inline Qt::TimeSpec extractSpec(QDateTimePrivate::StatusFlags status)
3088{
3089 return Qt::TimeSpec((status & QDateTimePrivate::TimeSpecMask).toInt() >> QDateTimePrivate::TimeSpecShift);
3090}
3091
3092// Set the Daylight Status if LocalTime set via msecs
3093static constexpr inline QDateTimePrivate::StatusFlags
3094mergeDaylightStatus(QDateTimePrivate::StatusFlags sf, QDateTimePrivate::DaylightStatus status)
3095{
3096 sf &= ~QDateTimePrivate::DaylightMask;
3097 if (status == QDateTimePrivate::DaylightTime) {
3098 sf |= QDateTimePrivate::SetToDaylightTime;
3099 } else if (status == QDateTimePrivate::StandardTime) {
3100 sf |= QDateTimePrivate::SetToStandardTime;
3101 }
3102 return sf;
3103}
3104
3105// Get the DST Status if LocalTime set via msecs
3106static constexpr inline
3107QDateTimePrivate::DaylightStatus extractDaylightStatus(QDateTimePrivate::StatusFlags status)
3108{
3109 if (status.testFlag(flag: QDateTimePrivate::SetToDaylightTime))
3110 return QDateTimePrivate::DaylightTime;
3111 if (status.testFlag(flag: QDateTimePrivate::SetToStandardTime))
3112 return QDateTimePrivate::StandardTime;
3113 return QDateTimePrivate::UnknownDaylightTime;
3114}
3115
3116static inline qint64 getMSecs(const QDateTimeData &d)
3117{
3118 if (d.isShort()) {
3119 // same as, but producing better code
3120 //return d.data.msecs;
3121 return qintptr(d.d) >> 8;
3122 }
3123 return d->m_msecs;
3124}
3125
3126static inline QDateTimePrivate::StatusFlags getStatus(const QDateTimeData &d)
3127{
3128 if (d.isShort()) {
3129 // same as, but producing better code
3130 //return StatusFlag(d.data.status);
3131 return QDateTimePrivate::StatusFlag(qintptr(d.d) & 0xFF);
3132 }
3133 return d->m_status;
3134}
3135
3136static inline Qt::TimeSpec getSpec(const QDateTimeData &d)
3137{
3138 return extractSpec(status: getStatus(d));
3139}
3140
3141/* True if we *can cheaply determine* that a and b use the same offset.
3142 If they use different offsets or it would be expensive to find out, false.
3143 Calls to toMSecsSinceEpoch() are expensive, for these purposes.
3144 See QDateTime's comparison operators.
3145*/
3146static inline bool usesSameOffset(const QDateTimeData &a, const QDateTimeData &b)
3147{
3148 const auto status = getStatus(d: a);
3149 if (status != getStatus(d: b))
3150 return false;
3151 // Status includes DST-ness, so we now know they match in it.
3152
3153 switch (extractSpec(status)) {
3154 case Qt::LocalTime:
3155 case Qt::UTC:
3156 return true;
3157
3158 case Qt::TimeZone:
3159 /* TimeZone always determines its offset during construction of the
3160 private data. Even if we're in different zones, what matters is the
3161 offset actually in effect at the specific time. (DST can cause things
3162 with the same time-zone to use different offsets, but we already
3163 checked their DSTs match.) */
3164 case Qt::OffsetFromUTC: // always knows its offset, which is all that matters.
3165 Q_ASSERT(!a.isShort() && !b.isShort());
3166 return a->m_offsetFromUtc == b->m_offsetFromUtc;
3167 }
3168 Q_UNREACHABLE_RETURN(false);
3169}
3170
3171// Refresh the LocalTime or TimeZone validity and offset
3172static void refreshZonedDateTime(QDateTimeData &d, const QTimeZone &zone,
3173 QDateTimePrivate::TransitionOptions resolve)
3174{
3175 Q_ASSERT(zone.timeSpec() == Qt::TimeZone || zone.timeSpec() == Qt::LocalTime);
3176 auto status = getStatus(d);
3177 Q_ASSERT(extractSpec(status) == zone.timeSpec());
3178 int offsetFromUtc = 0;
3179 /* Callers are:
3180 * QDTP::create(), where d is too new to be shared yet
3181 * reviseTimeZone(), which detach()es if not short before calling this
3182 * checkValidDateTime(), always follows a setDateTime() that detach()ed if not short
3183
3184 So we can assume d is not shared. We only need to detach() if we convert
3185 from short to pimpled to accommodate an oversize msecs, which can only be
3186 needed in the unlikely event we revise it.
3187 */
3188
3189 // If not valid date and time then is invalid
3190 if (!status.testFlags(flags: QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime)) {
3191 status.setFlag(flag: QDateTimePrivate::ValidDateTime, on: false);
3192 } else {
3193 // We have a valid date and time and a Qt::LocalTime or Qt::TimeZone
3194 // that might fall into a "missing" DST transition hour.
3195 qint64 msecs = getMSecs(d);
3196 QDateTimePrivate::ZoneState state = stateAtMillis(zone, millis: msecs, resolve);
3197 Q_ASSERT(!state.valid || (state.offset >= -SECS_PER_DAY && state.offset <= SECS_PER_DAY));
3198 if (state.dst == QDateTimePrivate::UnknownDaylightTime) { // Overflow
3199 status.setFlag(flag: QDateTimePrivate::ValidDateTime, on: false);
3200 } else if (state.valid) {
3201 status = mergeDaylightStatus(sf: status, status: state.dst);
3202 offsetFromUtc = state.offset;
3203 status.setFlag(flag: QDateTimePrivate::ValidDateTime, on: true);
3204 if (Q_UNLIKELY(msecs != state.when)) {
3205 // Update msecs to the resolution:
3206 if (status.testFlag(flag: QDateTimePrivate::ShortData)) {
3207 if (msecsCanBeSmall(msecs: state.when)) {
3208 d.data.msecs = qintptr(state.when);
3209 } else {
3210 // Convert to long-form so we can hold the revised msecs:
3211 status.setFlag(flag: QDateTimePrivate::ShortData, on: false);
3212 d.detach();
3213 }
3214 }
3215 if (!status.testFlag(flag: QDateTimePrivate::ShortData))
3216 d->m_msecs = state.when;
3217 }
3218 } else {
3219 status.setFlag(flag: QDateTimePrivate::ValidDateTime, on: false);
3220 }
3221 }
3222
3223 if (status.testFlag(flag: QDateTimePrivate::ShortData)) {
3224 d.data.status = status.toInt();
3225 } else {
3226 d->m_status = status;
3227 d->m_offsetFromUtc = offsetFromUtc;
3228 }
3229}
3230
3231// Check the UTC / offsetFromUTC validity
3232static void refreshSimpleDateTime(QDateTimeData &d)
3233{
3234 auto status = getStatus(d);
3235 Q_ASSERT(QTimeZone::isUtcOrFixedOffset(extractSpec(status)));
3236 status.setFlag(flag: QDateTimePrivate::ValidDateTime,
3237 on: status.testFlags(flags: QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime));
3238
3239 if (status.testFlag(flag: QDateTimePrivate::ShortData))
3240 d.data.status = status.toInt();
3241 else
3242 d->m_status = status;
3243}
3244
3245// Clean up and set status after assorted set-up or reworking:
3246static void checkValidDateTime(QDateTimeData &d, QDateTime::TransitionResolution resolve)
3247{
3248 auto spec = extractSpec(status: getStatus(d));
3249 switch (spec) {
3250 case Qt::OffsetFromUTC:
3251 case Qt::UTC:
3252 // for these, a valid date and a valid time imply a valid QDateTime
3253 refreshSimpleDateTime(d);
3254 break;
3255 case Qt::TimeZone:
3256 case Qt::LocalTime:
3257 // For these, we need to check whether (the zone is valid and) the time
3258 // is valid for the zone. Expensive, but we have no other option.
3259 refreshZonedDateTime(d, zone: d.timeZone(), resolve: toTransitionOptions(res: resolve));
3260 break;
3261 }
3262}
3263
3264static void reviseTimeZone(QDateTimeData &d, const QTimeZone &zone,
3265 QDateTime::TransitionResolution resolve)
3266{
3267 Qt::TimeSpec spec = zone.timeSpec();
3268 auto status = mergeSpec(status: getStatus(d), spec);
3269 bool reuse = d.isShort();
3270 int offset = 0;
3271
3272 switch (spec) {
3273 case Qt::UTC:
3274 Q_ASSERT(zone.fixedSecondsAheadOfUtc() == 0);
3275 break;
3276 case Qt::OffsetFromUTC:
3277 reuse = false;
3278 offset = zone.fixedSecondsAheadOfUtc();
3279 Q_ASSERT(offset);
3280 break;
3281 case Qt::TimeZone:
3282 reuse = false;
3283 break;
3284 case Qt::LocalTime:
3285 break;
3286 }
3287
3288 status &= ~(QDateTimePrivate::ValidDateTime | QDateTimePrivate::DaylightMask);
3289 if (reuse) {
3290 d.data.status = status.toInt();
3291 } else {
3292 d.detach();
3293 d->m_status = status & ~QDateTimePrivate::ShortData;
3294 d->m_offsetFromUtc = offset;
3295#if QT_CONFIG(timezone)
3296 if (spec == Qt::TimeZone)
3297 d->m_timeZone = zone;
3298#endif // timezone
3299 }
3300
3301 if (QTimeZone::isUtcOrFixedOffset(spec))
3302 refreshSimpleDateTime(d);
3303 else
3304 refreshZonedDateTime(d, zone, resolve: toTransitionOptions(res: resolve));
3305}
3306
3307static void setDateTime(QDateTimeData &d, QDate date, QTime time)
3308{
3309 // If the date is valid and the time is not we set time to 00:00:00
3310 if (!time.isValid() && date.isValid())
3311 time = QTime::fromMSecsSinceStartOfDay(msecs: 0);
3312
3313 QDateTimePrivate::StatusFlags newStatus = { };
3314
3315 // Set date value and status
3316 qint64 days = 0;
3317 if (date.isValid()) {
3318 days = date.toJulianDay() - JULIAN_DAY_FOR_EPOCH;
3319 newStatus = QDateTimePrivate::ValidDate;
3320 }
3321
3322 // Set time value and status
3323 int ds = 0;
3324 if (time.isValid()) {
3325 ds = time.msecsSinceStartOfDay();
3326 newStatus |= QDateTimePrivate::ValidTime;
3327 }
3328 Q_ASSERT(ds < MSECS_PER_DAY);
3329 // Only the later parts of the very first day are representable - its start
3330 // would overflow - so get ds the same side of 0 as days:
3331 if (days < 0 && ds > 0) {
3332 days++;
3333 ds -= MSECS_PER_DAY;
3334 }
3335
3336 // Check in representable range:
3337 qint64 msecs = 0;
3338 if (daysAndMillisOverflow(days, millisInDay: qint64(ds), sumMillis: &msecs)) {
3339 newStatus = QDateTimePrivate::StatusFlags{};
3340 msecs = 0;
3341 }
3342 if (d.isShort()) {
3343 // let's see if we can keep this short
3344 if (msecsCanBeSmall(msecs)) {
3345 // yes, we can
3346 d.data.msecs = qintptr(msecs);
3347 d.data.status &= ~(QDateTimePrivate::ValidityMask | QDateTimePrivate::DaylightMask).toInt();
3348 d.data.status |= newStatus.toInt();
3349 } else {
3350 // nope...
3351 d.detach();
3352 }
3353 }
3354 if (!d.isShort()) {
3355 d.detach();
3356 d->m_msecs = msecs;
3357 d->m_status &= ~(QDateTimePrivate::ValidityMask | QDateTimePrivate::DaylightMask);
3358 d->m_status |= newStatus;
3359 }
3360}
3361
3362static std::pair<QDate, QTime> getDateTime(const QDateTimeData &d)
3363{
3364 auto status = getStatus(d);
3365 const qint64 msecs = getMSecs(d);
3366 const auto dayMilli = QRoundingDown::qDivMod<MSECS_PER_DAY>(a: msecs);
3367 return { status.testFlag(flag: QDateTimePrivate::ValidDate)
3368 ? QDate::fromJulianDay(jd_: JULIAN_DAY_FOR_EPOCH + dayMilli.quotient)
3369 : QDate(),
3370 status.testFlag(flag: QDateTimePrivate::ValidTime)
3371 ? QTime::fromMSecsSinceStartOfDay(msecs: dayMilli.remainder)
3372 : QTime() };
3373}
3374
3375/*****************************************************************************
3376 QDateTime::Data member functions
3377 *****************************************************************************/
3378
3379inline QDateTime::Data::Data() noexcept
3380{
3381 // default-constructed data has a special exception:
3382 // it can be small even if CanBeSmall == false
3383 // (optimization so we don't allocate memory in the default constructor)
3384 quintptr value = mergeSpec(status: QDateTimePrivate::ShortData, spec: Qt::LocalTime).toInt();
3385 d = reinterpret_cast<QDateTimePrivate *>(value);
3386}
3387
3388inline QDateTime::Data::Data(const QTimeZone &zone)
3389{
3390 Qt::TimeSpec spec = zone.timeSpec();
3391 if (CanBeSmall && Q_LIKELY(specCanBeSmall(spec))) {
3392 quintptr value = mergeSpec(status: QDateTimePrivate::ShortData, spec).toInt();
3393 d = reinterpret_cast<QDateTimePrivate *>(value);
3394 Q_ASSERT(isShort());
3395 } else {
3396 // the structure is too small, we need to detach
3397 d = new QDateTimePrivate;
3398 d->ref.ref();
3399 d->m_status = mergeSpec(status: {}, spec);
3400 if (spec == Qt::OffsetFromUTC)
3401 d->m_offsetFromUtc = zone.fixedSecondsAheadOfUtc();
3402 else if (spec == Qt::TimeZone)
3403 d->m_timeZone = zone;
3404 Q_ASSERT(!isShort());
3405 }
3406}
3407
3408inline QDateTime::Data::Data(const Data &other) noexcept
3409 : data(other.data)
3410{
3411 if (!isShort()) {
3412 // check if we could shrink
3413 if (specCanBeSmall(spec: extractSpec(status: d->m_status)) && msecsCanBeSmall(msecs: d->m_msecs)) {
3414 ShortData sd;
3415 sd.msecs = qintptr(d->m_msecs);
3416 sd.status = (d->m_status | QDateTimePrivate::ShortData).toInt();
3417 data = sd;
3418 } else {
3419 // no, have to keep it big
3420 d->ref.ref();
3421 }
3422 }
3423}
3424
3425inline QDateTime::Data::Data(Data &&other) noexcept
3426 : data(other.data)
3427{
3428 // reset the other to a short state
3429 Data dummy;
3430 Q_ASSERT(dummy.isShort());
3431 other.data = dummy.data;
3432}
3433
3434inline QDateTime::Data &QDateTime::Data::operator=(const Data &other) noexcept
3435{
3436 if (isShort() ? data == other.data : d == other.d)
3437 return *this;
3438
3439 auto x = d;
3440 d = other.d;
3441 if (!other.isShort()) {
3442 // check if we could shrink
3443 if (specCanBeSmall(spec: extractSpec(status: other.d->m_status)) && msecsCanBeSmall(msecs: other.d->m_msecs)) {
3444 ShortData sd;
3445 sd.msecs = qintptr(other.d->m_msecs);
3446 sd.status = (other.d->m_status | QDateTimePrivate::ShortData).toInt();
3447 data = sd;
3448 } else {
3449 // no, have to keep it big
3450 other.d->ref.ref();
3451 }
3452 }
3453
3454 if (!(quintptr(x) & QDateTimePrivate::ShortData) && !x->ref.deref())
3455 delete x;
3456 return *this;
3457}
3458
3459inline QDateTime::Data::~Data()
3460{
3461 if (!isShort() && !d->ref.deref())
3462 delete d;
3463}
3464
3465inline bool QDateTime::Data::isShort() const
3466{
3467 bool b = quintptr(d) & QDateTimePrivate::ShortData;
3468
3469 // sanity check:
3470 Q_ASSERT(b || !d->m_status.testFlag(QDateTimePrivate::ShortData));
3471
3472 // even if CanBeSmall = false, we have short data for a default-constructed
3473 // QDateTime object. But it's unlikely.
3474 if constexpr (CanBeSmall)
3475 return Q_LIKELY(b);
3476 return Q_UNLIKELY(b);
3477}
3478
3479inline void QDateTime::Data::detach()
3480{
3481 QDateTimePrivate *x;
3482 bool wasShort = isShort();
3483 if (wasShort) {
3484 // force enlarging
3485 x = new QDateTimePrivate;
3486 x->m_status = QDateTimePrivate::StatusFlags::fromInt(i: data.status) & ~QDateTimePrivate::ShortData;
3487 x->m_msecs = data.msecs;
3488 } else {
3489 if (d->ref.loadRelaxed() == 1)
3490 return;
3491
3492 x = new QDateTimePrivate(*d);
3493 }
3494
3495 x->ref.storeRelaxed(newValue: 1);
3496 if (!wasShort && !d->ref.deref())
3497 delete d;
3498 d = x;
3499}
3500
3501void QDateTime::Data::invalidate()
3502{
3503 if (isShort()) {
3504 data.status &= ~int(QDateTimePrivate::ValidityMask);
3505 } else {
3506 detach();
3507 d->m_status &= ~QDateTimePrivate::ValidityMask;
3508 }
3509}
3510
3511QTimeZone QDateTime::Data::timeZone() const
3512{
3513 switch (getSpec(d: *this)) {
3514 case Qt::UTC:
3515 return QTimeZone::UTC;
3516 case Qt::OffsetFromUTC:
3517 return QTimeZone::fromSecondsAheadOfUtc(offset: d->m_offsetFromUtc);
3518 case Qt::TimeZone:
3519#if QT_CONFIG(timezone)
3520 if (d->m_timeZone.isValid())
3521 return d->m_timeZone;
3522#endif
3523 break;
3524 case Qt::LocalTime:
3525 return QTimeZone::LocalTime;
3526 }
3527 return QTimeZone();
3528}
3529
3530inline const QDateTimePrivate *QDateTime::Data::operator->() const
3531{
3532 Q_ASSERT(!isShort());
3533 return d;
3534}
3535
3536inline QDateTimePrivate *QDateTime::Data::operator->()
3537{
3538 // should we attempt to detach here?
3539 Q_ASSERT(!isShort());
3540 Q_ASSERT(d->ref.loadRelaxed() == 1);
3541 return d;
3542}
3543
3544/*****************************************************************************
3545 QDateTimePrivate member functions
3546 *****************************************************************************/
3547
3548Q_NEVER_INLINE
3549QDateTime::Data QDateTimePrivate::create(QDate toDate, QTime toTime, const QTimeZone &zone,
3550 QDateTime::TransitionResolution resolve)
3551{
3552 QDateTime::Data result(zone);
3553 setDateTime(d&: result, date: toDate, time: toTime);
3554 if (zone.isUtcOrFixedOffset())
3555 refreshSimpleDateTime(d&: result);
3556 else
3557 refreshZonedDateTime(d&: result, zone, resolve: toTransitionOptions(res: resolve));
3558 return result;
3559}
3560
3561/*****************************************************************************
3562 QDateTime member functions
3563 *****************************************************************************/
3564
3565/*!
3566 \class QDateTime
3567 \inmodule QtCore
3568 \ingroup shared
3569 \reentrant
3570 \brief The QDateTime class provides date and time functions.
3571
3572 \compares weak
3573
3574 A QDateTime object encodes a calendar date and a clock time (a "datetime")
3575 in accordance with a time representation. It combines features of the QDate
3576 and QTime classes. It can read the current datetime from the system
3577 clock. It provides functions for comparing datetimes and for manipulating a
3578 datetime by adding a number of seconds, days, months, or years.
3579
3580 QDateTime can describe datetimes with respect to \l{Qt::LocalTime}{local
3581 time}, to \l{Qt::UTC}{UTC}, to a specified \l{Qt::OffsetFromUTC}{offset from
3582 UTC} or to a specified \l{Qt::TimeZone}{time zone}. Each of these time
3583 representations can be encapsulated in a suitable instance of the QTimeZone
3584 class. For example, a time zone of "Europe/Berlin" will apply the
3585 daylight-saving rules as used in Germany. In contrast, a fixed offset from
3586 UTC of +3600 seconds is one hour ahead of UTC (usually written in ISO
3587 standard notation as "UTC+01:00"), with no daylight-saving
3588 complications. When using either local time or a specified time zone,
3589 time-zone transitions (see \l {Timezone transitions}{below}) are taken into
3590 account. A QDateTime's timeSpec() will tell you which of the four types of
3591 time representation is in use; its timeRepresentation() provides a full
3592 description of that time representation, as a QTimeZone.
3593
3594 A QDateTime object is typically created either by giving a date and time
3595 explicitly in the constructor, or by using a static function such as
3596 currentDateTime() or fromMSecsSinceEpoch(). The date and time can be changed
3597 with setDate() and setTime(). A datetime can also be set using the
3598 setMSecsSinceEpoch() function that takes the time, in milliseconds, since
3599 the start, in UTC, of the year 1970. The fromString() function returns a
3600 QDateTime, given a string and a date format used to interpret the date
3601 within the string.
3602
3603 QDateTime::currentDateTime() returns a QDateTime that expresses the current
3604 date and time with respect to a specific time representation, such as local
3605 time (its default). QDateTime::currentDateTimeUtc() returns a QDateTime that
3606 expresses the current date and time with respect to UTC; it is equivalent to
3607 \c {QDateTime::currentDateTime(QTimeZone::UTC)}.
3608
3609 The date() and time() functions provide access to the date and
3610 time parts of the datetime. The same information is provided in
3611 textual format by the toString() function.
3612
3613 QDateTime provides a full set of operators to compare two
3614 QDateTime objects, where smaller means earlier and larger means
3615 later.
3616
3617 You can increment (or decrement) a datetime by a given number of
3618 milliseconds using addMSecs(), seconds using addSecs(), or days using
3619 addDays(). Similarly, you can use addMonths() and addYears(). The daysTo()
3620 function returns the number of days between two datetimes, secsTo() returns
3621 the number of seconds between two datetimes, and msecsTo() returns the
3622 number of milliseconds between two datetimes. These operations are aware of
3623 daylight-saving time (DST) and other time-zone transitions, where
3624 applicable.
3625
3626 Use toTimeZone() to re-express a datetime in terms of a different time
3627 representation. By passing a lightweight QTimeZone that represents local
3628 time, UTC or a fixed offset from UTC, you can convert the datetime to use
3629 the corresponding time representation; or you can pass a full time zone
3630 (whose \l {QTimeZone::timeSpec()}{timeSpec()} is \c {Qt::TimeZone}) to use
3631 that instead.
3632
3633 \section1 Remarks
3634
3635 \note QDateTime does not account for leap seconds.
3636
3637 \note All conversion to and from string formats is done using the C locale.
3638 For localized conversions, see QLocale.
3639
3640 \note There is no year 0 in the Gregorian calendar. Dates in that year are
3641 considered invalid. The year -1 is the year "1 before Christ" or "1 before
3642 common era." The day before 1 January 1 CE is 31 December 1 BCE.
3643
3644 \note Using local time (the default) or a specified time zone implies a need
3645 to resolve any issues around \l {Timezone transitions}{transitions}. As a
3646 result, operations on such QDateTime instances (notably including
3647 constructing them) may be more expensive than the equivalent when using UTC
3648 or a fixed offset from it.
3649
3650 \section2 Range of Valid Dates
3651
3652 The range of values that QDateTime can represent is dependent on the
3653 internal storage implementation. QDateTime is currently stored in a qint64
3654 as a serial msecs value encoding the date and time. This restricts the date
3655 range to about ±292 million years, compared to the QDate range of ±2 billion
3656 years. Care must be taken when creating a QDateTime with extreme values that
3657 you do not overflow the storage. The exact range of supported values varies
3658 depending on the time representation used.
3659
3660 \section2 Use of Timezones
3661
3662 QDateTime uses the system's time zone information to determine the current
3663 local time zone and its offset from UTC. If the system is not configured
3664 correctly or not up-to-date, QDateTime will give wrong results.
3665
3666 QDateTime likewise uses system-provided information to determine the offsets
3667 of other timezones from UTC. If this information is incomplete or out of
3668 date, QDateTime will give wrong results. See the QTimeZone documentation for
3669 more details.
3670
3671 On modern Unix systems, this means QDateTime usually has accurate
3672 information about historical transitions (including DST, see below) whenever
3673 possible. On Windows, where the system doesn't support historical timezone
3674 data, historical accuracy is not maintained with respect to timezone
3675 transitions, notably including DST. However, building Qt with the ICU
3676 library will equip QTimeZone with the same timezone database as is used on
3677 Unix.
3678
3679 \section2 Timezone transitions
3680
3681 QDateTime takes into account timezone transitions, both the transitions
3682 between Standard Time and Daylight-Saving Time (DST) and the transitions
3683 that arise when a zone changes its standard offset. For example, if the
3684 transition is at 2am and the clock goes forward to 3am, then there is a
3685 "missing" hour from 02:00:00 to 02:59:59.999. Such a transition is known as
3686 a "spring forward" and the times skipped over have no meaning. When a
3687 transition goes the other way, known as a "fall back", a time interval is
3688 repeated, first in the old zone (usually DST), then in the new zone (usually
3689 Standard Time), so times in this interval are ambiguous.
3690
3691 Some zones use "reversed" DST, using standard time in summer and
3692 daylight-saving time (with a lowered offset) in winter. For such zones, the
3693 spring forward still happens in spring and skips an hour, but is a
3694 transition \e{out of} daylight-saving time, while the fall back still
3695 repeats an autumn hour but is a transition \e to daylight-saving time.
3696
3697 When converting from a UTC time (or a time at fixed offset from UTC), there
3698 is always an unambiguous valid result in any timezone. However, when
3699 combining a date and time to make a datetime, expressed with respect to
3700 local time or a specific time-zone, the nominal result may fall in a
3701 transition, making it either invalid or ambiguous. Methods where this
3702 situation may arise take a \c resolve parameter: this is always ignored if
3703 the requested datetime is valid and unambiguous. See \l TransitionResolution
3704 for the options it lets you control. Prior to Qt 6.7, the equivalent of its
3705 \l LegacyBehavior was selected.
3706
3707 For a spring forward's skipped interval, interpreting the requested time
3708 with either offset yields an actual time at which the other offset was in
3709 use; so passing \c TransitionResolution::RelativeToBefore for \c resolve
3710 will actually result in a time after the transition, that would have had the
3711 requested representation had the transition not happened. Likewise, \c
3712 TransitionResolution::RelativeToAfter for \c resolve results in a time
3713 before the transition, that would have had the requested representation, had
3714 the transition happened earlier.
3715
3716 When QDateTime performs arithmetic, as with addDay() or addSecs(), it takes
3717 care to produce a valid result. For example, on a day when there is a spring
3718 forward from 02:00 to 03:00, adding one second to 01:59:59 will get
3719 03:00:00. Adding one day to 02:30 on the preceding day will get 03:30 on the
3720 day of the transition, while subtracting one day, by calling \c{addDay(-1)},
3721 to 02:30 on the following day will get 01:30 on the day of the transition.
3722 While addSecs() will deliver a time offset by the given number of seconds,
3723 addDays() adjusts the date and only adjusts time if it would otherwise get
3724 an invalid result. Applying \c{addDays(1)} to 03:00 on the day before the
3725 spring-forward will simply get 03:00 on the day of the transition, even
3726 though the latter is only 23 hours after the former; but \c{addSecs(24 * 60
3727 * 60)} will get 04:00 on the day of the transition, since that's 24 hours
3728 later. Typical transitions make some days 23 or 25 hours long.
3729
3730 For datetimes that the system \c time_t can represent (from 1901-12-14 to
3731 2038-01-18 on systems with 32-bit \c time_t; for the full range QDateTime
3732 can represent if the type is 64-bit), the standard system APIs are used to
3733 determine local time's offset from UTC. For datetimes not handled by these
3734 system APIs (potentially including some within the \c time_t range),
3735 QTimeZone::systemTimeZone() is used, if available, or a best effort is made
3736 to estimate. In any case, the offset information used depends on the system
3737 and may be incomplete or, for past times, historically
3738 inaccurate. Furthermore, for future dates, the local time zone's offsets and
3739 DST rules may change before that date comes around.
3740
3741 \section3 Whole day transitions
3742
3743 A small number of zones have skipped or repeated entire days as part of
3744 moving The International Date Line across themselves. For these, daysTo()
3745 will be unaware of the duplication or gap, simply using the difference in
3746 calendar date; in contrast, msecsTo() and secsTo() know the true time
3747 interval. Likewise, addMSecs() and addSecs() correspond directly to elapsed
3748 time, where addDays(), addMonths() and addYears() follow the nominal
3749 calendar, aside from where landing in a gap or duplication requires
3750 resolving an ambiguity or invalidity due to a duplication or omission.
3751
3752 \note Days "lost" during a change of calendar, such as from Julian to
3753 Gregorian, do not affect QDateTime. Although the two calendars describe
3754 dates differently, the successive days across the change are described by
3755 consecutive QDate instances, each one day later than the previous, as
3756 described by either calendar or by their toJulianDay() values. In contrast,
3757 a zone skipping or duplicating a day is changing its description of \e time,
3758 not date, for all that it does so by a whole 24 hours.
3759
3760 \section2 Offsets From UTC
3761
3762 Offsets from UTC are measured in seconds east of Greenwich. The moment
3763 described by a particular date and time, such as noon on a particular day,
3764 depends on the time representation used. Those with a higher offset from UTC
3765 describe an earlier moment, and those with a lower offset a later moment, by
3766 any given combination of date and time.
3767
3768 There is no explicit size restriction on an offset from UTC, but there is an
3769 implicit limit imposed when using the toString() and fromString() methods
3770 which use a ±hh:mm format, effectively limiting the range to ± 99 hours and
3771 59 minutes and whole minutes only. Note that currently no time zone has an
3772 offset outside the range of ±14 hours and all known offsets are multiples of
3773 five minutes. Historical time zones have a wider range and may have offsets
3774 including seconds; these last cannot be faithfully represented in strings.
3775
3776 \sa QDate, QTime, QDateTimeEdit, QTimeZone
3777*/
3778
3779/*!
3780 \since 5.14
3781 \enum QDateTime::YearRange
3782
3783 This enumerated type describes the range of years (in the Gregorian
3784 calendar) representable by QDateTime:
3785
3786 \value First The later parts of this year are representable
3787 \value Last The earlier parts of this year are representable
3788
3789 All dates strictly between these two years are also representable.
3790 Note, however, that the Gregorian Calendar has no year zero.
3791
3792 \note QDate can describe dates in a wider range of years. For most
3793 purposes, this makes little difference, as the range of years that QDateTime
3794 can support reaches 292 million years either side of 1970.
3795
3796 \sa isValid(), QDate
3797*/
3798
3799/*!
3800 \since 6.7
3801 \enum QDateTime::TransitionResolution
3802
3803 This enumeration is used to resolve datetime combinations which fall in \l
3804 {Timezone transitions}.
3805
3806 When constructing a datetime, specified in terms of local time or a
3807 time-zone that has daylight-saving time, or revising one with setDate(),
3808 setTime() or setTimeZone(), the given parameters may imply a time
3809 representation that either has no meaning or has two meanings in the
3810 zone. Such time representations are described as being in the transition. In
3811 either case, we can simply return an invalid datetime, to indicate that the
3812 operation is ill-defined. In the ambiguous case, we can alternatively select
3813 one of the two times that could be meant. When there is no meaning, we can
3814 select a time either side of it that might plausibly have been meant. For
3815 example, when advancing from an earlier time, we can select the time after
3816 the transition that is actually the specified amount of time after the
3817 earlier time in question. The options specified here configure how such
3818 selection is performed.
3819
3820 \value Reject
3821 Treat any time in a transition as invalid. Either it really is, or it
3822 is ambiguous.
3823 \value RelativeToBefore
3824 Selects a time as if stepping forward from a time before the
3825 transition. This interprets the requested time using the offset in
3826 effect before the transition and, if necessary, converts the result
3827 to the offset in effect at the resulting time.
3828 \value RelativeToAfter
3829 Select a time as if stepping backward from a time after the
3830 transition. This interprets the requested time using the offset in
3831 effect after the transition and, if necessary, converts the result to
3832 the offset in effect at the resulting time.
3833 \value PreferBefore
3834 Selects a time before the transition,
3835 \value PreferAfter
3836 Selects a time after the transition.
3837 \value PreferStandard
3838 Selects a time on the standard time side of the transition.
3839 \value PreferDaylightSaving
3840 Selects a time on the daylight-saving-time side of the transition.
3841 \value LegacyBehavior
3842 An alias for RelativeToBefore, which is used as default for
3843 TransitionResolution parameters, as this most closely matches the
3844 behavior prior to Qt 6.7.
3845
3846 For \l addDays(), \l addMonths() or \l addYears(), the behavior is and
3847 (mostly) was to use \c RelativeToBefore if adding a positive adjustment and \c
3848 RelativeToAfter if adding a negative adjustment.
3849
3850 \note In time zones where daylight-saving increases the offset from UTC in
3851 summer (known as "positive DST"), PreferStandard is an alias for
3852 RelativeToAfter and PreferDaylightSaving for RelativeToBefore. In time zones
3853 where the daylight-saving mechanism is a decrease in offset from UTC in
3854 winter (known as "negative DST"), the reverse applies, provided the
3855 operating system reports - as it does on most platforms - whether a datetime
3856 is in DST or standard time. For some platforms, where transition times are
3857 unavailable even for Qt::TimeZone datetimes, QTimeZone is obliged to presume
3858 that the side with lower offset from UTC is standard time, effectively
3859 assuming positive DST.
3860
3861 The following tables illustrate how a QDateTime constructor resolves a
3862 request for 02:30 on a day when local time has a transition between 02:00
3863 and 03:00, with a nominal standard time LST and daylight-saving time LDT on
3864 the two sides, in the various possible cases. The transition type may be to
3865 skip an hour or repeat it. The type of transition and value of a parameter
3866 \c resolve determine which actual time on the given date is selected. First,
3867 the common case of positive daylight-saving, where:
3868
3869 \table
3870 \header \li Before \li 02:00--03:00 \li After \li \c resolve \li selected
3871 \row \li LST \li skip \li LDT \li RelativeToBefore \li 03:30 LDT
3872 \row \li LST \li skip \li LDT \li RelativeToAfter \li 01:30 LST
3873 \row \li LST \li skip \li LDT \li PreferBefore \li 01:30 LST
3874 \row \li LST \li skip \li LDT \li PreferAfter \li 03:30 LDT
3875 \row \li LST \li skip \li LDT \li PreferStandard \li 01:30 LST
3876 \row \li LST \li skip \li LDT \li PreferDaylightSaving \li 03:30 LDT
3877 \row \li LDT \li repeat \li LST \li RelativeToBefore \li 02:30 LDT
3878 \row \li LDT \li repeat \li LST \li RelativeToAfter \li 02:30 LST
3879 \row \li LDT \li repeat \li LST \li PreferBefore \li 02:30 LDT
3880 \row \li LDT \li repeat \li LST \li PreferAfter \li 02:30 LST
3881 \row \li LDT \li repeat \li LST \li PreferStandard \li 02:30 LST
3882 \row \li LDT \li repeat \li LST \li PreferDaylightSaving \li 02:30 LDT
3883 \endtable
3884
3885 Second, the case for negative daylight-saving, using LDT in winter and
3886 skipping an hour to transition to LST in summer, then repeating an hour at
3887 the transition back to winter:
3888
3889 \table
3890 \row \li LDT \li skip \li LST \li RelativeToBefore \li 03:30 LST
3891 \row \li LDT \li skip \li LST \li RelativeToAfter \li 01:30 LDT
3892 \row \li LDT \li skip \li LST \li PreferBefore \li 01:30 LDT
3893 \row \li LDT \li skip \li LST \li PreferAfter \li 03:30 LST
3894 \row \li LDT \li skip \li LST \li PreferStandard \li 03:30 LST
3895 \row \li LDT \li skip \li LST \li PreferDaylightSaving \li 01:30 LDT
3896 \row \li LST \li repeat \li LDT \li RelativeToBefore \li 02:30 LST
3897 \row \li LST \li repeat \li LDT \li RelativeToAfter \li 02:30 LDT
3898 \row \li LST \li repeat \li LDT \li PreferBefore \li 02:30 LST
3899 \row \li LST \li repeat \li LDT \li PreferAfter \li 02:30 LDT
3900 \row \li LST \li repeat \li LDT \li PreferStandard \li 02:30 LST
3901 \row \li LST \li repeat \li LDT \li PreferDaylightSaving \li 02:30 LDT
3902 \endtable
3903
3904 Reject can be used to prompt relevant QDateTime APIs to return an invalid
3905 datetime object so that your code can deal with transitions for itself, for
3906 example by alerting a user to the fact that the datetime they have selected
3907 is in a transition interval, to offer them the opportunity to resolve a
3908 conflict or ambiguity. Code using this may well find the other options above
3909 useful to determine relevant information to use in its own (or the user's)
3910 resolution. If the start or end of the transition, or the moment of the
3911 transition itself, is the right resolution, QTimeZone's transition APIs can
3912 be used to obtain that information. You can determine whether the transition
3913 is a repeated or skipped interval by using \l secsTo() to measure the actual
3914 time between noon on the previous and following days. The result will be
3915 less than 48 hours for a skipped interval (such as a spring-forward) and
3916 more than 48 hours for a repeated interval (such as a fall-back).
3917
3918 \note When a resolution other than Reject is specified, a valid QDateTime
3919 object is returned, if possible. If the requested date-time falls in a gap,
3920 the returned date-time will not have the time() requested - or, in some
3921 cases, the date(), if a whole day was skipped. You can thus detect when a
3922 gap is hit by comparing date() and time() to what was requested.
3923
3924 \section2 Relation to other datetime software
3925
3926 The Python programming language's datetime APIs have a \c fold parameter
3927 that corresponds to \c RelativeToBefore (\c{fold = True}) and \c
3928 RelativeToAfter (\c{fold = False}).
3929
3930 The \c Temporal proposal to replace JavaScript's \c Date offers four options
3931 for how to resolve a transition, as value for a \c disambiguation
3932 parameter. Its \c{'reject'} raises an exception, which roughly corresponds
3933 to \c Reject producing an invalid result. Its \c{'earlier'} and \c{'later'}
3934 options correspond to \c PreferBefore and \c PreferAfter. Its
3935 \c{'compatible'} option corresponds to \c RelativeToBefore (and Python's
3936 \c{fold = True}).
3937
3938 \sa {Timezone transitions}, QDateTime::TransitionResolution
3939*/
3940
3941/*!
3942 Constructs a null datetime, nominally using local time.
3943
3944 A null datetime is invalid, since its date and time are invalid.
3945
3946 \sa isValid(), setMSecsSinceEpoch(), setDate(), setTime(), setTimeZone()
3947*/
3948QDateTime::QDateTime() noexcept
3949{
3950#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED) || QT_POINTER_SIZE == 8
3951 static_assert(sizeof(ShortData) == sizeof(qint64));
3952 static_assert(sizeof(Data) == sizeof(qint64));
3953#endif
3954 static_assert(sizeof(ShortData) >= sizeof(void*), "oops, Data::swap() is broken!");
3955}
3956
3957#if QT_DEPRECATED_SINCE(6, 9)
3958/*!
3959 \deprecated [6.9] Use \c{QDateTime(date, time)} or \c{QDateTime(date, time, QTimeZone::fromSecondsAheadOfUtc(offsetSeconds))}.
3960
3961 Constructs a datetime with the given \a date and \a time, using the time
3962 representation implied by \a spec and \a offsetSeconds seconds.
3963
3964 If \a date is valid and \a time is not, the time will be set to midnight.
3965
3966 If \a spec is not Qt::OffsetFromUTC then \a offsetSeconds will be
3967 ignored. If \a spec is Qt::OffsetFromUTC and \a offsetSeconds is 0 then the
3968 timeSpec() will be set to Qt::UTC, i.e. an offset of 0 seconds.
3969
3970 If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
3971 i.e. the current system time zone. To create a Qt::TimeZone datetime
3972 use the correct constructor.
3973
3974 If \a date lies outside the range of dates representable by QDateTime, the
3975 result is invalid. If \a spec is Qt::LocalTime and the system's time-zone
3976 skipped over the given date and time, the result is invalid.
3977*/
3978QDateTime::QDateTime(QDate date, QTime time, Qt::TimeSpec spec, int offsetSeconds)
3979 : d(QDateTimePrivate::create(toDate: date, toTime: time, zone: asTimeZone(spec, offset: offsetSeconds, warner: "QDateTime"),
3980 resolve: TransitionResolution::LegacyBehavior))
3981{
3982}
3983#endif // 6.9 deprecation
3984
3985/*!
3986 \since 5.2
3987
3988 Constructs a datetime with the given \a date and \a time, using the time
3989 representation described by \a timeZone.
3990
3991 If \a date is valid and \a time is not, the time will be set to midnight.
3992 If \a timeZone is invalid then the datetime will be invalid. If \a date and
3993 \a time describe a moment close to a transition for \a timeZone, \a resolve
3994 controls how that situation is resolved.
3995
3996//! [pre-resolve-note]
3997 \note Prior to Qt 6.7, the version of this function lacked the \a resolve
3998 parameter so had no way to resolve the ambiguities related to transitions.
3999//! [pre-resolve-note]
4000*/
4001
4002QDateTime::QDateTime(QDate date, QTime time, const QTimeZone &timeZone, TransitionResolution resolve)
4003 : d(QDateTimePrivate::create(toDate: date, toTime: time, zone: timeZone, resolve))
4004{
4005}
4006
4007/*!
4008 \since 6.5
4009 \overload
4010
4011 Constructs a datetime with the given \a date and \a time, using local time.
4012
4013 If \a date is valid and \a time is not, midnight will be used as the
4014 time. If \a date and \a time describe a moment close to a transition for
4015 local time, \a resolve controls how that situation is resolved.
4016
4017 \include qdatetime.cpp pre-resolve-note
4018*/
4019
4020QDateTime::QDateTime(QDate date, QTime time, TransitionResolution resolve)
4021 : d(QDateTimePrivate::create(toDate: date, toTime: time, zone: QTimeZone::LocalTime, resolve))
4022{
4023}
4024
4025/*!
4026 Constructs a copy of the \a other datetime.
4027*/
4028QDateTime::QDateTime(const QDateTime &other) noexcept
4029 : d(other.d)
4030{
4031}
4032
4033/*!
4034 \since 5.8
4035 Moves the content of the temporary \a other datetime to this object and
4036 leaves \a other in an unspecified (but proper) state.
4037*/
4038QDateTime::QDateTime(QDateTime &&other) noexcept
4039 : d(std::move(other.d))
4040{
4041}
4042
4043/*!
4044 Destroys the datetime.
4045*/
4046QDateTime::~QDateTime()
4047{
4048}
4049
4050/*!
4051 Copies the \a other datetime into this and returns this copy.
4052*/
4053
4054QDateTime &QDateTime::operator=(const QDateTime &other) noexcept
4055{
4056 d = other.d;
4057 return *this;
4058}
4059/*!
4060 \fn void QDateTime::swap(QDateTime &other)
4061 \since 5.0
4062
4063 Swaps this datetime with \a other. This operation is very fast
4064 and never fails.
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(flag: 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(flag: 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(flag: QDateTimePrivate::ValidDate) ? msecsToDate(msecs: 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(flag: QDateTimePrivate::ValidTime) ? msecsToTime(msecs: 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(flags: 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(dst: extractDaylightStatus(status));
4213 return QDateTimePrivate::localStateAtMillis(millis: 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(format: Qt::ISODate, offset: 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(atDateTime: *this);
4257#endif // timezone
4258 case Qt::LocalTime:
4259 return QDateTimePrivate::localNameAtMillis(millis: getMSecs(d),
4260 dst: extractDaylightStatus(status: getStatus(d)));
4261 }
4262 return QString();
4263}
4264
4265/*!
4266 \since 5.2
4267
4268 Returns if this datetime falls in Daylight-Saving Time.
4269
4270 If the Qt::TimeSpec is not Qt::LocalTime or Qt::TimeZone then will always
4271 return false.
4272
4273 \sa timeSpec()
4274*/
4275
4276bool QDateTime::isDaylightTime() const
4277{
4278 if (!isValid())
4279 return false;
4280
4281 switch (getSpec(d)) {
4282 case Qt::UTC:
4283 case Qt::OffsetFromUTC:
4284 return false;
4285 case Qt::TimeZone:
4286#if !QT_CONFIG(timezone)
4287 break;
4288#else
4289 Q_ASSERT(d->m_timeZone.isValid());
4290 if (auto dst = extractDaylightStatus(status: getStatus(d));
4291 dst != QDateTimePrivate::UnknownDaylightTime) {
4292 return dst == QDateTimePrivate::DaylightTime;
4293 }
4294 return d->m_timeZone.d->isDaylightTime(atMSecsSinceEpoch: toMSecsSinceEpoch());
4295#endif // timezone
4296 case Qt::LocalTime: {
4297 auto dst = extractDaylightStatus(status: getStatus(d));
4298 if (dst == QDateTimePrivate::UnknownDaylightTime) {
4299 dst = QDateTimePrivate::localStateAtMillis(
4300 millis: getMSecs(d), resolve: toTransitionOptions(res: TransitionResolution::LegacyBehavior)).dst;
4301 }
4302 return dst == QDateTimePrivate::DaylightTime;
4303 }
4304 }
4305 return false;
4306}
4307
4308/*!
4309 Sets the date part of this datetime to \a date.
4310
4311 If no time is set yet, it is set to midnight. If \a date is invalid, this
4312 QDateTime becomes invalid.
4313
4314 If \a date and time() describe a moment close to a transition for this
4315 datetime's time representation, \a resolve controls how that situation is
4316 resolved.
4317
4318 \include qdatetime.cpp pre-resolve-note
4319
4320 \sa date(), setTime(), setTimeZone()
4321*/
4322
4323void QDateTime::setDate(QDate date, TransitionResolution resolve)
4324{
4325 setDateTime(d, date, time: time());
4326 checkValidDateTime(d, resolve);
4327}
4328
4329/*!
4330 Sets the time part of this datetime to \a time. If \a time is not valid,
4331 this function sets it to midnight. Therefore, it's possible to clear any
4332 set time in a QDateTime by setting it to a default QTime:
4333
4334 \code
4335 QDateTime dt = QDateTime::currentDateTime();
4336 dt.setTime(QTime());
4337 \endcode
4338
4339 If date() and \a time describe a moment close to a transition for this
4340 datetime's time representation, \a resolve controls how that situation is
4341 resolved.
4342
4343 \include qdatetime.cpp pre-resolve-note
4344
4345 \sa time(), setDate(), setTimeZone()
4346*/
4347
4348void QDateTime::setTime(QTime time, TransitionResolution resolve)
4349{
4350 setDateTime(d, date: date(), time);
4351 checkValidDateTime(d, resolve);
4352}
4353
4354#if QT_DEPRECATED_SINCE(6, 9)
4355/*!
4356 \deprecated [6.9] Use setTimeZone() instead
4357
4358 Sets the time specification used in this datetime to \a spec.
4359 The datetime may refer to a different point in time.
4360
4361 If \a spec is Qt::OffsetFromUTC then the timeSpec() will be set
4362 to Qt::UTC, i.e. an effective offset of 0.
4363
4364 If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
4365 i.e. the current system time zone.
4366
4367 Example:
4368 \snippet code/src_corelib_time_qdatetime.cpp 19
4369
4370 \sa setTimeZone(), timeSpec(), toTimeSpec(), setDate(), setTime()
4371*/
4372
4373void QDateTime::setTimeSpec(Qt::TimeSpec spec)
4374{
4375 reviseTimeZone(d, zone: asTimeZone(spec, offset: 0, warner: "QDateTime::setTimeSpec"),
4376 resolve: TransitionResolution::LegacyBehavior);
4377}
4378
4379/*!
4380 \since 5.2
4381 \deprecated [6.9] Use setTimeZone(QTimeZone::fromSecondsAheadOfUtc(offsetSeconds)) instead
4382
4383 Sets the timeSpec() to Qt::OffsetFromUTC and the offset to \a offsetSeconds.
4384 The datetime may refer to a different point in time.
4385
4386 The maximum and minimum offset is 14 positive or negative hours. If
4387 \a offsetSeconds is larger or smaller than that, then the result is
4388 undefined.
4389
4390 If \a offsetSeconds is 0 then the timeSpec() will be set to Qt::UTC.
4391
4392 \sa setTimeZone(), isValid(), offsetFromUtc(), toOffsetFromUtc()
4393*/
4394
4395void QDateTime::setOffsetFromUtc(int offsetSeconds)
4396{
4397 reviseTimeZone(d, zone: QTimeZone::fromSecondsAheadOfUtc(offset: offsetSeconds),
4398 resolve: TransitionResolution::Reject);
4399}
4400#endif // 6.9 deprecations
4401
4402/*!
4403 \since 5.2
4404
4405 Sets the time zone used in this datetime to \a toZone.
4406
4407 The datetime may refer to a different point in time. It uses the time
4408 representation of \a toZone, which may change the meaning of its unchanged
4409 date() and time().
4410
4411 If \a toZone is invalid then the datetime will be invalid. Otherwise, this
4412 datetime's timeSpec() after the call will match \c{toZone.timeSpec()}.
4413
4414 If date() and time() describe a moment close to a transition for \a toZone,
4415 \a resolve controls how that situation is resolved.
4416
4417 \include qdatetime.cpp pre-resolve-note
4418
4419 \sa timeRepresentation(), timeZone(), Qt::TimeSpec
4420*/
4421
4422void QDateTime::setTimeZone(const QTimeZone &toZone, TransitionResolution resolve)
4423{
4424 reviseTimeZone(d, zone: toZone, resolve);
4425}
4426
4427/*!
4428 \since 4.7
4429
4430 Returns the datetime as a number of milliseconds after the start, in UTC, of
4431 the year 1970.
4432
4433 On systems that do not support time zones, this function will
4434 behave as if local time were Qt::UTC.
4435
4436 The behavior for this function is undefined if the datetime stored in
4437 this object is not valid. However, for all valid dates, this function
4438 returns a unique value.
4439
4440 \sa toSecsSinceEpoch(), setMSecsSinceEpoch(), fromMSecsSinceEpoch()
4441*/
4442qint64 QDateTime::toMSecsSinceEpoch() const
4443{
4444 // Note: QDateTimeParser relies on this producing a useful result, even when
4445 // !isValid(), at least when the invalidity is a time in a fall-back (that
4446 // we'll have adjusted to lie outside it, but marked invalid because it's
4447 // not what was asked for). Other things may be doing similar. But that's
4448 // only relevant when we got enough data for resolution to find it invalid.
4449 const auto status = getStatus(d);
4450 if (!status.testFlags(flags: QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime))
4451 return 0;
4452
4453 switch (extractSpec(status)) {
4454 case Qt::UTC:
4455 return getMSecs(d);
4456
4457 case Qt::OffsetFromUTC:
4458 Q_ASSERT(!d.isShort());
4459 return d->m_msecs - d->m_offsetFromUtc * MSECS_PER_SEC;
4460
4461 case Qt::LocalTime:
4462 if (status.testFlag(flag: QDateTimePrivate::ShortData)) {
4463 // Short form has nowhere to cache the offset, so recompute.
4464 const auto resolve = toTransitionOptions(dst: extractDaylightStatus(status: getStatus(d)));
4465 const auto state = QDateTimePrivate::localStateAtMillis(millis: getMSecs(d), resolve);
4466 return state.when - state.offset * MSECS_PER_SEC;
4467 }
4468 // Use the offset saved by refreshZonedDateTime() on creation.
4469 return d->m_msecs - d->m_offsetFromUtc * MSECS_PER_SEC;
4470
4471 case Qt::TimeZone:
4472 Q_ASSERT(!d.isShort());
4473#if QT_CONFIG(timezone)
4474 // Use offset refreshZonedDateTime() saved on creation:
4475 if (d->m_timeZone.isValid())
4476 return d->m_msecs - d->m_offsetFromUtc * MSECS_PER_SEC;
4477#endif
4478 return 0;
4479 }
4480 Q_UNREACHABLE_RETURN(0);
4481}
4482
4483/*!
4484 \since 5.8
4485
4486 Returns the datetime as a number of seconds after the start, in UTC, of the
4487 year 1970.
4488
4489 On systems that do not support time zones, this function will
4490 behave as if local time were Qt::UTC.
4491
4492 The behavior for this function is undefined if the datetime stored in
4493 this object is not valid. However, for all valid dates, this function
4494 returns a unique value.
4495
4496 \sa toMSecsSinceEpoch(), fromSecsSinceEpoch(), setSecsSinceEpoch()
4497*/
4498qint64 QDateTime::toSecsSinceEpoch() const
4499{
4500 return toMSecsSinceEpoch() / MSECS_PER_SEC;
4501}
4502
4503/*!
4504 \since 4.7
4505
4506 Sets the datetime to represent a moment a given number, \a msecs, of
4507 milliseconds after the start, in UTC, of the year 1970.
4508
4509 On systems that do not support time zones, this function will
4510 behave as if local time were Qt::UTC.
4511
4512 Note that passing the minimum of \c qint64
4513 (\c{std::numeric_limits<qint64>::min()}) to \a msecs will result in
4514 undefined behavior.
4515
4516 \sa setSecsSinceEpoch(), toMSecsSinceEpoch(), fromMSecsSinceEpoch()
4517*/
4518void QDateTime::setMSecsSinceEpoch(qint64 msecs)
4519{
4520 auto status = getStatus(d);
4521 const auto spec = extractSpec(status);
4522 Q_ASSERT(specCanBeSmall(spec) || !d.isShort());
4523 QDateTimePrivate::ZoneState state(msecs);
4524
4525 status &= ~QDateTimePrivate::ValidityMask;
4526 if (QTimeZone::isUtcOrFixedOffset(spec)) {
4527 if (spec == Qt::OffsetFromUTC)
4528 state.offset = d->m_offsetFromUtc;
4529 if (!state.offset || !qAddOverflow(v1: msecs, v2: state.offset * MSECS_PER_SEC, r: &state.when))
4530 status |= QDateTimePrivate::ValidityMask;
4531 } else if (spec == Qt::LocalTime) {
4532 state = QDateTimePrivate::expressUtcAsLocal(utcMSecs: msecs);
4533 if (state.valid)
4534 status = mergeDaylightStatus(sf: status | QDateTimePrivate::ValidityMask, status: state.dst);
4535#if QT_CONFIG(timezone)
4536 } else if (spec == Qt::TimeZone && (d.detach(), d->m_timeZone.isValid())) {
4537 const auto data = d->m_timeZone.d->data(forMSecsSinceEpoch: msecs);
4538 if (Q_LIKELY(data.offsetFromUtc != QTimeZonePrivate::invalidSeconds())) {
4539 state.offset = data.offsetFromUtc;
4540 Q_ASSERT(state.offset >= -SECS_PER_DAY && state.offset <= SECS_PER_DAY);
4541 if (!state.offset
4542 || !Q_UNLIKELY(qAddOverflow(msecs, state.offset * MSECS_PER_SEC, &state.when))) {
4543 d->m_status = mergeDaylightStatus(sf: status | QDateTimePrivate::ValidityMask,
4544 status: data.daylightTimeOffset
4545 ? QDateTimePrivate::DaylightTime
4546 : QDateTimePrivate::StandardTime);
4547 d->m_msecs = state.when;
4548 d->m_offsetFromUtc = state.offset;
4549 return;
4550 } // else: zone can't represent this UTC time
4551 } // else: zone unable to represent given UTC time (should only happen on overflow).
4552#endif // timezone
4553 }
4554 Q_ASSERT(!status.testFlag(QDateTimePrivate::ValidDateTime)
4555 || (state.offset >= -SECS_PER_DAY && state.offset <= SECS_PER_DAY));
4556
4557 if (msecsCanBeSmall(msecs: state.when) && d.isShort()) {
4558 // we can keep short
4559 d.data.msecs = qintptr(state.when);
4560 d.data.status = status.toInt();
4561 } else {
4562 d.detach();
4563 d->m_status = status & ~QDateTimePrivate::ShortData;
4564 d->m_msecs = state.when;
4565 d->m_offsetFromUtc = state.offset;
4566 }
4567}
4568
4569/*!
4570 \since 5.8
4571
4572 Sets the datetime to represent a moment a given number, \a secs, of seconds
4573 after the start, in UTC, of the year 1970.
4574
4575 On systems that do not support time zones, this function will
4576 behave as if local time were Qt::UTC.
4577
4578 \sa setMSecsSinceEpoch(), toSecsSinceEpoch(), fromSecsSinceEpoch()
4579*/
4580void QDateTime::setSecsSinceEpoch(qint64 secs)
4581{
4582 qint64 msecs;
4583 if (!qMulOverflow(v1: secs, std::integral_constant<qint64, MSECS_PER_SEC>(), r: &msecs))
4584 setMSecsSinceEpoch(msecs);
4585 else
4586 d.invalidate();
4587}
4588
4589#if QT_CONFIG(datestring) // depends on, so implies, textdate
4590/*!
4591 \overload
4592
4593 Returns the datetime as a string in the \a format given.
4594
4595 If the \a format is Qt::TextDate, the string is formatted in the default
4596 way. The day and month names will be in English. An example of this
4597 formatting is "Wed May 20 03:40:13 1998". For localized formatting, see
4598 \l{QLocale::toString()}.
4599
4600 If the \a format is Qt::ISODate, the string format corresponds to the ISO
4601 8601 extended specification for representations of dates and times, taking
4602 the form yyyy-MM-ddTHH:mm:ss[Z|±HH:mm], depending on the timeSpec() of the
4603 QDateTime. If the timeSpec() is Qt::UTC, Z will be appended to the string;
4604 if the timeSpec() is Qt::OffsetFromUTC, the offset in hours and minutes from
4605 UTC will be appended to the string. To include milliseconds in the ISO 8601
4606 date, use the \a format Qt::ISODateWithMs, which corresponds to
4607 yyyy-MM-ddTHH:mm:ss.zzz[Z|±HH:mm].
4608
4609 If the \a format is Qt::RFC2822Date, the string is formatted
4610 following \l{RFC 2822}.
4611
4612 If the datetime is invalid, an empty string will be returned.
4613
4614 \warning The Qt::ISODate format is only valid for years in the
4615 range 0 to 9999.
4616
4617 \sa fromString(), QDate::toString(), QTime::toString(),
4618 QLocale::toString()
4619*/
4620QString QDateTime::toString(Qt::DateFormat format) const
4621{
4622 QString buf;
4623 if (!isValid())
4624 return buf;
4625
4626 switch (format) {
4627 case Qt::RFC2822Date:
4628 buf = QLocale::c().toString(dateTime: *this, format: u"dd MMM yyyy hh:mm:ss ");
4629 buf += toOffsetString(format: Qt::TextDate, offset: offsetFromUtc());
4630 return buf;
4631 default:
4632 case Qt::TextDate: {
4633 const std::pair<QDate, QTime> p = getDateTime(d);
4634 buf = toStringTextDate(date: p.first);
4635 // Insert time between date's day and year:
4636 buf.insert(i: buf.lastIndexOf(c: u' '),
4637 s: u' ' + p.second.toString(format: Qt::TextDate));
4638 // Append zone/offset indicator, as appropriate:
4639 switch (timeSpec()) {
4640 case Qt::LocalTime:
4641 break;
4642#if QT_CONFIG(timezone)
4643 case Qt::TimeZone:
4644 buf += u' ' + d->m_timeZone.displayName(
4645 atDateTime: *this, nameType: QTimeZone::OffsetName, locale: QLocale::c());
4646 break;
4647#endif
4648 default:
4649#if 0 // ### Qt 7 GMT: use UTC instead, see qnamespace.qdoc documentation
4650 buf += " UTC"_L1;
4651#else
4652 buf += " GMT"_L1;
4653#endif
4654 if (getSpec(d) == Qt::OffsetFromUTC)
4655 buf += toOffsetString(format: Qt::TextDate, offset: offsetFromUtc());
4656 }
4657 return buf;
4658 }
4659 case Qt::ISODate:
4660 case Qt::ISODateWithMs: {
4661 const std::pair<QDate, QTime> p = getDateTime(d);
4662 buf = toStringIsoDate(date: p.first);
4663 if (buf.isEmpty())
4664 return QString(); // failed to convert
4665 buf += u'T' + p.second.toString(format);
4666 switch (getSpec(d)) {
4667 case Qt::UTC:
4668 buf += u'Z';
4669 break;
4670 case Qt::OffsetFromUTC:
4671 case Qt::TimeZone:
4672 buf += toOffsetString(format: Qt::ISODate, offset: offsetFromUtc());
4673 break;
4674 default:
4675 break;
4676 }
4677 return buf;
4678 }
4679 }
4680}
4681
4682/*!
4683 \fn QString QDateTime::toString(const QString &format, QCalendar cal) const
4684 \fn QString QDateTime::toString(QStringView format, QCalendar cal) const
4685 \since 5.14
4686
4687 Returns the datetime as a string. The \a format parameter determines the
4688 format of the result string. If \a cal is supplied, it determines the
4689 calendar used to represent the date; it defaults to Gregorian. Prior to Qt
4690 5.14, there was no \a cal parameter and the Gregorian calendar was always
4691 used. See QTime::toString() and QDate::toString() for the supported
4692 specifiers for time and date, respectively, in the \a format parameter.
4693
4694 Any sequence of characters enclosed in single quotes will be included
4695 verbatim in the output string (stripped of the quotes), even if it contains
4696 formatting characters. Two consecutive single quotes ("''") are replaced by
4697 a single quote in the output. All other characters in the format string are
4698 included verbatim in the output string.
4699
4700 Formats without separators (e.g. "ddMM") are supported but must be used with
4701 care, as the resulting strings aren't always reliably readable (e.g. if "dM"
4702 produces "212" it could mean either the 2nd of December or the 21st of
4703 February).
4704
4705 Example format strings (assumed that the QDateTime is 21 May 2001
4706 14:13:09.120):
4707
4708 \table
4709 \header \li Format \li Result
4710 \row \li dd.MM.yyyy \li 21.05.2001
4711 \row \li ddd MMMM d yy \li Tue May 21 01
4712 \row \li hh:mm:ss.zzz \li 14:13:09.120
4713 \row \li hh:mm:ss.z \li 14:13:09.12
4714 \row \li h:m:s ap \li 2:13:9 pm
4715 \endtable
4716
4717 If the datetime is invalid, an empty string will be returned.
4718
4719 \note Day and month names as well as AM/PM indicators are given in English
4720 (C locale). To get localized month and day names and localized forms of
4721 AM/PM, use QLocale::system().toDateTime().
4722
4723 \sa fromString(), QDate::toString(), QTime::toString(), QLocale::toString()
4724*/
4725QString QDateTime::toString(QStringView format, QCalendar cal) const
4726{
4727 return QLocale::c().toString(dateTime: *this, format, cal);
4728}
4729
4730// Out-of-line no-calendar overloads, since QCalendar is a non-trivial type
4731/*!
4732 \overload
4733 \since 5.10
4734*/
4735QString QDateTime::toString(QStringView format) const
4736{
4737 return QLocale::c().toString(dateTime: *this, format, cal: QCalendar());
4738}
4739
4740/*!
4741 \overload
4742 \since 4.6
4743*/
4744QString QDateTime::toString(const QString &format) const
4745{
4746 return QLocale::c().toString(dateTime: *this, format: qToStringViewIgnoringNull(s: format), cal: QCalendar());
4747}
4748#endif // datestring
4749
4750static inline void massageAdjustedDateTime(QDateTimeData &d, QDate date, QTime time, bool forward)
4751{
4752 const QDateTimePrivate::TransitionOptions resolve = toTransitionOptions(
4753 res: forward ? QDateTime::TransitionResolution::RelativeToBefore
4754 : QDateTime::TransitionResolution::RelativeToAfter);
4755 auto status = getStatus(d);
4756 Q_ASSERT(status.testFlags(QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime
4757 | QDateTimePrivate::ValidDateTime));
4758 auto spec = extractSpec(status);
4759 if (QTimeZone::isUtcOrFixedOffset(spec)) {
4760 setDateTime(d, date, time);
4761 refreshSimpleDateTime(d);
4762 return;
4763 }
4764 qint64 local = timeToMSecs(date, time);
4765 const QDateTimePrivate::ZoneState state = stateAtMillis(zone: d.timeZone(), millis: local, resolve);
4766 Q_ASSERT(state.valid || state.dst == QDateTimePrivate::UnknownDaylightTime);
4767 if (state.dst == QDateTimePrivate::UnknownDaylightTime)
4768 status.setFlag(flag: QDateTimePrivate::ValidDateTime, on: false);
4769 else
4770 status = mergeDaylightStatus(sf: status | QDateTimePrivate::ValidDateTime, status: state.dst);
4771
4772 if (status & QDateTimePrivate::ShortData) {
4773 d.data.msecs = state.when;
4774 d.data.status = status.toInt();
4775 } else {
4776 d.detach();
4777 d->m_status = status;
4778 if (state.valid) {
4779 d->m_msecs = state.when;
4780 d->m_offsetFromUtc = state.offset;
4781 }
4782 }
4783}
4784
4785/*!
4786 Returns a QDateTime object containing a datetime \a ndays days
4787 later than the datetime of this object (or earlier if \a ndays is
4788 negative).
4789
4790 If the timeSpec() is Qt::LocalTime or Qt::TimeZone and the resulting date
4791 and time fall in the Standard Time to Daylight-Saving Time transition hour
4792 then the result will be just beyond this gap, in the direction of change.
4793 If the transition is at 2am and the clock goes forward to 3am, the result of
4794 aiming between 2am and 3am will be adjusted to fall before 2am (if \c{ndays
4795 < 0}) or after 3am (otherwise).
4796
4797 \sa daysTo(), addMonths(), addYears(), addSecs(), {Timezone transitions}
4798*/
4799
4800QDateTime QDateTime::addDays(qint64 ndays) const
4801{
4802 if (isNull())
4803 return QDateTime();
4804
4805 QDateTime dt(*this);
4806 std::pair<QDate, QTime> p = getDateTime(d);
4807 massageAdjustedDateTime(d&: dt.d, date: p.first.addDays(ndays), time: p.second, forward: ndays >= 0);
4808 return dt;
4809}
4810
4811/*!
4812 Returns a QDateTime object containing a datetime \a nmonths months
4813 later than the datetime of this object (or earlier if \a nmonths
4814 is negative).
4815
4816 If the timeSpec() is Qt::LocalTime or Qt::TimeZone and the resulting date
4817 and time fall in the Standard Time to Daylight-Saving Time transition hour
4818 then the result will be just beyond this gap, in the direction of change.
4819 If the transition is at 2am and the clock goes forward to 3am, the result of
4820 aiming between 2am and 3am will be adjusted to fall before 2am (if
4821 \c{nmonths < 0}) or after 3am (otherwise).
4822
4823 \sa daysTo(), addDays(), addYears(), addSecs(), {Timezone transitions}
4824*/
4825
4826QDateTime QDateTime::addMonths(int nmonths) const
4827{
4828 if (isNull())
4829 return QDateTime();
4830
4831 QDateTime dt(*this);
4832 std::pair<QDate, QTime> p = getDateTime(d);
4833 massageAdjustedDateTime(d&: dt.d, date: p.first.addMonths(nmonths), time: p.second, forward: nmonths >= 0);
4834 return dt;
4835}
4836
4837/*!
4838 Returns a QDateTime object containing a datetime \a nyears years
4839 later than the datetime of this object (or earlier if \a nyears is
4840 negative).
4841
4842 If the timeSpec() is Qt::LocalTime or Qt::TimeZone and the resulting date
4843 and time fall in the Standard Time to Daylight-Saving Time transition hour
4844 then the result will be just beyond this gap, in the direction of change.
4845 If the transition is at 2am and the clock goes forward to 3am, the result of
4846 aiming between 2am and 3am will be adjusted to fall before 2am (if \c{nyears
4847 < 0}) or after 3am (otherwise).
4848
4849 \sa daysTo(), addDays(), addMonths(), addSecs(), {Timezone transitions}
4850*/
4851
4852QDateTime QDateTime::addYears(int nyears) const
4853{
4854 if (isNull())
4855 return QDateTime();
4856
4857 QDateTime dt(*this);
4858 std::pair<QDate, QTime> p = getDateTime(d);
4859 massageAdjustedDateTime(d&: dt.d, date: p.first.addYears(nyears), time: p.second, forward: nyears >= 0);
4860 return dt;
4861}
4862
4863/*!
4864 Returns a QDateTime object containing a datetime \a s seconds
4865 later than the datetime of this object (or earlier if \a s is
4866 negative).
4867
4868 If this datetime is invalid, an invalid datetime will be returned.
4869
4870 \sa addMSecs(), secsTo(), addDays(), addMonths(), addYears()
4871*/
4872
4873QDateTime QDateTime::addSecs(qint64 s) const
4874{
4875 qint64 msecs;
4876 if (qMulOverflow(v1: s, std::integral_constant<qint64, MSECS_PER_SEC>(), r: &msecs))
4877 return QDateTime();
4878 return addMSecs(msecs);
4879}
4880
4881/*!
4882 Returns a QDateTime object containing a datetime \a msecs milliseconds
4883 later than the datetime of this object (or earlier if \a msecs is
4884 negative).
4885
4886 If this datetime is invalid, an invalid datetime will be returned.
4887
4888 \sa addSecs(), msecsTo(), addDays(), addMonths(), addYears()
4889*/
4890QDateTime QDateTime::addMSecs(qint64 msecs) const
4891{
4892 if (!isValid())
4893 return QDateTime();
4894
4895 QDateTime dt(*this);
4896 switch (getSpec(d)) {
4897 case Qt::LocalTime:
4898 case Qt::TimeZone:
4899 // Convert to real UTC first in case this crosses a DST transition:
4900 if (!qAddOverflow(v1: toMSecsSinceEpoch(), v2: msecs, r: &msecs))
4901 dt.setMSecsSinceEpoch(msecs);
4902 else
4903 dt.d.invalidate();
4904 break;
4905 case Qt::UTC:
4906 case Qt::OffsetFromUTC:
4907 // No need to convert, just add on
4908 if (qAddOverflow(v1: getMSecs(d), v2: msecs, r: &msecs)) {
4909 dt.d.invalidate();
4910 } else if (d.isShort() && msecsCanBeSmall(msecs)) {
4911 dt.d.data.msecs = qintptr(msecs);
4912 } else {
4913 dt.d.detach();
4914 dt.d->m_msecs = msecs;
4915 }
4916 break;
4917 }
4918 return dt;
4919}
4920
4921/*!
4922 \fn QDateTime QDateTime::addDuration(std::chrono::milliseconds msecs) const
4923
4924 \since 6.4
4925
4926 Returns a QDateTime object containing a datetime \a msecs milliseconds
4927 later than the datetime of this object (or earlier if \a msecs is
4928 negative).
4929
4930 If this datetime is invalid, an invalid datetime will be returned.
4931
4932 \note Adding durations expressed in \c{std::chrono::months} or
4933 \c{std::chrono::years} does not yield the same result obtained by using
4934 addMonths() or addYears(). The former are fixed durations, calculated in
4935 relation to the solar year; the latter use the Gregorian calendar definitions
4936 of months/years.
4937
4938 \sa addMSecs(), msecsTo(), addDays(), addMonths(), addYears()
4939*/
4940
4941/*!
4942 Returns the number of days from this datetime to the \a other
4943 datetime. The number of days is counted as the number of times
4944 midnight is reached between this datetime to the \a other
4945 datetime. This means that a 10 minute difference from 23:55 to
4946 0:05 the next day counts as one day.
4947
4948 If the \a other datetime is earlier than this datetime,
4949 the value returned is negative.
4950
4951 Example:
4952 \snippet code/src_corelib_time_qdatetime.cpp 15
4953
4954 \sa addDays(), secsTo(), msecsTo()
4955*/
4956
4957qint64 QDateTime::daysTo(const QDateTime &other) const
4958{
4959 return date().daysTo(d: other.date());
4960}
4961
4962/*!
4963 Returns the number of seconds from this datetime to the \a other
4964 datetime. If the \a other datetime is earlier than this datetime,
4965 the value returned is negative.
4966
4967 Before performing the comparison, the two datetimes are converted
4968 to Qt::UTC to ensure that the result is correct if daylight-saving
4969 (DST) applies to one of the two datetimes but not the other.
4970
4971 Returns 0 if either datetime is invalid.
4972
4973 Example:
4974 \snippet code/src_corelib_time_qdatetime.cpp 11
4975
4976 \sa addSecs(), daysTo(), QTime::secsTo()
4977*/
4978
4979qint64 QDateTime::secsTo(const QDateTime &other) const
4980{
4981 return msecsTo(other) / MSECS_PER_SEC;
4982}
4983
4984/*!
4985 Returns the number of milliseconds from this datetime to the \a other
4986 datetime. If the \a other datetime is earlier than this datetime,
4987 the value returned is negative.
4988
4989 Before performing the comparison, the two datetimes are converted
4990 to Qt::UTC to ensure that the result is correct if daylight-saving
4991 (DST) applies to one of the two datetimes and but not the other.
4992
4993 Returns 0 if either datetime is invalid.
4994
4995 \sa addMSecs(), daysTo(), QTime::msecsTo()
4996*/
4997
4998qint64 QDateTime::msecsTo(const QDateTime &other) const
4999{
5000 if (!isValid() || !other.isValid())
5001 return 0;
5002
5003 return other.toMSecsSinceEpoch() - toMSecsSinceEpoch();
5004}
5005
5006/*!
5007 \fn std::chrono::milliseconds QDateTime::operator-(const QDateTime &lhs, const QDateTime &rhs)
5008 \since 6.4
5009
5010 Returns the number of milliseconds between \a lhs and \a rhs.
5011 If \a lhs is earlier than \a rhs, the result will be negative.
5012
5013 Returns 0 if either datetime is invalid.
5014
5015 \sa msecsTo()
5016*/
5017
5018/*!
5019 \fn QDateTime QDateTime::operator+(const QDateTime &dateTime, std::chrono::milliseconds duration)
5020 \fn QDateTime QDateTime::operator+(std::chrono::milliseconds duration, const QDateTime &dateTime)
5021
5022 \since 6.4
5023
5024 Returns a QDateTime object containing a datetime \a duration milliseconds
5025 later than \a dateTime (or earlier if \a duration is negative).
5026
5027 If \a dateTime is invalid, an invalid datetime will be returned.
5028
5029 \sa addMSecs()
5030*/
5031
5032/*!
5033 \fn QDateTime &QDateTime::operator+=(std::chrono::milliseconds duration)
5034 \since 6.4
5035
5036 Modifies this datetime object by adding the given \a duration.
5037 The updated object will be later if \a duration is positive,
5038 or earlier if it is negative.
5039
5040 If this datetime is invalid, this function has no effect.
5041
5042 Returns a reference to this datetime object.
5043
5044 \sa addMSecs()
5045*/
5046
5047/*!
5048 \fn QDateTime QDateTime::operator-(const QDateTime &dateTime, std::chrono::milliseconds duration)
5049
5050 \since 6.4
5051
5052 Returns a QDateTime object containing a datetime \a duration milliseconds
5053 earlier than \a dateTime (or later if \a duration is negative).
5054
5055 If \a dateTime is invalid, an invalid datetime will be returned.
5056
5057 \sa addMSecs()
5058*/
5059
5060/*!
5061 \fn QDateTime &QDateTime::operator-=(std::chrono::milliseconds duration)
5062 \since 6.4
5063
5064 Modifies this datetime object by subtracting the given \a duration.
5065 The updated object will be earlier if \a duration is positive,
5066 or later if it is negative.
5067
5068 If this datetime is invalid, this function has no effect.
5069
5070 Returns a reference to this datetime object.
5071
5072 \sa addMSecs
5073*/
5074
5075#if QT_DEPRECATED_SINCE(6, 9)
5076/*!
5077 \deprecated [6.9] Use \l toTimeZone() instead.
5078
5079 Returns a copy of this datetime converted to the given time \a spec.
5080
5081 The result represents the same moment in time as, and is equal to, this datetime.
5082
5083 If \a spec is Qt::OffsetFromUTC then it is set to Qt::UTC. To set to a fixed
5084 offset from UTC, use toTimeZone() or toOffsetFromUtc().
5085
5086 If \a spec is Qt::TimeZone then it is set to Qt::LocalTime, i.e. the local
5087 Time Zone. To set a specified time-zone, use toTimeZone().
5088
5089 Example:
5090 \snippet code/src_corelib_time_qdatetime.cpp 16
5091
5092 \sa setTimeSpec(), timeSpec(), toTimeZone()
5093*/
5094
5095QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const
5096{
5097 return toTimeZone(toZone: asTimeZone(spec, offset: 0, warner: "toTimeSpec"));
5098}
5099#endif // 6.9 deprecation
5100
5101/*!
5102 \since 5.2
5103
5104 Returns a copy of this datetime converted to a spec of Qt::OffsetFromUTC
5105 with the given \a offsetSeconds. Equivalent to
5106 \c{toTimeZone(QTimeZone::fromSecondsAheadOfUtc(offsetSeconds))}.
5107
5108 If the \a offsetSeconds equals 0 then a UTC datetime will be returned.
5109
5110 The result represents the same moment in time as, and is equal to, this datetime.
5111
5112 \sa setOffsetFromUtc(), offsetFromUtc(), toTimeZone()
5113*/
5114
5115QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const
5116{
5117 return toTimeZone(toZone: QTimeZone::fromSecondsAheadOfUtc(offset: offsetSeconds));
5118}
5119
5120/*!
5121 Returns a copy of this datetime converted to local time.
5122
5123 The result represents the same moment in time as, and is equal to, this datetime.
5124
5125 Example:
5126
5127 \snippet code/src_corelib_time_qdatetime.cpp 17
5128
5129 \sa toTimeZone(), toUTC(), toOffsetFromUtc()
5130*/
5131QDateTime QDateTime::toLocalTime() const
5132{
5133 return toTimeZone(toZone: QTimeZone::LocalTime);
5134}
5135
5136/*!
5137 Returns a copy of this datetime converted to UTC.
5138
5139 The result represents the same moment in time as, and is equal to, this datetime.
5140
5141 Example:
5142
5143 \snippet code/src_corelib_time_qdatetime.cpp 18
5144
5145 \sa toTimeZone(), toLocalTime(), toOffsetFromUtc()
5146*/
5147QDateTime QDateTime::toUTC() const
5148{
5149 return toTimeZone(toZone: QTimeZone::UTC);
5150}
5151
5152/*!
5153 \since 5.2
5154
5155 Returns a copy of this datetime converted to the given \a timeZone.
5156
5157 The result represents the same moment in time as, and is equal to, this datetime.
5158
5159 The result describes the moment in time in terms of \a timeZone's time
5160 representation. For example:
5161
5162 \snippet code/src_corelib_time_qdatetime.cpp 23
5163
5164 If \a timeZone is invalid then the datetime will be invalid. Otherwise the
5165 returned datetime's timeSpec() will match \c{timeZone.timeSpec()}.
5166
5167 \sa timeRepresentation(), toLocalTime(), toUTC(), toOffsetFromUtc()
5168*/
5169
5170QDateTime QDateTime::toTimeZone(const QTimeZone &timeZone) const
5171{
5172 if (timeRepresentation() == timeZone)
5173 return *this;
5174
5175 if (!isValid()) {
5176 QDateTime ret = *this;
5177 ret.setTimeZone(toZone: timeZone);
5178 return ret;
5179 }
5180
5181 return fromMSecsSinceEpoch(msecs: toMSecsSinceEpoch(), timeZone);
5182}
5183
5184/*!
5185 \internal
5186 Returns \c true if this datetime is equal to the \a other datetime;
5187 otherwise returns \c false.
5188
5189 \sa precedes(), operator==()
5190*/
5191
5192bool QDateTime::equals(const QDateTime &other) const
5193{
5194 if (!isValid())
5195 return !other.isValid();
5196 if (!other.isValid())
5197 return false;
5198
5199 if (usesSameOffset(a: d, b: other.d))
5200 return getMSecs(d) == getMSecs(d: other.d);
5201
5202 // Convert to UTC and compare
5203 return toMSecsSinceEpoch() == other.toMSecsSinceEpoch();
5204}
5205
5206/*!
5207 \fn bool QDateTime::operator==(const QDateTime &lhs, const QDateTime &rhs)
5208
5209 Returns \c true if \a lhs represents the same moment in time as \a rhs;
5210 otherwise returns \c false.
5211
5212//! [datetime-order-details]
5213 Two datetimes using different time representations can have different
5214 offsets from UTC. In this case, they may compare equivalent even if their \l
5215 date() and \l time() differ, if that difference matches the difference in
5216 UTC offset. If their \c date() and \c time() coincide, the one with higher
5217 offset from UTC is less (earlier) than the one with lower offset. As a
5218 result, datetimes are only weakly ordered.
5219
5220 Since 5.14, all invalid datetimes are equivalent and less than all valid
5221 datetimes.
5222//! [datetime-order-details]
5223
5224 \sa operator!=(), operator<(), operator<=(), operator>(), operator>=()
5225*/
5226
5227/*!
5228 \fn bool QDateTime::operator!=(const QDateTime &lhs, const QDateTime &rhs)
5229
5230 Returns \c true if \a lhs is different from \a rhs; otherwise returns \c
5231 false.
5232
5233 \include qdatetime.cpp datetime-order-details
5234
5235 \sa operator==()
5236*/
5237
5238Qt::weak_ordering compareThreeWay(const QDateTime &lhs, const QDateTime &rhs)
5239{
5240 if (!lhs.isValid())
5241 return rhs.isValid() ? Qt::weak_ordering::less : Qt::weak_ordering::equivalent;
5242
5243 if (!rhs.isValid())
5244 return Qt::weak_ordering::greater; // we know that lhs is valid here
5245
5246 if (usesSameOffset(a: lhs.d, b: rhs.d))
5247 return Qt::compareThreeWay(lhs: getMSecs(d: lhs.d), rhs: getMSecs(d: rhs.d));
5248
5249 // Convert to UTC and compare
5250 return Qt::compareThreeWay(lhs: lhs.toMSecsSinceEpoch(), rhs: rhs.toMSecsSinceEpoch());
5251}
5252
5253/*!
5254 \fn bool QDateTime::operator<(const QDateTime &lhs, const QDateTime &rhs)
5255
5256 Returns \c true if \a lhs is earlier than \a rhs;
5257 otherwise returns \c false.
5258
5259 \include qdatetime.cpp datetime-order-details
5260
5261 \sa operator==()
5262*/
5263
5264/*!
5265 \fn bool QDateTime::operator<=(const QDateTime &lhs, const QDateTime &rhs)
5266
5267 Returns \c true if \a lhs is earlier than or equal to \a rhs; otherwise
5268 returns \c false.
5269
5270 \include qdatetime.cpp datetime-order-details
5271
5272 \sa operator==()
5273*/
5274
5275/*!
5276 \fn bool QDateTime::operator>(const QDateTime &lhs, const QDateTime &rhs)
5277
5278 Returns \c true if \a lhs is later than \a rhs; otherwise returns \c false.
5279
5280 \include qdatetime.cpp datetime-order-details
5281
5282 \sa operator==()
5283*/
5284
5285/*!
5286 \fn bool QDateTime::operator>=(const QDateTime &lhs, const QDateTime &rhs)
5287
5288 Returns \c true if \a lhs is later than or equal to \a rhs;
5289 otherwise returns \c false.
5290
5291 \include qdatetime.cpp datetime-order-details
5292
5293 \sa operator==()
5294*/
5295
5296/*!
5297 \since 6.5
5298 \fn QDateTime QDateTime::currentDateTime(const QTimeZone &zone)
5299
5300 Returns the system clock's current datetime, using the time representation
5301 described by \a zone. If \a zone is omitted, local time is used.
5302
5303 \sa currentDateTimeUtc(), QDate::currentDate(), QTime::currentTime(), toTimeSpec()
5304*/
5305
5306/*!
5307 \overload
5308 \since 0.90
5309*/
5310QDateTime QDateTime::currentDateTime()
5311{
5312 return currentDateTime(zone: QTimeZone::LocalTime);
5313}
5314
5315/*!
5316 \fn QDateTime QDateTime::currentDateTimeUtc()
5317 \since 4.7
5318 Returns the system clock's current datetime, expressed in terms of UTC.
5319
5320 Equivalent to \c{currentDateTime(QTimeZone::UTC)}.
5321
5322 \sa currentDateTime(), QDate::currentDate(), QTime::currentTime(), toTimeSpec()
5323*/
5324
5325QDateTime QDateTime::currentDateTimeUtc()
5326{
5327 return currentDateTime(zone: QTimeZone::UTC);
5328}
5329
5330/*!
5331 \fn qint64 QDateTime::currentMSecsSinceEpoch()
5332 \since 4.7
5333
5334 Returns the current number of milliseconds since the start, in UTC, of the year 1970.
5335
5336 This number is like the POSIX time_t variable, but expressed in milliseconds
5337 instead of seconds.
5338
5339 \sa currentDateTime(), currentDateTimeUtc(), toTimeSpec()
5340*/
5341
5342/*!
5343 \fn qint64 QDateTime::currentSecsSinceEpoch()
5344 \since 5.8
5345
5346 Returns the number of seconds since the start, in UTC, of the year 1970.
5347
5348 This number is like the POSIX time_t variable.
5349
5350 \sa currentMSecsSinceEpoch()
5351*/
5352
5353/*!
5354 \fn template <typename Clock, typename Duration> QDateTime QDateTime::fromStdTimePoint(const std::chrono::time_point<Clock, Duration> &time)
5355 \since 6.4
5356
5357 Constructs a datetime representing the same point in time as \a time,
5358 using Qt::UTC as its time representation.
5359
5360 The clock of \a time must be compatible with
5361 \c{std::chrono::system_clock}; in particular, a conversion
5362 supported by \c{std::chrono::clock_cast} must exist. After the
5363 conversion, the duration type of the result must be convertible to
5364 \c{std::chrono::milliseconds}.
5365
5366 If this is not the case, the caller must perform the necessary
5367 clock conversion towards \c{std::chrono::system_clock} and the
5368 necessary conversion of the duration type
5369 (cast/round/floor/ceil/...) so that the input to this function
5370 satisfies the constraints above.
5371
5372 \note This function requires C++20.
5373
5374 \sa toStdSysMilliseconds(), fromMSecsSinceEpoch()
5375*/
5376
5377/*!
5378 \since 6.4
5379 \overload
5380
5381 Constructs a datetime representing the same point in time as \a time,
5382 using Qt::UTC as its time representation.
5383*/
5384QDateTime QDateTime::fromStdTimePoint(
5385 std::chrono::time_point<
5386 std::chrono::system_clock,
5387 std::chrono::milliseconds
5388 > time)
5389{
5390 return fromMSecsSinceEpoch(msecs: time.time_since_epoch().count(), timeZone: QTimeZone::UTC);
5391}
5392
5393/*!
5394 \fn QDateTime QDateTime::fromStdTimePoint(const std::chrono::local_time<std::chrono::milliseconds> &time)
5395 \since 6.4
5396
5397 Constructs a datetime whose date and time are the number of milliseconds
5398 represented by \a time, counted since 1970-01-01T00:00:00.000 in local
5399 time (Qt::LocalTime).
5400
5401 \note This function requires C++20.
5402
5403 \sa toStdSysMilliseconds(), fromMSecsSinceEpoch()
5404*/
5405
5406/*!
5407 \fn QDateTime QDateTime::fromStdLocalTime(const std::chrono::local_time<std::chrono::milliseconds> &time)
5408 \since 6.4
5409
5410 Constructs a datetime whose date and time are the number of milliseconds
5411 represented by \a time, counted since 1970-01-01T00:00:00.000 in local
5412 time (Qt::LocalTime).
5413
5414 \note This function requires C++20.
5415
5416 \sa toStdSysMilliseconds(), fromMSecsSinceEpoch()
5417*/
5418
5419/*!
5420 \fn QDateTime QDateTime::fromStdZonedTime(const std::chrono::zoned_time<std::chrono::milliseconds, const std::chrono::time_zone *> &time);
5421 \since 6.4
5422
5423 Constructs a datetime representing the same point in time as \a time.
5424 The result will be expressed in \a{time}'s time zone.
5425
5426 \note This function requires C++20.
5427
5428 \sa QTimeZone
5429
5430 \sa toStdSysMilliseconds(), fromMSecsSinceEpoch()
5431*/
5432
5433/*!
5434 \fn std::chrono::sys_time<std::chrono::milliseconds> QDateTime::toStdSysMilliseconds() const
5435 \since 6.4
5436
5437 Converts this datetime object to the equivalent time point expressed in
5438 milliseconds, using \c{std::chrono::system_clock} as a clock.
5439
5440 \note This function requires C++20.
5441
5442 \sa fromStdTimePoint(), toMSecsSinceEpoch()
5443*/
5444
5445/*!
5446 \fn std::chrono::sys_seconds QDateTime::toStdSysSeconds() const
5447 \since 6.4
5448
5449 Converts this datetime object to the equivalent time point expressed in
5450 seconds, using \c{std::chrono::system_clock} as a clock.
5451
5452 \note This function requires C++20.
5453
5454 \sa fromStdTimePoint(), toSecsSinceEpoch()
5455*/
5456
5457#if defined(Q_OS_WIN)
5458static inline uint msecsFromDecomposed(int hour, int minute, int sec, int msec = 0)
5459{
5460 return MSECS_PER_HOUR * hour + MSECS_PER_MIN * minute + MSECS_PER_SEC * sec + msec;
5461}
5462
5463QDate QDate::currentDate()
5464{
5465 SYSTEMTIME st = {};
5466 GetLocalTime(&st);
5467 return QDate(st.wYear, st.wMonth, st.wDay);
5468}
5469
5470QTime QTime::currentTime()
5471{
5472 QTime ct;
5473 SYSTEMTIME st = {};
5474 GetLocalTime(&st);
5475 ct.setHMS(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
5476 return ct;
5477}
5478
5479QDateTime QDateTime::currentDateTime(const QTimeZone &zone)
5480{
5481 // We can get local time or "system" time (which is UTC); otherwise, we must
5482 // convert, which is most efficiently done from UTC.
5483 const Qt::TimeSpec spec = zone.timeSpec();
5484 SYSTEMTIME st = {};
5485 // GetSystemTime()'s page links to its partner page for GetLocalTime().
5486 // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtime
5487 (spec == Qt::LocalTime ? GetLocalTime : GetSystemTime)(&st);
5488 QDate d(st.wYear, st.wMonth, st.wDay);
5489 QTime t(msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds));
5490 if (spec == Qt::LocalTime)
5491 return QDateTime(d, t);
5492 QDateTime utc(d, t, QTimeZone::UTC);
5493 return spec == Qt::UTC ? utc : utc.toTimeZone(zone);
5494}
5495
5496qint64 QDateTime::currentMSecsSinceEpoch() noexcept
5497{
5498 SYSTEMTIME st = {};
5499 GetSystemTime(&st);
5500 const qint64 daysAfterEpoch = QDate(1970, 1, 1).daysTo(QDate(st.wYear, st.wMonth, st.wDay));
5501
5502 return msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds) +
5503 daysAfterEpoch * MSECS_PER_DAY;
5504}
5505
5506qint64 QDateTime::currentSecsSinceEpoch() noexcept
5507{
5508 SYSTEMTIME st = {};
5509 GetSystemTime(&st);
5510 const qint64 daysAfterEpoch = QDate(1970, 1, 1).daysTo(QDate(st.wYear, st.wMonth, st.wDay));
5511
5512 return st.wHour * SECS_PER_HOUR + st.wMinute * SECS_PER_MIN + st.wSecond +
5513 daysAfterEpoch * SECS_PER_DAY;
5514}
5515
5516#elif defined(Q_OS_UNIX) // Assume POSIX-compliant
5517QDate QDate::currentDate()
5518{
5519 return QDateTime::currentDateTime().date();
5520}
5521
5522QTime QTime::currentTime()
5523{
5524 return QDateTime::currentDateTime().time();
5525}
5526
5527QDateTime QDateTime::currentDateTime(const QTimeZone &zone)
5528{
5529 return fromMSecsSinceEpoch(msecs: currentMSecsSinceEpoch(), timeZone: zone);
5530}
5531
5532qint64 QDateTime::currentMSecsSinceEpoch() noexcept
5533{
5534 struct timespec when;
5535 if (clock_gettime(CLOCK_REALTIME, tp: &when) == 0) // should always succeed
5536 return when.tv_sec * MSECS_PER_SEC + (when.tv_nsec + 500'000) / 1'000'000;
5537 Q_UNREACHABLE_RETURN(0);
5538}
5539
5540qint64 QDateTime::currentSecsSinceEpoch() noexcept
5541{
5542 struct timespec when;
5543 if (clock_gettime(CLOCK_REALTIME, tp: &when) == 0) // should always succeed
5544 return when.tv_sec;
5545 Q_UNREACHABLE_RETURN(0);
5546}
5547#else
5548#error "What system is this?"
5549#endif
5550
5551#if QT_DEPRECATED_SINCE(6, 9)
5552/*!
5553 \since 5.2
5554 \overload
5555 \deprecated [6.9] Pass a \l QTimeZone instead, or omit \a spec and \a offsetSeconds.
5556
5557 Returns a datetime representing a moment the given number \a msecs of
5558 milliseconds after the start, in UTC, of the year 1970, described as
5559 specified by \a spec and \a offsetSeconds.
5560
5561 Note that there are possible values for \a msecs that lie outside the valid
5562 range of QDateTime, both negative and positive. The behavior of this
5563 function is undefined for those values.
5564
5565 If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be
5566 ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0
5567 then Qt::UTC will be used as the \a spec, since UTC has zero offset.
5568
5569 If \a spec is Qt::TimeZone then Qt::LocalTime will be used in its place,
5570 equivalent to using the current system time zone (but differently
5571 represented).
5572
5573 \sa fromSecsSinceEpoch(), toMSecsSinceEpoch(), setMSecsSinceEpoch()
5574*/
5575QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int offsetSeconds)
5576{
5577 return fromMSecsSinceEpoch(msecs,
5578 timeZone: asTimeZone(spec, offset: offsetSeconds, warner: "QDateTime::fromMSecsSinceEpoch"));
5579}
5580
5581/*!
5582 \since 5.8
5583 \overload
5584 \deprecated [6.9] Pass a \l QTimeZone instead, or omit \a spec and \a offsetSeconds.
5585
5586 Returns a datetime representing a moment the given number \a secs of seconds
5587 after the start, in UTC, of the year 1970, described as specified by \a spec
5588 and \a offsetSeconds.
5589
5590 Note that there are possible values for \a secs that lie outside the valid
5591 range of QDateTime, both negative and positive. The behavior of this
5592 function is undefined for those values.
5593
5594 If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be
5595 ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0
5596 then Qt::UTC will be used as the \a spec, since UTC has zero offset.
5597
5598 If \a spec is Qt::TimeZone then Qt::LocalTime will be used in its place,
5599 equivalent to using the current system time zone (but differently
5600 represented).
5601
5602 \sa fromMSecsSinceEpoch(), toSecsSinceEpoch(), setSecsSinceEpoch()
5603*/
5604QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec, int offsetSeconds)
5605{
5606 return fromSecsSinceEpoch(secs,
5607 timeZone: asTimeZone(spec, offset: offsetSeconds, warner: "QDateTime::fromSecsSinceEpoch"));
5608}
5609#endif // 6.9 deprecations
5610
5611/*!
5612 \since 5.2
5613
5614 Returns a datetime representing a moment the given number \a msecs of
5615 milliseconds after the start, in UTC, of the year 1970, described as
5616 specified by \a timeZone. The default time representation is local time.
5617
5618 Note that there are possible values for \a msecs that lie outside the valid
5619 range of QDateTime, both negative and positive. The behavior of this
5620 function is undefined for those values.
5621
5622 \sa fromSecsSinceEpoch(), toMSecsSinceEpoch(), setMSecsSinceEpoch()
5623*/
5624QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone)
5625{
5626 QDateTime dt;
5627 reviseTimeZone(d&: dt.d, zone: timeZone, resolve: TransitionResolution::Reject);
5628 if (timeZone.isValid())
5629 dt.setMSecsSinceEpoch(msecs);
5630 return dt;
5631}
5632
5633/*!
5634 \overload
5635*/
5636QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs)
5637{
5638 return fromMSecsSinceEpoch(msecs, timeZone: QTimeZone::LocalTime);
5639}
5640
5641/*!
5642 \since 5.8
5643
5644 Returns a datetime representing a moment the given number \a secs of seconds
5645 after the start, in UTC, of the year 1970, described as specified by \a
5646 timeZone. The default time representation is local time.
5647
5648 Note that there are possible values for \a secs that lie outside the valid
5649 range of QDateTime, both negative and positive. The behavior of this
5650 function is undefined for those values.
5651
5652 \sa fromMSecsSinceEpoch(), toSecsSinceEpoch(), setSecsSinceEpoch()
5653*/
5654QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, const QTimeZone &timeZone)
5655{
5656 QDateTime dt;
5657 reviseTimeZone(d&: dt.d, zone: timeZone, resolve: TransitionResolution::Reject);
5658 if (timeZone.isValid())
5659 dt.setSecsSinceEpoch(secs);
5660 return dt;
5661}
5662
5663/*!
5664 \overload
5665*/
5666QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs)
5667{
5668 return fromSecsSinceEpoch(secs, timeZone: QTimeZone::LocalTime);
5669}
5670
5671#if QT_CONFIG(datestring) // depends on, so implies, textdate
5672
5673/*!
5674 \fn QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format)
5675
5676 Returns the QDateTime represented by the \a string, using the
5677 \a format given, or an invalid datetime if this is not possible.
5678
5679 Note for Qt::TextDate: only English short month names (e.g. "Jan" in short
5680 form or "January" in long form) are recognized.
5681
5682 \sa toString(), QLocale::toDateTime()
5683*/
5684
5685/*!
5686 \overload
5687 \since 6.0
5688*/
5689QDateTime QDateTime::fromString(QStringView string, Qt::DateFormat format)
5690{
5691 if (string.isEmpty())
5692 return QDateTime();
5693
5694 switch (format) {
5695 case Qt::RFC2822Date: {
5696 const ParsedRfcDateTime rfc = rfcDateImpl(s: string);
5697
5698 if (!rfc.date.isValid() || !rfc.time.isValid())
5699 return QDateTime();
5700
5701 QDateTime dateTime(rfc.date, rfc.time, QTimeZone::UTC);
5702 dateTime.setTimeZone(toZone: QTimeZone::fromSecondsAheadOfUtc(offset: rfc.utcOffset));
5703 return dateTime;
5704 }
5705 case Qt::ISODate:
5706 case Qt::ISODateWithMs: {
5707 const int size = string.size();
5708 if (size < 10)
5709 return QDateTime();
5710
5711 QDate date = QDate::fromString(string: string.first(n: 10), format: Qt::ISODate);
5712 if (!date.isValid())
5713 return QDateTime();
5714 if (size == 10)
5715 return date.startOfDay();
5716
5717 QTimeZone zone = QTimeZone::LocalTime;
5718 QStringView isoString = string.sliced(pos: 10); // trim "yyyy-MM-dd"
5719
5720 // Must be left with T (or space) and at least one digit for the hour:
5721 if (isoString.size() < 2
5722 || !(isoString.startsWith(c: u'T', cs: Qt::CaseInsensitive)
5723 // RFC 3339 (section 5.6) allows a space here. (It actually
5724 // allows any separator one considers more readable, merely
5725 // giving space as an example - but let's not go wild !)
5726 || isoString.startsWith(c: u' '))) {
5727 return QDateTime();
5728 }
5729 isoString = isoString.sliced(pos: 1); // trim 'T' (or space)
5730
5731 // Check end of string for Time Zone definition, either Z for UTC or ±HH:mm for Offset
5732 if (isoString.endsWith(c: u'Z', cs: Qt::CaseInsensitive)) {
5733 zone = QTimeZone::UTC;
5734 isoString.chop(n: 1); // trim 'Z'
5735 } else {
5736 // the loop below is faster but functionally equal to:
5737 // const int signIndex = isoString.indexOf(QRegulargExpression(QStringLiteral("[+-]")));
5738 int signIndex = isoString.size() - 1;
5739 Q_ASSERT(signIndex >= 0);
5740 bool found = false;
5741 do {
5742 QChar character(isoString[signIndex]);
5743 found = character == u'+' || character == u'-';
5744 } while (!found && --signIndex >= 0);
5745
5746 if (found) {
5747 bool ok;
5748 int offset = fromOffsetString(offsetString: isoString.sliced(pos: signIndex), valid: &ok);
5749 if (!ok)
5750 return QDateTime();
5751 isoString = isoString.first(n: signIndex);
5752 zone = QTimeZone::fromSecondsAheadOfUtc(offset);
5753 }
5754 }
5755
5756 // Might be end of day (24:00, including variants), which QTime considers invalid.
5757 // ISO 8601 (section 4.2.3) says that 24:00 is equivalent to 00:00 the next day.
5758 bool isMidnight24 = false;
5759 QTime time = fromIsoTimeString(string: isoString, format, isMidnight24: &isMidnight24);
5760 if (!time.isValid())
5761 return QDateTime();
5762 if (isMidnight24) // time is 0:0, but we want the start of next day:
5763 return date.addDays(ndays: 1).startOfDay(zone);
5764 return QDateTime(date, time, zone);
5765 }
5766 case Qt::TextDate: {
5767 QVarLengthArray<QStringView, 6> parts;
5768
5769 auto tokens = string.tokenize(needle: u' ', flags: Qt::SkipEmptyParts);
5770 auto it = tokens.begin();
5771 for (int i = 0; i < 6 && it != tokens.end(); ++i, ++it)
5772 parts.emplace_back(args: *it);
5773
5774 // Documented as "ddd MMM d HH:mm:ss yyyy" with optional offset-suffix;
5775 // and allow time either before or after year.
5776 if (parts.size() < 5 || it != tokens.end())
5777 return QDateTime();
5778
5779 // Year and time can be in either order.
5780 // Guess which by looking for ':' in the time
5781 int yearPart = 3;
5782 int timePart = 3;
5783 if (parts.at(idx: 3).contains(c: u':'))
5784 yearPart = 4;
5785 else if (parts.at(idx: 4).contains(c: u':'))
5786 timePart = 4;
5787 else
5788 return QDateTime();
5789
5790 bool ok = false;
5791 int day = parts.at(idx: 2).toInt(ok: &ok);
5792 int year = ok ? parts.at(idx: yearPart).toInt(ok: &ok) : 0;
5793 int month = fromShortMonthName(monthName: parts.at(idx: 1));
5794 if (!ok || year == 0 || day == 0 || month < 1)
5795 return QDateTime();
5796
5797 const QDate date(year, month, day);
5798 if (!date.isValid())
5799 return QDateTime();
5800
5801 const QTime time = fromIsoTimeString(string: parts.at(idx: timePart), format, isMidnight24: nullptr);
5802 if (!time.isValid())
5803 return QDateTime();
5804
5805 if (parts.size() == 5)
5806 return QDateTime(date, time);
5807
5808 QStringView tz = parts.at(idx: 5);
5809 if (tz.startsWith(s: "UTC"_L1)
5810 // GMT has long been deprecated as an alias for UTC.
5811 || tz.startsWith(s: "GMT"_L1, cs: Qt::CaseInsensitive)) {
5812 tz = tz.sliced(pos: 3);
5813 if (tz.isEmpty())
5814 return QDateTime(date, time, QTimeZone::UTC);
5815
5816 int offset = fromOffsetString(offsetString: tz, valid: &ok);
5817 return ok ? QDateTime(date, time, QTimeZone::fromSecondsAheadOfUtc(offset))
5818 : QDateTime();
5819 }
5820 return QDateTime();
5821 }
5822 }
5823
5824 return QDateTime();
5825}
5826
5827/*!
5828 \fn QDateTime QDateTime::fromString(const QString &string, const QString &format, int baseYear, QCalendar cal)
5829
5830 Returns the QDateTime represented by the \a string, using the \a
5831 format given, or an invalid datetime if the string cannot be parsed.
5832
5833 Uses the calendar \a cal if supplied, else Gregorian.
5834
5835 \include qlocale.cpp base-year-for-two-digit
5836
5837 In addition to the expressions, recognized in the format string to represent
5838 parts of the date and time, by QDate::fromString() and QTime::fromString(),
5839 this method supports:
5840
5841 \table
5842 \header \li Expression \li Output
5843 \row \li t
5844 \li the timezone (offset, name, "Z" or offset with "UTC" prefix)
5845 \row \li tt
5846 \li the timezone in offset format with no colon between hours and
5847 minutes (for example "+0200")
5848 \row \li ttt
5849 \li the timezone in offset format with a colon between hours and
5850 minutes (for example "+02:00")
5851 \row \li tttt
5852 \li the timezone name (for example "Europe/Berlin"). The name
5853 recognized are those known to \l QTimeZone, which may depend on the
5854 operating system in use.
5855 \endtable
5856
5857 If no 't' format specifier is present, the system's local time-zone is used.
5858 For the defaults of all other fields, see QDate::fromString() and QTime::fromString().
5859
5860 For example:
5861
5862 \snippet code/src_corelib_time_qdatetime.cpp 14
5863
5864 All other input characters will be treated as text. Any non-empty sequence
5865 of characters enclosed in single quotes will also be treated (stripped of
5866 the quotes) as text and not be interpreted as expressions.
5867
5868 \snippet code/src_corelib_time_qdatetime.cpp 12
5869
5870 If the format is not satisfied, an invalid QDateTime is returned. If the
5871 format is satisfied but \a string represents an invalid datetime (e.g. in a
5872 gap skipped by a time-zone transition), an valid QDateTime is returned, that
5873 represents a near-by datetime that is valid.
5874
5875 The expressions that don't have leading zeroes (d, M, h, m, s, z) will be
5876 greedy. This means that they will use two digits (or three, for z) even if this will
5877 put them outside the range and/or leave too few digits for other
5878 sections.
5879
5880 \snippet code/src_corelib_time_qdatetime.cpp 13
5881
5882 This could have meant 1 January 00:30.00 but the M will grab
5883 two digits.
5884
5885 Incorrectly specified fields of the \a string will cause an invalid
5886 QDateTime to be returned. Only datetimes between the local time start of
5887 year 100 and end of year 9999 are supported. Note that datetimes near the
5888 ends of this range in other time-zones, notably including UTC, may fall
5889 outside the range (and thus be treated as invalid) depending on local time
5890 zone.
5891
5892 \note Day and month names as well as AM/PM indicators must be given in
5893 English (C locale). If localized month and day names or localized forms of
5894 AM/PM are to be recognized, use QLocale::system().toDateTime().
5895
5896 \note If a format character is repeated more times than the longest
5897 expression in the table above using it, this part of the format will be read
5898 as several expressions with no separator between them; the longest above,
5899 possibly repeated as many times as there are copies of it, ending with a
5900 residue that may be a shorter expression. Thus \c{'tttttt'} would match
5901 \c{"Europe/BerlinEurope/Berlin"} and set the zone to Berlin time; if the
5902 datetime string contained "Europe/BerlinZ" it would "match" but produce an
5903 inconsistent result, leading to an invalid datetime.
5904
5905 \sa toString(), QDate::fromString(), QTime::fromString(),
5906 QLocale::toDateTime()
5907*/
5908
5909/*!
5910 \fn QDateTime QDateTime::fromString(QStringView string, QStringView format, QCalendar cal)
5911 \overload
5912 \since 6.0
5913*/
5914
5915/*!
5916 \overload
5917 \since 6.0
5918*/
5919QDateTime QDateTime::fromString(const QString &string, QStringView format, int baseYear,
5920 QCalendar cal)
5921{
5922#if QT_CONFIG(datetimeparser)
5923 QDateTime datetime;
5924
5925 QDateTimeParser dt(QMetaType::QDateTime, QDateTimeParser::FromString, cal);
5926 dt.setDefaultLocale(QLocale::c());
5927 if (dt.parseFormat(format) && (dt.fromString(text: string, datetime: &datetime, baseYear)
5928 || !datetime.isValid())) {
5929 return datetime;
5930 }
5931#else
5932 Q_UNUSED(string);
5933 Q_UNUSED(format);
5934 Q_UNUSED(baseYear);
5935 Q_UNUSED(cal);
5936#endif
5937 return QDateTime();
5938}
5939
5940/*!
5941 \fn QDateTime QDateTime::fromString(const QString &string, const QString &format, QCalendar cal)
5942 \overload
5943 \since 5.14
5944*/
5945
5946/*!
5947 \fn QDateTime QDateTime::fromString(const QString &string, QStringView format, QCalendar cal)
5948 \overload
5949 \since 6.0
5950*/
5951
5952/*!
5953 \fn QDateTime QDateTime::fromString(QStringView string, QStringView format, int baseYear, QCalendar cal)
5954 \overload
5955 \since 6.7
5956*/
5957
5958/*!
5959 \fn QDateTime QDateTime::fromString(QStringView string, QStringView format, int baseYear)
5960 \overload
5961 \since 6.7
5962
5963 Uses a default-constructed QCalendar.
5964*/
5965
5966/*!
5967 \overload
5968 \since 6.7
5969
5970 Uses a default-constructed QCalendar.
5971*/
5972QDateTime QDateTime::fromString(const QString &string, QStringView format, int baseYear)
5973{
5974 return fromString(string, format, baseYear, cal: QCalendar());
5975}
5976
5977/*!
5978 \fn QDateTime QDateTime::fromString(const QString &string, const QString &format, int baseYear)
5979 \overload
5980 \since 6.7
5981
5982 Uses a default-constructed QCalendar.
5983*/
5984#endif // datestring
5985
5986/*****************************************************************************
5987 Date/time stream functions
5988 *****************************************************************************/
5989
5990#ifndef QT_NO_DATASTREAM
5991/*!
5992 \relates QDate
5993
5994 Writes the \a date to stream \a out.
5995
5996 \sa {Serializing Qt Data Types}
5997*/
5998
5999QDataStream &operator<<(QDataStream &out, QDate date)
6000{
6001 if (out.version() < QDataStream::Qt_5_0)
6002 return out << quint32(date.jd);
6003 else
6004 return out << date.jd;
6005}
6006
6007/*!
6008 \relates QDate
6009
6010 Reads a date from stream \a in into the \a date.
6011
6012 \sa {Serializing Qt Data Types}
6013*/
6014
6015QDataStream &operator>>(QDataStream &in, QDate &date)
6016{
6017 if (in.version() < QDataStream::Qt_5_0) {
6018 quint32 jd;
6019 in >> jd;
6020 // Older versions consider 0 an invalid jd.
6021 date.jd = (jd != 0 ? jd : QDate::nullJd());
6022 } else {
6023 in >> date.jd;
6024 }
6025
6026 return in;
6027}
6028
6029/*!
6030 \relates QTime
6031
6032 Writes \a time to stream \a out.
6033
6034 \sa {Serializing Qt Data Types}
6035*/
6036
6037QDataStream &operator<<(QDataStream &out, QTime time)
6038{
6039 if (out.version() >= QDataStream::Qt_4_0) {
6040 return out << quint32(time.mds);
6041 } else {
6042 // Qt3 had no support for reading -1, QTime() was valid and serialized as 0
6043 return out << quint32(time.isNull() ? 0 : time.mds);
6044 }
6045}
6046
6047/*!
6048 \relates QTime
6049
6050 Reads a time from stream \a in into the given \a time.
6051
6052 \sa {Serializing Qt Data Types}
6053*/
6054
6055QDataStream &operator>>(QDataStream &in, QTime &time)
6056{
6057 quint32 ds;
6058 in >> ds;
6059 if (in.version() >= QDataStream::Qt_4_0) {
6060 time.mds = int(ds);
6061 } else {
6062 // Qt3 would write 0 for a null time
6063 time.mds = (ds == 0) ? QTime::NullTime : int(ds);
6064 }
6065 return in;
6066}
6067
6068/*!
6069 \relates QDateTime
6070
6071 Writes \a dateTime to the \a out stream.
6072
6073 \sa {Serializing Qt Data Types}
6074*/
6075QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime)
6076{
6077 std::pair<QDate, QTime> dateAndTime;
6078
6079 // TODO: new version, route spec and details via QTimeZone
6080 if (out.version() >= QDataStream::Qt_5_2) {
6081
6082 // In 5.2 we switched to using Qt::TimeSpec and added offset and zone support
6083 dateAndTime = getDateTime(d: dateTime.d);
6084 out << dateAndTime << qint8(dateTime.timeSpec());
6085 if (dateTime.timeSpec() == Qt::OffsetFromUTC)
6086 out << qint32(dateTime.offsetFromUtc());
6087#if QT_CONFIG(timezone)
6088 else if (dateTime.timeSpec() == Qt::TimeZone)
6089 out << dateTime.timeZone();
6090#endif // timezone
6091
6092 } else if (out.version() == QDataStream::Qt_5_0) {
6093
6094 // In Qt 5.0 we incorrectly serialised all datetimes as UTC.
6095 // This approach is wrong and should not be used again; it breaks
6096 // the guarantee that a deserialised local datetime is the same time
6097 // of day, regardless of which timezone it was serialised in.
6098 dateAndTime = getDateTime(d: (dateTime.isValid() ? dateTime.toUTC() : dateTime).d);
6099 out << dateAndTime << qint8(dateTime.timeSpec());
6100
6101 } else if (out.version() >= QDataStream::Qt_4_0) {
6102
6103 // From 4.0 to 5.1 (except 5.0) we used QDateTimePrivate::Spec
6104 dateAndTime = getDateTime(d: dateTime.d);
6105 out << dateAndTime;
6106 switch (dateTime.timeSpec()) {
6107 case Qt::UTC:
6108 out << (qint8)QDateTimePrivate::UTC;
6109 break;
6110 case Qt::OffsetFromUTC:
6111 out << (qint8)QDateTimePrivate::OffsetFromUTC;
6112 break;
6113 case Qt::TimeZone:
6114 out << (qint8)QDateTimePrivate::TimeZone;
6115 break;
6116 case Qt::LocalTime:
6117 out << (qint8)QDateTimePrivate::LocalUnknown;
6118 break;
6119 }
6120
6121 } else { // version < QDataStream::Qt_4_0
6122
6123 // Before 4.0 there was no TimeSpec, only Qt::LocalTime was supported
6124 dateAndTime = getDateTime(d: dateTime.d);
6125 out << dateAndTime;
6126
6127 }
6128
6129 return out;
6130}
6131
6132/*!
6133 \relates QDateTime
6134
6135 Reads a datetime from the stream \a in into \a dateTime.
6136
6137 \sa {Serializing Qt Data Types}
6138*/
6139
6140QDataStream &operator>>(QDataStream &in, QDateTime &dateTime)
6141{
6142 QDate dt;
6143 QTime tm;
6144 qint8 ts = 0;
6145 QTimeZone zone(QTimeZone::LocalTime);
6146
6147 if (in.version() >= QDataStream::Qt_5_2) {
6148
6149 // In 5.2 we switched to using Qt::TimeSpec and added offset and zone support
6150 in >> dt >> tm >> ts;
6151 switch (static_cast<Qt::TimeSpec>(ts)) {
6152 case Qt::UTC:
6153 zone = QTimeZone::UTC;
6154 break;
6155 case Qt::OffsetFromUTC: {
6156 qint32 offset = 0;
6157 in >> offset;
6158 zone = QTimeZone::fromSecondsAheadOfUtc(offset);
6159 break;
6160 }
6161 case Qt::LocalTime:
6162 break;
6163 case Qt::TimeZone:
6164 in >> zone;
6165 break;
6166 }
6167 // Note: no way to resolve transition ambiguity, when relevant; use default.
6168 dateTime = QDateTime(dt, tm, zone);
6169
6170 } else if (in.version() == QDataStream::Qt_5_0) {
6171
6172 // In Qt 5.0 we incorrectly serialised all datetimes as UTC
6173 in >> dt >> tm >> ts;
6174 dateTime = QDateTime(dt, tm, QTimeZone::UTC);
6175 if (static_cast<Qt::TimeSpec>(ts) == Qt::LocalTime)
6176 dateTime = dateTime.toTimeZone(timeZone: zone);
6177
6178 } else if (in.version() >= QDataStream::Qt_4_0) {
6179
6180 // From 4.0 to 5.1 (except 5.0) we used QDateTimePrivate::Spec
6181 in >> dt >> tm >> ts;
6182 switch (static_cast<QDateTimePrivate::Spec>(ts)) {
6183 case QDateTimePrivate::OffsetFromUTC: // No offset was stored, so treat as UTC.
6184 case QDateTimePrivate::UTC:
6185 zone = QTimeZone::UTC;
6186 break;
6187 case QDateTimePrivate::TimeZone: // No zone was stored, so treat as LocalTime:
6188 case QDateTimePrivate::LocalUnknown:
6189 case QDateTimePrivate::LocalStandard:
6190 case QDateTimePrivate::LocalDST:
6191 break;
6192 }
6193 dateTime = QDateTime(dt, tm, zone);
6194
6195 } else { // version < QDataStream::Qt_4_0
6196
6197 // Before 4.0 there was no TimeSpec, only Qt::LocalTime was supported
6198 in >> dt >> tm;
6199 dateTime = QDateTime(dt, tm);
6200
6201 }
6202
6203 return in;
6204}
6205#endif // QT_NO_DATASTREAM
6206
6207/*****************************************************************************
6208 Date / Time Debug Streams
6209*****************************************************************************/
6210
6211#if !defined(QT_NO_DEBUG_STREAM) && QT_CONFIG(datestring)
6212QDebug operator<<(QDebug dbg, QDate date)
6213{
6214 QDebugStateSaver saver(dbg);
6215 dbg.nospace() << "QDate(";
6216 if (date.isValid())
6217 // QTBUG-91070, ISODate only supports years in the range 0-9999
6218 if (int y = date.year(); y > 0 && y <= 9999)
6219 dbg.nospace() << date.toString(format: Qt::ISODate);
6220 else
6221 dbg.nospace() << date.toString(format: Qt::TextDate);
6222 else
6223 dbg.nospace() << "Invalid";
6224 dbg.nospace() << ')';
6225 return dbg;
6226}
6227
6228QDebug operator<<(QDebug dbg, QTime time)
6229{
6230 QDebugStateSaver saver(dbg);
6231 dbg.nospace() << "QTime(";
6232 if (time.isValid())
6233 dbg.nospace() << time.toString(format: u"HH:mm:ss.zzz");
6234 else
6235 dbg.nospace() << "Invalid";
6236 dbg.nospace() << ')';
6237 return dbg;
6238}
6239
6240QDebug operator<<(QDebug dbg, const QDateTime &date)
6241{
6242 QDebugStateSaver saver(dbg);
6243 dbg.nospace() << "QDateTime(";
6244 if (date.isValid()) {
6245 const Qt::TimeSpec ts = date.timeSpec();
6246 dbg.noquote() << date.toString(format: u"yyyy-MM-dd HH:mm:ss.zzz t")
6247 << ' ' << ts;
6248 switch (ts) {
6249 case Qt::UTC:
6250 break;
6251 case Qt::OffsetFromUTC:
6252 dbg.space() << date.offsetFromUtc() << 's';
6253 break;
6254 case Qt::TimeZone:
6255#if QT_CONFIG(timezone)
6256 dbg.space() << date.timeZone().id();
6257#endif // timezone
6258 break;
6259 case Qt::LocalTime:
6260 break;
6261 }
6262 } else {
6263 dbg.nospace() << "Invalid";
6264 }
6265 return dbg.nospace() << ')';
6266}
6267#endif // debug_stream && datestring
6268
6269/*! \fn size_t qHash(const QDateTime &key, size_t seed = 0)
6270 \relates QHash
6271 \since 5.0
6272
6273 Returns the hash value for the \a key, using \a seed to seed the calculation.
6274*/
6275size_t qHash(const QDateTime &key, size_t seed)
6276{
6277 // Use to toMSecsSinceEpoch instead of individual qHash functions for
6278 // QDate/QTime/spec/offset because QDateTime::operator== converts both arguments
6279 // to the same timezone. If we don't, qHash would return different hashes for
6280 // two QDateTimes that are equivalent once converted to the same timezone.
6281 return key.isValid() ? qHash(key: key.toMSecsSinceEpoch(), seed) : seed;
6282}
6283
6284/*! \fn size_t qHash(QDate key, size_t seed = 0)
6285 \relates QHash
6286 \since 5.0
6287
6288 Returns the hash value for the \a key, using \a seed to seed the calculation.
6289*/
6290size_t qHash(QDate key, size_t seed) noexcept
6291{
6292 return qHash(key: key.toJulianDay(), seed);
6293}
6294
6295/*! \fn size_t qHash(QTime key, size_t seed = 0)
6296 \relates QHash
6297 \since 5.0
6298
6299 Returns the hash value for the \a key, using \a seed to seed the calculation.
6300*/
6301size_t qHash(QTime key, size_t seed) noexcept
6302{
6303 return qHash(key: key.msecsSinceStartOfDay(), seed);
6304}
6305
6306QT_END_NAMESPACE
6307

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