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