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#if QT_CONFIG(datetimeparser)
17#include "private/qdatetimeparser_p.h"
18#endif
19#ifdef Q_OS_DARWIN
20#include "private/qcore_mac_p.h"
21#endif
22#include "private/qgregoriancalendar_p.h"
23#include "private/qlocale_tools_p.h"
24#include "private/qlocaltime_p.h"
25#include "private/qnumeric_p.h"
26#include "private/qstringconverter_p.h"
27#include "private/qstringiterator_p.h"
28#if QT_CONFIG(timezone)
29#include "private/qtimezoneprivate_p.h"
30#endif
31
32#include <cmath>
33#ifdef Q_OS_WIN
34# include <qt_windows.h>
35#endif
36
37#include <private/qtools_p.h>
38
39QT_BEGIN_NAMESPACE
40
41using namespace Qt::StringLiterals;
42using namespace QtPrivate::DateTimeConstants;
43using namespace QtMiscUtils;
44
45/*****************************************************************************
46 Date/Time Constants
47 *****************************************************************************/
48
49/*****************************************************************************
50 QDate static helper functions
51 *****************************************************************************/
52static_assert(std::is_trivially_copyable_v<QCalendar::YearMonthDay>);
53
54static inline QDate fixedDate(QCalendar::YearMonthDay parts, QCalendar cal)
55{
56 if ((parts.year < 0 && !cal.isProleptic()) || (parts.year == 0 && !cal.hasYearZero()))
57 return QDate();
58
59 parts.day = qMin(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. intercallary 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 QDate date;
1871#if QT_CONFIG(datetimeparser)
1872 QDateTimeParser dt(QMetaType::QDate, QDateTimeParser::FromString, cal);
1873 dt.setDefaultLocale(QLocale::c());
1874 if (dt.parseFormat(format))
1875 dt.fromString(string, &date, nullptr, baseYear);
1876#else
1877 Q_UNUSED(string);
1878 Q_UNUSED(format);
1879 Q_UNUSED(baseYear);
1880 Q_UNUSED(cal);
1881#endif
1882 return date;
1883}
1884
1885/*!
1886 \since 5.14
1887 \overload fromString()
1888 \fn QDate QDate::fromString(const QString &string, const QString &format, QCalendar cal)
1889*/
1890
1891/*!
1892 \since 6.0
1893 \overload fromString()
1894 \fn QDate QDate::fromString(const QString &string, QStringView format, QCalendar cal)
1895*/
1896
1897/*!
1898 \since 6.7
1899 \overload fromString()
1900 \fn QDate QDate::fromString(QStringView string, QStringView format, int baseYear, QCalendar cal)
1901*/
1902
1903/*!
1904 \since 6.7
1905 \overload fromString()
1906 \fn QDate QDate::fromString(QStringView string, QStringView format, int baseYear)
1907
1908 Uses a default-constructed QCalendar.
1909*/
1910
1911/*!
1912 \since 6.7
1913 \overload fromString()
1914
1915 Uses a default-constructed QCalendar.
1916*/
1917QDate QDate::fromString(const QString &string, QStringView format, int baseYear)
1918{
1919 return fromString(string, format, baseYear, QCalendar());
1920}
1921
1922/*!
1923 \since 6.7
1924 \overload fromString()
1925 \fn QDate QDate::fromString(const QString &string, const QString &format, int baseYear)
1926
1927 Uses a default-constructed QCalendar.
1928*/
1929#endif // datestring
1930
1931/*!
1932 \overload isValid()
1933
1934 Returns \c true if the specified date (\a year, \a month, and \a day) is
1935 valid in the Gregorian calendar; otherwise returns \c false.
1936
1937 Example:
1938 \snippet code/src_corelib_time_qdatetime.cpp 4
1939
1940 \sa isNull(), setDate(), QCalendar::isDateValid()
1941*/
1942
1943bool QDate::isValid(int year, int month, int day)
1944{
1945 return QGregorianCalendar::validParts(year, month, day);
1946}
1947
1948/*!
1949 \fn bool QDate::isLeapYear(int year)
1950
1951 Returns \c true if the specified \a year is a leap year in the Gregorian
1952 calendar; otherwise returns \c false.
1953
1954 \sa QCalendar::isLeapYear()
1955*/
1956
1957bool QDate::isLeapYear(int y)
1958{
1959 return QGregorianCalendar::leapTest(y);
1960}
1961
1962/*! \fn static QDate QDate::fromJulianDay(qint64 jd)
1963
1964 Converts the Julian day \a jd to a QDate.
1965
1966 \sa toJulianDay()
1967*/
1968
1969/*! \fn int QDate::toJulianDay() const
1970
1971 Converts the date to a Julian day.
1972
1973 \sa fromJulianDay()
1974*/
1975
1976/*****************************************************************************
1977 QTime member functions
1978 *****************************************************************************/
1979
1980/*!
1981 \class QTime
1982 \inmodule QtCore
1983 \reentrant
1984
1985 \brief The QTime class provides clock time functions.
1986
1987 \compares strong
1988
1989 A QTime object contains a clock time, which it can express as the numbers of
1990 hours, minutes, seconds, and milliseconds since midnight. It provides
1991 functions for comparing times and for manipulating a time by adding a number
1992 of milliseconds. QTime objects should be passed by value rather than by
1993 reference to const; they simply package \c int.
1994
1995 QTime uses the 24-hour clock format; it has no concept of AM/PM.
1996 Unlike QDateTime, QTime knows nothing about time zones or
1997 daylight-saving time (DST).
1998
1999 A QTime object is typically created either by giving the number of hours,
2000 minutes, seconds, and milliseconds explicitly, or by using the static
2001 function currentTime(), which creates a QTime object that represents the
2002 system's local time.
2003
2004 The hour(), minute(), second(), and msec() functions provide
2005 access to the number of hours, minutes, seconds, and milliseconds
2006 of the time. The same information is provided in textual format by
2007 the toString() function.
2008
2009 The addSecs() and addMSecs() functions provide the time a given
2010 number of seconds or milliseconds later than a given time.
2011 Correspondingly, the number of seconds or milliseconds
2012 between two times can be found using secsTo() or msecsTo().
2013
2014 QTime provides a full set of operators to compare two QTime
2015 objects; an earlier time is considered smaller than a later one;
2016 if A.msecsTo(B) is positive, then A < B.
2017
2018 QTime objects can also be created from a text representation using
2019 fromString() and converted to a string representation using toString(). All
2020 conversion to and from string formats is done using the C locale. For
2021 localized conversions, see QLocale.
2022
2023 \sa QDate, QDateTime
2024*/
2025
2026/*!
2027 \fn QTime::QTime()
2028
2029 Constructs a null time object. For a null time, isNull() returns \c true and
2030 isValid() returns \c false. If you need a zero time, use QTime(0, 0). For
2031 the start of a day, see QDate::startOfDay().
2032
2033 \sa isNull(), isValid()
2034*/
2035
2036/*!
2037 Constructs a time with hour \a h, minute \a m, seconds \a s and
2038 milliseconds \a ms.
2039
2040 \a h must be in the range 0 to 23, \a m and \a s must be in the
2041 range 0 to 59, and \a ms must be in the range 0 to 999.
2042
2043 \sa isValid()
2044*/
2045
2046QTime::QTime(int h, int m, int s, int ms)
2047{
2048 setHMS(h, m, s, ms);
2049}
2050
2051
2052/*!
2053 \fn bool QTime::isNull() const
2054
2055 Returns \c true if the time is null (i.e., the QTime object was
2056 constructed using the default constructor); otherwise returns
2057 false. A null time is also an invalid time.
2058
2059 \sa isValid()
2060*/
2061
2062/*!
2063 \overload primary
2064
2065 Returns \c true if the time is valid; otherwise returns \c false. For example,
2066 the time 23:30:55.746 is valid, but 24:12:30 is invalid.
2067
2068 \sa isNull()
2069*/
2070
2071bool QTime::isValid() const
2072{
2073 return mds > NullTime && mds < MSECS_PER_DAY;
2074}
2075
2076
2077/*!
2078 Returns the hour part (0 to 23) of the time.
2079
2080 Returns -1 if the time is invalid.
2081
2082 \sa minute(), second(), msec()
2083*/
2084
2085int QTime::hour() const
2086{
2087 if (!isValid())
2088 return -1;
2089
2090 return ds() / MSECS_PER_HOUR;
2091}
2092
2093/*!
2094 Returns the minute part (0 to 59) of the time.
2095
2096 Returns -1 if the time is invalid.
2097
2098 \sa hour(), second(), msec()
2099*/
2100
2101int QTime::minute() const
2102{
2103 if (!isValid())
2104 return -1;
2105
2106 return (ds() % MSECS_PER_HOUR) / MSECS_PER_MIN;
2107}
2108
2109/*!
2110 Returns the second part (0 to 59) of the time.
2111
2112 Returns -1 if the time is invalid.
2113
2114 \sa hour(), minute(), msec()
2115*/
2116
2117int QTime::second() const
2118{
2119 if (!isValid())
2120 return -1;
2121
2122 return (ds() / MSECS_PER_SEC) % SECS_PER_MIN;
2123}
2124
2125/*!
2126 Returns the millisecond part (0 to 999) of the time.
2127
2128 Returns -1 if the time is invalid.
2129
2130 \sa hour(), minute(), second()
2131*/
2132
2133int QTime::msec() const
2134{
2135 if (!isValid())
2136 return -1;
2137
2138 return ds() % MSECS_PER_SEC;
2139}
2140
2141#if QT_CONFIG(datestring) // depends on, so implies, textdate
2142/*!
2143 \overload toString()
2144
2145 Returns the time as a string. The \a format parameter determines
2146 the format of the string.
2147
2148 If \a format is Qt::TextDate, the string format is HH:mm:ss;
2149 e.g. 1 second before midnight would be "23:59:59".
2150
2151 If \a format is Qt::ISODate, the string format corresponds to the
2152 ISO 8601 extended specification for representations of dates,
2153 represented by HH:mm:ss. To include milliseconds in the ISO 8601
2154 date, use the \a format Qt::ISODateWithMs, which corresponds to
2155 HH:mm:ss.zzz.
2156
2157 If the \a format is Qt::RFC2822Date, the string is formatted in
2158 an \l{RFC 2822} compatible way. An example of this formatting is
2159 "23:59:20".
2160
2161 If the time is invalid, an empty string will be returned.
2162
2163 \sa fromString(), QDate::toString(), QDateTime::toString(), QLocale::toString()
2164*/
2165
2166QString QTime::toString(Qt::DateFormat format) const
2167{
2168 if (!isValid())
2169 return QString();
2170
2171 switch (format) {
2172 case Qt::ISODateWithMs:
2173 return QString::asprintf("%02d:%02d:%02d.%03d", hour(), minute(), second(), msec());
2174 case Qt::RFC2822Date:
2175 case Qt::ISODate:
2176 case Qt::TextDate:
2177 default:
2178 return QString::asprintf("%02d:%02d:%02d", hour(), minute(), second());
2179 }
2180}
2181
2182/*!
2183 \overload primary
2184 \fn QString QTime::toString(const QString &format) const
2185 \fn QString QTime::toString(QStringView format) const
2186
2187 Returns a string representing the time.
2188
2189 The \a format parameter determines the format of the result string. If the
2190 time is invalid, an empty string will be returned.
2191
2192 These expressions may be used:
2193
2194 \table
2195 \header \li Expression \li Output
2196 \row \li h
2197 \li The hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
2198 \row \li hh
2199 \li The hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
2200 \row \li H
2201 \li The hour without a leading zero (0 to 23, even with AM/PM display)
2202 \row \li HH
2203 \li The hour with a leading zero (00 to 23, even with AM/PM display)
2204 \row \li m \li The minute without a leading zero (0 to 59)
2205 \row \li mm \li The minute with a leading zero (00 to 59)
2206 \row \li s \li The whole second, without any leading zero (0 to 59)
2207 \row \li ss \li The whole second, with a leading zero where applicable (00 to 59)
2208 \row \li z or zz
2209 \li The fractional part of the second, to go after a decimal point,
2210 without trailing zeroes. Thus \c{"s.z"} reports the seconds to full
2211 available (millisecond) precision without trailing zeroes (0 to
2212 999). For example, \c{"s.z"} would produce \c{"0.25"} for a time a
2213 quarter second into a minute.
2214 \row \li zzz
2215 \li The fractional part of the second, to millisecond precision,
2216 including trailing zeroes where applicable (000 to 999). For
2217 example, \c{"ss.zzz"} would produce \c{"00.250"} for a time a
2218 quarter second into a minute.
2219 \row \li AP or A
2220 \li Use AM/PM display. \c A/AP will be replaced by 'AM' or 'PM'. In
2221 localized forms (only relevant to \l{QLocale::toString()}), the
2222 locale-appropriate text is converted to upper-case.
2223 \row \li ap or a
2224 \li Use am/pm display. \c a/ap will be replaced by 'am' or 'pm'. In
2225 localized forms (only relevant to \l{QLocale::toString()}), the
2226 locale-appropriate text is converted to lower-case.
2227 \row \li aP or Ap
2228 \li Use AM/PM display (since 6.3). \c aP/Ap will be replaced by 'AM' or
2229 'PM'. In localized forms (only relevant to
2230 \l{QLocale::toString()}), the locale-appropriate text (returned by
2231 \l{QLocale::amText()} or \l{QLocale::pmText()}) is used without
2232 change of case.
2233 \row \li t
2234 \li The timezone abbreviation (for example "CEST"). Note that time zone
2235 abbreviations are not unique. In particular, \l fromString() cannot
2236 parse this.
2237 \row \li tt
2238 \li The timezone's offset from UTC with no colon between the hours and
2239 minutes (for example "+0200").
2240 \row \li ttt
2241 \li The timezone's offset from UTC with a colon between the hours and
2242 minutes (for example "+02:00").
2243 \row \li tttt
2244 \li The timezone name, as provided by \l QTimeZone::displayName() with
2245 the \l QTimeZone::LongName type. This may depend on the operating
2246 system in use. If no such name is available, the IANA ID of the
2247 zone (such as "Europe/Berlin") may be used. It may give no
2248 indication of whether the datetime was in daylight-saving time or
2249 standard time, which may lead to ambiguity if the datetime falls in
2250 an hour repeated by a transition between the two.
2251 \endtable
2252
2253 \note To get localized forms of AM or PM (the \c{AP}, \c{ap}, \c{A}, \c{a},
2254 \c{aP} or \c{Ap} formats) or of time zone representations (the \c{t}
2255 formats), use QLocale::system().toString().
2256
2257 When the timezone cannot be determined or no suitable representation of it
2258 is available, the \c{t} forms to represent it may be skipped. See \l
2259 QTimeZone::displayName() for details of when it returns an empty string.
2260
2261 Any non-empty sequence of characters enclosed in single quotes will be
2262 included verbatim in the output string (stripped of the quotes), even if it
2263 contains formatting characters. Two consecutive single quotes ("''") are
2264 replaced by a single quote in the output. All other characters in the format
2265 string are included verbatim in the output string.
2266
2267 Formats without separators (e.g. "ddMM") are supported but must be used with
2268 care, as the resulting strings aren't always reliably readable (e.g. if "dM"
2269 produces "212" it could mean either the 2nd of December or the 21st of
2270 February).
2271
2272 Example format strings (assuming that the QTime is 14:13:09.042)
2273
2274 \table
2275 \header \li Format \li Result
2276 \row \li hh:mm:ss.zzz \li 14:13:09.042
2277 \row \li h:m:s ap \li 2:13:9 pm
2278 \row \li H:m:s a \li 14:13:9 pm
2279 \endtable
2280
2281 \note If a format character is repeated more times than the longest
2282 expression in the table above using it, this part of the format will be read
2283 as several expressions with no separator between them; the longest above,
2284 possibly repeated as many times as there are copies of it, ending with a
2285 residue that may be a shorter expression. Thus \c{'HHHHH'} for the time
2286 08:00 will contribute \c{"08088"} to the output.
2287
2288 \sa fromString(), QDate::toString(), QDateTime::toString(), QLocale::toString()
2289*/
2290QString QTime::toString(QStringView format) const
2291{
2292 return QLocale::c().toString(*this, format);
2293}
2294// ### Qt 7 The 't' format specifiers should be specific to QDateTime (compare fromString).
2295#endif // datestring
2296
2297/*!
2298 Sets the time to hour \a h, minute \a m, seconds \a s and
2299 milliseconds \a ms.
2300
2301 \a h must be in the range 0 to 23, \a m and \a s must be in the
2302 range 0 to 59, and \a ms must be in the range 0 to 999.
2303 Returns \c true if the set time is valid; otherwise returns \c false.
2304
2305 \sa isValid()
2306*/
2307
2308bool QTime::setHMS(int h, int m, int s, int ms)
2309{
2310 if (!isValid(h,m,s,ms)) {
2311 mds = NullTime; // make this invalid
2312 return false;
2313 }
2314 mds = ((h * MINS_PER_HOUR + m) * SECS_PER_MIN + s) * MSECS_PER_SEC + ms;
2315 Q_ASSERT(mds >= 0 && mds < MSECS_PER_DAY);
2316 return true;
2317}
2318
2319/*!
2320 Returns a QTime object containing a time \a s seconds later
2321 than the time of this object (or earlier if \a s is negative).
2322
2323 Note that the time will wrap if it passes midnight.
2324
2325 Returns a null time if this time is invalid.
2326
2327 Example:
2328
2329 \snippet code/src_corelib_time_qdatetime.cpp 5
2330
2331 \sa addMSecs(), secsTo(), QDateTime::addSecs()
2332*/
2333
2334QTime QTime::addSecs(int s) const
2335{
2336 s %= SECS_PER_DAY;
2337 return addMSecs(s * MSECS_PER_SEC);
2338}
2339
2340/*!
2341 Returns the number of seconds from this time to \a t.
2342 If \a t is earlier than this time, the number of seconds returned
2343 is negative.
2344
2345 Because QTime measures time within a day and there are 86400
2346 seconds in a day, the result is always between -86400 and 86400.
2347
2348 secsTo() does not take into account any milliseconds.
2349
2350 Returns 0 if either time is invalid.
2351
2352 \sa addSecs(), QDateTime::secsTo()
2353*/
2354
2355int QTime::secsTo(QTime t) const
2356{
2357 if (!isValid() || !t.isValid())
2358 return 0;
2359
2360 // Truncate milliseconds as we do not want to consider them.
2361 int ourSeconds = ds() / MSECS_PER_SEC;
2362 int theirSeconds = t.ds() / MSECS_PER_SEC;
2363 return theirSeconds - ourSeconds;
2364}
2365
2366/*!
2367 Returns a QTime object containing a time \a ms milliseconds later
2368 than the time of this object (or earlier if \a ms is negative).
2369
2370 Note that the time will wrap if it passes midnight. See addSecs()
2371 for an example.
2372
2373 Returns a null time if this time is invalid.
2374
2375 \sa addSecs(), msecsTo(), QDateTime::addMSecs()
2376*/
2377
2378QTime QTime::addMSecs(int ms) const
2379{
2380 QTime t;
2381 if (isValid())
2382 t.mds = QRoundingDown::qMod<MSECS_PER_DAY>(ds() + ms);
2383 return t;
2384}
2385
2386/*!
2387 Returns the number of milliseconds from this time to \a t.
2388 If \a t is earlier than this time, the number of milliseconds returned
2389 is negative.
2390
2391 Because QTime measures time within a day and there are 86400
2392 seconds in a day, the result is always between -86400000 and
2393 86400000 ms.
2394
2395 Returns 0 if either time is invalid.
2396
2397 \sa secsTo(), addMSecs(), QDateTime::msecsTo()
2398*/
2399
2400int QTime::msecsTo(QTime t) const
2401{
2402 if (!isValid() || !t.isValid())
2403 return 0;
2404 return t.ds() - ds();
2405}
2406
2407
2408/*!
2409 \fn bool QTime::operator==(const QTime &lhs, const QTime &rhs)
2410
2411 Returns \c true if \a lhs is equal to \a rhs; otherwise returns \c false.
2412*/
2413
2414/*!
2415 \fn bool QTime::operator!=(const QTime &lhs, const QTime &rhs)
2416
2417 Returns \c true if \a lhs is different from \a rhs; otherwise returns \c false.
2418*/
2419
2420/*!
2421 \fn bool QTime::operator<(const QTime &lhs, const QTime &rhs)
2422
2423 Returns \c true if \a lhs is earlier than \a rhs; otherwise returns \c false.
2424*/
2425
2426/*!
2427 \fn bool QTime::operator<=(const QTime &lhs, const QTime &rhs)
2428
2429 Returns \c true if \a lhs is earlier than or equal to \a rhs;
2430 otherwise returns \c false.
2431*/
2432
2433/*!
2434 \fn bool QTime::operator>(const QTime &lhs, const QTime &rhs)
2435
2436 Returns \c true if \a lhs is later than \a rhs; otherwise returns \c false.
2437*/
2438
2439/*!
2440 \fn bool QTime::operator>=(const QTime &lhs, const QTime &rhs)
2441
2442 Returns \c true if \a lhs is later than or equal to \a rhs;
2443 otherwise returns \c false.
2444*/
2445
2446/*!
2447 \fn QTime QTime::fromMSecsSinceStartOfDay(int msecs)
2448
2449 Returns a new QTime instance with the time set to the number of \a msecs
2450 since the start of the day, i.e. since 00:00:00.
2451
2452 If \a msecs falls outside the valid range an invalid QTime will be returned.
2453
2454 \sa msecsSinceStartOfDay()
2455*/
2456
2457/*!
2458 \fn int QTime::msecsSinceStartOfDay() const
2459
2460 Returns the number of msecs since the start of the day, i.e. since 00:00:00.
2461
2462 \sa fromMSecsSinceStartOfDay()
2463*/
2464
2465/*!
2466 \fn QTime::currentTime()
2467
2468 Returns the current time as reported by the system clock.
2469
2470 Note that the accuracy depends on the accuracy of the underlying
2471 operating system; not all systems provide 1-millisecond accuracy.
2472
2473 Furthermore, currentTime() only increases within each day; it shall drop by
2474 24 hours each time midnight passes; and, beside this, changes in it may not
2475 correspond to elapsed time, if a daylight-saving transition intervenes.
2476
2477 \sa QDateTime::currentDateTime(), QDateTime::currentDateTimeUtc()
2478*/
2479
2480#if QT_CONFIG(datestring) // depends on, so implies, textdate
2481
2482static QTime fromIsoTimeString(QStringView string, Qt::DateFormat format, bool *isMidnight24)
2483{
2484 Q_ASSERT(format == Qt::TextDate || format == Qt::ISODate || format == Qt::ISODateWithMs);
2485 if (isMidnight24)
2486 *isMidnight24 = false;
2487 // Match /\d\d(:\d\d(:\d\d)?)?([,.]\d+)?/ as "HH[:mm[:ss]][.zzz]"
2488 // The fractional part, if present, is in the same units as the field it follows.
2489 // TextDate restricts fractional parts to the seconds field.
2490
2491 QStringView tail;
2492 const qsizetype dot = string.indexOf(u'.'), comma = string.indexOf(u',');
2493 if (dot != -1) {
2494 tail = string.sliced(dot + 1);
2495 if (tail.indexOf(u'.') != -1) // Forbid second dot:
2496 return QTime();
2497 string = string.first(dot);
2498 } else if (comma != -1) {
2499 tail = string.sliced(comma + 1);
2500 string = string.first(comma);
2501 }
2502 if (tail.indexOf(u',') != -1) // Forbid comma after first dot-or-comma:
2503 return QTime();
2504
2505 const ParsedInt frac = readInt(tail);
2506 // There must be *some* digits in a fractional part; and it must be all digits:
2507 if (tail.isEmpty() ? dot != -1 || comma != -1 : !frac.ok())
2508 return QTime();
2509 Q_ASSERT(frac.ok() ^ tail.isEmpty());
2510 double fraction = frac.ok() ? frac.result * std::pow(0.1, tail.size()) : 0.0;
2511
2512 const qsizetype size = string.size();
2513 if (size < 2 || size > 8)
2514 return QTime();
2515
2516 ParsedInt hour = readInt(string.first(2));
2517 if (!hour.ok() || hour.result > (format == Qt::TextDate ? 23 : 24))
2518 return QTime();
2519
2520 ParsedInt minute{};
2521 if (string.size() > 2) {
2522 if (string[2] == u':' && string.size() > 4)
2523 minute = readInt(string.sliced(3, 2));
2524 if (!minute.ok() || minute.result >= MINS_PER_HOUR)
2525 return QTime();
2526 } else if (format == Qt::TextDate) { // Requires minutes
2527 return QTime();
2528 } else if (frac.ok()) {
2529 Q_ASSERT(!(fraction < 0.0) && fraction < 1.0);
2530 fraction *= MINS_PER_HOUR;
2531 minute.result = qulonglong(fraction);
2532 fraction -= minute.result;
2533 }
2534
2535 ParsedInt second{};
2536 if (string.size() > 5) {
2537 if (string[5] == u':' && string.size() == 8)
2538 second = readInt(string.sliced(6, 2));
2539 if (!second.ok() || second.result >= SECS_PER_MIN)
2540 return QTime();
2541 } else if (frac.ok()) {
2542 if (format == Qt::TextDate) // Doesn't allow fraction of minutes
2543 return QTime();
2544 Q_ASSERT(!(fraction < 0.0) && fraction < 1.0);
2545 fraction *= SECS_PER_MIN;
2546 second.result = qulonglong(fraction);
2547 fraction -= second.result;
2548 }
2549
2550 Q_ASSERT(!(fraction < 0.0) && fraction < 1.0);
2551 // Round millis to nearest (unlike minutes and seconds, rounded down):
2552 int msec = frac.ok() ? qRound(MSECS_PER_SEC * fraction) : 0;
2553 // But handle overflow gracefully:
2554 if (msec == MSECS_PER_SEC) {
2555 // If we can (when data were otherwise valid) validly propagate overflow
2556 // into other fields, do so:
2557 if (isMidnight24 || hour.result < 23 || minute.result < 59 || second.result < 59) {
2558 msec = 0;
2559 if (++second.result == SECS_PER_MIN) {
2560 second.result = 0;
2561 if (++minute.result == MINS_PER_HOUR) {
2562 minute.result = 0;
2563 ++hour.result;
2564 // May need to propagate further via isMidnight24, see below
2565 }
2566 }
2567 } else {
2568 // QTime::fromString() or Qt::TextDate: rounding up would cause
2569 // 23:59:59.999... to become invalid; clip to 999 ms instead:
2570 msec = MSECS_PER_SEC - 1;
2571 }
2572 }
2573
2574 // For ISO date format, 24:0:0 means 0:0:0 on the next day:
2575 if (hour.result == 24 && minute.result == 0 && second.result == 0 && msec == 0) {
2576 Q_ASSERT(format != Qt::TextDate); // It clipped hour at 23, above.
2577 if (isMidnight24)
2578 *isMidnight24 = true;
2579 hour.result = 0;
2580 }
2581
2582 return QTime(hour.result, minute.result, second.result, msec);
2583}
2584
2585/*!
2586 \overload
2587 \fn QTime QTime::fromString(const QString &string, Qt::DateFormat format)
2588
2589 Returns the time represented in the \a string as a QTime using the
2590 \a format given, or an invalid time if this is not possible.
2591
2592 \sa toString(), QLocale::toTime()
2593*/
2594
2595/*!
2596 \since 6.0
2597 \overload fromString()
2598*/
2599QTime QTime::fromString(QStringView string, Qt::DateFormat format)
2600{
2601 if (string.isEmpty())
2602 return QTime();
2603
2604 switch (format) {
2605 case Qt::RFC2822Date:
2606 return rfcDateImpl(string).time;
2607 case Qt::ISODate:
2608 case Qt::ISODateWithMs:
2609 case Qt::TextDate:
2610 default:
2611 return fromIsoTimeString(string, format, nullptr);
2612 }
2613}
2614
2615/*!
2616 \overload primary
2617 \fn QTime QTime::fromString(const QString &string, const QString &format)
2618
2619 Returns the QTime represented by the \a string, using the \a
2620 format given, or an invalid time if the string cannot be parsed.
2621
2622 These expressions may be used for the format:
2623
2624 \table
2625 \header \li Expression \li Output
2626 \row \li h
2627 \li The hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
2628 \row \li hh
2629 \li The hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
2630 \row \li H
2631 \li The hour without a leading zero (0 to 23, even with AM/PM display)
2632 \row \li HH
2633 \li The hour with a leading zero (00 to 23, even with AM/PM display)
2634 \row \li m \li The minute without a leading zero (0 to 59)
2635 \row \li mm \li The minute with a leading zero (00 to 59)
2636 \row \li s \li The whole second, without any leading zero (0 to 59)
2637 \row \li ss \li The whole second, with a leading zero where applicable (00 to 59)
2638 \row \li z or zz
2639 \li The fractional part of the second, as would usually follow a
2640 decimal point, without requiring trailing zeroes (0 to 999). Thus
2641 \c{"s.z"} matches the seconds with up to three digits of fractional
2642 part supplying millisecond precision, without needing trailing
2643 zeroes. For example, \c{"s.z"} would recognize either \c{"00.250"}
2644 or \c{"0.25"} as representing a time a quarter second into its
2645 minute.
2646 \row \li zzz
2647 \li Three digit fractional part of the second, to millisecond
2648 precision, including trailing zeroes where applicable (000 to 999).
2649 For example, \c{"ss.zzz"} would reject \c{"0.25"} but recognize
2650 \c{"00.250"} as representing a time a quarter second into its
2651 minute.
2652 \row \li AP, A, ap, a, aP or Ap
2653 \li Either 'AM' indicating a time before 12:00 or 'PM' for later times,
2654 matched case-insensitively.
2655 \endtable
2656
2657 All other input characters will be treated as text. Any non-empty sequence
2658 of characters enclosed in single quotes will also be treated (stripped of
2659 the quotes) as text and not be interpreted as expressions.
2660
2661 \snippet code/src_corelib_time_qdatetime.cpp 6
2662
2663 If the format is not satisfied, an invalid QTime is returned.
2664 Expressions that do not expect leading zeroes to be given (h, m, s
2665 and z) are greedy. This means that they will use two digits (or three, for z) even if
2666 this puts them outside the range of accepted values and leaves too
2667 few digits for other sections. For example, the following string
2668 could have meant 00:07:10, but the m will grab two digits, resulting
2669 in an invalid time:
2670
2671 \snippet code/src_corelib_time_qdatetime.cpp 7
2672
2673 Any field that is not represented in the format will be set to zero.
2674 For example:
2675
2676 \snippet code/src_corelib_time_qdatetime.cpp 8
2677
2678 \note If localized forms of am or pm (the AP, ap, Ap, aP, A or a formats)
2679 are to be recognized, use QLocale::system().toTime().
2680
2681 \note If a format character is repeated more times than the longest
2682 expression in the table above using it, this part of the format will be read
2683 as several expressions with no separator between them; the longest above,
2684 possibly repeated as many times as there are copies of it, ending with a
2685 residue that may be a shorter expression. Thus \c{'HHHHH'} would match
2686 \c{"08088"} or \c{"080808"} and set the hour to 8; if the time string
2687 contained "070809" it would "match" but produce an inconsistent result,
2688 leading to an invalid time.
2689
2690 \sa toString(), QDateTime::fromString(), QDate::fromString(),
2691 QLocale::toTime(), QLocale::toDateTime()
2692*/
2693
2694/*!
2695 \since 6.0
2696 \overload fromString()
2697 \fn QTime QTime::fromString(QStringView string, QStringView format)
2698*/
2699
2700/*!
2701 \since 6.0
2702 \overload fromString()
2703*/
2704QTime QTime::fromString(const QString &string, QStringView format)
2705{
2706 QTime time;
2707#if QT_CONFIG(datetimeparser)
2708 QDateTimeParser dt(QMetaType::QTime, QDateTimeParser::FromString, QCalendar());
2709 dt.setDefaultLocale(QLocale::c());
2710 if (dt.parseFormat(format))
2711 dt.fromString(string, nullptr, &time);
2712#else
2713 Q_UNUSED(string);
2714 Q_UNUSED(format);
2715#endif
2716 return time;
2717}
2718#endif // datestring
2719
2720
2721/*!
2722 \overload isValid()
2723
2724 Returns \c true if the specified time is valid; otherwise returns
2725 false.
2726
2727 The time is valid if \a h is in the range 0 to 23, \a m and
2728 \a s are in the range 0 to 59, and \a ms is in the range 0 to 999.
2729
2730 Example:
2731
2732 \snippet code/src_corelib_time_qdatetime.cpp 9
2733*/
2734
2735bool QTime::isValid(int h, int m, int s, int ms)
2736{
2737 return (uint(h) < 24 && uint(m) < MINS_PER_HOUR && uint(s) < SECS_PER_MIN
2738 && uint(ms) < MSECS_PER_SEC);
2739}
2740
2741/*****************************************************************************
2742 QDateTime static helper functions
2743 *****************************************************************************/
2744
2745// get the types from QDateTime (through QDateTimePrivate)
2748
2749// Converts milliseconds since the start of 1970 into a date and/or time:
2750static qint64 msecsToJulianDay(qint64 msecs)
2751{
2752 return JULIAN_DAY_FOR_EPOCH + QRoundingDown::qDiv<MSECS_PER_DAY>(msecs);
2753}
2754
2755static QDate msecsToDate(qint64 msecs)
2756{
2757 return QDate::fromJulianDay(msecsToJulianDay(msecs));
2758}
2759
2760static QTime msecsToTime(qint64 msecs)
2761{
2762 return QTime::fromMSecsSinceStartOfDay(QRoundingDown::qMod<MSECS_PER_DAY>(msecs));
2763}
2764
2765// True if combining days with millis overflows; otherwise, stores result in *sumMillis
2766// The inputs should not have opposite signs.
2767static inline bool daysAndMillisOverflow(qint64 days, qint64 millisInDay, qint64 *sumMillis)
2768{
2769 return qMulOverflow(days, std::integral_constant<qint64, MSECS_PER_DAY>(), sumMillis)
2770 || qAddOverflow(*sumMillis, millisInDay, sumMillis);
2771}
2772
2773// Converts a date/time value into msecs
2774static qint64 timeToMSecs(QDate date, QTime time)
2775{
2776 qint64 days = date.toJulianDay() - JULIAN_DAY_FOR_EPOCH;
2777 qint64 msecs, dayms = time.msecsSinceStartOfDay();
2778 if (days < 0 && dayms > 0) {
2779 ++days;
2780 dayms -= MSECS_PER_DAY;
2781 }
2782 if (daysAndMillisOverflow(days, dayms, &msecs)) {
2783 using Bound = std::numeric_limits<qint64>;
2784 return days < 0 ? Bound::min() : Bound::max();
2785 }
2786 return msecs;
2787}
2788
2789/*!
2790 \internal
2791 Tests whether system functions can handle a given time.
2792
2793 The range of milliseconds for which the time_t-based functions work depends
2794 somewhat on platform (see computeSystemMillisRange() for details). This
2795 function tests whether the UTC time \a millis milliseconds from the epoch is
2796 in the supported range.
2797
2798 To test a local time, pass an upper bound on the magnitude of time-zone
2799 correction potentially needed as \a slack: in this case the range is
2800 extended by this many milliseconds at each end (where applicable). The
2801 function then returns true precisely if \a millis is within this (possibly)
2802 widened range. This doesn't guarantee that the time_t functions can handle
2803 the time, so check their returns to be sure. Values for which the function
2804 returns false should be assumed unrepresentable.
2805*/
2806static inline bool millisInSystemRange(qint64 millis, qint64 slack = 0)
2807{
2808 static const auto bounds = QLocalTime::computeSystemMillisRange();
2809 return (bounds.minClip || millis >= bounds.min - slack)
2810 && (bounds.maxClip || millis <= bounds.max + slack);
2811}
2812
2813/*!
2814 \internal
2815 Returns a year, in the system range, with the same day-of-week pattern
2816
2817 Returns the number of a year, in the range supported by system time_t
2818 functions, that starts and ends on the same days of the week as \a year.
2819 This implies it is a leap year precisely if \a year is. If year is before
2820 the epoch, a year early in the supported range is used; otherwise, one late
2821 in that range. For a leap year, this may be as much as 26 years years from
2822 the range's relevant end; for normal years at most a decade from the end.
2823
2824 This ensures that any DST rules based on, e.g., the last Sunday in a
2825 particular month will select the same date in the returned year as they
2826 would if applied to \a year. Of course, the zone's rules may be different in
2827 \a year than in the selected year, but it's hard to do better.
2828*/
2829static int systemTimeYearMatching(int year)
2830{
2831#if defined(Q_OS_WIN) || defined(Q_OS_WASM)// They don't support times before the epoch
2832 static constexpr int forLeapEarly[] = { 1984, 1996, 1980, 1992, 1976, 1988, 1972 };
2833 static constexpr int regularEarly[] = { 1978, 1973, 1974, 1975, 1970, 1971, 1977 };
2834#else // First year fully in 32-bit time_t range is 1902
2835 static constexpr int forLeapEarly[] = { 1928, 1912, 1924, 1908, 1920, 1904, 1916 };
2836 static constexpr int regularEarly[] = { 1905, 1906, 1907, 1902, 1903, 1909, 1910 };
2837#endif
2838 static constexpr int forLeapLate[] = { 2012, 2024, 2036, 2020, 2032, 2016, 2028 };
2839 static constexpr int regularLate[] = { 2034, 2035, 2030, 2031, 2037, 2027, 2033 };
2840 const int dow = QGregorianCalendar::yearStartWeekDay(year);
2841 Q_ASSERT(dow == QDate(year, 1, 1).dayOfWeek());
2842 const int res = (QGregorianCalendar::leapTest(year)
2843 ? (year < 1970 ? forLeapEarly : forLeapLate)
2844 : (year < 1970 ? regularEarly : regularLate))[dow == 7 ? 0 : dow];
2845 Q_ASSERT(QDate(res, 1, 1).dayOfWeek() == dow);
2846 Q_ASSERT(QDate(res, 12, 31).dayOfWeek() == QDate(year, 12, 31).dayOfWeek());
2847 return res;
2848}
2849
2850// Sets up d and status to represent local time at the given UTC msecs since epoch:
2851QDateTimePrivate::ZoneState QDateTimePrivate::expressUtcAsLocal(qint64 utcMSecs)
2852{
2853 ZoneState result{utcMSecs};
2854 // Within the time_t supported range, localtime() can handle it:
2855 if (millisInSystemRange(utcMSecs)) {
2856 result = QLocalTime::utcToLocal(utcMSecs);
2857 if (result.valid)
2858 return result;
2859 }
2860
2861 // Docs state any LocalTime after 2038-01-18 *will* have any DST applied.
2862 // When this falls outside the supported range, we need to fake it.
2863#if QT_CONFIG(timezone) // Use the system time-zone.
2864 if (const auto sys = QTimeZone::systemTimeZone(); sys.isValid()) {
2865 result.offset = sys.d->offsetFromUtc(utcMSecs);
2866 if (result.offset != QTimeZonePrivate::invalidSeconds()) {
2867 if (qAddOverflow(utcMSecs, result.offset * MSECS_PER_SEC, &result.when))
2868 return result;
2869 result.dst = sys.d->isDaylightTime(utcMSecs) ? DaylightTime : StandardTime;
2870 result.valid = true;
2871 return result;
2872 }
2873 }
2874#endif // timezone
2875
2876 // Kludge
2877 // Do the conversion in a year with the same days of the week, so DST
2878 // dates might be right, and adjust by the number of days that was off:
2879 const qint64 jd = msecsToJulianDay(utcMSecs);
2880 const auto ymd = QGregorianCalendar::partsFromJulian(jd);
2881 qint64 diffMillis, fakeUtc;
2882 const auto fakeJd = QGregorianCalendar::julianFromParts(systemTimeYearMatching(ymd.year),
2883 ymd.month, ymd.day);
2884 if (Q_UNLIKELY(!fakeJd
2885 || qMulOverflow(jd - *fakeJd, std::integral_constant<qint64, MSECS_PER_DAY>(),
2886 &diffMillis)
2887 || qSubOverflow(utcMSecs, diffMillis, &fakeUtc))) {
2888 return result;
2889 }
2890
2891 result = QLocalTime::utcToLocal(fakeUtc);
2892 // Now correct result.when for the use of the fake date:
2893 if (!result.valid || qAddOverflow(result.when, diffMillis, &result.when)) {
2894 // If utcToLocal() failed, its return has the fake when; restore utcMSecs.
2895 // Fail on overflow, but preserve offset and DST-ness.
2896 result.when = utcMSecs;
2897 result.valid = false;
2898 }
2899 return result;
2900}
2901
2902static auto millisToWithinRange(qint64 millis)
2903{
2904 struct R {
2905 qint64 shifted = 0;
2906 bool good = false;
2907 } result;
2908 qint64 jd = msecsToJulianDay(millis);
2909 auto ymd = QGregorianCalendar::partsFromJulian(jd);
2910 const auto fakeJd = QGregorianCalendar::julianFromParts(systemTimeYearMatching(ymd.year),
2911 ymd.month, ymd.day);
2912 result.good = fakeJd && !daysAndMillisOverflow(*fakeJd - jd, millis, &result.shifted);
2913 return result;
2914}
2915
2916/*!
2917 \internal
2918 \enum QDateTimePrivate::TransitionOption
2919
2920 This enumeration is used to resolve datetime combinations which fall in \l
2921 {Timezone transitions}. The transition is described as a "gap" if there are
2922 time representations skipped over by the zone, as is common in the "spring
2923 forward" transitions in many zones on entering daylight-saving time. The
2924 transition is described as a "fold" if there are time representations
2925 repeated in the zone, as in a "fall back" transition out of daylight-saving
2926 time.
2927
2928 When the options specified do not determine a resolution for a datetime, it
2929 is marked invalid.
2930
2931 The prepared option sets above are in fact composed from low-level atomic
2932 options. For each of gap and fold you can chose between two candidate times,
2933 one before or after the transition, based on the time requested; or you can
2934 pick the moment of transition, or the start or end of the transition
2935 interval. For a gap, the start and end of the interval are the moment of the
2936 transition, but for a repeated interval the start of the first pass is the
2937 start of the transition interval, the end of the second pass is the end of
2938 the transition interval and the moment of the transition itself is both the
2939 end of the first pass and the start of the second.
2940
2941 \value GapUseBefore For a time in a gap, use a time before the transition,
2942 as if stepping back from a later time.
2943 \value GapUseAfter For a time in a gap, use a time after the transition, as
2944 if stepping forward from an earlier time.
2945 \value FoldUseBefore For a repeated time, use the first candidate, which is
2946 before the transition.
2947 \value FoldUseAfter For a repeated time, use the second candidate, which is
2948 after the transition.
2949 \value FlipForReverseDst For "reversed" DST, this reverses the preceding
2950 four options (see below).
2951
2952 The last has no effect unless the "daylight-saving" time side of the
2953 transition is known to have a lower offset from UTC than the standard time
2954 side. (This is the "reversed" DST case of \l {Timezone transitions}.) In
2955 that case, if other options would select a time after the transition, a time
2956 before is used instead, and vice versa. This effectively turns a preference
2957 for the side with lower offset into a preference for the side that is
2958 officially standard time, even if it has higher offset; and conversely a
2959 preference for higher offset into a preference for daylight-saving time,
2960 even if it has a lower offset. This option has no effect on a resolution
2961 that selects the moment of transition or the start or end of the transition
2962 interval.
2963
2964 The result of combining more than one of the \c GapUse* options is
2965 undefined; likewise for the \c FoldUse*. Each of QDateTime's
2966 TransitionResolution values, aside from Reject, maps to a combination that
2967 incorporates one from each of these sets.
2968*/
2969
2970constexpr static QDateTimePrivate::TransitionOptions
2971toTransitionOptions(QDateTime::TransitionResolution res)
2972{
2973 switch (res) {
2974 case QDateTime::TransitionResolution::RelativeToBefore:
2975 return QDateTimePrivate::GapUseAfter | QDateTimePrivate::FoldUseBefore;
2976 case QDateTime::TransitionResolution::RelativeToAfter:
2977 return QDateTimePrivate::GapUseBefore | QDateTimePrivate::FoldUseAfter;
2978 case QDateTime::TransitionResolution::PreferBefore:
2979 return QDateTimePrivate::GapUseBefore | QDateTimePrivate::FoldUseBefore;
2980 case QDateTime::TransitionResolution::PreferAfter:
2981 return QDateTimePrivate::GapUseAfter | QDateTimePrivate::FoldUseAfter;
2982 case QDateTime::TransitionResolution::PreferStandard:
2983 return QDateTimePrivate::GapUseBefore
2984 | QDateTimePrivate::FoldUseAfter
2985 | QDateTimePrivate::FlipForReverseDst;
2986 case QDateTime::TransitionResolution::PreferDaylightSaving:
2987 return QDateTimePrivate::GapUseAfter
2988 | QDateTimePrivate::FoldUseBefore
2989 | QDateTimePrivate::FlipForReverseDst;
2990 case QDateTime::TransitionResolution::Reject: break;
2991 }
2992 return {};
2993}
2994
2995constexpr static QDateTimePrivate::TransitionOptions
2996toTransitionOptions(QDateTimePrivate::DaylightStatus dst)
2997{
2998 return toTransitionOptions(dst == QDateTimePrivate::DaylightTime
2999 ? QDateTime::TransitionResolution::PreferDaylightSaving
3000 : QDateTime::TransitionResolution::PreferStandard);
3001}
3002
3003QString QDateTimePrivate::localNameAtMillis(qint64 millis, DaylightStatus dst)
3004{
3005 const QDateTimePrivate::TransitionOptions resolve = toTransitionOptions(dst);
3006 QString abbreviation;
3007 if (millisInSystemRange(millis, MSECS_PER_DAY)) {
3008 abbreviation = QLocalTime::localTimeAbbbreviationAt(millis, resolve);
3009 if (!abbreviation.isEmpty())
3010 return abbreviation;
3011 }
3012
3013 // Otherwise, outside the system range.
3014#if QT_CONFIG(timezone)
3015 // Use the system zone:
3016 const auto sys = QTimeZone::systemTimeZone();
3017 if (sys.isValid()) {
3018 ZoneState state = zoneStateAtMillis(sys, millis, resolve);
3019 if (state.valid)
3020 return sys.d->abbreviation(state.when - state.offset * MSECS_PER_SEC);
3021 }
3022#endif // timezone
3023
3024 // Kludge
3025 // Use a time in the system range with the same day-of-week pattern to its year:
3026 auto fake = millisToWithinRange(millis);
3027 if (Q_LIKELY(fake.good))
3028 return QLocalTime::localTimeAbbbreviationAt(fake.shifted, resolve);
3029
3030 // Overflow, apparently.
3031 return {};
3032}
3033
3034// Determine the offset from UTC at the given local time as millis.
3035QDateTimePrivate::ZoneState QDateTimePrivate::localStateAtMillis(
3036 qint64 millis, QDateTimePrivate::TransitionOptions resolve)
3037{
3038 // First, if millis is within a day of the viable range, try mktime() in
3039 // case it does fall in the range and gets useful information:
3040 if (millisInSystemRange(millis, MSECS_PER_DAY)) {
3041 auto result = QLocalTime::mapLocalTime(millis, resolve);
3042 if (result.valid)
3043 return result;
3044 }
3045
3046 // Otherwise, outside the system range.
3047#if QT_CONFIG(timezone)
3048 // Use the system zone:
3049 const auto sys = QTimeZone::systemTimeZone();
3050 if (sys.isValid())
3051 return zoneStateAtMillis(sys, millis, resolve);
3052#endif // timezone
3053
3054 // Kludge
3055 // Use a time in the system range with the same day-of-week pattern to its year:
3056 auto fake = millisToWithinRange(millis);
3057 if (Q_LIKELY(fake.good)) {
3058 auto result = QLocalTime::mapLocalTime(fake.shifted, resolve);
3059 if (result.valid) {
3060 qint64 adjusted;
3061 if (Q_UNLIKELY(qAddOverflow(result.when, millis - fake.shifted, &adjusted))) {
3062 using Bound = std::numeric_limits<qint64>;
3063 adjusted = millis < fake.shifted ? Bound::min() : Bound::max();
3064 }
3065 result.when = adjusted;
3066 } else {
3067 result.when = millis;
3068 }
3069 return result;
3070 }
3071 // Overflow, apparently.
3072 return {millis};
3073}
3074
3075#if QT_CONFIG(timezone)
3076// For a TimeZone and a time expressed in zone msecs encoding, compute the
3077// actual DST-ness and offset, adjusting the time if needed to escape a
3078// spring-forward.
3079QDateTimePrivate::ZoneState QDateTimePrivate::zoneStateAtMillis(
3080 const QTimeZone &zone, qint64 millis, QDateTimePrivate::TransitionOptions resolve)
3081{
3082 Q_ASSERT(zone.isValid());
3083 Q_ASSERT(zone.timeSpec() == Qt::TimeZone);
3084 return zone.d->stateAtZoneTime(millis, resolve);
3085}
3086#endif // timezone
3087
3088static inline QDateTimePrivate::ZoneState stateAtMillis(const QTimeZone &zone, qint64 millis,
3089 QDateTimePrivate::TransitionOptions resolve)
3090{
3091 if (zone.timeSpec() == Qt::LocalTime)
3092 return QDateTimePrivate::localStateAtMillis(millis, resolve);
3093#if QT_CONFIG(timezone)
3094 if (zone.timeSpec() == Qt::TimeZone && zone.isValid())
3095 return QDateTimePrivate::zoneStateAtMillis(zone, millis, resolve);
3096#endif
3097 return {millis};
3098}
3099
3100static inline bool specCanBeSmall(Qt::TimeSpec spec)
3101{
3102 return spec == Qt::LocalTime || spec == Qt::UTC;
3103}
3104
3105static inline bool msecsCanBeSmall(qint64 msecs)
3106{
3107 if constexpr (!QDateTimeData::CanBeSmall)
3108 return false;
3109
3110 ShortData sd;
3111 sd.msecs = qintptr(msecs);
3112 return sd.msecs == msecs;
3113}
3114
3115static constexpr inline
3116QDateTimePrivate::StatusFlags mergeSpec(QDateTimePrivate::StatusFlags status, Qt::TimeSpec spec)
3117{
3118 status &= ~QDateTimePrivate::TimeSpecMask;
3119 status |= QDateTimePrivate::StatusFlags::fromInt(int(spec) << QDateTimePrivate::TimeSpecShift);
3120 return status;
3121}
3122
3123static constexpr inline Qt::TimeSpec extractSpec(QDateTimePrivate::StatusFlags status)
3124{
3125 return Qt::TimeSpec((status & QDateTimePrivate::TimeSpecMask).toInt() >> QDateTimePrivate::TimeSpecShift);
3126}
3127
3128// Set the Daylight Status if LocalTime set via msecs
3129static constexpr inline QDateTimePrivate::StatusFlags
3130mergeDaylightStatus(QDateTimePrivate::StatusFlags sf, QDateTimePrivate::DaylightStatus status)
3131{
3132 sf &= ~QDateTimePrivate::DaylightMask;
3133 if (status == QDateTimePrivate::DaylightTime) {
3134 sf |= QDateTimePrivate::SetToDaylightTime;
3135 } else if (status == QDateTimePrivate::StandardTime) {
3136 sf |= QDateTimePrivate::SetToStandardTime;
3137 }
3138 return sf;
3139}
3140
3141// Get the DST Status if LocalTime set via msecs
3142static constexpr inline
3143QDateTimePrivate::DaylightStatus extractDaylightStatus(QDateTimePrivate::StatusFlags status)
3144{
3145 if (status.testFlag(QDateTimePrivate::SetToDaylightTime))
3146 return QDateTimePrivate::DaylightTime;
3147 if (status.testFlag(QDateTimePrivate::SetToStandardTime))
3148 return QDateTimePrivate::StandardTime;
3149 return QDateTimePrivate::UnknownDaylightTime;
3150}
3151
3152static inline qint64 getMSecs(const QDateTimeData &d)
3153{
3154 if (d.isShort()) {
3155 // same as, but producing better code
3156 //return d.data.msecs;
3157 return qintptr(d.d) >> 8;
3158 }
3159 return d->m_msecs;
3160}
3161
3163{
3164 if (d.isShort()) {
3165 // same as, but producing better code
3166 //return StatusFlag(d.data.status);
3167 return QDateTimePrivate::StatusFlag(qintptr(d.d) & 0xFF);
3168 }
3169 return d->m_status;
3170}
3171
3172static inline Qt::TimeSpec getSpec(const QDateTimeData &d)
3173{
3174 return extractSpec(getStatus(d));
3175}
3176
3177/* True if we *can cheaply determine* that a and b use the same offset.
3178 If they use different offsets or it would be expensive to find out, false.
3179 Calls to toMSecsSinceEpoch() are expensive, for these purposes.
3180 See QDateTime's comparison operators and areFarEnoughApart().
3181*/
3182static inline bool usesSameOffset(const QDateTimeData &a, const QDateTimeData &b)
3183{
3184 const auto status = getStatus(a);
3185 if (status != getStatus(b))
3186 return false;
3187 // Status includes DST-ness, so we now know they match in it.
3188
3189 switch (extractSpec(status)) {
3190 case Qt::LocalTime:
3191 case Qt::UTC:
3192 return true;
3193
3194 case Qt::TimeZone:
3195 /* TimeZone always determines its offset during construction of the
3196 private data. Even if we're in different zones, what matters is the
3197 offset actually in effect at the specific time. (DST can cause things
3198 with the same time-zone to use different offsets, but we already
3199 checked their DSTs match.) */
3200 case Qt::OffsetFromUTC: // always knows its offset, which is all that matters.
3201 Q_ASSERT(!a.isShort() && !b.isShort());
3202 return a->m_offsetFromUtc == b->m_offsetFromUtc;
3203 }
3204 Q_UNREACHABLE_RETURN(false);
3205}
3206
3207/* Even datetimes with different offset can be ordered by their getMSecs()
3208 provided the difference is bigger than the largest difference in offset we're
3209 prepared to believe in. Technically, it may be possible to construct a zone
3210 with an offset outside the range and get wrong results - but the answer to
3211 someone doing that is that their contrived timezone and its consequences are
3212 their own responsibility.
3213
3214 If two datetimes' millis lie within the offset range of one another, we can't
3215 take any short-cuts, even if they're in the same zone, because there may be a
3216 zone transition between them. (The full 32-hour difference would only arise
3217 before 1845, for one date-time in The Philippines, the other in Alaska.)
3218*/
3219bool areFarEnoughApart(qint64 leftMillis, qint64 rightMillis)
3220{
3221 constexpr quint64 UtcOffsetMillisRange
3222 = quint64(QTimeZone::MaxUtcOffsetSecs - QTimeZone::MinUtcOffsetSecs) * MSECS_PER_SEC;
3223 qint64 gap = 0;
3224 return qSubOverflow(leftMillis, rightMillis, &gap) || QtPrivate::qUnsignedAbs(gap) > UtcOffsetMillisRange;
3225}
3226
3227// Refresh the LocalTime or TimeZone validity and offset
3228static void refreshZonedDateTime(QDateTimeData &d, const QTimeZone &zone,
3229 QDateTimePrivate::TransitionOptions resolve)
3230{
3231 Q_ASSERT(zone.timeSpec() == Qt::TimeZone || zone.timeSpec() == Qt::LocalTime);
3232 auto status = getStatus(d);
3233 Q_ASSERT(extractSpec(status) == zone.timeSpec());
3234 int offsetFromUtc = 0;
3235 /* Callers are:
3236 * QDTP::create(), where d is too new to be shared yet
3237 * reviseTimeZone(), which detach()es if not short before calling this
3238 * checkValidDateTime(), always follows a setDateTime() that detach()ed if not short
3239
3240 So we can assume d is not shared. We only need to detach() if we convert
3241 from short to pimpled to accommodate an oversize msecs, which can only be
3242 needed in the unlikely event we revise it.
3243 */
3244
3245 // If not valid date and time then is invalid
3246 if (!status.testFlags(QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime)) {
3247 status.setFlag(QDateTimePrivate::ValidDateTime, false);
3248 } else {
3249 // We have a valid date and time and a Qt::LocalTime or Qt::TimeZone
3250 // that might fall into a "missing" DST transition hour.
3251 qint64 msecs = getMSecs(d);
3252 QDateTimePrivate::ZoneState state = stateAtMillis(zone, msecs, resolve);
3253 Q_ASSERT(!state.valid || (state.offset >= -SECS_PER_DAY && state.offset <= SECS_PER_DAY));
3254 if (state.dst == QDateTimePrivate::UnknownDaylightTime) { // Overflow
3255 status.setFlag(QDateTimePrivate::ValidDateTime, false);
3256 } else if (state.valid) {
3257 status = mergeDaylightStatus(status, state.dst);
3258 offsetFromUtc = state.offset;
3259 status.setFlag(QDateTimePrivate::ValidDateTime, true);
3260 if (Q_UNLIKELY(msecs != state.when)) {
3261 // Update msecs to the resolution:
3262 if (status.testFlag(QDateTimePrivate::ShortData)) {
3263 if (msecsCanBeSmall(state.when)) {
3264 d.data.msecs = qintptr(state.when);
3265 } else {
3266 // Convert to long-form so we can hold the revised msecs:
3267 status.setFlag(QDateTimePrivate::ShortData, false);
3268 d.detach();
3269 }
3270 }
3271 if (!status.testFlag(QDateTimePrivate::ShortData))
3272 d->m_msecs = state.when;
3273 }
3274 } else {
3275 status.setFlag(QDateTimePrivate::ValidDateTime, false);
3276 }
3277 }
3278
3279 if (status.testFlag(QDateTimePrivate::ShortData)) {
3280 d.data.status = status.toInt();
3281 } else {
3282 d->m_status = status;
3283 d->m_offsetFromUtc = offsetFromUtc;
3284 }
3285}
3286
3287// Check the UTC / offsetFromUTC validity
3289{
3290 auto status = getStatus(d);
3291 Q_ASSERT(QTimeZone::isUtcOrFixedOffset(extractSpec(status)));
3292 status.setFlag(QDateTimePrivate::ValidDateTime,
3293 status.testFlags(QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime));
3294
3295 if (status.testFlag(QDateTimePrivate::ShortData))
3296 d.data.status = status.toInt();
3297 else
3298 d->m_status = status;
3299}
3300
3301// Clean up and set status after assorted set-up or reworking:
3302static void checkValidDateTime(QDateTimeData &d, QDateTime::TransitionResolution resolve)
3303{
3304 auto spec = extractSpec(getStatus(d));
3305 switch (spec) {
3306 case Qt::OffsetFromUTC:
3307 case Qt::UTC:
3308 // for these, a valid date and a valid time imply a valid QDateTime
3310 break;
3311 case Qt::TimeZone:
3312 case Qt::LocalTime:
3313 // For these, we need to check whether (the zone is valid and) the time
3314 // is valid for the zone. Expensive, but we have no other option.
3315 refreshZonedDateTime(d, d.timeZone(), toTransitionOptions(resolve));
3316 break;
3317 }
3318}
3319
3320static void reviseTimeZone(QDateTimeData &d, const QTimeZone &zone,
3321 QDateTime::TransitionResolution resolve)
3322{
3323 Qt::TimeSpec spec = zone.timeSpec();
3324 auto status = mergeSpec(getStatus(d), spec);
3325 bool reuse = d.isShort();
3326 int offset = 0;
3327
3328 switch (spec) {
3329 case Qt::UTC:
3330 Q_ASSERT(zone.fixedSecondsAheadOfUtc() == 0);
3331 break;
3332 case Qt::OffsetFromUTC:
3333 reuse = false;
3334 offset = zone.fixedSecondsAheadOfUtc();
3335 Q_ASSERT(offset);
3336 break;
3337 case Qt::TimeZone:
3338 reuse = false;
3339 break;
3340 case Qt::LocalTime:
3341 break;
3342 }
3343
3344 status &= ~(QDateTimePrivate::ValidDateTime | QDateTimePrivate::DaylightMask);
3345 if (reuse) {
3346 d.data.status = status.toInt();
3347 } else {
3348 d.detach();
3349 d->m_status = status & ~QDateTimePrivate::ShortData;
3350 d->m_offsetFromUtc = offset;
3351#if QT_CONFIG(timezone)
3352 if (spec == Qt::TimeZone)
3353 d->m_timeZone = zone;
3354#endif // timezone
3355 }
3356
3357 if (QTimeZone::isUtcOrFixedOffset(spec))
3359 else
3360 refreshZonedDateTime(d, zone, toTransitionOptions(resolve));
3361}
3362
3363static void setDateTime(QDateTimeData &d, QDate date, QTime time)
3364{
3365 // If the date is valid and the time is not we set time to 00:00:00
3366 if (!time.isValid() && date.isValid())
3367 time = QTime::fromMSecsSinceStartOfDay(0);
3368
3369 QDateTimePrivate::StatusFlags newStatus = { };
3370
3371 // Set date value and status
3372 qint64 days = 0;
3373 if (date.isValid()) {
3374 days = date.toJulianDay() - JULIAN_DAY_FOR_EPOCH;
3375 newStatus = QDateTimePrivate::ValidDate;
3376 }
3377
3378 // Set time value and status
3379 int ds = 0;
3380 if (time.isValid()) {
3381 ds = time.msecsSinceStartOfDay();
3382 newStatus |= QDateTimePrivate::ValidTime;
3383 }
3384 Q_ASSERT(ds < MSECS_PER_DAY);
3385 // Only the later parts of the very first day are representable - its start
3386 // would overflow - so get ds the same side of 0 as days:
3387 if (days < 0 && ds > 0) {
3388 days++;
3389 ds -= MSECS_PER_DAY;
3390 }
3391
3392 // Check in representable range:
3393 qint64 msecs = 0;
3394 if (daysAndMillisOverflow(days, qint64(ds), &msecs)) {
3395 newStatus = QDateTimePrivate::StatusFlags{};
3396 msecs = 0;
3397 }
3398 if (d.isShort()) {
3399 // let's see if we can keep this short
3400 if (msecsCanBeSmall(msecs)) {
3401 // yes, we can
3402 d.data.msecs = qintptr(msecs);
3403 d.data.status &= ~(QDateTimePrivate::ValidityMask | QDateTimePrivate::DaylightMask).toInt();
3404 d.data.status |= newStatus.toInt();
3405 } else {
3406 // nope...
3407 d.detach();
3408 }
3409 }
3410 if (!d.isShort()) {
3411 d.detach();
3412 d->m_msecs = msecs;
3413 d->m_status &= ~(QDateTimePrivate::ValidityMask | QDateTimePrivate::DaylightMask);
3414 d->m_status |= newStatus;
3415 }
3416}
3417
3418static std::pair<QDate, QTime> getDateTime(const QDateTimeData &d)
3419{
3420 auto status = getStatus(d);
3421 const qint64 msecs = getMSecs(d);
3422 const auto dayMilli = QRoundingDown::qDivMod<MSECS_PER_DAY>(msecs);
3423 return { status.testFlag(QDateTimePrivate::ValidDate)
3424 ? QDate::fromJulianDay(JULIAN_DAY_FOR_EPOCH + dayMilli.quotient)
3425 : QDate(),
3426 status.testFlag(QDateTimePrivate::ValidTime)
3427 ? QTime::fromMSecsSinceStartOfDay(dayMilli.remainder)
3428 : QTime() };
3429}
3430
3431/*****************************************************************************
3432 QDateTime::Data member functions
3433 *****************************************************************************/
3434
3435inline QDateTime::Data::Data() noexcept
3436{
3437 // default-constructed data has a special exception:
3438 // it can be small even if CanBeSmall == false
3439 // (optimization so we don't allocate memory in the default constructor)
3440 quintptr value = mergeSpec(QDateTimePrivate::ShortData, Qt::LocalTime).toInt();
3441 d = reinterpret_cast<QDateTimePrivate *>(value);
3442}
3443
3444inline QDateTime::Data::Data(const QTimeZone &zone)
3445{
3446 Qt::TimeSpec spec = zone.timeSpec();
3447 if (CanBeSmall && Q_LIKELY(specCanBeSmall(spec))) {
3448 quintptr value = mergeSpec(QDateTimePrivate::ShortData, spec).toInt();
3449 d = reinterpret_cast<QDateTimePrivate *>(value);
3450 Q_ASSERT(isShort());
3451 } else {
3452 // the structure is too small, we need to detach
3453 d = new QDateTimePrivate;
3454 d->ref.ref();
3455 d->m_status = mergeSpec({}, spec);
3456 if (spec == Qt::OffsetFromUTC)
3457 d->m_offsetFromUtc = zone.fixedSecondsAheadOfUtc();
3458 else if (spec == Qt::TimeZone)
3459 d->m_timeZone = zone;
3460 Q_ASSERT(!isShort());
3461 }
3462}
3463
3464inline QDateTime::Data::Data(const Data &other) noexcept
3465 : data(other.data)
3466{
3467 if (!isShort()) {
3468 // check if we could shrink
3469 if (specCanBeSmall(extractSpec(d->m_status)) && msecsCanBeSmall(d->m_msecs)) {
3470 ShortData sd;
3471 sd.msecs = qintptr(d->m_msecs);
3472 sd.status = (d->m_status | QDateTimePrivate::ShortData).toInt();
3473 data = sd;
3474 } else {
3475 // no, have to keep it big
3476 d->ref.ref();
3477 }
3478 }
3479}
3480
3481inline QDateTime::Data::Data(Data &&other) noexcept
3482 : data(other.data)
3483{
3484 // reset the other to a short state
3485 Data dummy;
3486 Q_ASSERT(dummy.isShort());
3487 other.data = dummy.data;
3488}
3489
3490inline QDateTime::Data &QDateTime::Data::operator=(const Data &other) noexcept
3491{
3492 if (isShort() ? data == other.data : d == other.d)
3493 return *this;
3494
3495 auto x = d;
3496 d = other.d;
3497 if (!other.isShort()) {
3498 // check if we could shrink
3499 if (specCanBeSmall(extractSpec(other.d->m_status)) && msecsCanBeSmall(other.d->m_msecs)) {
3500 ShortData sd;
3501 sd.msecs = qintptr(other.d->m_msecs);
3502 sd.status = (other.d->m_status | QDateTimePrivate::ShortData).toInt();
3503 data = sd;
3504 } else {
3505 // no, have to keep it big
3506 other.d->ref.ref();
3507 }
3508 }
3509
3510 if (!(quintptr(x) & QDateTimePrivate::ShortData) && !x->ref.deref())
3511 delete x;
3512 return *this;
3513}
3514
3515inline QDateTime::Data::~Data()
3516{
3517 if (!isShort() && !d->ref.deref())
3518 delete d;
3519}
3520
3521inline bool QDateTime::Data::isShort() const
3522{
3523 bool b = quintptr(d) & QDateTimePrivate::ShortData;
3524
3525 // sanity check:
3526 Q_ASSERT(b || !d->m_status.testFlag(QDateTimePrivate::ShortData));
3527
3528 // even if CanBeSmall = false, we have short data for a default-constructed
3529 // QDateTime object. But it's unlikely.
3530 if constexpr (CanBeSmall)
3531 return Q_LIKELY(b);
3532 return Q_UNLIKELY(b);
3533}
3534
3535inline void QDateTime::Data::detach()
3536{
3537 QDateTimePrivate *x;
3538 bool wasShort = isShort();
3539 if (wasShort) {
3540 // force enlarging
3541 x = new QDateTimePrivate;
3542 x->m_status = QDateTimePrivate::StatusFlags::fromInt(data.status) & ~QDateTimePrivate::ShortData;
3543 x->m_msecs = data.msecs;
3544 } else {
3545 if (d->ref.loadRelaxed() == 1)
3546 return;
3547
3548 x = new QDateTimePrivate(*d);
3549 }
3550
3551 x->ref.storeRelaxed(1);
3552 if (!wasShort && !d->ref.deref())
3553 delete d;
3554 d = x;
3555}
3556
3557void QDateTime::Data::invalidate()
3558{
3559 if (isShort()) {
3560 data.status &= ~int(QDateTimePrivate::ValidityMask);
3561 } else {
3562 detach();
3563 d->m_status &= ~QDateTimePrivate::ValidityMask;
3564 }
3565}
3566
3567QTimeZone QDateTime::Data::timeZone() const
3568{
3569 switch (getSpec(*this)) {
3570 case Qt::UTC:
3571 return QTimeZone::UTC;
3572 case Qt::OffsetFromUTC:
3573 return QTimeZone::fromSecondsAheadOfUtc(d->m_offsetFromUtc);
3574 case Qt::TimeZone:
3575#if QT_CONFIG(timezone)
3576 if (d->m_timeZone.isValid())
3577 return d->m_timeZone;
3578#endif
3579 break;
3580 case Qt::LocalTime:
3581 return QTimeZone::LocalTime;
3582 }
3583 return QTimeZone();
3584}
3585
3586inline const QDateTimePrivate *QDateTime::Data::operator->() const
3587{
3588 Q_ASSERT(!isShort());
3589 return d;
3590}
3591
3592inline QDateTimePrivate *QDateTime::Data::operator->()
3593{
3594 // should we attempt to detach here?
3595 Q_ASSERT(!isShort());
3596 Q_ASSERT(d->ref.loadRelaxed() == 1);
3597 return d;
3598}
3599
3600/*****************************************************************************
3601 QDateTimePrivate member functions
3602 *****************************************************************************/
3603
3604Q_NEVER_INLINE
3605QDateTime::Data QDateTimePrivate::create(QDate toDate, QTime toTime, const QTimeZone &zone,
3606 QDateTime::TransitionResolution resolve)
3607{
3608 QDateTime::Data result(zone);
3609 setDateTime(result, toDate, toTime);
3610 if (zone.isUtcOrFixedOffset())
3611 refreshSimpleDateTime(result);
3612 else
3613 refreshZonedDateTime(result, zone, toTransitionOptions(resolve));
3614 return result;
3615}
3616
3617/*****************************************************************************
3618 QDateTime member functions
3619 *****************************************************************************/
3620
3621/*!
3622 \class QDateTime
3623 \inmodule QtCore
3624 \ingroup shared
3625 \reentrant
3626 \brief The QDateTime class provides date and time functions.
3627
3628 \compares weak
3629
3630 A QDateTime object encodes a calendar date and a clock time (a "datetime")
3631 in accordance with a time representation. It combines features of the QDate
3632 and QTime classes. It can read the current datetime from the system
3633 clock. It provides functions for comparing datetimes and for manipulating a
3634 datetime by adding a number of seconds, days, months, or years.
3635
3636 QDateTime can describe datetimes with respect to \l{Qt::LocalTime}{local
3637 time}, to \l{Qt::UTC}{UTC}, to a specified \l{Qt::OffsetFromUTC}{offset from
3638 UTC} or to a specified \l{Qt::TimeZone}{time zone}. Each of these time
3639 representations can be encapsulated in a suitable instance of the QTimeZone
3640 class. For example, a time zone of "Europe/Berlin" will apply the
3641 daylight-saving rules as used in Germany. In contrast, a fixed offset from
3642 UTC of +3600 seconds is one hour ahead of UTC (usually written in ISO
3643 standard notation as "UTC+01:00"), with no daylight-saving
3644 complications. When using either local time or a specified time zone,
3645 time-zone transitions (see \l {Timezone transitions}{below}) are taken into
3646 account. A QDateTime's timeSpec() will tell you which of the four types of
3647 time representation is in use; its timeRepresentation() provides a full
3648 description of that time representation, as a QTimeZone.
3649
3650 A QDateTime object is typically created either by giving a date and time
3651 explicitly in the constructor, or by using a static function such as
3652 currentDateTime() or fromMSecsSinceEpoch(). The date and time can be changed
3653 with setDate() and setTime(). A datetime can also be set using the
3654 setMSecsSinceEpoch() function that takes the time, in milliseconds, since
3655 the start, in UTC, of the year 1970. The fromString() function returns a
3656 QDateTime, given a string and a date format used to interpret the date
3657 within the string.
3658
3659 QDateTime::currentDateTime() returns a QDateTime that expresses the current
3660 date and time with respect to a specific time representation, such as local
3661 time (its default). QDateTime::currentDateTimeUtc() returns a QDateTime that
3662 expresses the current date and time with respect to UTC; it is equivalent to
3663 \c {QDateTime::currentDateTime(QTimeZone::UTC)}.
3664
3665 The date() and time() functions provide access to the date and
3666 time parts of the datetime. The same information is provided in
3667 textual format by the toString() function.
3668
3669 QDateTime provides a full set of operators to compare two
3670 QDateTime objects, where smaller means earlier and larger means
3671 later.
3672
3673 You can increment (or decrement) a datetime by a given number of
3674 milliseconds using addMSecs(), seconds using addSecs(), or days using
3675 addDays(). Similarly, you can use addMonths() and addYears(). The daysTo()
3676 function returns the number of days between two datetimes, secsTo() returns
3677 the number of seconds between two datetimes, and msecsTo() returns the
3678 number of milliseconds between two datetimes. These operations are aware of
3679 daylight-saving time (DST) and other time-zone transitions, where
3680 applicable.
3681
3682 Use toTimeZone() to re-express a datetime in terms of a different time
3683 representation. By passing a lightweight QTimeZone that represents local
3684 time, UTC or a fixed offset from UTC, you can convert the datetime to use
3685 the corresponding time representation; or you can pass a full time zone
3686 (whose \l {QTimeZone::timeSpec()}{timeSpec()} is \c {Qt::TimeZone}) to use
3687 that instead.
3688
3689 \section1 Remarks
3690
3691 QDateTime does not account for leap seconds.
3692
3693 All conversions to and from string formats are done using the C locale.
3694 For localized conversions, see QLocale.
3695
3696 There is no year 0 in the Gregorian calendar. Dates in that year are
3697 considered invalid. The year -1 is the year "1 before Christ" or "1 before
3698 common era." The day before 1 January 1 CE is 31 December 1 BCE.
3699
3700 Using local time (the default) or a specified time zone implies a need
3701 to resolve any issues around \l {Timezone transitions}{transitions}. As a
3702 result, operations on such QDateTime instances (notably including
3703 constructing them) may be more expensive than the equivalent when using UTC
3704 or a fixed offset from it.
3705
3706 \section2 Range of Valid Dates
3707
3708 The range of values that QDateTime can represent is dependent on the
3709 internal storage implementation. QDateTime is currently stored in a qint64
3710 as a serial msecs value encoding the date and time. This restricts the date
3711 range to about ±292 million years, compared to the QDate range of ±2 billion
3712 years. Care must be taken when creating a QDateTime with extreme values that
3713 you do not overflow the storage. The exact range of supported values varies
3714 depending on the time representation used.
3715
3716 \section2 Use of Timezones
3717
3718 QDateTime uses the system's time zone information to determine the current
3719 local time zone and its offset from UTC. If the system is not configured
3720 correctly or not up-to-date, QDateTime will give wrong results.
3721
3722 QDateTime likewise uses system-provided information to determine the offsets
3723 of other timezones from UTC. If this information is incomplete or out of
3724 date, QDateTime will give wrong results. See the QTimeZone documentation for
3725 more details.
3726
3727 On modern Unix systems, this means QDateTime usually has accurate
3728 information about historical transitions (including DST, see below) whenever
3729 possible. On Windows, where the system doesn't support historical timezone
3730 data, historical accuracy is not maintained with respect to timezone
3731 transitions, notably including DST. However, building Qt with the ICU
3732 library will equip QTimeZone with the same timezone database as is used on
3733 Unix.
3734
3735 \section2 Timezone transitions
3736
3737 QDateTime takes into account timezone transitions, both the transitions
3738 between Standard Time and Daylight-Saving Time (DST) and the transitions
3739 that arise when a zone changes its standard offset. For example, if the
3740 transition is at 2am and the clock goes forward to 3am, then there is a
3741 "missing" hour from 02:00:00 to 02:59:59.999. Such a transition is known as
3742 a "spring forward" and the times skipped over have no meaning. When a
3743 transition goes the other way, known as a "fall back", a time interval is
3744 repeated, first in the old zone (usually DST), then in the new zone (usually
3745 Standard Time), so times in this interval are ambiguous.
3746
3747 Some zones use "reversed" DST, using standard time in summer and
3748 daylight-saving time (with a lowered offset) in winter. For such zones, the
3749 spring forward still happens in spring and skips an hour, but is a
3750 transition \e{out of} daylight-saving time, while the fall back still
3751 repeats an autumn hour but is a transition \e to daylight-saving time.
3752
3753 When converting from a UTC time (or a time at fixed offset from UTC), there
3754 is always an unambiguous valid result in any timezone. However, when
3755 combining a date and time to make a datetime, expressed with respect to
3756 local time or a specific time-zone, the nominal result may fall in a
3757 transition, making it either invalid or ambiguous. Methods where this
3758 situation may arise take a \c resolve parameter: this is always ignored if
3759 the requested datetime is valid and unambiguous. See \l TransitionResolution
3760 for the options it lets you control. Prior to Qt 6.7, the equivalent of its
3761 \l LegacyBehavior was selected.
3762
3763 For a spring forward's skipped interval, interpreting the requested time
3764 with either offset yields an actual time at which the other offset was in
3765 use; so passing \c TransitionResolution::RelativeToBefore for \c resolve
3766 will actually result in a time after the transition, that would have had the
3767 requested representation had the transition not happened. Likewise, \c
3768 TransitionResolution::RelativeToAfter for \c resolve results in a time
3769 before the transition, that would have had the requested representation, had
3770 the transition happened earlier.
3771
3772 When QDateTime performs arithmetic, as with addDay() or addSecs(), it takes
3773 care to produce a valid result. For example, on a day when there is a spring
3774 forward from 02:00 to 03:00, adding one second to 01:59:59 will get
3775 03:00:00. Adding one day to 02:30 on the preceding day will get 03:30 on the
3776 day of the transition, while subtracting one day, by calling \c{addDay(-1)},
3777 to 02:30 on the following day will get 01:30 on the day of the transition.
3778 While addSecs() will deliver a time offset by the given number of seconds,
3779 addDays() adjusts the date and only adjusts time if it would otherwise get
3780 an invalid result. Applying \c{addDays(1)} to 03:00 on the day before the
3781 spring-forward will simply get 03:00 on the day of the transition, even
3782 though the latter is only 23 hours after the former; but \c{addSecs(24 * 60
3783 * 60)} will get 04:00 on the day of the transition, since that's 24 hours
3784 later. Typical transitions make some days 23 or 25 hours long.
3785
3786 For datetimes that the system \c time_t can represent (from 1901-12-14 to
3787 2038-01-18 on systems with 32-bit \c time_t; for the full range QDateTime
3788 can represent if the type is 64-bit), the standard system APIs are used to
3789 determine local time's offset from UTC. For datetimes not handled by these
3790 system APIs (potentially including some within the \c time_t range),
3791 QTimeZone::systemTimeZone() is used, if available, or a best effort is made
3792 to estimate. In any case, the offset information used depends on the system
3793 and may be incomplete or, for past times, historically
3794 inaccurate. Furthermore, for future dates, the local time zone's offsets and
3795 DST rules may change before that date comes around.
3796
3797 \section3 Whole day transitions
3798
3799 A small number of zones have skipped or repeated entire days as part of
3800 moving The International Date Line across themselves. For these, daysTo()
3801 will be unaware of the duplication or gap, simply using the difference in
3802 calendar date; in contrast, msecsTo() and secsTo() know the true time
3803 interval. Likewise, addMSecs() and addSecs() correspond directly to elapsed
3804 time, where addDays(), addMonths() and addYears() follow the nominal
3805 calendar, aside from where landing in a gap or duplication requires
3806 resolving an ambiguity or invalidity due to a duplication or omission.
3807
3808 \note Days "lost" during a change of calendar, such as from Julian to
3809 Gregorian, do not affect QDateTime. Although the two calendars describe
3810 dates differently, the successive days across the change are described by
3811 consecutive QDate instances, each one day later than the previous, as
3812 described by either calendar or by their toJulianDay() values. In contrast,
3813 a zone skipping or duplicating a day is changing its description of \e time,
3814 not date, for all that it does so by a whole 24 hours.
3815
3816 \section2 Offsets From UTC
3817
3818 Offsets from UTC are measured in seconds east of Greenwich. The moment
3819 described by a particular date and time, such as noon on a particular day,
3820 depends on the time representation used. Those with a higher offset from UTC
3821 describe an earlier moment, and those with a lower offset a later moment, by
3822 any given combination of date and time.
3823
3824 There is no explicit size restriction on an offset from UTC, but there is an
3825 implicit limit imposed when using the toString() and fromString() methods
3826 which use a ±hh:mm format, effectively limiting the range to ± 99 hours and
3827 59 minutes and whole minutes only. Note that currently no time zone has an
3828 offset outside the range of ±14 hours and all known offsets are multiples of
3829 five minutes. Historical time zones have a wider range and may have offsets
3830 including seconds; these last cannot be faithfully represented in strings.
3831
3832 \sa QDate, QTime, QDateTimeEdit, QTimeZone
3833*/
3834
3835/*!
3836 \since 5.14
3837 \enum QDateTime::YearRange
3838
3839 This enumerated type describes the range of years (in the Gregorian
3840 calendar) representable by QDateTime:
3841
3842 \value First The later parts of this year are representable
3843 \value Last The earlier parts of this year are representable
3844
3845 All dates strictly between these two years are also representable.
3846 Note, however, that the Gregorian Calendar has no year zero.
3847
3848 \note QDate can describe dates in a wider range of years. For most
3849 purposes, this makes little difference, as the range of years that QDateTime
3850 can support reaches 292 million years either side of 1970.
3851
3852 \sa isValid(), QDate
3853*/
3854
3855/*!
3856 \since 6.7
3857 \enum QDateTime::TransitionResolution
3858
3859 This enumeration is used to resolve datetime combinations which fall in \l
3860 {Timezone transitions}.
3861
3862 When constructing a datetime, specified in terms of local time or a
3863 time-zone that has daylight-saving time, or revising one with setDate(),
3864 setTime() or setTimeZone(), the given parameters may imply a time
3865 representation that either has no meaning or has two meanings in the
3866 zone. Such time representations are described as being in the transition. In
3867 either case, we can simply return an invalid datetime, to indicate that the
3868 operation is ill-defined. In the ambiguous case, we can alternatively select
3869 one of the two times that could be meant. When there is no meaning, we can
3870 select a time either side of it that might plausibly have been meant. For
3871 example, when advancing from an earlier time, we can select the time after
3872 the transition that is actually the specified amount of time after the
3873 earlier time in question. The options specified here configure how such
3874 selection is performed.
3875
3876 \value Reject
3877 Treat any time in a transition as invalid. Either it really is, or it
3878 is ambiguous.
3879 \value RelativeToBefore
3880 Selects a time as if stepping forward from a time before the
3881 transition. This interprets the requested time using the offset in
3882 effect before the transition and, if necessary, converts the result
3883 to the offset in effect at the resulting time.
3884 \value RelativeToAfter
3885 Select a time as if stepping backward from a time after the
3886 transition. This interprets the requested time using the offset in
3887 effect after the transition and, if necessary, converts the result to
3888 the offset in effect at the resulting time.
3889 \value PreferBefore
3890 Selects a time before the transition,
3891 \value PreferAfter
3892 Selects a time after the transition.
3893 \value PreferStandard
3894 Selects a time on the standard time side of the transition.
3895 \value PreferDaylightSaving
3896 Selects a time on the daylight-saving-time side of the transition.
3897 \value LegacyBehavior
3898 An alias for RelativeToBefore, which is used as default for
3899 TransitionResolution parameters, as this most closely matches the
3900 behavior prior to Qt 6.7.
3901
3902 For \l addDays(), \l addMonths() or \l addYears(), the behavior is and
3903 (mostly) was to use \c RelativeToBefore if adding a positive adjustment and \c
3904 RelativeToAfter if adding a negative adjustment.
3905
3906 \note In time zones where daylight-saving increases the offset from UTC in
3907 summer (known as "positive DST"), PreferStandard is an alias for
3908 RelativeToAfter and PreferDaylightSaving for RelativeToBefore. In time zones
3909 where the daylight-saving mechanism is a decrease in offset from UTC in
3910 winter (known as "negative DST"), the reverse applies, provided the
3911 operating system reports - as it does on most platforms - whether a datetime
3912 is in DST or standard time. For some platforms, where transition times are
3913 unavailable even for Qt::TimeZone datetimes, QTimeZone is obliged to presume
3914 that the side with lower offset from UTC is standard time, effectively
3915 assuming positive DST.
3916
3917 The following tables illustrate how a QDateTime constructor resolves a
3918 request for 02:30 on a day when local time has a transition between 02:00
3919 and 03:00, with a nominal standard time LST and daylight-saving time LDT on
3920 the two sides, in the various possible cases. The transition type may be to
3921 skip an hour or repeat it. The type of transition and value of a parameter
3922 \c resolve determine which actual time on the given date is selected. First,
3923 the common case of positive daylight-saving, where:
3924
3925 \table
3926 \header \li Before \li 02:00--03:00 \li After \li \c resolve \li selected
3927 \row \li LST \li skip \li LDT \li RelativeToBefore \li 03:30 LDT
3928 \row \li LST \li skip \li LDT \li RelativeToAfter \li 01:30 LST
3929 \row \li LST \li skip \li LDT \li PreferBefore \li 01:30 LST
3930 \row \li LST \li skip \li LDT \li PreferAfter \li 03:30 LDT
3931 \row \li LST \li skip \li LDT \li PreferStandard \li 01:30 LST
3932 \row \li LST \li skip \li LDT \li PreferDaylightSaving \li 03:30 LDT
3933 \row \li LDT \li repeat \li LST \li RelativeToBefore \li 02:30 LDT
3934 \row \li LDT \li repeat \li LST \li RelativeToAfter \li 02:30 LST
3935 \row \li LDT \li repeat \li LST \li PreferBefore \li 02:30 LDT
3936 \row \li LDT \li repeat \li LST \li PreferAfter \li 02:30 LST
3937 \row \li LDT \li repeat \li LST \li PreferStandard \li 02:30 LST
3938 \row \li LDT \li repeat \li LST \li PreferDaylightSaving \li 02:30 LDT
3939 \endtable
3940
3941 Second, the case for negative daylight-saving, using LDT in winter and
3942 skipping an hour to transition to LST in summer, then repeating an hour at
3943 the transition back to winter:
3944
3945 \table
3946 \row \li LDT \li skip \li LST \li RelativeToBefore \li 03:30 LST
3947 \row \li LDT \li skip \li LST \li RelativeToAfter \li 01:30 LDT
3948 \row \li LDT \li skip \li LST \li PreferBefore \li 01:30 LDT
3949 \row \li LDT \li skip \li LST \li PreferAfter \li 03:30 LST
3950 \row \li LDT \li skip \li LST \li PreferStandard \li 03:30 LST
3951 \row \li LDT \li skip \li LST \li PreferDaylightSaving \li 01:30 LDT
3952 \row \li LST \li repeat \li LDT \li RelativeToBefore \li 02:30 LST
3953 \row \li LST \li repeat \li LDT \li RelativeToAfter \li 02:30 LDT
3954 \row \li LST \li repeat \li LDT \li PreferBefore \li 02:30 LST
3955 \row \li LST \li repeat \li LDT \li PreferAfter \li 02:30 LDT
3956 \row \li LST \li repeat \li LDT \li PreferStandard \li 02:30 LST
3957 \row \li LST \li repeat \li LDT \li PreferDaylightSaving \li 02:30 LDT
3958 \endtable
3959
3960 Reject can be used to prompt relevant QDateTime APIs to return an invalid
3961 datetime object so that your code can deal with transitions for itself, for
3962 example by alerting a user to the fact that the datetime they have selected
3963 is in a transition interval, to offer them the opportunity to resolve a
3964 conflict or ambiguity. Code using this may well find the other options above
3965 useful to determine relevant information to use in its own (or the user's)
3966 resolution. If the start or end of the transition, or the moment of the
3967 transition itself, is the right resolution, QTimeZone's transition APIs can
3968 be used to obtain that information. You can determine whether the transition
3969 is a repeated or skipped interval by using \l secsTo() to measure the actual
3970 time between noon on the previous and following days. The result will be
3971 less than 48 hours for a skipped interval (such as a spring-forward) and
3972 more than 48 hours for a repeated interval (such as a fall-back).
3973
3974 \note When a resolution other than Reject is specified, a valid QDateTime
3975 object is returned, if possible. If the requested date-time falls in a gap,
3976 the returned date-time will not have the time() requested - or, in some
3977 cases, the date(), if a whole day was skipped. You can thus detect when a
3978 gap is hit by comparing date() and time() to what was requested.
3979
3980 \section2 Relation to other datetime software
3981
3982 The Python programming language's datetime APIs have a \c fold parameter
3983 that corresponds to \c RelativeToBefore (\c{fold = True}) and \c
3984 RelativeToAfter (\c{fold = False}).
3985
3986 The \c Temporal proposal to replace JavaScript's \c Date offers four options
3987 for how to resolve a transition, as value for a \c disambiguation
3988 parameter. Its \c{'reject'} raises an exception, which roughly corresponds
3989 to \c Reject producing an invalid result. Its \c{'earlier'} and \c{'later'}
3990 options correspond to \c PreferBefore and \c PreferAfter. Its
3991 \c{'compatible'} option corresponds to \c RelativeToBefore (and Python's
3992 \c{fold = True}).
3993
3994 \sa {Timezone transitions}
3995*/
3996
3997/*!
3998 Constructs a null datetime, nominally using local time.
3999
4000 A null datetime is invalid, since its date and time are invalid.
4001
4002 \sa isValid(), setMSecsSinceEpoch(), setDate(), setTime(), setTimeZone()
4003*/
4004QDateTime::QDateTime() noexcept
4005{
4006#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED) || QT_POINTER_SIZE == 8
4007 static_assert(sizeof(ShortData) == sizeof(qint64));
4008 static_assert(sizeof(Data) == sizeof(qint64));
4009#endif
4010 static_assert(sizeof(ShortData) >= sizeof(void*), "oops, Data::swap() is broken!");
4011}
4012
4013#if QT_DEPRECATED_SINCE(6, 9)
4014/*!
4015 \deprecated [6.9] Use \c{QDateTime(date, time)} or \c{QDateTime(date, time, QTimeZone::fromSecondsAheadOfUtc(offsetSeconds))}.
4016
4017 Constructs a datetime with the given \a date and \a time, using the time
4018 representation implied by \a spec and \a offsetSeconds seconds.
4019
4020 If \a date is valid and \a time is not, the time will be set to midnight.
4021
4022 If \a spec is not Qt::OffsetFromUTC then \a offsetSeconds will be
4023 ignored. If \a spec is Qt::OffsetFromUTC and \a offsetSeconds is 0 then the
4024 timeSpec() will be set to Qt::UTC, i.e. an offset of 0 seconds.
4025
4026 If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
4027 i.e. the current system time zone. To create a Qt::TimeZone datetime
4028 use the correct constructor.
4029
4030 If \a date lies outside the range of dates representable by QDateTime, the
4031 result is invalid. If \a spec is Qt::LocalTime and the system's time-zone
4032 skipped over the given date and time, the result is invalid.
4033*/
4034QDateTime::QDateTime(QDate date, QTime time, Qt::TimeSpec spec, int offsetSeconds)
4035 : d(QDateTimePrivate::create(date, time, asTimeZone(spec, offsetSeconds, "QDateTime"),
4036 TransitionResolution::LegacyBehavior))
4037{
4038}
4039#endif // 6.9 deprecation
4040
4041/*!
4042 \since 5.2
4043 \overload primary
4044
4045 Constructs a datetime with the given \a date and \a time, using the time
4046 representation described by \a timeZone.
4047
4048 If \a date is valid and \a time is not, the time will be set to midnight.
4049 If \a timeZone is invalid then the datetime will be invalid. If \a date and
4050 \a time describe a moment close to a transition for \a timeZone, \a resolve
4051 controls how that situation is resolved.
4052
4053//! [pre-resolve-note]
4054 \note Prior to Qt 6.7, the version of this function lacked the \a resolve
4055 parameter so had no way to resolve the ambiguities related to transitions.
4056//! [pre-resolve-note]
4057*/
4058
4059QDateTime::QDateTime(QDate date, QTime time, const QTimeZone &timeZone, TransitionResolution resolve)
4060 : d(QDateTimePrivate::create(date, time, timeZone, resolve))
4061{
4062}
4063
4064/*!
4065 \since 6.5
4066 \overload
4067
4068 Constructs a datetime with the given \a date and \a time, using local time.
4069
4070 If \a date is valid and \a time is not, midnight will be used as the
4071 time. If \a date and \a time describe a moment close to a transition for
4072 local time, \a resolve controls how that situation is resolved.
4073
4074 \include qdatetime.cpp pre-resolve-note
4075*/
4076
4077QDateTime::QDateTime(QDate date, QTime time, TransitionResolution resolve)
4078 : d(QDateTimePrivate::create(date, time, QTimeZone::LocalTime, resolve))
4079{
4080}
4081
4082/*!
4083 Constructs a copy of the \a other datetime.
4084*/
4085QDateTime::QDateTime(const QDateTime &other) noexcept
4086 : d(other.d)
4087{
4088}
4089
4090/*!
4091 \since 5.8
4092 Moves the content of the temporary \a other datetime to this object and
4093 leaves \a other in an unspecified (but proper) state.
4094*/
4095QDateTime::QDateTime(QDateTime &&other) noexcept
4096 : d(std::move(other.d))
4097{
4098}
4099
4100/*!
4101 Destroys the datetime.
4102*/
4103QDateTime::~QDateTime()
4104{
4105}
4106
4107/*!
4108 Copies the \a other datetime into this and returns this copy.
4109*/
4110
4111QDateTime &QDateTime::operator=(const QDateTime &other) noexcept
4112{
4113 d = other.d;
4114 return *this;
4115}
4116/*!
4117 \fn void QDateTime::swap(QDateTime &other)
4118 \since 5.0
4119 \memberswap{datetime}
4120*/
4121
4122/*!
4123 Returns \c true if both the date and the time are null; otherwise
4124 returns \c false. A null datetime is invalid.
4125
4126 \sa QDate::isNull(), QTime::isNull(), isValid()
4127*/
4128
4129bool QDateTime::isNull() const
4130{
4131 // If date or time is invalid, we don't set datetime valid.
4132 return !getStatus(d).testAnyFlag(QDateTimePrivate::ValidityMask);
4133}
4134
4135/*!
4136 Returns \c true if this datetime represents a definite moment, otherwise \c false.
4137
4138 A datetime is valid if both its date and its time are valid and the time
4139 representation used gives a valid meaning to their combination. When the
4140 time representation is a specific time-zone or local time, there may be
4141 times on some dates that the zone skips in its representation, as when a
4142 daylight-saving transition skips an hour (typically during a night in
4143 spring). For example, if DST ends at 2am with the clock advancing to 3am,
4144 then datetimes from 02:00:00 to 02:59:59.999 on that day are invalid.
4145
4146 \sa QDateTime::YearRange, QDate::isValid(), QTime::isValid()
4147*/
4148
4149bool QDateTime::isValid() const
4150{
4151 return getStatus(d).testFlag(QDateTimePrivate::ValidDateTime);
4152}
4153
4154/*!
4155 Returns the date part of the datetime.
4156
4157 \sa setDate(), time(), timeRepresentation()
4158*/
4159
4160QDate QDateTime::date() const
4161{
4162 return getStatus(d).testFlag(QDateTimePrivate::ValidDate) ? msecsToDate(getMSecs(d)) : QDate();
4163}
4164
4165/*!
4166 Returns the time part of the datetime.
4167
4168 \sa setTime(), date(), timeRepresentation()
4169*/
4170
4171QTime QDateTime::time() const
4172{
4173 return getStatus(d).testFlag(QDateTimePrivate::ValidTime) ? msecsToTime(getMSecs(d)) : QTime();
4174}
4175
4176/*!
4177 Returns the time specification of the datetime.
4178
4179 This classifies its time representation as local time, UTC, a fixed offset
4180 from UTC (without indicating the offset) or a time zone (without giving the
4181 details of that time zone). Equivalent to
4182 \c{timeRepresentation().timeSpec()}.
4183
4184 \sa setTimeZone(), timeRepresentation(), date(), time()
4185*/
4186
4187Qt::TimeSpec QDateTime::timeSpec() const
4188{
4189 return getSpec(d);
4190}
4191
4192/*!
4193 \since 6.5
4194 Returns a QTimeZone identifying how this datetime represents time.
4195
4196 The timeSpec() of the returned QTimeZone will coincide with that of this
4197 datetime; if it is not Qt::TimeZone then the returned QTimeZone is a time
4198 representation. When their timeSpec() is Qt::OffsetFromUTC, the returned
4199 QTimeZone's fixedSecondsAheadOfUtc() supplies the offset. When timeSpec()
4200 is Qt::TimeZone, the QTimeZone object itself is the full representation of
4201 that time zone.
4202
4203 \sa timeZone(), setTimeZone(), QTimeZone::asBackendZone()
4204*/
4205
4206QTimeZone QDateTime::timeRepresentation() const
4207{
4208 return d.timeZone();
4209}
4210
4211#if QT_CONFIG(timezone)
4212/*!
4213 \since 5.2
4214
4215 Returns the time zone of the datetime.
4216
4217 The result is the same as \c{timeRepresentation().asBackendZone()}. In all
4218 cases, the result's \l {QTimeZone::timeSpec()}{timeSpec()} is Qt::TimeZone.
4219
4220 When timeSpec() is Qt::LocalTime, the result will describe local time at the
4221 time this method was called. It will not reflect subsequent changes to the
4222 system time zone, even when the QDateTime from which it was obtained does.
4223
4224 \sa timeRepresentation(), setTimeZone(), Qt::TimeSpec, QTimeZone::asBackendZone()
4225*/
4226
4227QTimeZone QDateTime::timeZone() const
4228{
4229 return d.timeZone().asBackendZone();
4230}
4231#endif // timezone
4232
4233/*!
4234 \since 5.2
4235
4236 Returns this datetime's Offset From UTC in seconds.
4237
4238 The result depends on timeSpec():
4239 \list
4240 \li \c Qt::UTC The offset is 0.
4241 \li \c Qt::OffsetFromUTC The offset is the value originally set.
4242 \li \c Qt::LocalTime The local time's offset from UTC is returned.
4243 \li \c Qt::TimeZone The offset used by the time-zone is returned.
4244 \endlist
4245
4246 For the last two, the offset at this date and time will be returned, taking
4247 account of Daylight-Saving Offset. The offset is the difference between the
4248 local time or time in the given time-zone and UTC time; it is positive in
4249 time-zones ahead of UTC (East of The Prime Meridian), negative for those
4250 behind UTC (West of The Prime Meridian).
4251
4252 \sa setTimeZone()
4253*/
4254
4255int QDateTime::offsetFromUtc() const
4256{
4257 const auto status = getStatus(d);
4258 if (!status.testFlags(QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime))
4259 return 0;
4260 // But allow invalid date-time (e.g. gap's resolution) to report its offset.
4261 if (!d.isShort())
4262 return d->m_offsetFromUtc;
4263
4264 auto spec = extractSpec(status);
4265 if (spec == Qt::LocalTime) {
4266 // We didn't cache the value, so we need to calculate it:
4267 const auto resolve = toTransitionOptions(extractDaylightStatus(status));
4268 return QDateTimePrivate::localStateAtMillis(getMSecs(d), resolve).offset;
4269 }
4270
4271 Q_ASSERT(spec == Qt::UTC);
4272 return 0;
4273}
4274
4275/*!
4276 \since 5.2
4277
4278 Returns the Time Zone Abbreviation for this datetime.
4279
4280 The returned string depends on timeSpec():
4281
4282 \list
4283 \li For Qt::UTC it is "UTC".
4284 \li For Qt::OffsetFromUTC it will be in the format "UTC±00:00".
4285 \li For Qt::LocalTime, the host system is queried.
4286 \li For Qt::TimeZone, the associated QTimeZone object is queried.
4287 \endlist
4288
4289 \note The abbreviation is not guaranteed to be unique, i.e. different time
4290 zones may have the same abbreviation. For Qt::LocalTime and Qt::TimeZone,
4291 when returned by the host system, the abbreviation may be localized.
4292
4293 \sa timeSpec(), QTimeZone::abbreviation()
4294*/
4295
4296QString QDateTime::timeZoneAbbreviation() const
4297{
4298 if (!isValid())
4299 return QString();
4300
4301 switch (getSpec(d)) {
4302 case Qt::UTC:
4303 return "UTC"_L1;
4304 case Qt::OffsetFromUTC:
4305 return "UTC"_L1 + toOffsetString(Qt::ISODate, d->m_offsetFromUtc);
4306 case Qt::TimeZone:
4307#if !QT_CONFIG(timezone)
4308 break;
4309#else
4310 Q_ASSERT(d->m_timeZone.isValid());
4311 return d->m_timeZone.abbreviation(*this);
4312#endif // timezone
4313 case Qt::LocalTime:
4314#if defined(Q_OS_WIN) && QT_CONFIG(timezone)
4315 // MS's tzname is a full MS-name, not an abbreviation:
4316 if (QString sys = QTimeZone::systemTimeZone().abbreviation(*this); !sys.isEmpty())
4317 return sys;
4318 // ... but, even so, a full name isn't as bad as empty.
4319#endif
4320 return QDateTimePrivate::localNameAtMillis(getMSecs(d),
4321 extractDaylightStatus(getStatus(d)));
4322 }
4323 return QString();
4324}
4325
4326/*!
4327 \since 5.2
4328
4329 Returns if this datetime falls in Daylight-Saving Time.
4330
4331 If the Qt::TimeSpec is not Qt::LocalTime or Qt::TimeZone then will always
4332 return false.
4333
4334 \sa timeSpec()
4335*/
4336
4337bool QDateTime::isDaylightTime() const
4338{
4339 if (!isValid())
4340 return false;
4341
4342 switch (getSpec(d)) {
4343 case Qt::UTC:
4344 case Qt::OffsetFromUTC:
4345 return false;
4346 case Qt::TimeZone:
4347#if !QT_CONFIG(timezone)
4348 break;
4349#else
4350 Q_ASSERT(d->m_timeZone.isValid());
4351 if (auto dst = extractDaylightStatus(getStatus(d));
4352 dst != QDateTimePrivate::UnknownDaylightTime) {
4353 return dst == QDateTimePrivate::DaylightTime;
4354 }
4355 return d->m_timeZone.d->isDaylightTime(toMSecsSinceEpoch());
4356#endif // timezone
4357 case Qt::LocalTime: {
4358 auto dst = extractDaylightStatus(getStatus(d));
4359 if (dst == QDateTimePrivate::UnknownDaylightTime) {
4360 dst = QDateTimePrivate::localStateAtMillis(
4361 getMSecs(d), toTransitionOptions(TransitionResolution::LegacyBehavior)).dst;
4362 }
4363 return dst == QDateTimePrivate::DaylightTime;
4364 }
4365 }
4366 return false;
4367}
4368
4369/*!
4370 Sets the date part of this datetime to \a date.
4371
4372 If no time is set yet, it is set to midnight. If \a date is invalid, this
4373 QDateTime becomes invalid.
4374
4375 If \a date and time() describe a moment close to a transition for this
4376 datetime's time representation, \a resolve controls how that situation is
4377 resolved.
4378
4379 \include qdatetime.cpp pre-resolve-note
4380
4381 \sa date(), setTime(), setTimeZone()
4382*/
4383
4384void QDateTime::setDate(QDate date, TransitionResolution resolve)
4385{
4386 setDateTime(d, date, time());
4387 checkValidDateTime(d, resolve);
4388}
4389
4390/*!
4391 Sets the time part of this datetime to \a time. If \a time is not valid,
4392 this function sets it to midnight. Therefore, it's possible to clear any
4393 set time in a QDateTime by setting it to a default QTime:
4394
4395 \code
4396 QDateTime dt = QDateTime::currentDateTime();
4397 dt.setTime(QTime());
4398 \endcode
4399
4400 If date() and \a time describe a moment close to a transition for this
4401 datetime's time representation, \a resolve controls how that situation is
4402 resolved.
4403
4404 \include qdatetime.cpp pre-resolve-note
4405
4406 \sa time(), setDate(), setTimeZone()
4407*/
4408
4409void QDateTime::setTime(QTime time, TransitionResolution resolve)
4410{
4411 setDateTime(d, date(), time);
4412 checkValidDateTime(d, resolve);
4413}
4414
4415#if QT_DEPRECATED_SINCE(6, 9)
4416/*!
4417 \deprecated [6.9] Use setTimeZone() instead
4418
4419 Sets the time specification used in this datetime to \a spec.
4420 The datetime may refer to a different point in time.
4421
4422 If \a spec is Qt::OffsetFromUTC then the timeSpec() will be set
4423 to Qt::UTC, i.e. an effective offset of 0.
4424
4425 If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
4426 i.e. the current system time zone.
4427
4428 Example:
4429 \snippet code/src_corelib_time_qdatetime.cpp 19
4430
4431 \sa setTimeZone(), timeSpec(), toTimeSpec(), setDate(), setTime()
4432*/
4433
4434void QDateTime::setTimeSpec(Qt::TimeSpec spec)
4435{
4436 reviseTimeZone(d, asTimeZone(spec, 0, "QDateTime::setTimeSpec"),
4437 TransitionResolution::LegacyBehavior);
4438}
4439
4440/*!
4441 \since 5.2
4442 \deprecated [6.9] Use setTimeZone(QTimeZone::fromSecondsAheadOfUtc(offsetSeconds)) instead
4443
4444 Sets the timeSpec() to Qt::OffsetFromUTC and the offset to \a offsetSeconds.
4445 The datetime may refer to a different point in time.
4446
4447 The maximum and minimum offset is 14 positive or negative hours. If
4448 \a offsetSeconds is larger or smaller than that, then the result is
4449 undefined.
4450
4451 If \a offsetSeconds is 0 then the timeSpec() will be set to Qt::UTC.
4452
4453 \sa setTimeZone(), isValid(), offsetFromUtc(), toOffsetFromUtc()
4454*/
4455
4456void QDateTime::setOffsetFromUtc(int offsetSeconds)
4457{
4458 reviseTimeZone(d, QTimeZone::fromSecondsAheadOfUtc(offsetSeconds),
4459 TransitionResolution::Reject);
4460}
4461#endif // 6.9 deprecations
4462
4463/*!
4464 \since 5.2
4465
4466 Sets the time zone used in this datetime to \a toZone.
4467
4468 The datetime may refer to a different point in time. It uses the time
4469 representation of \a toZone, which may change the meaning of its unchanged
4470 date() and time().
4471
4472 If \a toZone is invalid then the datetime will be invalid. Otherwise, this
4473 datetime's timeSpec() after the call will match \c{toZone.timeSpec()}.
4474
4475 If date() and time() describe a moment close to a transition for \a toZone,
4476 \a resolve controls how that situation is resolved.
4477
4478 \include qdatetime.cpp pre-resolve-note
4479
4480 \sa timeRepresentation(), timeZone(), Qt::TimeSpec
4481*/
4482
4483void QDateTime::setTimeZone(const QTimeZone &toZone, TransitionResolution resolve)
4484{
4485 reviseTimeZone(d, toZone, resolve);
4486}
4487
4488/*!
4489 \since 4.7
4490
4491 Returns the datetime as a number of milliseconds after the start, in UTC, of
4492 the year 1970.
4493
4494 On systems that do not support time zones, this function will
4495 behave as if local time were Qt::UTC.
4496
4497 The behavior for this function is undefined if the datetime stored in
4498 this object is not valid. However, for all valid dates, this function
4499 returns a unique value.
4500
4501 \sa toSecsSinceEpoch(), setMSecsSinceEpoch(), fromMSecsSinceEpoch()
4502*/
4503qint64 QDateTime::toMSecsSinceEpoch() const
4504{
4505 // Note: QDateTimeParser relies on this producing a useful result, even when
4506 // !isValid(), at least when the invalidity is a time in a fall-back (that
4507 // we'll have adjusted to lie outside it, but marked invalid because it's
4508 // not what was asked for). Other things may be doing similar. But that's
4509 // only relevant when we got enough data for resolution to find it invalid.
4510 const auto status = getStatus(d);
4511 if (!status.testFlags(QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime))
4512 return 0;
4513
4514 switch (extractSpec(status)) {
4515 case Qt::UTC:
4516 return getMSecs(d);
4517
4518 case Qt::OffsetFromUTC:
4519 Q_ASSERT(!d.isShort());
4520 return d->m_msecs - d->m_offsetFromUtc * MSECS_PER_SEC;
4521
4522 case Qt::LocalTime:
4523 if (status.testFlag(QDateTimePrivate::ShortData)) {
4524 // Short form has nowhere to cache the offset, so recompute.
4525 const auto resolve = toTransitionOptions(extractDaylightStatus(getStatus(d)));
4526 const auto state = QDateTimePrivate::localStateAtMillis(getMSecs(d), resolve);
4527 return state.when - state.offset * MSECS_PER_SEC;
4528 }
4529 // Use the offset saved by refreshZonedDateTime() on creation.
4530 return d->m_msecs - d->m_offsetFromUtc * MSECS_PER_SEC;
4531
4532 case Qt::TimeZone:
4533 Q_ASSERT(!d.isShort());
4534#if QT_CONFIG(timezone)
4535 // Use offset refreshZonedDateTime() saved on creation:
4536 if (d->m_timeZone.isValid())
4537 return d->m_msecs - d->m_offsetFromUtc * MSECS_PER_SEC;
4538#endif
4539 return 0;
4540 }
4541 Q_UNREACHABLE_RETURN(0);
4542}
4543
4544/*!
4545 \since 5.8
4546
4547 Returns the datetime as a number of seconds after the start, in UTC, of the
4548 year 1970.
4549
4550 On systems that do not support time zones, this function will
4551 behave as if local time were Qt::UTC.
4552
4553 The behavior for this function is undefined if the datetime stored in
4554 this object is not valid. However, for all valid dates, this function
4555 returns a unique value.
4556
4557 \sa toMSecsSinceEpoch(), fromSecsSinceEpoch(), setSecsSinceEpoch()
4558*/
4559qint64 QDateTime::toSecsSinceEpoch() const
4560{
4561 return toMSecsSinceEpoch() / MSECS_PER_SEC;
4562}
4563
4564/*!
4565 \since 4.7
4566
4567 Sets the datetime to represent a moment a given number, \a msecs, of
4568 milliseconds after the start, in UTC, of the year 1970.
4569
4570 On systems that do not support time zones, this function will
4571 behave as if local time were Qt::UTC.
4572
4573 Note that passing the minimum of \c qint64
4574 (\c{std::numeric_limits<qint64>::min()}) to \a msecs will result in
4575 undefined behavior.
4576
4577 \sa setSecsSinceEpoch(), toMSecsSinceEpoch(), fromMSecsSinceEpoch()
4578*/
4579void QDateTime::setMSecsSinceEpoch(qint64 msecs)
4580{
4581 auto status = getStatus(d);
4582 const auto spec = extractSpec(status);
4583 Q_ASSERT(specCanBeSmall(spec) || !d.isShort());
4584 QDateTimePrivate::ZoneState state(msecs);
4585
4586 status &= ~QDateTimePrivate::ValidityMask;
4587 if (QTimeZone::isUtcOrFixedOffset(spec)) {
4588 if (spec == Qt::OffsetFromUTC)
4589 state.offset = d->m_offsetFromUtc;
4590 if (!state.offset || !qAddOverflow(msecs, state.offset * MSECS_PER_SEC, &state.when))
4591 status |= QDateTimePrivate::ValidityMask;
4592 } else if (spec == Qt::LocalTime) {
4593 state = QDateTimePrivate::expressUtcAsLocal(msecs);
4594 if (state.valid)
4595 status = mergeDaylightStatus(status | QDateTimePrivate::ValidityMask, state.dst);
4596#if QT_CONFIG(timezone)
4597 } else if (spec == Qt::TimeZone && (d.detach(), d->m_timeZone.isValid())) {
4598 const auto data = d->m_timeZone.d->data(msecs);
4599 if (Q_LIKELY(data.offsetFromUtc != QTimeZonePrivate::invalidSeconds())) {
4600 state.offset = data.offsetFromUtc;
4601 Q_ASSERT(state.offset >= -SECS_PER_DAY && state.offset <= SECS_PER_DAY);
4602 if (!state.offset
4603 || !Q_UNLIKELY(qAddOverflow(msecs, state.offset * MSECS_PER_SEC, &state.when))) {
4604 d->m_status = mergeDaylightStatus(status | QDateTimePrivate::ValidityMask,
4605 data.daylightTimeOffset
4606 ? QDateTimePrivate::DaylightTime
4607 : QDateTimePrivate::StandardTime);
4608 d->m_msecs = state.when;
4609 d->m_offsetFromUtc = state.offset;
4610 return;
4611 } // else: zone can't represent this UTC time
4612 } // else: zone unable to represent given UTC time (should only happen on overflow).
4613#endif // timezone
4614 }
4615 Q_ASSERT(!status.testFlag(QDateTimePrivate::ValidDateTime)
4616 || (state.offset >= -SECS_PER_DAY && state.offset <= SECS_PER_DAY));
4617
4618 if (msecsCanBeSmall(state.when) && d.isShort()) {
4619 // we can keep short
4620 d.data.msecs = qintptr(state.when);
4621 d.data.status = status.toInt();
4622 } else {
4623 d.detach();
4624 d->m_status = status & ~QDateTimePrivate::ShortData;
4625 d->m_msecs = state.when;
4626 d->m_offsetFromUtc = state.offset;
4627 }
4628}
4629
4630/*!
4631 \since 5.8
4632
4633 Sets the datetime to represent a moment a given number, \a secs, of seconds
4634 after the start, in UTC, of the year 1970.
4635
4636 On systems that do not support time zones, this function will
4637 behave as if local time were Qt::UTC.
4638
4639 \sa setMSecsSinceEpoch(), toSecsSinceEpoch(), fromSecsSinceEpoch()
4640*/
4641void QDateTime::setSecsSinceEpoch(qint64 secs)
4642{
4643 qint64 msecs;
4644 if (!qMulOverflow(secs, std::integral_constant<qint64, MSECS_PER_SEC>(), &msecs))
4645 setMSecsSinceEpoch(msecs);
4646 else
4647 d.invalidate();
4648}
4649
4650#if QT_CONFIG(datestring) // depends on, so implies, textdate
4651/*!
4652 \overload toString()
4653
4654 Returns the datetime as a string in the \a format given.
4655
4656 If the \a format is Qt::TextDate, the string is formatted in the default
4657 way. The day and month names will be in English. An example of this
4658 formatting is "Wed May 20 03:40:13 1998". For localized formatting, see
4659 \l{QLocale::toString()}.
4660
4661 If the \a format is Qt::ISODate, the string format corresponds to the ISO
4662 8601 extended specification for representations of dates and times, taking
4663 the form yyyy-MM-ddTHH:mm:ss[Z|±HH:mm], depending on the timeSpec() of the
4664 QDateTime. If the timeSpec() is Qt::UTC, Z will be appended to the string;
4665 if the timeSpec() is Qt::OffsetFromUTC, the offset in hours and minutes from
4666 UTC will be appended to the string. To include milliseconds in the ISO 8601
4667 date, use the \a format Qt::ISODateWithMs, which corresponds to
4668 yyyy-MM-ddTHH:mm:ss.zzz[Z|±HH:mm].
4669
4670 If the \a format is Qt::RFC2822Date, the string is formatted
4671 following \l{RFC 2822}.
4672
4673 If the datetime is invalid, an empty string will be returned.
4674
4675 \warning The Qt::ISODate format is only valid for years in the
4676 range 0 to 9999.
4677
4678 \sa fromString(), QDate::toString(), QTime::toString(),
4679 QLocale::toString()
4680*/
4681QString QDateTime::toString(Qt::DateFormat format) const
4682{
4683 QString buf;
4684 if (!isValid())
4685 return buf;
4686
4687 switch (format) {
4688 case Qt::RFC2822Date:
4689 buf = QLocale::c().toString(*this, u"dd MMM yyyy hh:mm:ss ");
4690 buf += toOffsetString(Qt::TextDate, offsetFromUtc());
4691 return buf;
4692 default:
4693 case Qt::TextDate: {
4694 const std::pair<QDate, QTime> p = getDateTime(d);
4695 buf = toStringTextDate(p.first);
4696 // Insert time between date's day and year:
4697 buf.insert(buf.lastIndexOf(u' '),
4698 u' ' + p.second.toString(Qt::TextDate));
4699 // Append zone/offset indicator, as appropriate:
4700 switch (timeSpec()) {
4701 case Qt::LocalTime:
4702 break;
4703#if QT_CONFIG(timezone)
4704 case Qt::TimeZone:
4705 buf += u' ' + d->m_timeZone.displayName(
4706 *this, QTimeZone::OffsetName, QLocale::c());
4707 break;
4708#endif
4709 default:
4710#if 0 // ### Qt 7 GMT: use UTC instead, see qnamespace.qdoc documentation
4711 buf += " UTC"_L1;
4712#else
4713 buf += " GMT"_L1;
4714#endif
4715 if (getSpec(d) == Qt::OffsetFromUTC)
4716 buf += toOffsetString(Qt::TextDate, offsetFromUtc());
4717 }
4718 return buf;
4719 }
4720 case Qt::ISODate:
4721 case Qt::ISODateWithMs: {
4722 const std::pair<QDate, QTime> p = getDateTime(d);
4723 buf = toStringIsoDate(p.first);
4724 if (buf.isEmpty())
4725 return QString(); // failed to convert
4726 buf += u'T' + p.second.toString(format);
4727 switch (getSpec(d)) {
4728 case Qt::UTC:
4729 buf += u'Z';
4730 break;
4731 case Qt::OffsetFromUTC:
4732 case Qt::TimeZone:
4733 buf += toOffsetString(Qt::ISODate, offsetFromUtc());
4734 break;
4735 default:
4736 break;
4737 }
4738 return buf;
4739 }
4740 }
4741}
4742
4743/*!
4744 \since 5.14
4745 \overload primary
4746 \fn QString QDateTime::toString(const QString &format, QCalendar cal) const
4747 \fn QString QDateTime::toString(QStringView format, QCalendar cal) const
4748
4749 Returns the datetime as a string. The \a format parameter determines the
4750 format of the result string. If \a cal is supplied, it determines the
4751 calendar used to represent the date; it defaults to Gregorian. Prior to Qt
4752 5.14, there was no \a cal parameter and the Gregorian calendar was always
4753 used. See QTime::toString() and QDate::toString() for the supported
4754 specifiers for time and date, respectively, in the \a format parameter.
4755
4756 Any sequence of characters enclosed in single quotes will be included
4757 verbatim in the output string (stripped of the quotes), even if it contains
4758 formatting characters. Two consecutive single quotes ("''") are replaced by
4759 a single quote in the output. All other characters in the format string are
4760 included verbatim in the output string.
4761
4762 Formats without separators (e.g. "ddMM") are supported but must be used with
4763 care, as the resulting strings aren't always reliably readable (e.g. if "dM"
4764 produces "212" it could mean either the 2nd of December or the 21st of
4765 February).
4766
4767 Example format strings (assumed that the QDateTime is 21 May 2001
4768 14:13:09.120):
4769
4770 \table
4771 \header \li Format \li Result
4772 \row \li dd.MM.yyyy \li 21.05.2001
4773 \row \li ddd MMMM d yy \li Tue May 21 01
4774 \row \li hh:mm:ss.zzz \li 14:13:09.120
4775 \row \li hh:mm:ss.z \li 14:13:09.12
4776 \row \li h:m:s ap \li 2:13:9 pm
4777 \endtable
4778
4779 If the datetime is invalid, an empty string will be returned.
4780
4781 \note Day and month names as well as AM/PM indicators are given in English
4782 (C locale). To get localized month and day names and localized forms of
4783 AM/PM, use QLocale::system().toDateTime().
4784
4785 \sa fromString(), QDate::toString(), QTime::toString(), QLocale::toString()
4786*/
4787QString QDateTime::toString(QStringView format, QCalendar cal) const
4788{
4789 return QLocale::c().toString(*this, format, cal);
4790}
4791
4792// Out-of-line no-calendar overloads, since QCalendar is a non-trivial type
4793/*!
4794 \since 5.10
4795 \overload toString()
4796*/
4797QString QDateTime::toString(QStringView format) const
4798{
4799 return QLocale::c().toString(*this, format, QCalendar());
4800}
4801
4802/*!
4803 \since 4.6
4804 \overload toString()
4805*/
4806QString QDateTime::toString(const QString &format) const
4807{
4808 return QLocale::c().toString(*this, qToStringViewIgnoringNull(format), QCalendar());
4809}
4810#endif // datestring
4811
4812static inline void massageAdjustedDateTime(QDateTimeData &d, QDate date, QTime time, bool forward)
4813{
4814 const QDateTimePrivate::TransitionOptions resolve = toTransitionOptions(
4815 forward ? QDateTime::TransitionResolution::RelativeToBefore
4816 : QDateTime::TransitionResolution::RelativeToAfter);
4817 auto status = getStatus(d);
4818 Q_ASSERT(status.testFlags(QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime
4819 | QDateTimePrivate::ValidDateTime));
4820 auto spec = extractSpec(status);
4821 if (QTimeZone::isUtcOrFixedOffset(spec)) {
4822 setDateTime(d, date, time);
4824 return;
4825 }
4826 qint64 local = timeToMSecs(date, time);
4827 const QDateTimePrivate::ZoneState state = stateAtMillis(d.timeZone(), local, resolve);
4828 Q_ASSERT(state.valid || state.dst == QDateTimePrivate::UnknownDaylightTime);
4829 if (state.dst == QDateTimePrivate::UnknownDaylightTime)
4830 status.setFlag(QDateTimePrivate::ValidDateTime, false);
4831 else
4832 status = mergeDaylightStatus(status | QDateTimePrivate::ValidDateTime, state.dst);
4833
4834 if (status & QDateTimePrivate::ShortData) {
4835 d.data.msecs = state.when;
4836 d.data.status = status.toInt();
4837 } else {
4838 d.detach();
4839 d->m_status = status;
4840 if (state.valid) {
4841 d->m_msecs = state.when;
4842 d->m_offsetFromUtc = state.offset;
4843 }
4844 }
4845}
4846
4847/*!
4848 Returns a QDateTime object containing a datetime \a ndays days
4849 later than the datetime of this object (or earlier if \a ndays is
4850 negative).
4851
4852 If the timeSpec() is Qt::LocalTime or Qt::TimeZone and the resulting date
4853 and time fall in the Standard Time to Daylight-Saving Time transition hour
4854 then the result will be just beyond this gap, in the direction of change.
4855 If the transition is at 2am and the clock goes forward to 3am, the result of
4856 aiming between 2am and 3am will be adjusted to fall before 2am (if \c{ndays
4857 < 0}) or after 3am (otherwise).
4858
4859 \sa daysTo(), addMonths(), addYears(), addSecs(), {Timezone transitions}
4860*/
4861
4862QDateTime QDateTime::addDays(qint64 ndays) const
4863{
4864 if (isNull())
4865 return QDateTime();
4866
4867 QDateTime dt(*this);
4868 std::pair<QDate, QTime> p = getDateTime(d);
4869 massageAdjustedDateTime(dt.d, p.first.addDays(ndays), p.second, ndays >= 0);
4870 return dt;
4871}
4872
4873/*!
4874 \fn QDate &QDate::operator++(QDate &date)
4875 \since 6.11
4876
4877 The prefix \c{++} operator, adds a day to \a date and returns a reference to
4878 the modified date object.
4879
4880 \sa addDays(), operator--()
4881*/
4882
4883/*!
4884 \fn QDate QDate::operator++(QDate &date, int)
4885 \since 6.11
4886
4887 The postfix \c{++} operator, adds a day to \a date and returns a copy of
4888 \a date with the previous date.
4889
4890 \sa addDays(), operator--()
4891*/
4892
4893/*!
4894 \fn QDate &QDate::operator--(QDate &date)
4895 \since 6.11
4896
4897 The prefix \c{--} operator, subtracts a day from \a date and returns a
4898 reference to the modified date object.
4899
4900 \sa addDays(), operator++()
4901*/
4902
4903/*!
4904 \fn QDate QDate::operator--(QDate &date, int)
4905 \since 6.11
4906
4907 The postfix \c{--} operator, subtracts a day from \a date and returns a
4908 copy of \a date with the next date.
4909
4910 \sa addDays(), operator++()
4911*/
4912
4913/*!
4914 Returns a QDateTime object containing a datetime \a nmonths months
4915 later than the datetime of this object (or earlier if \a nmonths
4916 is negative).
4917
4918 If the timeSpec() is Qt::LocalTime or Qt::TimeZone and the resulting date
4919 and time fall in the Standard Time to Daylight-Saving Time transition hour
4920 then the result will be just beyond this gap, in the direction of change.
4921 If the transition is at 2am and the clock goes forward to 3am, the result of
4922 aiming between 2am and 3am will be adjusted to fall before 2am (if
4923 \c{nmonths < 0}) or after 3am (otherwise).
4924
4925 \sa daysTo(), addDays(), addYears(), addSecs(), {Timezone transitions}
4926*/
4927
4928QDateTime QDateTime::addMonths(int nmonths) const
4929{
4930 if (isNull())
4931 return QDateTime();
4932
4933 QDateTime dt(*this);
4934 std::pair<QDate, QTime> p = getDateTime(d);
4935 massageAdjustedDateTime(dt.d, p.first.addMonths(nmonths), p.second, nmonths >= 0);
4936 return dt;
4937}
4938
4939/*!
4940 Returns a QDateTime object containing a datetime \a nyears years
4941 later than the datetime of this object (or earlier if \a nyears is
4942 negative).
4943
4944 If the timeSpec() is Qt::LocalTime or Qt::TimeZone and the resulting date
4945 and time fall in the Standard Time to Daylight-Saving Time transition hour
4946 then the result will be just beyond this gap, in the direction of change.
4947 If the transition is at 2am and the clock goes forward to 3am, the result of
4948 aiming between 2am and 3am will be adjusted to fall before 2am (if \c{nyears
4949 < 0}) or after 3am (otherwise).
4950
4951 \sa daysTo(), addDays(), addMonths(), addSecs(), {Timezone transitions}
4952*/
4953
4954QDateTime QDateTime::addYears(int nyears) const
4955{
4956 if (isNull())
4957 return QDateTime();
4958
4959 QDateTime dt(*this);
4960 std::pair<QDate, QTime> p = getDateTime(d);
4961 massageAdjustedDateTime(dt.d, p.first.addYears(nyears), p.second, nyears >= 0);
4962 return dt;
4963}
4964
4965/*!
4966 Returns a QDateTime object containing a datetime \a s seconds
4967 later than the datetime of this object (or earlier if \a s is
4968 negative).
4969
4970 If this datetime is invalid, an invalid datetime will be returned.
4971
4972 \sa addMSecs(), secsTo(), addDays(), addMonths(), addYears()
4973*/
4974
4975QDateTime QDateTime::addSecs(qint64 s) const
4976{
4977 qint64 msecs;
4978 if (qMulOverflow(s, std::integral_constant<qint64, MSECS_PER_SEC>(), &msecs))
4979 return QDateTime();
4980 return addMSecs(msecs);
4981}
4982
4983/*!
4984 Returns a QDateTime object containing a datetime \a msecs milliseconds
4985 later than the datetime of this object (or earlier if \a msecs is
4986 negative).
4987
4988 If this datetime is invalid, an invalid datetime will be returned.
4989
4990 \sa addSecs(), msecsTo(), addDays(), addMonths(), addYears()
4991*/
4992QDateTime QDateTime::addMSecs(qint64 msecs) const
4993{
4994 if (!isValid())
4995 return QDateTime();
4996
4997 QDateTime dt(*this);
4998 switch (getSpec(d)) {
4999 case Qt::LocalTime:
5000 case Qt::TimeZone:
5001 // Convert to real UTC first in case this crosses a DST transition:
5002 if (!qAddOverflow(toMSecsSinceEpoch(), msecs, &msecs))
5003 dt.setMSecsSinceEpoch(msecs);
5004 else
5005 dt.d.invalidate();
5006 break;
5007 case Qt::UTC:
5008 case Qt::OffsetFromUTC:
5009 // No need to convert, just add on
5010 if (qAddOverflow(getMSecs(d), msecs, &msecs)) {
5011 dt.d.invalidate();
5012 } else if (d.isShort() && msecsCanBeSmall(msecs)) {
5013 dt.d.data.msecs = qintptr(msecs);
5014 } else {
5015 dt.d.detach();
5016 dt.d->m_msecs = msecs;
5017 }
5018 break;
5019 }
5020 return dt;
5021}
5022
5023/*!
5024 \fn QDateTime QDateTime::addDuration(std::chrono::milliseconds msecs) const
5025
5026 \since 6.4
5027
5028 Returns a QDateTime object containing a datetime \a msecs milliseconds
5029 later than the datetime of this object (or earlier if \a msecs is
5030 negative).
5031
5032 If this datetime is invalid, an invalid datetime will be returned.
5033
5034 \note Adding durations expressed in \c{std::chrono::months} or
5035 \c{std::chrono::years} does not yield the same result obtained by using
5036 addMonths() or addYears(). The former are fixed durations, calculated in
5037 relation to the solar year; the latter use the Gregorian calendar definitions
5038 of months/years.
5039
5040 \sa addMSecs(), msecsTo(), addDays(), addMonths(), addYears()
5041*/
5042
5043/*!
5044 Returns the number of days from this datetime to the \a other
5045 datetime. The number of days is counted as the number of times
5046 midnight is reached between this datetime to the \a other
5047 datetime. This means that a 10 minute difference from 23:55 to
5048 0:05 the next day counts as one day.
5049
5050 If the \a other datetime is earlier than this datetime,
5051 the value returned is negative.
5052
5053 Example:
5054 \snippet code/src_corelib_time_qdatetime.cpp 15
5055
5056 \sa addDays(), secsTo(), msecsTo()
5057*/
5058
5059qint64 QDateTime::daysTo(const QDateTime &other) const
5060{
5061 return date().daysTo(other.date());
5062}
5063
5064/*!
5065 Returns the number of seconds from this datetime to the \a other
5066 datetime. If the \a other datetime is earlier than this datetime,
5067 the value returned is negative.
5068
5069 Before performing the comparison, the two datetimes are converted
5070 to Qt::UTC to ensure that the result is correct if daylight-saving
5071 (DST) applies to one of the two datetimes but not the other.
5072
5073 Returns 0 if either datetime is invalid.
5074
5075 Example:
5076 \snippet code/src_corelib_time_qdatetime.cpp 11
5077
5078 \sa addSecs(), daysTo(), QTime::secsTo()
5079*/
5080
5081qint64 QDateTime::secsTo(const QDateTime &other) const
5082{
5083 return msecsTo(other) / MSECS_PER_SEC;
5084}
5085
5086/*!
5087 Returns the number of milliseconds from this datetime to the \a other
5088 datetime. If the \a other datetime is earlier than this datetime,
5089 the value returned is negative.
5090
5091 Before performing the comparison, the two datetimes are converted
5092 to Qt::UTC to ensure that the result is correct if daylight-saving
5093 (DST) applies to one of the two datetimes and but not the other.
5094
5095 Returns 0 if either datetime is invalid.
5096
5097 \sa addMSecs(), daysTo(), QTime::msecsTo()
5098*/
5099
5100qint64 QDateTime::msecsTo(const QDateTime &other) const
5101{
5102 if (!isValid() || !other.isValid())
5103 return 0;
5104
5105 return other.toMSecsSinceEpoch() - toMSecsSinceEpoch();
5106}
5107
5108/*!
5109 \fn std::chrono::milliseconds QDateTime::operator-(const QDateTime &lhs, const QDateTime &rhs)
5110 \since 6.4
5111
5112 Returns the number of milliseconds between \a lhs and \a rhs.
5113 If \a lhs is earlier than \a rhs, the result will be negative.
5114
5115 Returns 0 if either datetime is invalid.
5116
5117 \sa msecsTo()
5118*/
5119
5120/*!
5121 \fn QDateTime QDateTime::operator+(const QDateTime &dateTime, std::chrono::milliseconds duration)
5122 \fn QDateTime QDateTime::operator+(std::chrono::milliseconds duration, const QDateTime &dateTime)
5123
5124 \since 6.4
5125
5126 Returns a QDateTime object containing a datetime \a duration milliseconds
5127 later than \a dateTime (or earlier if \a duration is negative).
5128
5129 If \a dateTime is invalid, an invalid datetime will be returned.
5130
5131 \sa addMSecs()
5132*/
5133
5134/*!
5135 \fn QDateTime &QDateTime::operator+=(std::chrono::milliseconds duration)
5136 \since 6.4
5137
5138 Modifies this datetime object by adding the given \a duration.
5139 The updated object will be later if \a duration is positive,
5140 or earlier if it is negative.
5141
5142 If this datetime is invalid, this function has no effect.
5143
5144 Returns a reference to this datetime object.
5145
5146 \sa addMSecs()
5147*/
5148
5149/*!
5150 \fn QDateTime QDateTime::operator-(const QDateTime &dateTime, std::chrono::milliseconds duration)
5151
5152 \since 6.4
5153
5154 Returns a QDateTime object containing a datetime \a duration milliseconds
5155 earlier than \a dateTime (or later if \a duration is negative).
5156
5157 If \a dateTime is invalid, an invalid datetime will be returned.
5158
5159 \sa addMSecs()
5160*/
5161
5162/*!
5163 \fn QDateTime &QDateTime::operator-=(std::chrono::milliseconds duration)
5164 \since 6.4
5165
5166 Modifies this datetime object by subtracting the given \a duration.
5167 The updated object will be earlier if \a duration is positive,
5168 or later if it is negative.
5169
5170 If this datetime is invalid, this function has no effect.
5171
5172 Returns a reference to this datetime object.
5173
5174 \sa addMSecs
5175*/
5176
5177#if QT_DEPRECATED_SINCE(6, 9)
5178/*!
5179 \deprecated [6.9] Use \l toTimeZone() instead.
5180
5181 Returns a copy of this datetime converted to the given time \a spec.
5182
5183 The result represents the same moment in time as, and is equal to, this datetime.
5184
5185 If \a spec is Qt::OffsetFromUTC then it is set to Qt::UTC. To set to a fixed
5186 offset from UTC, use toTimeZone() or toOffsetFromUtc().
5187
5188 If \a spec is Qt::TimeZone then it is set to Qt::LocalTime, i.e. the local
5189 Time Zone. To set a specified time-zone, use toTimeZone().
5190
5191 Example:
5192 \snippet code/src_corelib_time_qdatetime.cpp 16
5193
5194 \sa setTimeSpec(), timeSpec(), toTimeZone()
5195*/
5196
5197QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const
5198{
5199 return toTimeZone(asTimeZone(spec, 0, "toTimeSpec"));
5200}
5201#endif // 6.9 deprecation
5202
5203/*!
5204 \since 5.2
5205
5206 Returns a copy of this datetime converted to a spec of Qt::OffsetFromUTC
5207 with the given \a offsetSeconds. Equivalent to
5208 \c{toTimeZone(QTimeZone::fromSecondsAheadOfUtc(offsetSeconds))}.
5209
5210 If the \a offsetSeconds equals 0 then a UTC datetime will be returned.
5211
5212 The result represents the same moment in time as, and is equal to, this datetime.
5213
5214 \sa offsetFromUtc(), toTimeZone()
5215*/
5216
5217QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const
5218{
5219 return toTimeZone(QTimeZone::fromSecondsAheadOfUtc(offsetSeconds));
5220}
5221
5222/*!
5223 Returns a copy of this datetime converted to local time.
5224
5225 The result represents the same moment in time as, and is equal to, this datetime.
5226
5227 Example:
5228
5229 \snippet code/src_corelib_time_qdatetime.cpp 17
5230
5231 \sa toTimeZone(), toUTC(), toOffsetFromUtc()
5232*/
5233QDateTime QDateTime::toLocalTime() const
5234{
5235 return toTimeZone(QTimeZone::LocalTime);
5236}
5237
5238/*!
5239 Returns a copy of this datetime converted to UTC.
5240
5241 The result represents the same moment in time as, and is equal to, this datetime.
5242
5243 Example:
5244
5245 \snippet code/src_corelib_time_qdatetime.cpp 18
5246
5247 \sa toTimeZone(), toLocalTime(), toOffsetFromUtc()
5248*/
5249QDateTime QDateTime::toUTC() const
5250{
5251 return toTimeZone(QTimeZone::UTC);
5252}
5253
5254/*!
5255 \since 5.2
5256
5257 Returns a copy of this datetime converted to the given \a timeZone.
5258
5259 The result represents the same moment in time as, and is equal to, this datetime.
5260
5261 The result describes the moment in time in terms of \a timeZone's time
5262 representation. For example:
5263
5264 \snippet code/src_corelib_time_qdatetime.cpp 23
5265
5266 If \a timeZone is invalid then the datetime will be invalid. Otherwise the
5267 returned datetime's timeSpec() will match \c{timeZone.timeSpec()}.
5268
5269 \sa timeRepresentation(), toLocalTime(), toUTC(), toOffsetFromUtc()
5270*/
5271
5272QDateTime QDateTime::toTimeZone(const QTimeZone &timeZone) const
5273{
5274 if (timeRepresentation() == timeZone)
5275 return *this;
5276
5277 if (!isValid()) {
5278 QDateTime ret = *this;
5279 ret.setTimeZone(timeZone);
5280 return ret;
5281 }
5282
5283 return fromMSecsSinceEpoch(toMSecsSinceEpoch(), timeZone);
5284}
5285
5286/*!
5287 \internal
5288 Returns \c true if this datetime is equal to the \a other datetime;
5289 otherwise returns \c false.
5290
5291 \sa precedes(), operator==()
5292*/
5293
5294bool QDateTime::equals(const QDateTime &other) const
5295{
5296 if (!isValid())
5297 return !other.isValid();
5298 if (!other.isValid())
5299 return false;
5300
5301 const qint64 thisMs = getMSecs(d);
5302 const qint64 yourMs = getMSecs(other.d);
5303 if (usesSameOffset(d, other.d) || areFarEnoughApart(thisMs, yourMs))
5304 return thisMs == yourMs;
5305
5306 // Convert to UTC and compare
5307 return toMSecsSinceEpoch() == other.toMSecsSinceEpoch();
5308}
5309
5310/*!
5311 \fn bool QDateTime::operator==(const QDateTime &lhs, const QDateTime &rhs)
5312
5313 Returns \c true if \a lhs represents the same moment in time as \a rhs;
5314 otherwise returns \c false.
5315
5316//! [datetime-order-details]
5317 Two datetimes using different time representations can have different
5318 offsets from UTC. In this case, they may compare equivalent even if their \l
5319 date() and \l time() differ, if that difference matches the difference in
5320 UTC offset. If their \c date() and \c time() coincide, the one with higher
5321 offset from UTC is less (earlier) than the one with lower offset. As a
5322 result, datetimes are only weakly ordered.
5323
5324 Since 5.14, all invalid datetimes are equivalent and less than all valid
5325 datetimes.
5326//! [datetime-order-details]
5327
5328 \sa operator!=(), operator<(), operator<=(), operator>(), operator>=()
5329*/
5330
5331/*!
5332 \fn bool QDateTime::operator!=(const QDateTime &lhs, const QDateTime &rhs)
5333
5334 Returns \c true if \a lhs is different from \a rhs; otherwise returns \c
5335 false.
5336
5337 \include qdatetime.cpp datetime-order-details
5338
5339 \sa operator==()
5340*/
5341
5342Qt::weak_ordering compareThreeWay(const QDateTime &lhs, const QDateTime &rhs)
5343{
5344 if (!lhs.isValid())
5345 return rhs.isValid() ? Qt::weak_ordering::less : Qt::weak_ordering::equivalent;
5346
5347 if (!rhs.isValid())
5348 return Qt::weak_ordering::greater; // we know that lhs is valid here
5349
5350 const qint64 lhms = getMSecs(lhs.d), rhms = getMSecs(rhs.d);
5351 if (usesSameOffset(lhs.d, rhs.d) || areFarEnoughApart(lhms, rhms))
5352 return Qt::compareThreeWay(lhms, rhms);
5353
5354 // Convert to UTC and compare
5355 return Qt::compareThreeWay(lhs.toMSecsSinceEpoch(), rhs.toMSecsSinceEpoch());
5356}
5357
5358/*!
5359 \fn bool QDateTime::operator<(const QDateTime &lhs, const QDateTime &rhs)
5360
5361 Returns \c true if \a lhs is earlier than \a rhs;
5362 otherwise returns \c false.
5363
5364 \include qdatetime.cpp datetime-order-details
5365
5366 \sa operator==()
5367*/
5368
5369/*!
5370 \fn bool QDateTime::operator<=(const QDateTime &lhs, const QDateTime &rhs)
5371
5372 Returns \c true if \a lhs is earlier than or equal to \a rhs; otherwise
5373 returns \c false.
5374
5375 \include qdatetime.cpp datetime-order-details
5376
5377 \sa operator==()
5378*/
5379
5380/*!
5381 \fn bool QDateTime::operator>(const QDateTime &lhs, const QDateTime &rhs)
5382
5383 Returns \c true if \a lhs is later than \a rhs; otherwise returns \c false.
5384
5385 \include qdatetime.cpp datetime-order-details
5386
5387 \sa operator==()
5388*/
5389
5390/*!
5391 \fn bool QDateTime::operator>=(const QDateTime &lhs, const QDateTime &rhs)
5392
5393 Returns \c true if \a lhs is later than or equal to \a rhs;
5394 otherwise returns \c false.
5395
5396 \include qdatetime.cpp datetime-order-details
5397
5398 \sa operator==()
5399*/
5400
5401/*!
5402 \since 6.5
5403 \overload primary
5404 \fn QDateTime QDateTime::currentDateTime(const QTimeZone &zone)
5405
5406 Returns the system clock's current datetime, using the time representation
5407 described by \a zone. If \a zone is omitted, local time is used.
5408
5409 \sa currentDateTimeUtc(), QDate::currentDate(), QTime::currentTime(), toTimeZone()
5410*/
5411
5412/*!
5413 \since 0.90
5414 \overload currentDateTime()
5416QDateTime QDateTime::currentDateTime()
5417{
5418 return currentDateTime(QTimeZone::LocalTime);
5419}
5420
5421/*!
5422 \fn QDateTime QDateTime::currentDateTimeUtc()
5423 \since 4.7
5424 Returns the system clock's current datetime, expressed in terms of UTC.
5425
5426 Equivalent to \c{currentDateTime(QTimeZone::UTC)}.
5427
5428 \sa currentDateTime(), QDate::currentDate(), QTime::currentTime(), toTimeZone()
5429*/
5430
5431QDateTime QDateTime::currentDateTimeUtc()
5432{
5433 return currentDateTime(QTimeZone::UTC);
5434}
5435
5436/*!
5437 \fn qint64 QDateTime::currentMSecsSinceEpoch()
5438 \since 4.7
5439
5440 Returns the current number of milliseconds since the start, in UTC, of the year 1970.
5441
5442 This number is like the POSIX time_t variable, but expressed in milliseconds
5443 instead of seconds.
5444
5445 \sa currentDateTime(), currentDateTimeUtc(), toTimeZone()
5446*/
5447
5448/*!
5449 \fn qint64 QDateTime::currentSecsSinceEpoch()
5450 \since 5.8
5451
5452 Returns the number of seconds since the start, in UTC, of the year 1970.
5453
5454 This number is like the POSIX time_t variable.
5455
5456 \sa currentMSecsSinceEpoch()
5457*/
5458
5459/*!
5460 \since 6.4
5461 \overload primary
5462 \fn template <typename Clock, typename Duration> QDateTime QDateTime::fromStdTimePoint(const std::chrono::time_point<Clock, Duration> &time)
5463
5464 Constructs a datetime representing the same point in time as \a time,
5465 using Qt::UTC as its time representation.
5466
5467 The clock of \a time must be compatible with
5468 \c{std::chrono::system_clock}; in particular, a conversion
5469 supported by \c{std::chrono::clock_cast} must exist. After the
5470 conversion, the duration type of the result must be convertible to
5471 \c{std::chrono::milliseconds}.
5472
5473 If this is not the case, the caller must perform the necessary
5474 clock conversion towards \c{std::chrono::system_clock} and the
5475 necessary conversion of the duration type
5476 (cast/round/floor/ceil/...) so that the input to this function
5477 satisfies the constraints above.
5478
5479 \note This function requires C++20.
5480
5481 \sa toStdSysMilliseconds(), fromMSecsSinceEpoch()
5482*/
5483
5484/*!
5485 \since 6.4
5486 \overload fromStdTimePoint()
5488 Constructs a datetime representing the same point in time as \a time,
5489 using Qt::UTC as its time representation.
5490*/
5491QDateTime QDateTime::fromStdTimePoint(
5492 std::chrono::time_point<
5493 std::chrono::system_clock,
5494 std::chrono::milliseconds
5495 > time)
5496{
5497 return fromMSecsSinceEpoch(time.time_since_epoch().count(), QTimeZone::UTC);
5498}
5499
5500/*!
5501 \fn QDateTime QDateTime::fromStdTimePoint(const std::chrono::local_time<std::chrono::milliseconds> &time)
5502 \since 6.4
5503
5504 Constructs a datetime whose date and time are the number of milliseconds
5505 represented by \a time, counted since 1970-01-01T00:00:00.000 in local
5506 time (Qt::LocalTime).
5507
5508 \note This function requires C++20.
5509
5510 \sa toStdSysMilliseconds(), fromMSecsSinceEpoch()
5511*/
5512
5513/*!
5514 \fn QDateTime QDateTime::fromStdLocalTime(const std::chrono::local_time<std::chrono::milliseconds> &time)
5515 \since 6.4
5516
5517 Constructs a datetime whose date and time are the number of milliseconds
5518 represented by \a time, counted since 1970-01-01T00:00:00.000 in local
5519 time (Qt::LocalTime).
5520
5521 \note This function requires C++20.
5522
5523 \sa toStdSysMilliseconds(), fromMSecsSinceEpoch()
5524*/
5525
5526/*!
5527 \fn QDateTime QDateTime::fromStdZonedTime(const std::chrono::zoned_time<std::chrono::milliseconds, const std::chrono::time_zone *> &time);
5528 \since 6.4
5529
5530 Constructs a datetime representing the same point in time as \a time.
5531 The result will be expressed in \a{time}'s time zone.
5532
5533 \note This function requires C++20.
5534
5535 \sa QTimeZone
5536
5537 \sa toStdSysMilliseconds(), fromMSecsSinceEpoch()
5538*/
5539
5540/*!
5541 \fn std::chrono::sys_time<std::chrono::milliseconds> QDateTime::toStdSysMilliseconds() const
5542 \since 6.4
5543
5544 Converts this datetime object to the equivalent time point expressed in
5545 milliseconds, using \c{std::chrono::system_clock} as a clock.
5546
5547 \note This function requires C++20.
5548
5549 \sa fromStdTimePoint(), toMSecsSinceEpoch()
5550*/
5551
5552/*!
5553 \fn std::chrono::sys_seconds QDateTime::toStdSysSeconds() const
5554 \since 6.4
5555
5556 Converts this datetime object to the equivalent time point expressed in
5557 seconds, using \c{std::chrono::system_clock} as a clock.
5558
5559 \note This function requires C++20.
5560
5561 \sa fromStdTimePoint(), toSecsSinceEpoch()
5562*/
5563
5564#if defined(Q_OS_WIN)
5565static inline uint msecsFromDecomposed(int hour, int minute, int sec, int msec = 0)
5566{
5567 return MSECS_PER_HOUR * hour + MSECS_PER_MIN * minute + MSECS_PER_SEC * sec + msec;
5568}
5569
5570QDate QDate::currentDate()
5571{
5572 SYSTEMTIME st = {};
5573 GetLocalTime(&st);
5574 return QDate(st.wYear, st.wMonth, st.wDay);
5575}
5576
5577QTime QTime::currentTime()
5578{
5579 QTime ct;
5580 SYSTEMTIME st = {};
5581 GetLocalTime(&st);
5582 ct.setHMS(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
5583 return ct;
5584}
5585
5586QDateTime QDateTime::currentDateTime(const QTimeZone &zone)
5587{
5588 // We can get local time or "system" time (which is UTC); otherwise, we must
5589 // convert, which is most efficiently done from UTC.
5590 const Qt::TimeSpec spec = zone.timeSpec();
5591 SYSTEMTIME st = {};
5592 // https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtime
5593 // We previously used GetLocalTime for spec == LocalTime but it didn't provide enough
5594 // information to differentiate between repeated hours of a tradition and would report the same
5595 // timezone (eg always CEST, never CET) for both. But toTimeZone handles it correctly, given
5596 // the UTC time.
5597 GetSystemTime(&st);
5598 QDate d(st.wYear, st.wMonth, st.wDay);
5599 QTime t(msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds));
5600 QDateTime utc(d, t, QTimeZone::UTC);
5601 return spec == Qt::UTC ? utc : utc.toTimeZone(zone);
5602}
5603
5604qint64 QDateTime::currentMSecsSinceEpoch() noexcept
5605{
5606 SYSTEMTIME st = {};
5607 GetSystemTime(&st);
5608 const qint64 daysAfterEpoch = QDate(1970, 1, 1).daysTo(QDate(st.wYear, st.wMonth, st.wDay));
5609
5610 return msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds) +
5611 daysAfterEpoch * MSECS_PER_DAY;
5612}
5613
5614qint64 QDateTime::currentSecsSinceEpoch() noexcept
5615{
5616 SYSTEMTIME st = {};
5617 GetSystemTime(&st);
5618 const qint64 daysAfterEpoch = QDate(1970, 1, 1).daysTo(QDate(st.wYear, st.wMonth, st.wDay));
5619
5620 return st.wHour * SECS_PER_HOUR + st.wMinute * SECS_PER_MIN + st.wSecond +
5621 daysAfterEpoch * SECS_PER_DAY;
5622}
5623
5624#elif defined(Q_OS_UNIX) // Assume POSIX-compliant
5625QDate QDate::currentDate()
5626{
5627 return QDateTime::currentDateTime().date();
5628}
5629
5630QTime QTime::currentTime()
5631{
5632 return QDateTime::currentDateTime().time();
5633}
5634
5635QDateTime QDateTime::currentDateTime(const QTimeZone &zone)
5636{
5637 return fromMSecsSinceEpoch(currentMSecsSinceEpoch(), zone);
5638}
5639
5640qint64 QDateTime::currentMSecsSinceEpoch() noexcept
5641{
5642 struct timespec when;
5643 if (clock_gettime(CLOCK_REALTIME, &when) == 0) // should always succeed
5644 return when.tv_sec * MSECS_PER_SEC + (when.tv_nsec + 500'000) / 1'000'000;
5645 Q_UNREACHABLE_RETURN(0);
5646}
5647
5648qint64 QDateTime::currentSecsSinceEpoch() noexcept
5649{
5650 struct timespec when;
5651 if (clock_gettime(CLOCK_REALTIME, &when) == 0) // should always succeed
5652 return when.tv_sec;
5653 Q_UNREACHABLE_RETURN(0);
5654}
5655#else
5656#error "What system is this?"
5657#endif
5658
5659#if QT_DEPRECATED_SINCE(6, 9)
5660/*!
5661 \since 5.2
5662 \overload fromMSecsSinceEpoch()
5663 \deprecated [6.9] Pass a \l QTimeZone instead, or omit \a spec and \a offsetSeconds.
5664
5665 Returns a datetime representing a moment the given number \a msecs of
5666 milliseconds after the start, in UTC, of the year 1970, described as
5667 specified by \a spec and \a offsetSeconds.
5668
5669 Note that there are possible values for \a msecs that lie outside the valid
5670 range of QDateTime, both negative and positive. The behavior of this
5671 function is undefined for those values.
5672
5673 If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be
5674 ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0
5675 then Qt::UTC will be used as the \a spec, since UTC has zero offset.
5676
5677 If \a spec is Qt::TimeZone then Qt::LocalTime will be used in its place,
5678 equivalent to using the current system time zone (but differently
5679 represented).
5680
5681 \sa fromSecsSinceEpoch(), toMSecsSinceEpoch(), setMSecsSinceEpoch()
5682*/
5683QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int offsetSeconds)
5684{
5685 return fromMSecsSinceEpoch(msecs,
5686 asTimeZone(spec, offsetSeconds, "QDateTime::fromMSecsSinceEpoch"));
5687}
5688
5689/*!
5690 \since 5.8
5691 \overload fromSecsSinceEpoch
5692 \deprecated [6.9] Pass a \l QTimeZone instead, or omit \a spec and \a offsetSeconds.
5693
5694 Returns a datetime representing a moment the given number \a secs of seconds
5695 after the start, in UTC, of the year 1970, described as specified by \a spec
5696 and \a offsetSeconds.
5697
5698 Note that there are possible values for \a secs that lie outside the valid
5699 range of QDateTime, both negative and positive. The behavior of this
5700 function is undefined for those values.
5701
5702 If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be
5703 ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0
5704 then Qt::UTC will be used as the \a spec, since UTC has zero offset.
5705
5706 If \a spec is Qt::TimeZone then Qt::LocalTime will be used in its place,
5707 equivalent to using the current system time zone (but differently
5708 represented).
5709
5710 \sa fromMSecsSinceEpoch(), toSecsSinceEpoch(), setSecsSinceEpoch()
5711*/
5712QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec, int offsetSeconds)
5713{
5714 return fromSecsSinceEpoch(secs,
5715 asTimeZone(spec, offsetSeconds, "QDateTime::fromSecsSinceEpoch"));
5716}
5717#endif // 6.9 deprecations
5718
5719/*!
5720 \since 5.2
5721 \overload primary
5722
5723 Returns a datetime representing a moment the given number \a msecs of
5724 milliseconds after the start, in UTC, of the year 1970, described as
5725 specified by \a timeZone. The default time representation is local time.
5726
5727 Note that there are possible values for \a msecs that lie outside the valid
5728 range of QDateTime, both negative and positive. The behavior of this
5729 function is undefined for those values.
5730
5731 \sa fromSecsSinceEpoch(), toMSecsSinceEpoch(), setMSecsSinceEpoch()
5732*/
5733QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone)
5734{
5735 QDateTime dt;
5736 reviseTimeZone(dt.d, timeZone, TransitionResolution::Reject);
5737 if (timeZone.isValid())
5738 dt.setMSecsSinceEpoch(msecs);
5739 return dt;
5740}
5741
5742/*!
5743 \overload fromMSecsSinceEpoch()
5745QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs)
5746{
5747 return fromMSecsSinceEpoch(msecs, QTimeZone::LocalTime);
5748}
5749
5750/*!
5751 \since 5.8
5752 \overload primary
5753
5754 Returns a datetime representing a moment the given number \a secs of seconds
5755 after the start, in UTC, of the year 1970, described as specified by \a
5756 timeZone. The default time representation is local time.
5757
5758 Note that there are possible values for \a secs that lie outside the valid
5759 range of QDateTime, both negative and positive. The behavior of this
5760 function is undefined for those values.
5761
5762 \sa fromMSecsSinceEpoch(), toSecsSinceEpoch(), setSecsSinceEpoch()
5763*/
5764QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, const QTimeZone &timeZone)
5765{
5766 QDateTime dt;
5767 reviseTimeZone(dt.d, timeZone, TransitionResolution::Reject);
5768 if (timeZone.isValid())
5769 dt.setSecsSinceEpoch(secs);
5770 return dt;
5771}
5772
5773/*!
5774 \overload fromSecsSinceEpoch()
5776QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs)
5777{
5778 return fromSecsSinceEpoch(secs, QTimeZone::LocalTime);
5779}
5780
5781#if QT_CONFIG(datestring) // depends on, so implies, textdate
5782
5783/*!
5784 \overload
5785 \fn QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format)
5786
5787 Returns the QDateTime represented by the \a string, using the
5788 \a format given, or an invalid datetime if this is not possible.
5789
5790 Note for Qt::TextDate: only English short month names (e.g. "Jan" in short
5791 form or "January" in long form) are recognized.
5792
5793 \sa toString(), QLocale::toDateTime()
5794*/
5795
5796/*!
5797 \since 6.0
5798 \overload fromString()
5799*/
5800QDateTime QDateTime::fromString(QStringView string, Qt::DateFormat format)
5801{
5802 if (string.isEmpty())
5803 return QDateTime();
5804
5805 switch (format) {
5806 case Qt::RFC2822Date: {
5807 const ParsedRfcDateTime rfc = rfcDateImpl(string);
5808
5809 if (!rfc.date.isValid() || !rfc.time.isValid())
5810 return QDateTime();
5811
5812 QDateTime dateTime(rfc.date, rfc.time, QTimeZone::UTC);
5813 dateTime.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(rfc.utcOffset));
5814 return dateTime;
5815 }
5816 case Qt::ISODate:
5817 case Qt::ISODateWithMs: {
5818 const int size = string.size();
5819 if (size < 10)
5820 return QDateTime();
5821
5822 QDate date = QDate::fromString(string.first(10), Qt::ISODate);
5823 if (!date.isValid())
5824 return QDateTime();
5825 if (size == 10)
5826 return date.startOfDay();
5827
5828 QTimeZone zone = QTimeZone::LocalTime;
5829 QStringView isoString = string.sliced(10); // trim "yyyy-MM-dd"
5830
5831 // Must be left with T (or space) and at least one digit for the hour:
5832 if (isoString.size() < 2
5833 || !(isoString.startsWith(u'T', Qt::CaseInsensitive)
5834 // RFC 3339 (section 5.6) allows a space here. (It actually
5835 // allows any separator one considers more readable, merely
5836 // giving space as an example - but let's not go wild !)
5837 || isoString.startsWith(u' '))) {
5838 return QDateTime();
5839 }
5840 isoString = isoString.sliced(1); // trim 'T' (or space)
5841
5842 // Check end of string for Time Zone definition, either Z for UTC or ±HH:mm for Offset
5843 if (isoString.endsWith(u'Z', Qt::CaseInsensitive)) {
5844 zone = QTimeZone::UTC;
5845 isoString.chop(1); // trim 'Z'
5846 } else {
5847 // the loop below is faster but functionally equal to:
5848 // const int signIndex = isoString.indexOf(QRegulargExpression(QStringLiteral("[+-]")));
5849 int signIndex = isoString.size() - 1;
5850 Q_ASSERT(signIndex >= 0);
5851 bool found = false;
5852 do {
5853 QChar character(isoString[signIndex]);
5854 found = character == u'+' || character == u'-';
5855 } while (!found && --signIndex >= 0);
5856
5857 if (found) {
5858 bool ok;
5859 int offset = fromOffsetString(isoString.sliced(signIndex), &ok);
5860 if (!ok)
5861 return QDateTime();
5862 isoString = isoString.first(signIndex);
5863 zone = QTimeZone::fromSecondsAheadOfUtc(offset);
5864 }
5865 }
5866
5867 // Might be end of day (24:00, including variants), which QTime considers invalid.
5868 // ISO 8601 (section 4.2.3) says that 24:00 is equivalent to 00:00 the next day.
5869 bool isMidnight24 = false;
5870 QTime time = fromIsoTimeString(isoString, format, &isMidnight24);
5871 if (!time.isValid())
5872 return QDateTime();
5873 if (isMidnight24) // time is 0:0, but we want the start of next day:
5874 return date.addDays(1).startOfDay(zone);
5875 return QDateTime(date, time, zone);
5876 }
5877 case Qt::TextDate: {
5878 QVarLengthArray<QStringView, 6> parts;
5879
5880 auto tokens = string.tokenize(u' ', Qt::SkipEmptyParts);
5881 auto it = tokens.begin();
5882 for (int i = 0; i < 6 && it != tokens.end(); ++i, ++it)
5883 parts.emplace_back(*it);
5884
5885 // Documented as "ddd MMM d HH:mm:ss yyyy" with optional offset-suffix;
5886 // and allow time either before or after year.
5887 if (parts.size() < 5 || it != tokens.end())
5888 return QDateTime();
5889
5890 // Year and time can be in either order.
5891 // Guess which by looking for ':' in the time
5892 int yearPart = 3;
5893 int timePart = 3;
5894 if (parts.at(3).contains(u':'))
5895 yearPart = 4;
5896 else if (parts.at(4).contains(u':'))
5897 timePart = 4;
5898 else
5899 return QDateTime();
5900
5901 bool ok = false;
5902 int day = parts.at(2).toInt(&ok);
5903 int year = ok ? parts.at(yearPart).toInt(&ok) : 0;
5904 int month = fromShortMonthName(parts.at(1));
5905 if (!ok || year == 0 || day == 0 || month < 1)
5906 return QDateTime();
5907
5908 const QDate date(year, month, day);
5909 if (!date.isValid())
5910 return QDateTime();
5911
5912 const QTime time = fromIsoTimeString(parts.at(timePart), format, nullptr);
5913 if (!time.isValid())
5914 return QDateTime();
5915
5916 if (parts.size() == 5)
5917 return QDateTime(date, time);
5918
5919 QStringView tz = parts.at(5);
5920 if (tz.startsWith("UTC"_L1)
5921 // GMT has long been deprecated as an alias for UTC.
5922 || tz.startsWith("GMT"_L1, Qt::CaseInsensitive)) {
5923 tz = tz.sliced(3);
5924 if (tz.isEmpty())
5925 return QDateTime(date, time, QTimeZone::UTC);
5926
5927 int offset = fromOffsetString(tz, &ok);
5928 return ok ? QDateTime(date, time, QTimeZone::fromSecondsAheadOfUtc(offset))
5929 : QDateTime();
5930 }
5931 return QDateTime();
5932 }
5933 }
5934
5935 return QDateTime();
5936}
5937
5938/*!
5939 \overload primary
5940 \fn QDateTime QDateTime::fromString(const QString &string, const QString &format, int baseYear, QCalendar cal)
5941
5942 Returns the QDateTime represented by the \a string, using the \a
5943 format given, or an invalid datetime if the string cannot be parsed.
5944
5945 Uses the calendar \a cal if supplied, else Gregorian.
5946
5947 \include qlocale.cpp base-year-for-two-digit
5948
5949 In addition to the expressions, recognized in the format string to represent
5950 parts of the date and time, by QDate::fromString() and QTime::fromString(),
5951 this method supports:
5952
5953 \table
5954 \header \li Expression \li Output
5955 \row \li t
5956 \li the timezone (offset, name, "Z" or offset with "UTC" prefix)
5957 \row \li tt
5958 \li the timezone in offset format with no colon between hours and
5959 minutes (for example "+0200")
5960 \row \li ttt
5961 \li the timezone in offset format with a colon between hours and
5962 minutes (for example "+02:00")
5963 \row \li tttt
5964 \li the timezone name, either what \l QTimeZone::displayName() reports
5965 for \l QTimeZone::LongName or the IANA ID of the zone (for example
5966 "Europe/Berlin"). The names recognized are those known to \l
5967 QTimeZone, which may depend on the operating system in use.
5968 \endtable
5969
5970 If no 't' format specifier is present, the system's local time-zone is used.
5971 For the defaults of all other fields, see QDate::fromString() and QTime::fromString().
5972
5973 For example:
5974
5975 \snippet code/src_corelib_time_qdatetime.cpp 14
5976
5977 All other input characters will be treated as text. Any non-empty sequence
5978 of characters enclosed in single quotes will also be treated (stripped of
5979 the quotes) as text and not be interpreted as expressions.
5980
5981 \snippet code/src_corelib_time_qdatetime.cpp 12
5982
5983 If the format is not satisfied, an invalid QDateTime is returned. If the
5984 format is satisfied but \a string represents an invalid datetime (e.g. in a
5985 gap skipped by a time-zone transition), an valid QDateTime is returned, that
5986 represents a near-by datetime that is valid.
5987
5988 The expressions that don't have leading zeroes (d, M, h, m, s, z) will be
5989 greedy. This means that they will use two digits (or three, for z) even if this will
5990 put them outside the range and/or leave too few digits for other
5991 sections.
5992
5993 \snippet code/src_corelib_time_qdatetime.cpp 13
5994
5995 This could have meant 1 January 00:30.00 but the M will grab
5996 two digits.
5997
5998 Incorrectly specified fields of the \a string will cause an invalid
5999 QDateTime to be returned. Only datetimes between the local time start of
6000 year 100 and end of year 9999 are supported. Note that datetimes near the
6001 ends of this range in other time-zones, notably including UTC, may fall
6002 outside the range (and thus be treated as invalid) depending on local time
6003 zone.
6004
6005 \note Day and month names as well as AM/PM indicators must be given in
6006 English (C locale). If localized month and day names or localized forms of
6007 AM/PM are to be recognized, use QLocale::system().toDateTime().
6008
6009 \note If a format character is repeated more times than the longest
6010 expression in the table above using it, this part of the format will be read
6011 as several expressions with no separator between them; the longest above,
6012 possibly repeated as many times as there are copies of it, ending with a
6013 residue that may be a shorter expression. Thus \c{'tttttt'} would match
6014 \c{"Europe/BerlinEurope/Berlin"} and set the zone to Berlin time; if the
6015 datetime string contained "Europe/BerlinZ" it would "match" but produce an
6016 inconsistent result, leading to an invalid datetime.
6017
6018 \sa toString(), QDate::fromString(), QTime::fromString(),
6019 QLocale::toDateTime()
6020*/
6021
6022/*!
6023 \since 6.0
6024 \overload fromString()
6025 \fn QDateTime QDateTime::fromString(QStringView string, QStringView format, QCalendar cal)
6026*/
6027
6028/*!
6029 \since 6.0
6030 \overload fromString()
6031*/
6032QDateTime QDateTime::fromString(const QString &string, QStringView format, int baseYear,
6033 QCalendar cal)
6034{
6035#if QT_CONFIG(datetimeparser)
6036 QDateTime datetime;
6037
6038 QDateTimeParser dt(QMetaType::QDateTime, QDateTimeParser::FromString, cal);
6039 dt.setDefaultLocale(QLocale::c());
6040 if (dt.parseFormat(format) && (dt.fromString(string, &datetime, baseYear)
6041 || !datetime.isValid())) {
6042 return datetime;
6043 }
6044#else
6045 Q_UNUSED(string);
6046 Q_UNUSED(format);
6047 Q_UNUSED(baseYear);
6048 Q_UNUSED(cal);
6049#endif
6050 return QDateTime();
6051}
6052
6053/*!
6054 \since 5.14
6055 \overload fromString()
6056 \fn QDateTime QDateTime::fromString(const QString &string, const QString &format, QCalendar cal)
6057*/
6058
6059/*!
6060 \since 6.0
6061 \overload fromString()
6062 \fn QDateTime QDateTime::fromString(const QString &string, QStringView format, QCalendar cal)
6063*/
6064
6065/*!
6066 \since 6.7
6067 \overload fromString()
6068 \fn QDateTime QDateTime::fromString(QStringView string, QStringView format, int baseYear, QCalendar cal)
6069*/
6070
6071/*!
6072 \since 6.7
6073 \overload fromString()
6074 \fn QDateTime QDateTime::fromString(QStringView string, QStringView format, int baseYear)
6075
6076 Uses a default-constructed QCalendar.
6077*/
6078
6079/*!
6080 \since 6.7
6081 \overload fromString()
6082
6083 Uses a default-constructed QCalendar.
6084*/
6085QDateTime QDateTime::fromString(const QString &string, QStringView format, int baseYear)
6086{
6087 return fromString(string, format, baseYear, QCalendar());
6088}
6089
6090/*!
6091 \since 6.7
6092 \overload fromString()
6093 \fn QDateTime QDateTime::fromString(const QString &string, const QString &format, int baseYear)
6094
6095 Uses a default-constructed QCalendar.
6096*/
6097#endif // datestring
6098
6099/*****************************************************************************
6100 Date/time stream functions
6101 *****************************************************************************/
6102
6103#ifndef QT_NO_DATASTREAM
6104/*!
6105 \relates QDate
6106
6107 Writes the \a date to stream \a out.
6108
6109 \sa {Serializing Qt Data Types}
6110*/
6111
6112QDataStream &operator<<(QDataStream &out, QDate date)
6113{
6114 if (out.version() < QDataStream::Qt_5_0)
6115 return out << quint32(date.jd);
6116 else
6117 return out << date.jd;
6118}
6119
6120/*!
6121 \relates QDate
6122
6123 Reads a date from stream \a in into the \a date.
6124
6125 \sa {Serializing Qt Data Types}
6126*/
6127
6128QDataStream &operator>>(QDataStream &in, QDate &date)
6129{
6130 if (in.version() < QDataStream::Qt_5_0) {
6131 quint32 jd;
6132 in >> jd;
6133 // Older versions consider 0 an invalid jd.
6134 date.jd = (jd != 0 ? jd : QDate::nullJd());
6135 } else {
6136 in >> date.jd;
6137 }
6138
6139 return in;
6140}
6141
6142/*!
6143 \relates QTime
6144
6145 Writes \a time to stream \a out.
6146
6147 \sa {Serializing Qt Data Types}
6148*/
6149
6150QDataStream &operator<<(QDataStream &out, QTime time)
6151{
6152 if (out.version() >= QDataStream::Qt_4_0) {
6153 return out << quint32(time.mds);
6154 } else {
6155 // Qt3 had no support for reading -1, QTime() was valid and serialized as 0
6156 return out << quint32(time.isNull() ? 0 : time.mds);
6157 }
6158}
6159
6160/*!
6161 \relates QTime
6162
6163 Reads a time from stream \a in into the given \a time.
6164
6165 \sa {Serializing Qt Data Types}
6166*/
6167
6168QDataStream &operator>>(QDataStream &in, QTime &time)
6169{
6170 quint32 ds;
6171 in >> ds;
6172 if (in.version() >= QDataStream::Qt_4_0) {
6173 time.mds = int(ds);
6174 } else {
6175 // Qt3 would write 0 for a null time
6176 time.mds = (ds == 0) ? QTime::NullTime : int(ds);
6177 }
6178 return in;
6179}
6180
6181/*!
6182 \relates QDateTime
6183
6184 Writes \a dateTime to the \a out stream.
6185
6186 \sa {Serializing Qt Data Types}
6187*/
6188QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime)
6189{
6190 std::pair<QDate, QTime> dateAndTime;
6191
6192 // TODO: new version, route spec and details via QTimeZone
6193 if (out.version() >= QDataStream::Qt_5_2) {
6194
6195 // In 5.2 we switched to using Qt::TimeSpec and added offset and zone support
6196 dateAndTime = getDateTime(dateTime.d);
6197 out << dateAndTime << qint8(dateTime.timeSpec());
6198 if (dateTime.timeSpec() == Qt::OffsetFromUTC)
6199 out << qint32(dateTime.offsetFromUtc());
6200#if QT_CONFIG(timezone)
6201 else if (dateTime.timeSpec() == Qt::TimeZone)
6202 out << dateTime.timeZone();
6203#endif // timezone
6204
6205 } else if (out.version() == QDataStream::Qt_5_0) {
6206
6207 // In Qt 5.0 we incorrectly serialised all datetimes as UTC.
6208 // This approach is wrong and should not be used again; it breaks
6209 // the guarantee that a deserialised local datetime is the same time
6210 // of day, regardless of which timezone it was serialised in.
6211 dateAndTime = getDateTime((dateTime.isValid() ? dateTime.toUTC() : dateTime).d);
6212 out << dateAndTime << qint8(dateTime.timeSpec());
6213
6214 } else if (out.version() >= QDataStream::Qt_4_0) {
6215
6216 // From 4.0 to 5.1 (except 5.0) we used QDateTimePrivate::Spec
6217 dateAndTime = getDateTime(dateTime.d);
6218 out << dateAndTime;
6219 switch (dateTime.timeSpec()) {
6220 case Qt::UTC:
6221 out << (qint8)QDateTimePrivate::UTC;
6222 break;
6223 case Qt::OffsetFromUTC:
6224 out << (qint8)QDateTimePrivate::OffsetFromUTC;
6225 break;
6226 case Qt::TimeZone:
6227 out << (qint8)QDateTimePrivate::TimeZone;
6228 break;
6229 case Qt::LocalTime:
6230 out << (qint8)QDateTimePrivate::LocalUnknown;
6231 break;
6232 }
6233
6234 } else { // version < QDataStream::Qt_4_0
6235
6236 // Before 4.0 there was no TimeSpec, only Qt::LocalTime was supported
6237 dateAndTime = getDateTime(dateTime.d);
6238 out << dateAndTime;
6239
6240 }
6241
6242 return out;
6243}
6244
6245/*!
6246 \relates QDateTime
6247
6248 Reads a datetime from the stream \a in into \a dateTime.
6249
6250 \sa {Serializing Qt Data Types}
6251*/
6252
6253QDataStream &operator>>(QDataStream &in, QDateTime &dateTime)
6254{
6255 QDate dt;
6256 QTime tm;
6257 qint8 ts = 0;
6258 QTimeZone zone(QTimeZone::LocalTime);
6259
6260 if (in.version() >= QDataStream::Qt_5_2) {
6261
6262 // In 5.2 we switched to using Qt::TimeSpec and added offset and zone support
6263 in >> dt >> tm >> ts;
6264 switch (static_cast<Qt::TimeSpec>(ts)) {
6265 case Qt::UTC:
6266 zone = QTimeZone::UTC;
6267 break;
6268 case Qt::OffsetFromUTC: {
6269 qint32 offset = 0;
6270 in >> offset;
6271 zone = QTimeZone::fromSecondsAheadOfUtc(offset);
6272 break;
6273 }
6274 case Qt::LocalTime:
6275 break;
6276 case Qt::TimeZone:
6277 in >> zone;
6278 break;
6279 }
6280 // Note: no way to resolve transition ambiguity, when relevant; use default.
6281 dateTime = QDateTime(dt, tm, zone);
6282
6283 } else if (in.version() == QDataStream::Qt_5_0) {
6284
6285 // In Qt 5.0 we incorrectly serialised all datetimes as UTC
6286 in >> dt >> tm >> ts;
6287 dateTime = QDateTime(dt, tm, QTimeZone::UTC);
6288 if (static_cast<Qt::TimeSpec>(ts) == Qt::LocalTime)
6289 dateTime = dateTime.toTimeZone(zone);
6290
6291 } else if (in.version() >= QDataStream::Qt_4_0) {
6292
6293 // From 4.0 to 5.1 (except 5.0) we used QDateTimePrivate::Spec
6294 in >> dt >> tm >> ts;
6295 switch (static_cast<QDateTimePrivate::Spec>(ts)) {
6296 case QDateTimePrivate::OffsetFromUTC: // No offset was stored, so treat as UTC.
6297 case QDateTimePrivate::UTC:
6298 zone = QTimeZone::UTC;
6299 break;
6300 case QDateTimePrivate::TimeZone: // No zone was stored, so treat as LocalTime:
6301 case QDateTimePrivate::LocalUnknown:
6302 case QDateTimePrivate::LocalStandard:
6303 case QDateTimePrivate::LocalDST:
6304 break;
6305 }
6306 dateTime = QDateTime(dt, tm, zone);
6307
6308 } else { // version < QDataStream::Qt_4_0
6309
6310 // Before 4.0 there was no TimeSpec, only Qt::LocalTime was supported
6311 in >> dt >> tm;
6312 dateTime = QDateTime(dt, tm);
6313
6314 }
6315
6316 return in;
6317}
6318#endif // QT_NO_DATASTREAM
6319
6320/*****************************************************************************
6321 Date / Time Debug Streams
6322*****************************************************************************/
6323
6324#if !defined(QT_NO_DEBUG_STREAM) && QT_CONFIG(datestring)
6325QDebug operator<<(QDebug dbg, QDate date)
6326{
6327 QDebugStateSaver saver(dbg);
6328 dbg.nospace() << "QDate(";
6329 if (date.isValid())
6330 // QTBUG-91070, ISODate only supports years in the range 0-9999
6331 if (int y = date.year(); y > 0 && y <= 9999)
6332 dbg.nospace() << date.toString(Qt::ISODate);
6333 else
6334 dbg.nospace() << date.toString(Qt::TextDate);
6335 else
6336 dbg.nospace() << "Invalid";
6337 dbg.nospace() << ')';
6338 return dbg;
6339}
6340
6341QDebug operator<<(QDebug dbg, QTime time)
6342{
6343 QDebugStateSaver saver(dbg);
6344 dbg.nospace() << "QTime(";
6345 if (time.isValid())
6346 dbg.nospace() << time.toString(u"HH:mm:ss.zzz");
6347 else
6348 dbg.nospace() << "Invalid";
6349 dbg.nospace() << ')';
6350 return dbg;
6351}
6352
6353QDebug operator<<(QDebug dbg, const QDateTime &date)
6354{
6355 QDebugStateSaver saver(dbg);
6356 dbg.nospace() << "QDateTime(";
6357 if (date.isValid()) {
6358 const Qt::TimeSpec ts = date.timeSpec();
6359 dbg.noquote() << date.toString(u"yyyy-MM-dd HH:mm:ss.zzz t")
6360 << ' ' << ts;
6361 switch (ts) {
6362 case Qt::UTC:
6363 break;
6364 case Qt::OffsetFromUTC:
6365 dbg.space() << date.offsetFromUtc() << 's';
6366 break;
6367 case Qt::TimeZone:
6368#if QT_CONFIG(timezone)
6369 dbg.space() << date.timeZone().id();
6370#endif // timezone
6371 break;
6372 case Qt::LocalTime:
6373 break;
6374 }
6375 } else {
6376 dbg.nospace() << "Invalid";
6377 }
6378 return dbg.nospace() << ')';
6379}
6380#endif // debug_stream && datestring
6381
6382/*! \fn size_t qHash(const QDateTime &key, size_t seed = 0)
6383 \qhashold{QHash}
6384 \since 5.0
6385*/
6386size_t qHash(const QDateTime &key, size_t seed)
6387{
6388 // Use to toMSecsSinceEpoch instead of individual qHash functions for
6389 // QDate/QTime/spec/offset because QDateTime::operator== converts both arguments
6390 // to the same timezone. If we don't, qHash would return different hashes for
6391 // two QDateTimes that are equivalent once converted to the same timezone.
6392 return key.isValid() ? qHash(key.toMSecsSinceEpoch(), seed) : seed;
6393}
6394
6395/*! \fn size_t qHash(QDate key, size_t seed = 0)
6396 \qhashold{QHash}
6397 \since 5.0
6398*/
6399size_t qHash(QDate key, size_t seed) noexcept
6400{
6401 return qHash(key.toJulianDay(), seed);
6402}
6403
6404/*! \fn size_t qHash(QTime key, size_t seed = 0)
6405 \qhashold{QHash}
6406 \since 5.0
6407*/
6408size_t qHash(QTime key, size_t seed) noexcept
6409{
6410 return qHash(key.msecsSinceStartOfDay(), seed);
6411}
6412
6413QT_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