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