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