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

source code of qtbase/src/corelib/time/qdatetime.cpp