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