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