summaryrefslogtreecommitdiffstats
path: root/src/corelib/time/qdatetime.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/time/qdatetime.cpp')
-rw-r--r--src/corelib/time/qdatetime.cpp5802
1 files changed, 5802 insertions, 0 deletions
diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp
new file mode 100644
index 0000000000..878a2c1e46
--- /dev/null
+++ b/src/corelib/time/qdatetime.cpp
@@ -0,0 +1,5802 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2016 Intel Corporation.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+#include "private/qdatetime_p.h"
+#if QT_CONFIG(datetimeparser)
+#include "private/qdatetimeparser_p.h"
+#endif
+
+#include "qdatastream.h"
+#include "qset.h"
+#include "qlocale.h"
+#include "qdatetime.h"
+#if QT_CONFIG(timezone)
+#include "qtimezoneprivate_p.h"
+#endif
+#include "qregexp.h"
+#include "qdebug.h"
+#ifndef Q_OS_WIN
+#include <locale.h>
+#endif
+
+#include <cmath>
+#ifdef Q_CC_MINGW
+# include <unistd.h> // Define _POSIX_THREAD_SAFE_FUNCTIONS to obtain localtime_r()
+#endif
+#include <time.h>
+#ifdef Q_OS_WIN
+# include <qt_windows.h>
+# ifdef Q_OS_WINRT
+# include "qfunctions_winrt.h"
+# endif
+#endif
+
+#if defined(Q_OS_MAC)
+#include <private/qcore_mac_p.h>
+#endif
+
+#include "qcalendar.h"
+#include "qgregoriancalendar_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*****************************************************************************
+ Date/Time Constants
+ *****************************************************************************/
+
+enum {
+ SECS_PER_DAY = 86400,
+ MSECS_PER_DAY = 86400000,
+ SECS_PER_HOUR = 3600,
+ MSECS_PER_HOUR = 3600000,
+ SECS_PER_MIN = 60,
+ MSECS_PER_MIN = 60000,
+ TIME_T_MAX = 2145916799, // int maximum 2037-12-31T23:59:59 UTC
+ JULIAN_DAY_FOR_EPOCH = 2440588 // result of julianDayFromDate(1970, 1, 1)
+};
+
+/*****************************************************************************
+ QDate static helper functions
+ *****************************************************************************/
+
+static inline QDate fixedDate(QCalendar::YearMonthDay &&parts, QCalendar cal)
+{
+ if ((parts.year < 0 && !cal.isProleptic()) || (parts.year == 0 && !cal.hasYearZero()))
+ return QDate();
+
+ parts.day = qMin(parts.day, cal.daysInMonth(parts.month, parts.year));
+ return cal.dateFromParts(parts);
+}
+
+static inline QDate fixedDate(QCalendar::YearMonthDay &&parts)
+{
+ if (parts.year) {
+ parts.day = qMin(parts.day, QGregorianCalendar::monthLength(parts.month, parts.year));
+ qint64 jd;
+ if (QGregorianCalendar::julianFromParts(parts.year, parts.month, parts.day, &jd))
+ return QDate::fromJulianDay(jd);
+ }
+ return QDate();
+}
+
+/*****************************************************************************
+ Date/Time formatting helper functions
+ *****************************************************************************/
+
+#if QT_CONFIG(textdate)
+static const char qt_shortMonthNames[][4] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static int qt_monthNumberFromShortName(QStringRef shortName)
+{
+ for (unsigned int i = 0; i < sizeof(qt_shortMonthNames) / sizeof(qt_shortMonthNames[0]); ++i) {
+ if (shortName == QLatin1String(qt_shortMonthNames[i], 3))
+ return i + 1;
+ }
+ return -1;
+}
+static int qt_monthNumberFromShortName(const QString &shortName)
+{ return qt_monthNumberFromShortName(QStringRef(&shortName)); }
+
+static int fromShortMonthName(const QStringRef &monthName, int year)
+{
+ // Assume that English monthnames are the default
+ int month = qt_monthNumberFromShortName(monthName);
+ if (month != -1)
+ return month;
+ // If English names can't be found, search the localized ones
+ for (int i = 1; i <= 12; ++i) {
+ if (monthName == QCalendar().monthName(QLocale::system(), i, year, QLocale::ShortFormat))
+ return i;
+ }
+ return -1;
+}
+#endif // textdate
+
+#if QT_CONFIG(datestring)
+struct ParsedRfcDateTime {
+ QDate date;
+ QTime time;
+ int utcOffset;
+};
+
+static ParsedRfcDateTime rfcDateImpl(const QString &s)
+{
+ ParsedRfcDateTime result;
+
+ // Matches "Wdy, dd Mon yyyy HH:mm:ss ±hhmm" (Wdy, being optional)
+ QRegExp rex(QStringLiteral("^(?:[A-Z][a-z]+,)?[ \\t]*(\\d{1,2})[ \\t]+([A-Z][a-z]+)[ \\t]+(\\d\\d\\d\\d)(?:[ \\t]+(\\d\\d):(\\d\\d)(?::(\\d\\d))?)?[ \\t]*(?:([+-])(\\d\\d)(\\d\\d))?"));
+ if (s.indexOf(rex) == 0) {
+ const QStringList cap = rex.capturedTexts();
+ result.date = QDate(cap[3].toInt(), qt_monthNumberFromShortName(cap[2]), cap[1].toInt());
+ if (!cap[4].isEmpty())
+ result.time = QTime(cap[4].toInt(), cap[5].toInt(), cap[6].toInt());
+ const bool positiveOffset = (cap[7] == QLatin1String("+"));
+ const int hourOffset = cap[8].toInt();
+ const int minOffset = cap[9].toInt();
+ result.utcOffset = ((hourOffset * 60 + minOffset) * (positiveOffset ? 60 : -60));
+ } else {
+ // Matches "Wdy Mon dd HH:mm:ss yyyy"
+ QRegExp rex(QStringLiteral("^[A-Z][a-z]+[ \\t]+([A-Z][a-z]+)[ \\t]+(\\d\\d)(?:[ \\t]+(\\d\\d):(\\d\\d):(\\d\\d))?[ \\t]+(\\d\\d\\d\\d)[ \\t]*(?:([+-])(\\d\\d)(\\d\\d))?"));
+ if (s.indexOf(rex) == 0) {
+ const QStringList cap = rex.capturedTexts();
+ result.date = QDate(cap[6].toInt(), qt_monthNumberFromShortName(cap[1]), cap[2].toInt());
+ if (!cap[3].isEmpty())
+ result.time = QTime(cap[3].toInt(), cap[4].toInt(), cap[5].toInt());
+ const bool positiveOffset = (cap[7] == QLatin1String("+"));
+ const int hourOffset = cap[8].toInt();
+ const int minOffset = cap[9].toInt();
+ result.utcOffset = ((hourOffset * 60 + minOffset) * (positiveOffset ? 60 : -60));
+ }
+ }
+
+ return result;
+}
+#endif // datestring
+
+// Return offset in [+-]HH:mm format
+static QString toOffsetString(Qt::DateFormat format, int offset)
+{
+ return QString::asprintf("%c%02d%s%02d",
+ offset >= 0 ? '+' : '-',
+ qAbs(offset) / SECS_PER_HOUR,
+ // Qt::ISODate puts : between the hours and minutes, but Qt:TextDate does not:
+ format == Qt::TextDate ? "" : ":",
+ (qAbs(offset) / 60) % 60);
+}
+
+#if QT_CONFIG(datestring)
+// Parse offset in [+-]HH[[:]mm] format
+static int fromOffsetString(const QStringRef &offsetString, bool *valid) noexcept
+{
+ *valid = false;
+
+ const int size = offsetString.size();
+ if (size < 2 || size > 6)
+ return 0;
+
+ // sign will be +1 for a positive and -1 for a negative offset
+ int sign;
+
+ // First char must be + or -
+ const QChar signChar = offsetString.at(0);
+ if (signChar == QLatin1Char('+'))
+ sign = 1;
+ else if (signChar == QLatin1Char('-'))
+ sign = -1;
+ else
+ return 0;
+
+ // Split the hour and minute parts
+ const QStringRef time = offsetString.mid(1);
+ int hhLen = time.indexOf(QLatin1Char(':'));
+ int mmIndex;
+ if (hhLen == -1)
+ mmIndex = hhLen = 2; // [+-]HHmm or [+-]HH format
+ else
+ mmIndex = hhLen + 1;
+
+ const QStringRef hhRef = time.left(hhLen);
+ bool ok = false;
+ const int hour = hhRef.toInt(&ok);
+ if (!ok)
+ return 0;
+
+ const QStringRef mmRef = time.mid(mmIndex);
+ const int minute = mmRef.isEmpty() ? 0 : mmRef.toInt(&ok);
+ if (!ok || minute < 0 || minute > 59)
+ return 0;
+
+ *valid = true;
+ return sign * ((hour * 60) + minute) * 60;
+}
+#endif // datestring
+
+/*****************************************************************************
+ QDate member functions
+ *****************************************************************************/
+
+/*!
+ \since 4.5
+
+ \enum QDate::MonthNameType
+
+ This enum describes the types of the string representation used
+ for the month name.
+
+ \value DateFormat This type of name can be used for date-to-string formatting.
+ \value StandaloneFormat This type is used when you need to enumerate months or weekdays.
+ Usually standalone names are represented in singular forms with
+ capitalized first letter.
+*/
+
+/*!
+ \class QDate
+ \inmodule QtCore
+ \reentrant
+ \brief The QDate class provides date functions.
+
+
+ A QDate object represents a particular date. This can be expressed as a
+ calendar date, i.e. year, month, and day numbers, in the proleptic Gregorian
+ calendar.
+
+ A QDate object is typically created by giving the year, month, and day
+ numbers explicitly. Note that QDate interprets year numbers less than 100 as
+ presented, i.e., as years 1 through 99, without adding any offset. The
+ static function currentDate() creates a QDate object containing the date
+ read from the system clock. An explicit date can also be set using
+ setDate(). The fromString() function returns a QDate given a string and a
+ date format which is used to interpret the date within the string.
+
+ The year(), month(), and day() functions provide access to the year, month,
+ and day numbers. Also, dayOfWeek() and dayOfYear() functions are
+ provided. The same information is provided in textual format by
+ toString(). The day and month numbers can be mapped to names using QLocale.
+
+ QDate provides a full set of operators to compare two QDate
+ objects where smaller means earlier, and larger means later.
+
+ You can increment (or decrement) a date by a given number of days
+ using addDays(). Similarly you can use addMonths() and addYears().
+ The daysTo() function returns the number of days between two
+ dates.
+
+ The daysInMonth() and daysInYear() functions return how many days
+ there are in this date's month and year, respectively. The
+ isLeapYear() function indicates whether a date is in a leap year.
+
+ \section1 Remarks
+
+ \section2 No Year 0
+
+ There is no year 0. Dates in that year are considered invalid. The year -1
+ is the year "1 before Christ" or "1 before current era." The day before 1
+ January 1 CE, QDate(1, 1, 1), is 31 December 1 BCE, QDate(-1, 12, 31).
+
+ \section2 Range of Valid Dates
+
+ Dates are stored internally as a Julian Day number, an integer count of
+ every day in a contiguous range, with 24 November 4714 BCE in the Gregorian
+ calendar being Julian Day 0 (1 January 4713 BCE in the Julian calendar).
+ As well as being an efficient and accurate way of storing an absolute date,
+ it is suitable for converting a date into other calendar systems such as
+ Hebrew, Islamic or Chinese. The Julian Day number can be obtained using
+ QDate::toJulianDay() and can be set using QDate::fromJulianDay().
+
+ The range of dates able to be stored by QDate as a Julian Day number is
+ for technical reasons limited to between -784350574879 and 784354017364,
+ which means from before 2 billion BCE to after 2 billion CE.
+
+ \sa QTime, QDateTime, QCalendar, QDateTime::YearRange, QDateEdit, QDateTimeEdit, QCalendarWidget
+*/
+
+/*!
+ \fn QDate::QDate()
+
+ Constructs a null date. Null dates are invalid.
+
+ \sa isNull(), isValid()
+*/
+
+/*!
+ Constructs a date with year \a y, month \a m and day \a d.
+
+ The date is understood in terms of the Gregorian calendar. If the specified
+ date is invalid, the date is not set and isValid() returns \c false.
+
+ \warning Years 1 to 99 are interpreted as is. Year 0 is invalid.
+
+ \sa isValid(), QCalendar::dateFromParts()
+*/
+
+QDate::QDate(int y, int m, int d)
+{
+ if (!QGregorianCalendar::julianFromParts(y, m, d, &jd))
+ jd = nullJd();
+}
+
+QDate::QDate(int y, int m, int d, QCalendar cal)
+{
+ *this = cal.dateFromParts(y, m, d);
+}
+
+/*!
+ \fn bool QDate::isNull() const
+
+ Returns \c true if the date is null; otherwise returns \c false. A null
+ date is invalid.
+
+ \note The behavior of this function is equivalent to isValid().
+
+ \sa isValid()
+*/
+
+/*!
+ \fn bool QDate::isValid() const
+
+ Returns \c true if this date is valid; otherwise returns \c false.
+
+ \sa isNull(), QCalendar::isDateValid()
+*/
+
+/*!
+ Returns the year of this date.
+
+ Uses \a cal as calendar, if supplied, else the Gregorian calendar.
+
+ Returns 0 if the date is invalid. For some calendars, dates before their
+ first year may all be invalid.
+
+ If using a calendar which has a year 0, check using isValid() if the return
+ is 0. Such calendars use negative year numbers in the obvious way, with
+ year 1 preceded by year 0, in turn preceded by year -1 and so on.
+
+ Some calendars, despite having no year 0, have a conventional numbering of
+ the years before their first year, counting backwards from 1. For example,
+ in the proleptic Gregorian calendar, successive years before 1 CE (the first
+ year) are identified as 1 BCE, 2 BCE, 3 BCE and so on. For such calendars,
+ negative year numbers are used to indicate these years before year 1, with
+ -1 indicating the year before 1.
+
+ \sa month(), day(), QCalendar::hasYearZero(), QCalendar::isProleptic()
+*/
+
+int QDate::year(QCalendar cal) const
+{
+ if (isValid()) {
+ const auto parts = cal.partsFromDate(*this);
+ if (parts.isValid())
+ return parts.year;
+ }
+ return 0;
+}
+
+/*!
+ \overload
+ */
+
+int QDate::year() const
+{
+ if (isValid()) {
+ const auto parts = QGregorianCalendar::partsFromJulian(jd);
+ if (parts.isValid())
+ return parts.year;
+ }
+ return 0;
+}
+
+/*!
+ Returns the month-number for the date.
+
+ Numbers the months of the year starting with 1 for the first. Uses \a cal
+ as calendar if supplied, else the Gregorian calendar, for which the month
+ numbering is as follows:
+
+ \list
+ \li 1 = "January"
+ \li 2 = "February"
+ \li 3 = "March"
+ \li 4 = "April"
+ \li 5 = "May"
+ \li 6 = "June"
+ \li 7 = "July"
+ \li 8 = "August"
+ \li 9 = "September"
+ \li 10 = "October"
+ \li 11 = "November"
+ \li 12 = "December"
+ \endlist
+
+ Returns 0 if the date is invalid. Note that some calendars may have more
+ than 12 months in some years.
+
+ \sa year(), day()
+*/
+
+int QDate::month(QCalendar cal) const
+{
+ if (isValid()) {
+ const auto parts = cal.partsFromDate(*this);
+ if (parts.isValid())
+ return parts.month;
+ }
+ return 0;
+}
+
+/*!
+ \overload
+ */
+
+int QDate::month() const
+{
+ if (isValid()) {
+ const auto parts = QGregorianCalendar::partsFromJulian(jd);
+ if (parts.isValid())
+ return parts.month;
+ }
+ return 0;
+}
+
+/*!
+ Returns the day of the month for this date.
+
+ Uses \a cal as calendar if supplied, else the Gregorian calendar (for which
+ the return ranges from 1 to 31). Returns 0 if the date is invalid.
+
+ \sa year(), month(), dayOfWeek()
+*/
+
+int QDate::day(QCalendar cal) const
+{
+ if (isValid()) {
+ const auto parts = cal.partsFromDate(*this);
+ if (parts.isValid())
+ return parts.day;
+ }
+ return 0;
+}
+
+/*!
+ \overload
+ */
+
+int QDate::day() const
+{
+ if (isValid()) {
+ const auto parts = QGregorianCalendar::partsFromJulian(jd);
+ if (parts.isValid())
+ return parts.day;
+ }
+ return 0;
+}
+
+/*!
+ Returns the weekday (1 = Monday to 7 = Sunday) for this date.
+
+ Uses \a cal as calendar if supplied, else the Gregorian calendar. Returns 0
+ if the date is invalid. Some calendars may give special meaning
+ (e.g. intercallary days) to values greater than 7.
+
+ \sa day(), dayOfYear(), Qt::DayOfWeek
+*/
+
+int QDate::dayOfWeek(QCalendar cal) const
+{
+ if (isNull())
+ return 0;
+
+ return cal.dayOfWeek(*this);
+}
+
+/*!
+ \overload
+ */
+
+int QDate::dayOfWeek() const
+{
+ return isValid() ? QGregorianCalendar::weekDayOfJulian(jd) : 0;
+}
+
+/*!
+ Returns the day of the year (1 for the first day) for this date.
+
+ Uses \a cal as calendar if supplied, else the Gregorian calendar.
+ Returns 0 if either the date or the first day of its year is invalid.
+
+ \sa day(), dayOfWeek()
+*/
+
+int QDate::dayOfYear(QCalendar cal) const
+{
+ if (isValid()) {
+ QDate firstDay = cal.dateFromParts(year(cal), 1, 1);
+ if (firstDay.isValid())
+ return firstDay.daysTo(*this) + 1;
+ }
+ return 0;
+}
+
+/*!
+ \overload
+ */
+
+int QDate::dayOfYear() const
+{
+ if (isValid()) {
+ qint64 first;
+ if (QGregorianCalendar::julianFromParts(year(), 1, 1, &first))
+ return jd - first + 1;
+ }
+ return 0;
+}
+
+/*!
+ Returns the number of days in the month for this date.
+
+ Uses \a cal as calendar if supplied, else the Gregorian calendar (for which
+ the result ranges from 28 to 31). Returns 0 if the date is invalid.
+
+ \sa day(), daysInYear()
+*/
+
+int QDate::daysInMonth(QCalendar cal) const
+{
+ if (isValid()) {
+ const auto parts = cal.partsFromDate(*this);
+ if (parts.isValid())
+ return cal.daysInMonth(parts.month, parts.year);
+ }
+ return 0;
+}
+
+/*!
+ \overload
+ */
+
+int QDate::daysInMonth() const
+{
+ if (isValid()) {
+ const auto parts = QGregorianCalendar::partsFromJulian(jd);
+ if (parts.isValid())
+ return QGregorianCalendar::monthLength(parts.month, parts.year);
+ }
+ return 0;
+}
+
+/*!
+ Returns the number of days in the year for this date.
+
+ Uses \a cal as calendar if supplied, else the Gregorian calendar (for which
+ the result is 365 or 366). Returns 0 if the date is invalid.
+
+ \sa day(), daysInMonth()
+*/
+
+int QDate::daysInYear(QCalendar cal) const
+{
+ if (isNull())
+ return 0;
+
+ return cal.daysInYear(year(cal));
+}
+
+/*!
+ \overload
+ */
+
+int QDate::daysInYear() const
+{
+ return isValid() ? QGregorianCalendar::leapTest(year()) ? 366 : 365 : 0;
+}
+
+/*!
+ Returns the ISO 8601 week number (1 to 53).
+
+ Returns 0 if the date is invalid. Otherwise, returns the week number for the
+ date. If \a yearNumber is not \nullptr (its default), stores the year as
+ *\a{yearNumber}.
+
+ In accordance with ISO 8601, each week falls in the year to which most of
+ its days belong, in the Gregorian calendar. As ISO 8601's week starts on
+ Monday, this is the year in which the week's Thursday falls. Most years have
+ 52 weeks, but some have 53.
+
+ \note *\a{yearNumber} is not always the same as year(). For example, 1
+ January 2000 has week number 52 in the year 1999, and 31 December
+ 2002 has week number 1 in the year 2003.
+
+ \sa isValid()
+*/
+
+int QDate::weekNumber(int *yearNumber) const
+{
+ if (!isValid())
+ return 0;
+
+ // This could be replaced by use of QIso8601Calendar, once we implement it.
+ // The Thursday of the same week determines our answer:
+ QDate thursday(addDays(4 - dayOfWeek()));
+ int year = thursday.year();
+ // Week n's Thurs's DOY has 1 <= DOY - 7*(n-1) < 8, so 0 <= DOY + 6 - 7*n < 7:
+ int week = (thursday.dayOfYear() + 6) / 7;
+
+ if (yearNumber)
+ *yearNumber = year;
+ return week;
+}
+
+static bool inDateTimeRange(qint64 jd, bool start)
+{
+ using Bounds = std::numeric_limits<qint64>;
+ if (jd < Bounds::min() + JULIAN_DAY_FOR_EPOCH)
+ return false;
+ jd -= JULIAN_DAY_FOR_EPOCH;
+ const qint64 maxDay = Bounds::max() / MSECS_PER_DAY;
+ const qint64 minDay = Bounds::min() / MSECS_PER_DAY - 1;
+ // (Divisions rounded towards zero, as MSECS_PER_DAY has factors other than two.)
+ // Range includes start of last day and end of first:
+ if (start)
+ return jd > minDay && jd <= maxDay;
+ return jd >= minDay && jd < maxDay;
+}
+
+static QDateTime toEarliest(const QDate &day, const QDateTime &form)
+{
+ const Qt::TimeSpec spec = form.timeSpec();
+ const int offset = (spec == Qt::OffsetFromUTC) ? form.offsetFromUtc() : 0;
+#if QT_CONFIG(timezone)
+ QTimeZone zone;
+ if (spec == Qt::TimeZone)
+ zone = form.timeZone();
+#endif
+ auto moment = [=](QTime time) {
+ switch (spec) {
+ case Qt::OffsetFromUTC: return QDateTime(day, time, spec, offset);
+#if QT_CONFIG(timezone)
+ case Qt::TimeZone: return QDateTime(day, time, zone);
+#endif
+ default: return QDateTime(day, time, spec);
+ }
+ };
+ // Longest routine time-zone transition is 2 hours:
+ QDateTime when = moment(QTime(2, 0));
+ if (!when.isValid()) {
+ // Noon should be safe ...
+ when = moment(QTime(12, 0));
+ if (!when.isValid()) {
+ // ... unless it's a 24-hour jump (moving the date-line)
+ when = moment(QTime(23, 59, 59, 999));
+ if (!when.isValid())
+ return QDateTime();
+ }
+ }
+ int high = when.time().msecsSinceStartOfDay() / 60000;
+ int low = 0;
+ // Binary chop to the right minute
+ while (high > low + 1) {
+ int mid = (high + low) / 2;
+ QDateTime probe = moment(QTime(mid / 60, mid % 60));
+ if (probe.isValid() && probe.date() == day) {
+ high = mid;
+ when = probe;
+ } else {
+ low = mid;
+ }
+ }
+ return when;
+}
+
+/*!
+ \since 5.14
+ \fn QDateTime QDate::startOfDay(Qt::TimeSpec spec, int offsetSeconds) const
+ \fn QDateTime QDate::startOfDay(const QTimeZone &zone) const
+
+ Returns the start-moment of the day. Usually, this shall be midnight at the
+ start of the day: however, if a time-zone transition causes the given date
+ to skip over that midnight (e.g. a DST spring-forward skipping from the end
+ of the previous day to 01:00 of the new day), the actual earliest time in
+ the day is returned. This can only arise when the start-moment is specified
+ in terms of a time-zone (by passing its QTimeZone as \a zone) or in terms of
+ local time (by passing Qt::LocalTime as \a spec; this is its default).
+
+ The \a offsetSeconds is ignored unless \a spec is Qt::OffsetFromUTC, when it
+ gives the implied zone's offset from UTC. As UTC and such zones have no
+ transitions, the start of the day is QTime(0, 0) in these cases.
+
+ In the rare case of a date that was entirely skipped (this happens when a
+ zone east of the international date-line switches to being west of it), the
+ return shall be invalid. Passing Qt::TimeZone as \a spec (instead of
+ passing a QTimeZone) or passing an invalid time-zone as \a zone will also
+ produce an invalid result, as shall dates that start outside the range
+ representable by QDateTime.
+
+ \sa endOfDay()
+*/
+QDateTime QDate::startOfDay(Qt::TimeSpec spec, int offsetSeconds) const
+{
+ if (!inDateTimeRange(jd, true))
+ return QDateTime();
+
+ switch (spec) {
+ case Qt::TimeZone: // should pass a QTimeZone instead of Qt::TimeZone
+ qWarning() << "Called QDate::startOfDay(Qt::TimeZone) on" << *this;
+ return QDateTime();
+ case Qt::OffsetFromUTC:
+ case Qt::UTC:
+ return QDateTime(*this, QTime(0, 0), spec, offsetSeconds);
+
+ case Qt::LocalTime:
+ if (offsetSeconds)
+ qWarning("Ignoring offset (%d seconds) passed with Qt::LocalTime", offsetSeconds);
+ break;
+ }
+ QDateTime when(*this, QTime(0, 0), spec);
+ if (!when.isValid())
+ when = toEarliest(*this, when);
+
+ return when.isValid() ? when : QDateTime();
+}
+
+#if QT_CONFIG(timezone)
+/*!
+ \overload
+ \since 5.14
+*/
+QDateTime QDate::startOfDay(const QTimeZone &zone) const
+{
+ if (!inDateTimeRange(jd, true) || !zone.isValid())
+ return QDateTime();
+
+ QDateTime when(*this, QTime(0, 0), zone);
+ if (when.isValid())
+ return when;
+
+ // The start of the day must have fallen in a spring-forward's gap; find the spring-forward:
+ if (zone.hasTransitions()) {
+ QTimeZone::OffsetData tran = zone.previousTransition(QDateTime(*this, QTime(23, 59, 59, 999), zone));
+ const QDateTime &at = tran.atUtc.toTimeZone(zone);
+ if (at.isValid() && at.date() == *this)
+ return at;
+ }
+
+ when = toEarliest(*this, when);
+ return when.isValid() ? when : QDateTime();
+}
+#endif // timezone
+
+static QDateTime toLatest(const QDate &day, const QDateTime &form)
+{
+ const Qt::TimeSpec spec = form.timeSpec();
+ const int offset = (spec == Qt::OffsetFromUTC) ? form.offsetFromUtc() : 0;
+#if QT_CONFIG(timezone)
+ QTimeZone zone;
+ if (spec == Qt::TimeZone)
+ zone = form.timeZone();
+#endif
+ auto moment = [=](QTime time) {
+ switch (spec) {
+ case Qt::OffsetFromUTC: return QDateTime(day, time, spec, offset);
+#if QT_CONFIG(timezone)
+ case Qt::TimeZone: return QDateTime(day, time, zone);
+#endif
+ default: return QDateTime(day, time, spec);
+ }
+ };
+ // Longest routine time-zone transition is 2 hours:
+ QDateTime when = moment(QTime(21, 59, 59, 999));
+ if (!when.isValid()) {
+ // Noon should be safe ...
+ when = moment(QTime(12, 0));
+ if (!when.isValid()) {
+ // ... unless it's a 24-hour jump (moving the date-line)
+ when = moment(QTime(0, 0));
+ if (!when.isValid())
+ return QDateTime();
+ }
+ }
+ int high = 24 * 60;
+ int low = when.time().msecsSinceStartOfDay() / 60000;
+ // Binary chop to the right minute
+ while (high > low + 1) {
+ int mid = (high + low) / 2;
+ QDateTime probe = moment(QTime(mid / 60, mid % 60, 59, 999));
+ if (probe.isValid() && probe.date() == day) {
+ low = mid;
+ when = probe;
+ } else {
+ high = mid;
+ }
+ }
+ return when;
+}
+
+/*!
+ \since 5.14
+ \fn QDateTime QDate::endOfDay(Qt::TimeSpec spec, int offsetSeconds) const
+ \fn QDateTime QDate::endOfDay(const QTimeZone &zone) const
+
+ Returns the end-moment of the day. Usually, this is one millisecond before
+ the midnight at the end of the day: however, if a time-zone transition
+ causes the given date to skip over that midnight (e.g. a DST spring-forward
+ skipping from just before 23:00 to the start of the next day), the actual
+ latest time in the day is returned. This can only arise when the
+ start-moment is specified in terms of a time-zone (by passing its QTimeZone
+ as \a zone) or in terms of local time (by passing Qt::LocalTime as \a spec;
+ this is its default).
+
+ The \a offsetSeconds is ignored unless \a spec is Qt::OffsetFromUTC, when it
+ gives the implied zone's offset from UTC. As UTC and such zones have no
+ transitions, the end of the day is QTime(23, 59, 59, 999) in these cases.
+
+ In the rare case of a date that was entirely skipped (this happens when a
+ zone east of the international date-line switches to being west of it), the
+ return shall be invalid. Passing Qt::TimeZone as \a spec (instead of
+ passing a QTimeZone) will also produce an invalid result, as shall dates
+ that end outside the range representable by QDateTime.
+
+ \sa startOfDay()
+*/
+QDateTime QDate::endOfDay(Qt::TimeSpec spec, int offsetSeconds) const
+{
+ if (!inDateTimeRange(jd, false))
+ return QDateTime();
+
+ switch (spec) {
+ case Qt::TimeZone: // should pass a QTimeZone instead of Qt::TimeZone
+ qWarning() << "Called QDate::endOfDay(Qt::TimeZone) on" << *this;
+ return QDateTime();
+ case Qt::UTC:
+ case Qt::OffsetFromUTC:
+ return QDateTime(*this, QTime(23, 59, 59, 999), spec, offsetSeconds);
+
+ case Qt::LocalTime:
+ if (offsetSeconds)
+ qWarning("Ignoring offset (%d seconds) passed with Qt::LocalTime", offsetSeconds);
+ break;
+ }
+ QDateTime when(*this, QTime(23, 59, 59, 999), spec);
+ if (!when.isValid())
+ when = toLatest(*this, when);
+ return when.isValid() ? when : QDateTime();
+}
+
+#if QT_CONFIG(timezone)
+/*!
+ \overload
+ \since 5.14
+*/
+QDateTime QDate::endOfDay(const QTimeZone &zone) const
+{
+ if (!inDateTimeRange(jd, false) || !zone.isValid())
+ return QDateTime();
+
+ QDateTime when(*this, QTime(23, 59, 59, 999), zone);
+ if (when.isValid())
+ return when;
+
+ // The end of the day must have fallen in a spring-forward's gap; find the spring-forward:
+ if (zone.hasTransitions()) {
+ QTimeZone::OffsetData tran = zone.nextTransition(QDateTime(*this, QTime(0, 0), zone));
+ const QDateTime &at = tran.atUtc.toTimeZone(zone);
+ if (at.isValid() && at.date() == *this)
+ return at;
+ }
+
+ when = toLatest(*this, when);
+ return when.isValid() ? when : QDateTime();
+}
+#endif // timezone
+
+#if QT_DEPRECATED_SINCE(5, 11) && QT_CONFIG(textdate)
+
+/*!
+ \since 4.5
+ \deprecated
+
+ Returns the short name of the \a month for the representation specified
+ by \a type.
+
+ The months are enumerated using the following convention:
+
+ \list
+ \li 1 = "Jan"
+ \li 2 = "Feb"
+ \li 3 = "Mar"
+ \li 4 = "Apr"
+ \li 5 = "May"
+ \li 6 = "Jun"
+ \li 7 = "Jul"
+ \li 8 = "Aug"
+ \li 9 = "Sep"
+ \li 10 = "Oct"
+ \li 11 = "Nov"
+ \li 12 = "Dec"
+ \endlist
+
+ The month names will be localized according to the system's
+ locale settings, i.e. using QLocale::system().
+
+ Returns an empty string if the date is invalid.
+
+ \sa toString(), longMonthName(), shortDayName(), longDayName()
+*/
+
+QString QDate::shortMonthName(int month, QDate::MonthNameType type)
+{
+ switch (type) {
+ case QDate::DateFormat:
+ return QCalendar().monthName(QLocale::system(), month,
+ QCalendar::Unspecified, QLocale::ShortFormat);
+ case QDate::StandaloneFormat:
+ return QCalendar().standaloneMonthName(QLocale::system(), month,
+ QCalendar::Unspecified, QLocale::ShortFormat);
+ }
+ return QString();
+}
+
+/*!
+ \since 4.5
+ \deprecated
+
+ Returns the long name of the \a month for the representation specified
+ by \a type.
+
+ The months are enumerated using the following convention:
+
+ \list
+ \li 1 = "January"
+ \li 2 = "February"
+ \li 3 = "March"
+ \li 4 = "April"
+ \li 5 = "May"
+ \li 6 = "June"
+ \li 7 = "July"
+ \li 8 = "August"
+ \li 9 = "September"
+ \li 10 = "October"
+ \li 11 = "November"
+ \li 12 = "December"
+ \endlist
+
+ The month names will be localized according to the system's
+ locale settings, i.e. using QLocale::system().
+
+ Returns an empty string if the date is invalid.
+
+ \sa toString(), shortMonthName(), shortDayName(), longDayName()
+*/
+
+QString QDate::longMonthName(int month, MonthNameType type)
+{
+ switch (type) {
+ case QDate::DateFormat:
+ return QCalendar().monthName(QLocale::system(), month,
+ QCalendar::Unspecified, QLocale::LongFormat);
+ case QDate::StandaloneFormat:
+ return QCalendar().standaloneMonthName(QLocale::system(), month,
+ QCalendar::Unspecified, QLocale::LongFormat);
+ }
+ return QString();
+}
+
+/*!
+ \since 4.5
+ \deprecated
+
+ Returns the short name of the \a weekday for the representation specified
+ by \a type.
+
+ The days are enumerated using the following convention:
+
+ \list
+ \li 1 = "Mon"
+ \li 2 = "Tue"
+ \li 3 = "Wed"
+ \li 4 = "Thu"
+ \li 5 = "Fri"
+ \li 6 = "Sat"
+ \li 7 = "Sun"
+ \endlist
+
+ The day names will be localized according to the system's
+ locale settings, i.e. using QLocale::system().
+
+ Returns an empty string if the date is invalid.
+
+ \sa toString(), shortMonthName(), longMonthName(), longDayName()
+*/
+
+QString QDate::shortDayName(int weekday, MonthNameType type)
+{
+ switch (type) {
+ case QDate::DateFormat:
+ return QLocale::system().dayName(weekday, QLocale::ShortFormat);
+ case QDate::StandaloneFormat:
+ return QLocale::system().standaloneDayName(weekday, QLocale::ShortFormat);
+ }
+ return QString();
+}
+
+/*!
+ \since 4.5
+ \deprecated
+
+ Returns the long name of the \a weekday for the representation specified
+ by \a type.
+
+ The days are enumerated using the following convention:
+
+ \list
+ \li 1 = "Monday"
+ \li 2 = "Tuesday"
+ \li 3 = "Wednesday"
+ \li 4 = "Thursday"
+ \li 5 = "Friday"
+ \li 6 = "Saturday"
+ \li 7 = "Sunday"
+ \endlist
+
+ The day names will be localized according to the system's
+ locale settings, i.e. using QLocale::system().
+
+ Returns an empty string if the date is invalid.
+
+ \sa toString(), shortDayName(), shortMonthName(), longMonthName()
+*/
+
+QString QDate::longDayName(int weekday, MonthNameType type)
+{
+ switch (type) {
+ case QDate::DateFormat:
+ return QLocale::system().dayName(weekday, QLocale::LongFormat);
+ case QDate::StandaloneFormat:
+ return QLocale::system().standaloneDayName(weekday, QLocale::LongFormat);
+ }
+ return QString();
+}
+#endif // textdate && deprecated
+
+#if QT_CONFIG(datestring)
+
+#if QT_CONFIG(textdate)
+static QString toStringTextDate(QDate date, QCalendar cal)
+{
+ if (date.isValid()) {
+ const auto parts = cal.partsFromDate(date);
+ if (parts.isValid()) {
+ const QLatin1Char sp(' ');
+ return QLocale::system().dayName(cal.dayOfWeek(date), QLocale::ShortFormat) + sp
+ + cal.monthName(QLocale::system(), parts.month, parts.year, QLocale::ShortFormat)
+ + sp + QString::number(parts.day) + sp + QString::number(parts.year);
+ }
+ }
+ return QString();
+}
+
+static QString toStringTextDate(QDate date)
+{
+ return toStringTextDate(date, QCalendar());
+}
+#endif // textdate
+
+static QString toStringIsoDate(const QDate &date)
+{
+ const auto parts = QCalendar().partsFromDate(date);
+ if (parts.isValid() && parts.year >= 0 && parts.year <= 9999)
+ return QString::asprintf("%04d-%02d-%02d", parts.year, parts.month, parts.day);
+ return QString();
+}
+
+/*!
+ \fn QString QDate::toString(Qt::DateFormat format) const
+
+ \overload
+
+ Returns the date as a string. The \a format parameter determines
+ the format of the string.
+
+ If the \a format is Qt::TextDate, the string is formatted in the default
+ way. The day and month names will be localized names using the system
+ locale, i.e. QLocale::system(). An example of this formatting
+ is "Sat May 20 1995".
+
+ If the \a format is Qt::ISODate, the string format corresponds
+ to the ISO 8601 extended specification for representations of
+ dates and times, taking the form yyyy-MM-dd, where yyyy is the
+ year, MM is the month of the year (between 01 and 12), and dd is
+ the day of the month between 01 and 31.
+
+ If the \a format is Qt::SystemLocaleShortDate or
+ Qt::SystemLocaleLongDate, the string format depends on the locale
+ settings of the system. Identical to calling
+ QLocale::system().toString(date, QLocale::ShortFormat) or
+ QLocale::system().toString(date, QLocale::LongFormat).
+
+ If the \a format is Qt::DefaultLocaleShortDate or
+ Qt::DefaultLocaleLongDate, the string format depends on the
+ default application locale. This is the locale set with
+ QLocale::setDefault(), or the system locale if no default locale
+ has been set. Identical to calling
+ \l {QLocale::toString()}{QLocale().toString(date, QLocale::ShortFormat) } or
+ \l {QLocale::toString()}{QLocale().toString(date, QLocale::LongFormat)}.
+
+ If the \a format is Qt::RFC2822Date, the string is formatted in
+ an \l{RFC 2822} compatible way. An example of this formatting is
+ "20 May 1995".
+
+ If the date is invalid, an empty string will be returned.
+
+ \warning The Qt::ISODate format is only valid for years in the
+ range 0 to 9999. This restriction may apply to locale-aware
+ formats as well, depending on the locale settings.
+
+ \sa fromString(), QLocale::toString()
+*/
+QString QDate::toString(Qt::DateFormat format) const
+{
+ if (!isValid())
+ return QString();
+
+ switch (format) {
+ case Qt::SystemLocaleDate:
+ case Qt::SystemLocaleShortDate:
+ return QLocale::system().toString(*this, QLocale::ShortFormat);
+ case Qt::SystemLocaleLongDate:
+ return QLocale::system().toString(*this, QLocale::LongFormat);
+ case Qt::LocaleDate:
+ case Qt::DefaultLocaleShortDate:
+ return QLocale().toString(*this, QLocale::ShortFormat);
+ case Qt::DefaultLocaleLongDate:
+ return QLocale().toString(*this, QLocale::LongFormat);
+ case Qt::RFC2822Date:
+ return QLocale::c().toString(*this, u"dd MMM yyyy");
+ default:
+#if QT_CONFIG(textdate)
+ case Qt::TextDate:
+ return toStringTextDate(*this);
+#endif
+ case Qt::ISODate:
+ case Qt::ISODateWithMs:
+ return toStringIsoDate(*this);
+ }
+}
+
+/*!
+ \fn QString QDate::toString(const QString &format) const
+ \fn QString QDate::toString(QStringView format) const
+
+ Returns the date as a string. The \a format parameter determines
+ the format of the result string.
+
+ These expressions may be used:
+
+ \table
+ \header \li Expression \li Output
+ \row \li d \li The day as a number without a leading zero (1 to 31)
+ \row \li dd \li The day as a number with a leading zero (01 to 31)
+ \row \li ddd
+ \li The abbreviated localized day name (e.g. 'Mon' to 'Sun').
+ Uses the system locale to localize the name, i.e. QLocale::system().
+ \row \li dddd
+ \li The long localized day name (e.g. 'Monday' to 'Sunday').
+ Uses the system locale to localize the name, i.e. QLocale::system().
+ \row \li M \li The month as a number without a leading zero (1 to 12)
+ \row \li MM \li The month as a number with a leading zero (01 to 12)
+ \row \li MMM
+ \li The abbreviated localized month name (e.g. 'Jan' to 'Dec').
+ Uses the system locale to localize the name, i.e. QLocale::system().
+ \row \li MMMM
+ \li The long localized month name (e.g. 'January' to 'December').
+ Uses the system locale to localize the name, i.e. QLocale::system().
+ \row \li yy \li The year as a two digit number (00 to 99)
+ \row \li yyyy \li The year as a four digit number. If the year is negative,
+ a minus sign is prepended, making five characters.
+ \endtable
+
+ Any sequence of characters enclosed in single quotes will be included
+ verbatim in the output string (stripped of the quotes), even if it contains
+ formatting characters. Two consecutive single quotes ("''") are replaced by
+ a single quote in the output. All other characters in the format string are
+ included verbatim in the output string.
+
+ Formats without separators (e.g. "ddMM") are supported but must be used with
+ care, as the resulting strings aren't always reliably readable (e.g. if "dM"
+ produces "212" it could mean either the 2nd of December or the 21st of
+ February).
+
+ Example format strings (assuming that the QDate is the 20 July
+ 1969):
+
+ \table
+ \header \li Format \li Result
+ \row \li dd.MM.yyyy \li 20.07.1969
+ \row \li ddd MMMM d yy \li Sun July 20 69
+ \row \li 'The day is' dddd \li The day is Sunday
+ \endtable
+
+ If the datetime is invalid, an empty string will be returned.
+
+ \sa fromString(), QDateTime::toString(), QTime::toString(), QLocale::toString()
+
+*/
+QString QDate::toString(QStringView format) const
+{
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
+}
+
+#if QT_STRINGVIEW_LEVEL < 2
+QString QDate::toString(const QString &format) const
+{
+ return toString(qToStringViewIgnoringNull(format));
+}
+#endif
+
+QString QDate::toString(Qt::DateFormat format, QCalendar cal) const
+{
+ if (!isValid())
+ return QString();
+
+ switch (format) {
+ case Qt::SystemLocaleDate:
+ case Qt::SystemLocaleShortDate:
+ return QLocale::system().toString(*this, QLocale::ShortFormat, cal);
+ case Qt::SystemLocaleLongDate:
+ return QLocale::system().toString(*this, QLocale::LongFormat, cal);
+ case Qt::LocaleDate:
+ case Qt::DefaultLocaleShortDate:
+ return QLocale().toString(*this, QLocale::ShortFormat, cal);
+ case Qt::DefaultLocaleLongDate:
+ return QLocale().toString(*this, QLocale::LongFormat, cal);
+ case Qt::RFC2822Date:
+ return QLocale::c().toString(*this, QStringView(u"dd MMM yyyy"), cal);
+ default:
+#ifndef QT_NO_TEXTDATE
+ case Qt::TextDate:
+ return toStringTextDate(*this, cal);
+#endif
+ case Qt::ISODate:
+ case Qt::ISODateWithMs:
+ return toStringIsoDate(*this);
+ }
+}
+
+QString QDate::toString(QStringView format, QCalendar cal) const
+{
+ return QLocale::system().toString(*this, format, cal); // QLocale::c() ### Qt6
+}
+
+#if QT_STRINGVIEW_LEVEL < 2
+QString QDate::toString(const QString &format, QCalendar cal) const
+{
+ return toString(qToStringViewIgnoringNull(format), cal);
+}
+#endif
+
+#endif // datestring
+
+/*!
+ \fn bool QDate::setYMD(int y, int m, int d)
+
+ \deprecated in 5.0, use setDate() instead.
+
+ Sets the date's year \a y, month \a m, and day \a d.
+
+ If \a y is in the range 0 to 99, it is interpreted as 1900 to
+ 1999.
+ Returns \c false if the date is invalid.
+
+ Use setDate() instead.
+*/
+
+/*!
+ \since 4.2
+
+ Sets this to represent the date, in the Gregorian calendar, with the given
+ \a year, \a month and \a day numbers. Returns true if the resulting date is
+ valid, otherwise it sets this to represent an invalid date and returns
+ false.
+
+ \sa isValid(), QCalendar::dateFromParts()
+*/
+bool QDate::setDate(int year, int month, int day)
+{
+ if (QGregorianCalendar::julianFromParts(year, month, day, &jd))
+ return true;
+
+ jd = nullJd();
+ return false;
+}
+
+/*!
+ \since 5.14
+
+ Sets this to represent the date, in the given calendar \a cal, with the
+ given \a year, \a month and \a day numbers. Returns true if the resulting
+ date is valid, otherwise it sets this to represent an invalid date and
+ returns false.
+
+ \sa isValid(), QCalendar::dateFromParts()
+*/
+
+bool QDate::setDate(int year, int month, int day, QCalendar cal)
+{
+ *this = QDate(year, month, day, cal);
+ return isValid();
+}
+
+/*!
+ \since 4.5
+
+ Extracts the date's year, month, and day, and assigns them to
+ *\a year, *\a month, and *\a day. The pointers may be null.
+
+ Returns 0 if the date is invalid.
+
+ \note In Qt versions prior to 5.7, this function is marked as non-\c{const}.
+
+ \sa year(), month(), day(), isValid(), QCalendar::partsFromDate()
+*/
+void QDate::getDate(int *year, int *month, int *day) const
+{
+ QCalendar::YearMonthDay parts; // invalid by default
+ if (isValid())
+ parts = QGregorianCalendar::partsFromJulian(jd);
+
+ const bool ok = parts.isValid();
+ if (year)
+ *year = ok ? parts.year : 0;
+ if (month)
+ *month = ok ? parts.month : 0;
+ if (day)
+ *day = ok ? parts.day : 0;
+}
+
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+/*!
+ \overload
+ \internal
+*/
+void QDate::getDate(int *year, int *month, int *day)
+{
+ qAsConst(*this).getDate(year, month, day);
+}
+#endif // < Qt 6
+
+/*!
+ Returns a QDate object containing a date \a ndays later than the
+ date of this object (or earlier if \a ndays is negative).
+
+ Returns a null date if the current date is invalid or the new date is
+ out of range.
+
+ \sa addMonths(), addYears(), daysTo()
+*/
+
+QDate QDate::addDays(qint64 ndays) const
+{
+ if (isNull())
+ return QDate();
+
+ // Due to limits on minJd() and maxJd() we know that any overflow
+ // will be invalid and caught by fromJulianDay().
+ return fromJulianDay(jd + ndays);
+}
+
+/*!
+ Returns a QDate object containing a date \a nmonths later than the
+ date of this object (or earlier if \a nmonths is negative).
+
+ Uses \a cal as calendar, if supplied, else the Gregorian calendar.
+
+ \note If the ending day/month combination does not exist in the resulting
+ month/year, this function will return a date that is the latest valid date
+ in the selected month.
+
+ \sa addDays(), addYears()
+*/
+
+QDate QDate::addMonths(int nmonths, QCalendar cal) const
+{
+ if (!isValid())
+ return QDate();
+
+ if (nmonths == 0)
+ return *this;
+
+ auto parts = cal.partsFromDate(*this);
+
+ if (!parts.isValid())
+ return QDate();
+ Q_ASSERT(parts.year || cal.hasYearZero());
+
+ parts.month += nmonths;
+ while (parts.month <= 0) {
+ if (--parts.year || cal.hasYearZero())
+ parts.month += cal.monthsInYear(parts.year);
+ }
+ int count = cal.monthsInYear(parts.year);
+ while (parts.month > count) {
+ parts.month -= count;
+ count = (++parts.year || cal.hasYearZero()) ? cal.monthsInYear(parts.year) : 0;
+ }
+
+ return fixedDate(std::move(parts), cal);
+}
+
+/*!
+ \overload
+*/
+
+QDate QDate::addMonths(int nmonths) const
+{
+ if (isNull())
+ return QDate();
+
+ if (nmonths == 0)
+ return *this;
+
+ auto parts = QGregorianCalendar::partsFromJulian(jd);
+
+ if (!parts.isValid())
+ return QDate();
+ Q_ASSERT(parts.year);
+
+ parts.month += nmonths;
+ while (parts.month <= 0) {
+ if (--parts.year) // skip over year 0
+ parts.month += 12;
+ }
+ while (parts.month > 12) {
+ parts.month -= 12;
+ if (!++parts.year) // skip over year 0
+ ++parts.year;
+ }
+
+ return fixedDate(std::move(parts));
+}
+
+/*!
+ Returns a QDate object containing a date \a nyears later than the
+ date of this object (or earlier if \a nyears is negative).
+
+ Uses \a cal as calendar, if supplied, else the Gregorian calendar.
+
+ \note If the ending day/month combination does not exist in the resulting
+ year (e.g., for the Gregorian calendar, if the date was Feb 29 and the final
+ year is not a leap year), this function will return a date that is the
+ latest valid date in the given month (in the example, Feb 28).
+
+ \sa addDays(), addMonths()
+*/
+
+QDate QDate::addYears(int nyears, QCalendar cal) const
+{
+ if (!isValid())
+ return QDate();
+
+ auto parts = cal.partsFromDate(*this);
+ if (!parts.isValid())
+ return QDate();
+
+ int old_y = parts.year;
+ parts.year += nyears;
+
+ // If we just crossed (or hit) a missing year zero, adjust year by +/- 1:
+ if (!cal.hasYearZero() && ((old_y > 0) != (parts.year > 0) || !parts.year))
+ parts.year += nyears > 0 ? +1 : -1;
+
+ return fixedDate(std::move(parts), cal);
+}
+
+/*!
+ \overload
+*/
+
+QDate QDate::addYears(int nyears) const
+{
+ if (isNull())
+ return QDate();
+
+ auto parts = QGregorianCalendar::partsFromJulian(jd);
+ if (!parts.isValid())
+ return QDate();
+
+ int old_y = parts.year;
+ parts.year += nyears;
+
+ // If we just crossed (or hit) a missing year zero, adjust year by +/- 1:
+ if ((old_y > 0) != (parts.year > 0) || !parts.year)
+ parts.year += nyears > 0 ? +1 : -1;
+
+ return fixedDate(std::move(parts));
+}
+
+/*!
+ Returns the number of days from this date to \a d (which is
+ negative if \a d is earlier than this date).
+
+ Returns 0 if either date is invalid.
+
+ Example:
+ \snippet code/src_corelib_tools_qdatetime.cpp 0
+
+ \sa addDays()
+*/
+
+qint64 QDate::daysTo(const QDate &d) const
+{
+ if (isNull() || d.isNull())
+ return 0;
+
+ // Due to limits on minJd() and maxJd() we know this will never overflow
+ return d.jd - jd;
+}
+
+
+/*!
+ \fn bool QDate::operator==(const QDate &d) const
+
+ Returns \c true if this date is equal to \a d; otherwise returns
+ false.
+
+*/
+
+/*!
+ \fn bool QDate::operator!=(const QDate &d) const
+
+ Returns \c true if this date is different from \a d; otherwise
+ returns \c false.
+*/
+
+/*!
+ \fn bool QDate::operator<(const QDate &d) const
+
+ Returns \c true if this date is earlier than \a d; otherwise returns
+ false.
+*/
+
+/*!
+ \fn bool QDate::operator<=(const QDate &d) const
+
+ Returns \c true if this date is earlier than or equal to \a d;
+ otherwise returns \c false.
+*/
+
+/*!
+ \fn bool QDate::operator>(const QDate &d) const
+
+ Returns \c true if this date is later than \a d; otherwise returns
+ false.
+*/
+
+/*!
+ \fn bool QDate::operator>=(const QDate &d) const
+
+ Returns \c true if this date is later than or equal to \a d;
+ otherwise returns \c false.
+*/
+
+/*!
+ \fn QDate::currentDate()
+ Returns the current date, as reported by the system clock.
+
+ \sa QTime::currentTime(), QDateTime::currentDateTime()
+*/
+
+#if QT_CONFIG(datestring)
+/*!
+ Returns the QDate represented by the \a string, using the
+ \a format given, or an invalid date if the string cannot be
+ parsed.
+
+ Note for Qt::TextDate: It is recommended that you use the
+ English short month names (e.g. "Jan"). Although localized month
+ names can also be used, they depend on the user's locale settings.
+
+ \sa toString(), QLocale::toDate()
+*/
+
+QDate QDate::fromString(const QString &string, Qt::DateFormat format)
+{
+ if (string.isEmpty())
+ return QDate();
+
+ switch (format) {
+ case Qt::SystemLocaleDate:
+ case Qt::SystemLocaleShortDate:
+ return QLocale::system().toDate(string, QLocale::ShortFormat);
+ case Qt::SystemLocaleLongDate:
+ return QLocale::system().toDate(string, QLocale::LongFormat);
+ case Qt::LocaleDate:
+ case Qt::DefaultLocaleShortDate:
+ return QLocale().toDate(string, QLocale::ShortFormat);
+ case Qt::DefaultLocaleLongDate:
+ return QLocale().toDate(string, QLocale::LongFormat);
+ case Qt::RFC2822Date:
+ return rfcDateImpl(string).date;
+ default:
+#if QT_CONFIG(textdate)
+ case Qt::TextDate: {
+ QVector<QStringRef> parts = string.splitRef(QLatin1Char(' '), QString::SkipEmptyParts);
+
+ if (parts.count() != 4)
+ return QDate();
+
+ bool ok = false;
+ int year = parts.at(3).toInt(&ok);
+ int day = ok ? parts.at(2).toInt(&ok) : 0;
+ if (!ok || !day)
+ return QDate();
+
+ const int month = fromShortMonthName(parts.at(1), year);
+ if (month == -1) // Month name matches no English or localised name.
+ return QDate();
+
+ return QDate(year, month, day);
+ }
+#endif // textdate
+ case Qt::ISODate: {
+ // Semi-strict parsing, must be long enough and have non-numeric separators
+ if (string.size() < 10 || string.at(4).isDigit() || string.at(7).isDigit()
+ || (string.size() > 10 && string.at(10).isDigit())) {
+ return QDate();
+ }
+ const int year = string.midRef(0, 4).toInt();
+ if (year <= 0 || year > 9999)
+ return QDate();
+ return QDate(year, string.midRef(5, 2).toInt(), string.midRef(8, 2).toInt());
+ }
+ }
+ return QDate();
+}
+
+/*!
+ Returns the QDate represented by the \a string, using the \a
+ format given, or an invalid date if the string cannot be parsed.
+
+ Uses \a cal as calendar if supplied, else the Gregorian calendar. Ranges of
+ values in the format descriptions below are for the latter; they may be
+ different for other calendars.
+
+ These expressions may be used for the format:
+
+ \table
+ \header \li Expression \li Output
+ \row \li d \li The day as a number without a leading zero (1 to 31)
+ \row \li dd \li The day as a number with a leading zero (01 to 31)
+ \row \li ddd
+ \li The abbreviated localized day name (e.g. 'Mon' to 'Sun').
+ Uses the system locale to localize the name, i.e. QLocale::system().
+ \row \li dddd
+ \li The long localized day name (e.g. 'Monday' to 'Sunday').
+ Uses the system locale to localize the name, i.e. QLocale::system().
+ \row \li M \li The month as a number without a leading zero (1 to 12)
+ \row \li MM \li The month as a number with a leading zero (01 to 12)
+ \row \li MMM
+ \li The abbreviated localized month name (e.g. 'Jan' to 'Dec').
+ Uses the system locale to localize the name, i.e. QLocale::system().
+ \row \li MMMM
+ \li The long localized month name (e.g. 'January' to 'December').
+ Uses the system locale to localize the name, i.e. QLocale::system().
+ \row \li yy \li The year as a two digit number (00 to 99)
+ \row \li yyyy \li The year as a four digit number, possibly plus a leading
+ minus sign for negative years.
+ \endtable
+
+ \note Unlike the other version of this function, day and month names must
+ be given in the user's local language. It is only possible to use the English
+ names if the user's language is English.
+
+ All other input characters will be treated as text. Any sequence
+ of characters that are enclosed in single quotes will also be
+ treated as text and will not be used as an expression. For example:
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 1
+
+ If the format is not satisfied, an invalid QDate is returned. The
+ expressions that don't expect leading zeroes (d, M) will be
+ greedy. This means that they will use two digits even if this
+ will put them outside the accepted range of values and leaves too
+ few digits for other sections. For example, the following format
+ string could have meant January 30 but the M will grab two
+ digits, resulting in an invalid date:
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 2
+
+ For any field that is not represented in the format the following
+ defaults are used:
+
+ \table
+ \header \li Field \li Default value
+ \row \li Year \li 1900
+ \row \li Month \li 1
+ \row \li Day \li 1
+ \endtable
+
+ The following examples demonstrate the default values:
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 3
+
+ \sa toString(), QDateTime::fromString(), QTime::fromString(),
+ QLocale::toDate()
+*/
+
+QDate QDate::fromString(const QString &string, const QString &format, QCalendar cal)
+{
+ QDate date;
+#if QT_CONFIG(datetimeparser)
+ QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString, cal);
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
+ if (dt.parseFormat(format))
+ dt.fromString(string, &date, 0);
+#else
+ Q_UNUSED(string);
+ Q_UNUSED(format);
+ Q_UNUSED(cal);
+#endif
+ return date;
+}
+
+/*!
+ \overload
+*/
+
+QDate QDate::fromString(const QString &string, const QString &format)
+{
+ return fromString(string, format, QCalendar());
+}
+#endif // datestring
+
+/*!
+ \overload
+
+ Returns \c true if the specified date (\a year, \a month, and \a day) is
+ valid in the Gregorian calendar; otherwise returns \c false.
+
+ Example:
+ \snippet code/src_corelib_tools_qdatetime.cpp 4
+
+ \sa isNull(), setDate(), QCalendar::isDateValid()
+*/
+
+bool QDate::isValid(int year, int month, int day)
+{
+ return QGregorianCalendar::validParts(year, month, day);
+}
+
+/*!
+ \fn bool QDate::isLeapYear(int year)
+
+ Returns \c true if the specified \a year is a leap year in the Gregorian
+ calendar; otherwise returns \c false.
+
+ \sa QCalendar::isLeapYear()
+*/
+
+bool QDate::isLeapYear(int y)
+{
+ return QGregorianCalendar::leapTest(y);
+}
+
+/*! \fn static QDate QDate::fromJulianDay(qint64 jd)
+
+ Converts the Julian day \a jd to a QDate.
+
+ \sa toJulianDay()
+*/
+
+/*! \fn int QDate::toJulianDay() const
+
+ Converts the date to a Julian day.
+
+ \sa fromJulianDay()
+*/
+
+/*****************************************************************************
+ QTime member functions
+ *****************************************************************************/
+
+/*!
+ \class QTime
+ \inmodule QtCore
+ \reentrant
+
+ \brief The QTime class provides clock time functions.
+
+
+ A QTime object contains a clock time, which it can express as the numbers of
+ hours, minutes, seconds, and milliseconds since midnight. It provides
+ functions for comparing times and for manipulating a time by adding a number
+ of milliseconds.
+
+ QTime uses the 24-hour clock format; it has no concept of AM/PM.
+ Unlike QDateTime, QTime knows nothing about time zones or
+ daylight-saving time (DST).
+
+ A QTime object is typically created either by giving the number of hours,
+ minutes, seconds, and milliseconds explicitly, or by using the static
+ function currentTime(), which creates a QTime object that represents the
+ system's local time.
+
+ The hour(), minute(), second(), and msec() functions provide
+ access to the number of hours, minutes, seconds, and milliseconds
+ of the time. The same information is provided in textual format by
+ the toString() function.
+
+ The addSecs() and addMSecs() functions provide the time a given
+ number of seconds or milliseconds later than a given time.
+ Correspondingly, the number of seconds or milliseconds
+ between two times can be found using secsTo() or msecsTo().
+
+ QTime provides a full set of operators to compare two QTime
+ objects; an earlier time is considered smaller than a later one;
+ if A.msecsTo(B) is positive, then A < B.
+
+ \sa QDate, QDateTime
+*/
+
+/*!
+ \fn QTime::QTime()
+
+ Constructs a null time object. For a null time, isNull() returns \c true and
+ isValid() returns \c false. If you need a zero time, use QTime(0, 0). For
+ the start of a day, see QDate::startOfDay().
+
+ \sa isNull(), isValid()
+*/
+
+/*!
+ Constructs a time with hour \a h, minute \a m, seconds \a s and
+ milliseconds \a ms.
+
+ \a h must be in the range 0 to 23, \a m and \a s must be in the
+ range 0 to 59, and \a ms must be in the range 0 to 999.
+
+ \sa isValid()
+*/
+
+QTime::QTime(int h, int m, int s, int ms)
+{
+ setHMS(h, m, s, ms);
+}
+
+
+/*!
+ \fn bool QTime::isNull() const
+
+ Returns \c true if the time is null (i.e., the QTime object was
+ constructed using the default constructor); otherwise returns
+ false. A null time is also an invalid time.
+
+ \sa isValid()
+*/
+
+/*!
+ Returns \c true if the time is valid; otherwise returns \c false. For example,
+ the time 23:30:55.746 is valid, but 24:12:30 is invalid.
+
+ \sa isNull()
+*/
+
+bool QTime::isValid() const
+{
+ return mds > NullTime && mds < MSECS_PER_DAY;
+}
+
+
+/*!
+ Returns the hour part (0 to 23) of the time.
+
+ Returns -1 if the time is invalid.
+
+ \sa minute(), second(), msec()
+*/
+
+int QTime::hour() const
+{
+ if (!isValid())
+ return -1;
+
+ return ds() / MSECS_PER_HOUR;
+}
+
+/*!
+ Returns the minute part (0 to 59) of the time.
+
+ Returns -1 if the time is invalid.
+
+ \sa hour(), second(), msec()
+*/
+
+int QTime::minute() const
+{
+ if (!isValid())
+ return -1;
+
+ return (ds() % MSECS_PER_HOUR) / MSECS_PER_MIN;
+}
+
+/*!
+ Returns the second part (0 to 59) of the time.
+
+ Returns -1 if the time is invalid.
+
+ \sa hour(), minute(), msec()
+*/
+
+int QTime::second() const
+{
+ if (!isValid())
+ return -1;
+
+ return (ds() / 1000)%SECS_PER_MIN;
+}
+
+/*!
+ Returns the millisecond part (0 to 999) of the time.
+
+ Returns -1 if the time is invalid.
+
+ \sa hour(), minute(), second()
+*/
+
+int QTime::msec() const
+{
+ if (!isValid())
+ return -1;
+
+ return ds() % 1000;
+}
+
+#if QT_CONFIG(datestring)
+/*!
+ \overload
+
+ Returns the time as a string. The \a format parameter determines
+ the format of the string.
+
+ If \a format is Qt::TextDate, the string format is HH:mm:ss;
+ e.g. 1 second before midnight would be "23:59:59".
+
+ If \a format is Qt::ISODate, the string format corresponds to the
+ ISO 8601 extended specification for representations of dates,
+ represented by HH:mm:ss. To include milliseconds in the ISO 8601
+ date, use the \a format Qt::ISODateWithMs, which corresponds to
+ HH:mm:ss.zzz.
+
+ If the \a format is Qt::SystemLocaleShortDate or
+ Qt::SystemLocaleLongDate, the string format depends on the locale
+ settings of the system. Identical to calling
+ QLocale::system().toString(time, QLocale::ShortFormat) or
+ QLocale::system().toString(time, QLocale::LongFormat).
+
+ If the \a format is Qt::DefaultLocaleShortDate or
+ Qt::DefaultLocaleLongDate, the string format depends on the
+ default application locale. This is the locale set with
+ QLocale::setDefault(), or the system locale if no default locale
+ has been set. Identical to calling
+
+ \l {QLocale::toString()}{QLocale().toString(time, QLocale::ShortFormat)} or
+ \l {QLocale::toString()}{QLocale().toString(time, QLocale::LongFormat)}.
+
+ If the \a format is Qt::RFC2822Date, the string is formatted in
+ an \l{RFC 2822} compatible way. An example of this formatting is
+ "23:59:20".
+
+ If the time is invalid, an empty string will be returned.
+
+ \sa fromString(), QDate::toString(), QDateTime::toString(), QLocale::toString()
+*/
+
+QString QTime::toString(Qt::DateFormat format) const
+{
+ if (!isValid())
+ return QString();
+
+ switch (format) {
+ case Qt::SystemLocaleDate:
+ case Qt::SystemLocaleShortDate:
+ return QLocale::system().toString(*this, QLocale::ShortFormat);
+ case Qt::SystemLocaleLongDate:
+ return QLocale::system().toString(*this, QLocale::LongFormat);
+ case Qt::LocaleDate:
+ case Qt::DefaultLocaleShortDate:
+ return QLocale().toString(*this, QLocale::ShortFormat);
+ case Qt::DefaultLocaleLongDate:
+ return QLocale().toString(*this, QLocale::LongFormat);
+ case Qt::ISODateWithMs:
+ return QString::asprintf("%02d:%02d:%02d.%03d", hour(), minute(), second(), msec());
+ case Qt::RFC2822Date:
+ case Qt::ISODate:
+ case Qt::TextDate:
+ default:
+ return QString::asprintf("%02d:%02d:%02d", hour(), minute(), second());
+ }
+}
+
+/*!
+ \fn QString QTime::toString(const QString &format) const
+ \fn QString QTime::toString(QStringView format) const
+
+ Returns the time as a string. The \a format parameter determines
+ the format of the result string.
+
+ These expressions may be used:
+
+ \table
+ \header \li Expression \li Output
+ \row \li h
+ \li The hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
+ \row \li hh
+ \li The hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
+ \row \li H
+ \li The hour without a leading zero (0 to 23, even with AM/PM display)
+ \row \li HH
+ \li The hour with a leading zero (00 to 23, even with AM/PM display)
+ \row \li m \li The minute without a leading zero (0 to 59)
+ \row \li mm \li The minute with a leading zero (00 to 59)
+ \row \li s \li The whole second, without any leading zero (0 to 59)
+ \row \li ss \li The whole second, with a leading zero where applicable (00 to 59)
+ \row \li z \li The fractional part of the second, to go after a decimal
+ point, without trailing zeroes (0 to 999). Thus "\c{s.z}"
+ reports the seconds to full available (millisecond) precision
+ without trailing zeroes.
+ \row \li zzz \li The fractional part of the second, to millisecond
+ precision, including trailing zeroes where applicable (000 to 999).
+ \row \li AP or A
+ \li Use AM/PM display. \e A/AP will be replaced by an upper-case
+ version of either QLocale::amText() or QLocale::pmText().
+ \row \li ap or a
+ \li Use am/pm display. \e a/ap will be replaced by a lower-case version
+ of either QLocale::amText() or QLocale::pmText().
+ \row \li t \li The timezone (for example "CEST")
+ \endtable
+
+ Any sequence of characters enclosed in single quotes will be included
+ verbatim in the output string (stripped of the quotes), even if it contains
+ formatting characters. Two consecutive single quotes ("''") are replaced by
+ a single quote in the output. All other characters in the format string are
+ included verbatim in the output string.
+
+ Formats without separators (e.g. "ddMM") are supported but must be used with
+ care, as the resulting strings aren't always reliably readable (e.g. if "dM"
+ produces "212" it could mean either the 2nd of December or the 21st of
+ February).
+
+ Example format strings (assuming that the QTime is 14:13:09.042 and the system
+ locale is \c{en_US})
+
+ \table
+ \header \li Format \li Result
+ \row \li hh:mm:ss.zzz \li 14:13:09.042
+ \row \li h:m:s ap \li 2:13:9 pm
+ \row \li H:m:s a \li 14:13:9 pm
+ \endtable
+
+ If the time is invalid, an empty string will be returned.
+ If \a format is empty, the default format "hh:mm:ss" is used.
+
+ \sa fromString(), QDate::toString(), QDateTime::toString(), QLocale::toString()
+*/
+QString QTime::toString(QStringView format) const
+{
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
+}
+
+#if QT_STRINGVIEW_VERSION < 2
+QString QTime::toString(const QString &format) const
+{
+ return toString(qToStringViewIgnoringNull(format));
+}
+#endif
+
+#endif // datestring
+
+/*!
+ Sets the time to hour \a h, minute \a m, seconds \a s and
+ milliseconds \a ms.
+
+ \a h must be in the range 0 to 23, \a m and \a s must be in the
+ range 0 to 59, and \a ms must be in the range 0 to 999.
+ Returns \c true if the set time is valid; otherwise returns \c false.
+
+ \sa isValid()
+*/
+
+bool QTime::setHMS(int h, int m, int s, int ms)
+{
+ if (!isValid(h,m,s,ms)) {
+ mds = NullTime; // make this invalid
+ return false;
+ }
+ mds = (h*SECS_PER_HOUR + m*SECS_PER_MIN + s)*1000 + ms;
+ return true;
+}
+
+/*!
+ Returns a QTime object containing a time \a s seconds later
+ than the time of this object (or earlier if \a s is negative).
+
+ Note that the time will wrap if it passes midnight.
+
+ Returns a null time if this time is invalid.
+
+ Example:
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 5
+
+ \sa addMSecs(), secsTo(), QDateTime::addSecs()
+*/
+
+QTime QTime::addSecs(int s) const
+{
+ s %= SECS_PER_DAY;
+ return addMSecs(s * 1000);
+}
+
+/*!
+ Returns the number of seconds from this time to \a t.
+ If \a t is earlier than this time, the number of seconds returned
+ is negative.
+
+ Because QTime measures time within a day and there are 86400
+ seconds in a day, the result is always between -86400 and 86400.
+
+ secsTo() does not take into account any milliseconds.
+
+ Returns 0 if either time is invalid.
+
+ \sa addSecs(), QDateTime::secsTo()
+*/
+
+int QTime::secsTo(const QTime &t) const
+{
+ if (!isValid() || !t.isValid())
+ return 0;
+
+ // Truncate milliseconds as we do not want to consider them.
+ int ourSeconds = ds() / 1000;
+ int theirSeconds = t.ds() / 1000;
+ return theirSeconds - ourSeconds;
+}
+
+/*!
+ Returns a QTime object containing a time \a ms milliseconds later
+ than the time of this object (or earlier if \a ms is negative).
+
+ Note that the time will wrap if it passes midnight. See addSecs()
+ for an example.
+
+ Returns a null time if this time is invalid.
+
+ \sa addSecs(), msecsTo(), QDateTime::addMSecs()
+*/
+
+QTime QTime::addMSecs(int ms) const
+{
+ QTime t;
+ if (isValid()) {
+ if (ms < 0) {
+ // %,/ not well-defined for -ve, so always work with +ve.
+ int negdays = (MSECS_PER_DAY - ms) / MSECS_PER_DAY;
+ t.mds = (ds() + ms + negdays * MSECS_PER_DAY) % MSECS_PER_DAY;
+ } else {
+ t.mds = (ds() + ms) % MSECS_PER_DAY;
+ }
+ }
+ return t;
+}
+
+/*!
+ Returns the number of milliseconds from this time to \a t.
+ If \a t is earlier than this time, the number of milliseconds returned
+ is negative.
+
+ Because QTime measures time within a day and there are 86400
+ seconds in a day, the result is always between -86400000 and
+ 86400000 ms.
+
+ Returns 0 if either time is invalid.
+
+ \sa secsTo(), addMSecs(), QDateTime::msecsTo()
+*/
+
+int QTime::msecsTo(const QTime &t) const
+{
+ if (!isValid() || !t.isValid())
+ return 0;
+ return t.ds() - ds();
+}
+
+
+/*!
+ \fn bool QTime::operator==(const QTime &t) const
+
+ Returns \c true if this time is equal to \a t; otherwise returns \c false.
+*/
+
+/*!
+ \fn bool QTime::operator!=(const QTime &t) const
+
+ Returns \c true if this time is different from \a t; otherwise returns \c false.
+*/
+
+/*!
+ \fn bool QTime::operator<(const QTime &t) const
+
+ Returns \c true if this time is earlier than \a t; otherwise returns \c false.
+*/
+
+/*!
+ \fn bool QTime::operator<=(const QTime &t) const
+
+ Returns \c true if this time is earlier than or equal to \a t;
+ otherwise returns \c false.
+*/
+
+/*!
+ \fn bool QTime::operator>(const QTime &t) const
+
+ Returns \c true if this time is later than \a t; otherwise returns \c false.
+*/
+
+/*!
+ \fn bool QTime::operator>=(const QTime &t) const
+
+ Returns \c true if this time is later than or equal to \a t;
+ otherwise returns \c false.
+*/
+
+/*!
+ \fn QTime QTime::fromMSecsSinceStartOfDay(int msecs)
+
+ Returns a new QTime instance with the time set to the number of \a msecs
+ since the start of the day, i.e. since 00:00:00.
+
+ If \a msecs falls outside the valid range an invalid QTime will be returned.
+
+ \sa msecsSinceStartOfDay()
+*/
+
+/*!
+ \fn int QTime::msecsSinceStartOfDay() const
+
+ Returns the number of msecs since the start of the day, i.e. since 00:00:00.
+
+ \sa fromMSecsSinceStartOfDay()
+*/
+
+/*!
+ \fn QTime::currentTime()
+
+ Returns the current time as reported by the system clock.
+
+ Note that the accuracy depends on the accuracy of the underlying
+ operating system; not all systems provide 1-millisecond accuracy.
+
+ Furthermore, currentTime() only increases within each day; it shall drop by
+ 24 hours each time midnight passes; and, beside this, changes in it may not
+ correspond to elapsed time, if a daylight-saving transition intervenes.
+
+ \sa QDateTime::currentDateTime(), QDateTime::currentDateTimeUtc()
+*/
+
+#if QT_CONFIG(datestring)
+
+static QTime fromIsoTimeString(const QStringRef &string, Qt::DateFormat format, bool *isMidnight24)
+{
+ if (isMidnight24)
+ *isMidnight24 = false;
+
+ const int size = string.size();
+ if (size < 5)
+ return QTime();
+
+ bool ok = false;
+ int hour = string.mid(0, 2).toInt(&ok);
+ if (!ok)
+ return QTime();
+ const int minute = string.mid(3, 2).toInt(&ok);
+ if (!ok)
+ return QTime();
+ int second = 0;
+ int msec = 0;
+
+ if (size == 5) {
+ // HH:mm format
+ second = 0;
+ msec = 0;
+ } else if (string.at(5) == QLatin1Char(',') || string.at(5) == QLatin1Char('.')) {
+ if (format == Qt::TextDate)
+ return QTime();
+ // ISODate HH:mm.ssssss format
+ // We only want 5 digits worth of fraction of minute. This follows the existing
+ // behavior that determines how milliseconds are read; 4 millisecond digits are
+ // read and then rounded to 3. If we read at most 5 digits for fraction of minute,
+ // the maximum amount of millisecond digits it will expand to once converted to
+ // seconds is 4. E.g. 12:34,99999 will expand to 12:34:59.9994. The milliseconds
+ // will then be rounded up AND clamped to 999.
+
+ const QStringRef minuteFractionStr = string.mid(6, 5);
+ const long minuteFractionInt = minuteFractionStr.toLong(&ok);
+ if (!ok)
+ return QTime();
+ const float minuteFraction = double(minuteFractionInt) / (std::pow(double(10), minuteFractionStr.count()));
+
+ const float secondWithMs = minuteFraction * 60;
+ const float secondNoMs = std::floor(secondWithMs);
+ const float secondFraction = secondWithMs - secondNoMs;
+ second = secondNoMs;
+ msec = qMin(qRound(secondFraction * 1000.0), 999);
+ } else {
+ // HH:mm:ss or HH:mm:ss.zzz
+ second = string.mid(6, 2).toInt(&ok);
+ if (!ok)
+ return QTime();
+ if (size > 8 && (string.at(8) == QLatin1Char(',') || string.at(8) == QLatin1Char('.'))) {
+ const QStringRef msecStr(string.mid(9, 4));
+ int msecInt = msecStr.isEmpty() ? 0 : msecStr.toInt(&ok);
+ if (!ok)
+ return QTime();
+ const double secondFraction(msecInt / (std::pow(double(10), msecStr.count())));
+ msec = qMin(qRound(secondFraction * 1000.0), 999);
+ }
+ }
+
+ const bool isISODate = format == Qt::ISODate || format == Qt::ISODateWithMs;
+ if (isISODate && hour == 24 && minute == 0 && second == 0 && msec == 0) {
+ if (isMidnight24)
+ *isMidnight24 = true;
+ hour = 0;
+ }
+
+ return QTime(hour, minute, second, msec);
+}
+
+/*!
+ Returns the time represented in the \a string as a QTime using the
+ \a format given, or an invalid time if this is not possible.
+
+ Note that fromString() uses a "C" locale encoded string to convert
+ milliseconds to a float value. If the default locale is not "C",
+ this may result in two conversion attempts (if the conversion
+ fails for the default locale). This should be considered an
+ implementation detail.
+
+ \sa toString(), QLocale::toTime()
+*/
+QTime QTime::fromString(const QString &string, Qt::DateFormat format)
+{
+ if (string.isEmpty())
+ return QTime();
+
+ switch (format) {
+ case Qt::SystemLocaleDate:
+ case Qt::SystemLocaleShortDate:
+ return QLocale::system().toTime(string, QLocale::ShortFormat);
+ case Qt::SystemLocaleLongDate:
+ return QLocale::system().toTime(string, QLocale::LongFormat);
+ case Qt::LocaleDate:
+ case Qt::DefaultLocaleShortDate:
+ return QLocale().toTime(string, QLocale::ShortFormat);
+ case Qt::DefaultLocaleLongDate:
+ return QLocale().toTime(string, QLocale::LongFormat);
+ case Qt::RFC2822Date:
+ return rfcDateImpl(string).time;
+ case Qt::ISODate:
+ case Qt::ISODateWithMs:
+ case Qt::TextDate:
+ default:
+ return fromIsoTimeString(QStringRef(&string), format, nullptr);
+ }
+}
+
+/*!
+ Returns the QTime represented by the \a string, using the \a
+ format given, or an invalid time if the string cannot be parsed.
+
+ These expressions may be used for the format:
+
+ \table
+ \header \li Expression \li Output
+ \row \li h
+ \li The hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
+ \row \li hh
+ \li The hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
+ \row \li H
+ \li The hour without a leading zero (0 to 23, even with AM/PM display)
+ \row \li HH
+ \li The hour with a leading zero (00 to 23, even with AM/PM display)
+ \row \li m \li The minute without a leading zero (0 to 59)
+ \row \li mm \li The minute with a leading zero (00 to 59)
+ \row \li s \li The whole second, without any leading zero (0 to 59)
+ \row \li ss \li The whole second, with a leading zero where applicable (00 to 59)
+ \row \li z \li The fractional part of the second, to go after a decimal
+ point, without trailing zeroes (0 to 999). Thus "\c{s.z}"
+ reports the seconds to full available (millisecond) precision
+ without trailing zeroes.
+ \row \li zzz \li The fractional part of the second, to millisecond
+ precision, including trailing zeroes where applicable (000 to 999).
+ \row \li AP or A
+ \li Interpret as an AM/PM time. \e A/AP will match an upper-case
+ version of either QLocale::amText() or QLocale::pmText().
+ \row \li ap or a
+ \li Interpret as an am/pm time. \e a/ap will match a lower-case version
+ of either QLocale::amText() or QLocale::pmText().
+ \row \li t \li the timezone (for example "CEST")
+ \endtable
+
+ All other input characters will be treated as text. Any sequence
+ of characters that are enclosed in single quotes will also be
+ treated as text and not be used as an expression.
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 6
+
+ If the format is not satisfied, an invalid QTime is returned.
+ Expressions that do not expect leading zeroes to be given (h, m, s
+ and z) are greedy. This means that they will use two digits even if
+ this puts them outside the range of accepted values and leaves too
+ few digits for other sections. For example, the following string
+ could have meant 00:07:10, but the m will grab two digits, resulting
+ in an invalid time:
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 7
+
+ Any field that is not represented in the format will be set to zero.
+ For example:
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 8
+
+ \sa toString(), QDateTime::fromString(), QDate::fromString(),
+ QLocale::toTime()
+*/
+
+QTime QTime::fromString(const QString &string, const QString &format)
+{
+ QTime time;
+#if QT_CONFIG(datetimeparser)
+ QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString, QCalendar());
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
+ if (dt.parseFormat(format))
+ dt.fromString(string, 0, &time);
+#else
+ Q_UNUSED(string);
+ Q_UNUSED(format);
+#endif
+ return time;
+}
+
+#endif // datestring
+
+
+/*!
+ \overload
+
+ Returns \c true if the specified time is valid; otherwise returns
+ false.
+
+ The time is valid if \a h is in the range 0 to 23, \a m and
+ \a s are in the range 0 to 59, and \a ms is in the range 0 to 999.
+
+ Example:
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 9
+*/
+
+bool QTime::isValid(int h, int m, int s, int ms)
+{
+ return (uint)h < 24 && (uint)m < 60 && (uint)s < 60 && (uint)ms < 1000;
+}
+
+#if QT_DEPRECATED_SINCE(5, 14) // ### Qt 6: remove
+/*!
+ Sets this time to the current time. This is practical for timing:
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 10
+
+ \sa restart(), elapsed(), currentTime()
+*/
+
+void QTime::start()
+{
+ *this = currentTime();
+}
+
+/*!
+ Sets this time to the current time and returns the number of
+ milliseconds that have elapsed since the last time start() or
+ restart() was called.
+
+ This function is guaranteed to be atomic and is thus very handy
+ for repeated measurements. Call start() to start the first
+ measurement, and restart() for each later measurement.
+
+ Note that the counter wraps to zero 24 hours after the last call
+ to start() or restart().
+
+ \warning If the system's clock setting has been changed since the
+ last time start() or restart() was called, the result is
+ undefined. This can happen when daylight-saving time is turned on
+ or off.
+
+ \sa start(), elapsed(), currentTime()
+*/
+
+int QTime::restart()
+{
+ QTime t = currentTime();
+ int n = msecsTo(t);
+ if (n < 0) // passed midnight
+ n += 86400*1000;
+ *this = t;
+ return n;
+}
+
+/*!
+ Returns the number of milliseconds that have elapsed since the
+ last time start() or restart() was called.
+
+ Note that the counter wraps to zero 24 hours after the last call
+ to start() or restart.
+
+ Note that the accuracy depends on the accuracy of the underlying
+ operating system; not all systems provide 1-millisecond accuracy.
+
+ \warning If the system's clock setting has been changed since the
+ last time start() or restart() was called, the result is
+ undefined. This can happen when daylight-saving time is turned on
+ or off.
+
+ \sa start(), restart()
+*/
+
+int QTime::elapsed() const
+{
+ int n = msecsTo(currentTime());
+ if (n < 0) // passed midnight
+ n += 86400 * 1000;
+ return n;
+}
+#endif // Use QElapsedTimer instead !
+
+/*****************************************************************************
+ QDateTime static helper functions
+ *****************************************************************************/
+
+// get the types from QDateTime (through QDateTimePrivate)
+typedef QDateTimePrivate::QDateTimeShortData ShortData;
+typedef QDateTimePrivate::QDateTimeData QDateTimeData;
+
+// Returns the platform variant of timezone, i.e. the standard time offset
+// The timezone external variable is documented as always holding the
+// Standard Time offset as seconds west of Greenwich, i.e. UTC+01:00 is -3600
+// Note this may not be historicaly accurate.
+// Relies on tzset, mktime, or localtime having been called to populate timezone
+static int qt_timezone()
+{
+#if defined(_MSC_VER)
+ long offset;
+ _get_timezone(&offset);
+ return offset;
+#elif defined(Q_OS_BSD4) && !defined(Q_OS_DARWIN)
+ time_t clock = time(NULL);
+ struct tm t;
+ localtime_r(&clock, &t);
+ // QTBUG-36080 Workaround for systems without the POSIX timezone
+ // variable. This solution is not very efficient but fixing it is up to
+ // the libc implementations.
+ //
+ // tm_gmtoff has some important differences compared to the timezone
+ // variable:
+ // - It returns the number of seconds east of UTC, and we want the
+ // number of seconds west of UTC.
+ // - It also takes DST into account, so we need to adjust it to always
+ // get the Standard Time offset.
+ return -t.tm_gmtoff + (t.tm_isdst ? (long)SECS_PER_HOUR : 0L);
+#elif defined(Q_OS_INTEGRITY) || defined(Q_OS_RTEMS)
+ return 0;
+#else
+ return timezone;
+#endif // Q_OS_WIN
+}
+
+// Returns the tzname, assume tzset has been called already
+static QString qt_tzname(QDateTimePrivate::DaylightStatus daylightStatus)
+{
+ int isDst = (daylightStatus == QDateTimePrivate::DaylightTime) ? 1 : 0;
+#if defined(Q_CC_MSVC)
+ size_t s = 0;
+ char name[512];
+ if (_get_tzname(&s, name, 512, isDst))
+ return QString();
+ return QString::fromLocal8Bit(name);
+#else
+ return QString::fromLocal8Bit(tzname[isDst]);
+#endif // Q_OS_WIN
+}
+
+#if QT_CONFIG(datetimeparser) && QT_CONFIG(timezone)
+/*
+ \internal
+ Implemented here to share qt_tzname()
+*/
+int QDateTimeParser::startsWithLocalTimeZone(const QStringRef name)
+{
+ QDateTimePrivate::DaylightStatus zones[2] = {
+ QDateTimePrivate::StandardTime,
+ QDateTimePrivate::DaylightTime
+ };
+ for (const auto z : zones) {
+ QString zone(qt_tzname(z));
+ if (name.startsWith(zone))
+ return zone.size();
+ }
+ return 0;
+}
+#endif // datetimeparser && timezone
+
+// Calls the platform variant of mktime for the given date, time and daylightStatus,
+// and updates the date, time, daylightStatus and abbreviation with the returned values
+// If the date falls outside the 1970 to 2037 range supported by mktime / time_t
+// then null date/time will be returned, you should adjust the date first if
+// you need a guaranteed result.
+static qint64 qt_mktime(QDate *date, QTime *time, QDateTimePrivate::DaylightStatus *daylightStatus,
+ QString *abbreviation, bool *ok = nullptr)
+{
+ const qint64 msec = time->msec();
+ int yy, mm, dd;
+ date->getDate(&yy, &mm, &dd);
+
+ // All other platforms provide standard C library time functions
+ tm local;
+ memset(&local, 0, sizeof(local)); // tm_[wy]day plus any non-standard fields
+ local.tm_sec = time->second();
+ local.tm_min = time->minute();
+ local.tm_hour = time->hour();
+ local.tm_mday = dd;
+ local.tm_mon = mm - 1;
+ local.tm_year = yy - 1900;
+ if (daylightStatus)
+ local.tm_isdst = int(*daylightStatus);
+ else
+ local.tm_isdst = -1;
+
+#if defined(Q_OS_WIN)
+ int hh = local.tm_hour;
+#endif // Q_OS_WIN
+ time_t secsSinceEpoch = qMkTime(&local);
+ if (secsSinceEpoch != time_t(-1)) {
+ *date = QDate(local.tm_year + 1900, local.tm_mon + 1, local.tm_mday);
+ *time = QTime(local.tm_hour, local.tm_min, local.tm_sec, msec);
+#if defined(Q_OS_WIN)
+ // Windows mktime for the missing hour subtracts 1 hour from the time
+ // instead of adding 1 hour. If time differs and is standard time then
+ // this has happened, so add 2 hours to the time and 1 hour to the msecs
+ if (local.tm_isdst == 0 && local.tm_hour != hh) {
+ if (time->hour() >= 22)
+ *date = date->addDays(1);
+ *time = time->addSecs(2 * SECS_PER_HOUR);
+ secsSinceEpoch += SECS_PER_HOUR;
+ local.tm_isdst = 1;
+ }
+#endif // Q_OS_WIN
+ if (local.tm_isdst >= 1) {
+ if (daylightStatus)
+ *daylightStatus = QDateTimePrivate::DaylightTime;
+ if (abbreviation)
+ *abbreviation = qt_tzname(QDateTimePrivate::DaylightTime);
+ } else if (local.tm_isdst == 0) {
+ if (daylightStatus)
+ *daylightStatus = QDateTimePrivate::StandardTime;
+ if (abbreviation)
+ *abbreviation = qt_tzname(QDateTimePrivate::StandardTime);
+ } else {
+ if (daylightStatus)
+ *daylightStatus = QDateTimePrivate::UnknownDaylightTime;
+ if (abbreviation)
+ *abbreviation = qt_tzname(QDateTimePrivate::StandardTime);
+ }
+ if (ok)
+ *ok = true;
+ } else {
+ *date = QDate();
+ *time = QTime();
+ if (daylightStatus)
+ *daylightStatus = QDateTimePrivate::UnknownDaylightTime;
+ if (abbreviation)
+ *abbreviation = QString();
+ if (ok)
+ *ok = false;
+ }
+
+ return ((qint64)secsSinceEpoch * 1000) + msec;
+}
+
+// Calls the platform variant of localtime for the given msecs, and updates
+// the date, time, and DST status with the returned values.
+static bool qt_localtime(qint64 msecsSinceEpoch, QDate *localDate, QTime *localTime,
+ QDateTimePrivate::DaylightStatus *daylightStatus)
+{
+ const time_t secsSinceEpoch = msecsSinceEpoch / 1000;
+ const int msec = msecsSinceEpoch % 1000;
+
+ tm local;
+ bool valid = false;
+
+ // localtime() is specified to work as if it called tzset().
+ // localtime_r() does not have this constraint, so make an explicit call.
+ // The explicit call should also request the timezone info be re-parsed.
+ qTzSet();
+#if QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
+ // Use the reentrant version of localtime() where available
+ // as is thread-safe and doesn't use a shared static data area
+ tm *res = nullptr;
+ res = localtime_r(&secsSinceEpoch, &local);
+ if (res)
+ valid = true;
+#elif defined(Q_CC_MSVC)
+ if (!_localtime64_s(&local, &secsSinceEpoch))
+ valid = true;
+#else
+ // Returns shared static data which may be overwritten at any time
+ // So copy the result asap
+ tm *res = nullptr;
+ res = localtime(&secsSinceEpoch);
+ if (res) {
+ local = *res;
+ valid = true;
+ }
+#endif
+ if (valid) {
+ *localDate = QDate(local.tm_year + 1900, local.tm_mon + 1, local.tm_mday);
+ *localTime = QTime(local.tm_hour, local.tm_min, local.tm_sec, msec);
+ if (daylightStatus) {
+ if (local.tm_isdst > 0)
+ *daylightStatus = QDateTimePrivate::DaylightTime;
+ else if (local.tm_isdst < 0)
+ *daylightStatus = QDateTimePrivate::UnknownDaylightTime;
+ else
+ *daylightStatus = QDateTimePrivate::StandardTime;
+ }
+ return true;
+ } else {
+ *localDate = QDate();
+ *localTime = QTime();
+ if (daylightStatus)
+ *daylightStatus = QDateTimePrivate::UnknownDaylightTime;
+ return false;
+ }
+}
+
+// Converts an msecs value into a date and time
+static void msecsToTime(qint64 msecs, QDate *date, QTime *time)
+{
+ qint64 jd = JULIAN_DAY_FOR_EPOCH;
+ qint64 ds = 0;
+
+ if (msecs >= MSECS_PER_DAY || msecs <= -MSECS_PER_DAY) {
+ jd += msecs / MSECS_PER_DAY;
+ msecs %= MSECS_PER_DAY;
+ }
+
+ if (msecs < 0) {
+ ds = MSECS_PER_DAY - msecs - 1;
+ jd -= ds / MSECS_PER_DAY;
+ ds = ds % MSECS_PER_DAY;
+ ds = MSECS_PER_DAY - ds - 1;
+ } else {
+ ds = msecs;
+ }
+
+ if (date)
+ *date = QDate::fromJulianDay(jd);
+ if (time)
+ *time = QTime::fromMSecsSinceStartOfDay(ds);
+}
+
+// Converts a date/time value into msecs
+static qint64 timeToMSecs(const QDate &date, const QTime &time)
+{
+ return ((date.toJulianDay() - JULIAN_DAY_FOR_EPOCH) * MSECS_PER_DAY)
+ + time.msecsSinceStartOfDay();
+}
+
+// Convert an MSecs Since Epoch into Local Time
+static bool epochMSecsToLocalTime(qint64 msecs, QDate *localDate, QTime *localTime,
+ QDateTimePrivate::DaylightStatus *daylightStatus = nullptr)
+{
+ if (msecs < 0) {
+ // Docs state any LocalTime before 1970-01-01 will *not* have any Daylight Time applied
+ // Instead just use the standard offset from UTC to convert to UTC time
+ qTzSet();
+ msecsToTime(msecs - qt_timezone() * 1000, localDate, localTime);
+ if (daylightStatus)
+ *daylightStatus = QDateTimePrivate::StandardTime;
+ return true;
+ } else if (msecs > (qint64(TIME_T_MAX) * 1000)) {
+ // Docs state any LocalTime after 2037-12-31 *will* have any DST applied
+ // but this may fall outside the supported time_t range, so need to fake it.
+ // Use existing method to fake the conversion, but this is deeply flawed as it may
+ // apply the conversion from the wrong day number, e.g. if rule is last Sunday of month
+ // TODO Use QTimeZone when available to apply the future rule correctly
+ QDate utcDate;
+ QTime utcTime;
+ msecsToTime(msecs, &utcDate, &utcTime);
+ int year, month, day;
+ utcDate.getDate(&year, &month, &day);
+ // 2037 is not a leap year, so make sure date isn't Feb 29
+ if (month == 2 && day == 29)
+ --day;
+ QDate fakeDate(2037, month, day);
+ qint64 fakeMsecs = QDateTime(fakeDate, utcTime, Qt::UTC).toMSecsSinceEpoch();
+ bool res = qt_localtime(fakeMsecs, localDate, localTime, daylightStatus);
+ *localDate = localDate->addDays(fakeDate.daysTo(utcDate));
+ return res;
+ } else {
+ // Falls inside time_t suported range so can use localtime
+ return qt_localtime(msecs, localDate, localTime, daylightStatus);
+ }
+}
+
+// Convert a LocalTime expressed in local msecs encoding and the corresponding
+// DST status into a UTC epoch msecs. Optionally populate the returned
+// values from mktime for the adjusted local date and time.
+static qint64 localMSecsToEpochMSecs(qint64 localMsecs,
+ QDateTimePrivate::DaylightStatus *daylightStatus,
+ QDate *localDate = nullptr, QTime *localTime = nullptr,
+ QString *abbreviation = nullptr)
+{
+ QDate dt;
+ QTime tm;
+ msecsToTime(localMsecs, &dt, &tm);
+
+ const qint64 msecsMax = qint64(TIME_T_MAX) * 1000;
+
+ if (localMsecs <= qint64(MSECS_PER_DAY)) {
+
+ // Docs state any LocalTime before 1970-01-01 will *not* have any DST applied
+
+ // First, if localMsecs is within +/- 1 day of minimum time_t try mktime in case it does
+ // fall after minimum and needs proper DST conversion
+ if (localMsecs >= -qint64(MSECS_PER_DAY)) {
+ bool valid;
+ qint64 utcMsecs = qt_mktime(&dt, &tm, daylightStatus, abbreviation, &valid);
+ if (valid && utcMsecs >= 0) {
+ // mktime worked and falls in valid range, so use it
+ if (localDate)
+ *localDate = dt;
+ if (localTime)
+ *localTime = tm;
+ return utcMsecs;
+ }
+ } else {
+ // If we don't call mktime then need to call tzset to get offset
+ qTzSet();
+ }
+ // Time is clearly before 1970-01-01 so just use standard offset to convert
+ qint64 utcMsecs = localMsecs + qt_timezone() * 1000;
+ if (localDate || localTime)
+ msecsToTime(localMsecs, localDate, localTime);
+ if (daylightStatus)
+ *daylightStatus = QDateTimePrivate::StandardTime;
+ if (abbreviation)
+ *abbreviation = qt_tzname(QDateTimePrivate::StandardTime);
+ return utcMsecs;
+
+ } else if (localMsecs >= msecsMax - MSECS_PER_DAY) {
+
+ // Docs state any LocalTime after 2037-12-31 *will* have any DST applied
+ // but this may fall outside the supported time_t range, so need to fake it.
+
+ // First, if localMsecs is within +/- 1 day of maximum time_t try mktime in case it does
+ // fall before maximum and can use proper DST conversion
+ if (localMsecs <= msecsMax + MSECS_PER_DAY) {
+ bool valid;
+ qint64 utcMsecs = qt_mktime(&dt, &tm, daylightStatus, abbreviation, &valid);
+ if (valid && utcMsecs <= msecsMax) {
+ // mktime worked and falls in valid range, so use it
+ if (localDate)
+ *localDate = dt;
+ if (localTime)
+ *localTime = tm;
+ return utcMsecs;
+ }
+ }
+ // Use existing method to fake the conversion, but this is deeply flawed as it may
+ // apply the conversion from the wrong day number, e.g. if rule is last Sunday of month
+ // TODO Use QTimeZone when available to apply the future rule correctly
+ int year, month, day;
+ dt.getDate(&year, &month, &day);
+ // 2037 is not a leap year, so make sure date isn't Feb 29
+ if (month == 2 && day == 29)
+ --day;
+ QDate fakeDate(2037, month, day);
+ qint64 fakeDiff = fakeDate.daysTo(dt);
+ qint64 utcMsecs = qt_mktime(&fakeDate, &tm, daylightStatus, abbreviation);
+ if (localDate)
+ *localDate = fakeDate.addDays(fakeDiff);
+ if (localTime)
+ *localTime = tm;
+ QDate utcDate;
+ QTime utcTime;
+ msecsToTime(utcMsecs, &utcDate, &utcTime);
+ utcDate = utcDate.addDays(fakeDiff);
+ utcMsecs = timeToMSecs(utcDate, utcTime);
+ return utcMsecs;
+
+ } else {
+
+ // Clearly falls inside 1970-2037 suported range so can use mktime
+ qint64 utcMsecs = qt_mktime(&dt, &tm, daylightStatus, abbreviation);
+ if (localDate)
+ *localDate = dt;
+ if (localTime)
+ *localTime = tm;
+ return utcMsecs;
+
+ }
+}
+
+static inline bool specCanBeSmall(Qt::TimeSpec spec)
+{
+ return spec == Qt::LocalTime || spec == Qt::UTC;
+}
+
+static inline bool msecsCanBeSmall(qint64 msecs)
+{
+ if (!QDateTimeData::CanBeSmall)
+ return false;
+
+ ShortData sd;
+ sd.msecs = qintptr(msecs);
+ return sd.msecs == msecs;
+}
+
+static Q_DECL_CONSTEXPR inline
+QDateTimePrivate::StatusFlags mergeSpec(QDateTimePrivate::StatusFlags status, Qt::TimeSpec spec)
+{
+ return QDateTimePrivate::StatusFlags((status & ~QDateTimePrivate::TimeSpecMask) |
+ (int(spec) << QDateTimePrivate::TimeSpecShift));
+}
+
+static Q_DECL_CONSTEXPR inline Qt::TimeSpec extractSpec(QDateTimePrivate::StatusFlags status)
+{
+ return Qt::TimeSpec((status & QDateTimePrivate::TimeSpecMask) >> QDateTimePrivate::TimeSpecShift);
+}
+
+// Set the Daylight Status if LocalTime set via msecs
+static Q_DECL_RELAXED_CONSTEXPR inline QDateTimePrivate::StatusFlags
+mergeDaylightStatus(QDateTimePrivate::StatusFlags sf, QDateTimePrivate::DaylightStatus status)
+{
+ sf &= ~QDateTimePrivate::DaylightMask;
+ if (status == QDateTimePrivate::DaylightTime) {
+ sf |= QDateTimePrivate::SetToDaylightTime;
+ } else if (status == QDateTimePrivate::StandardTime) {
+ sf |= QDateTimePrivate::SetToStandardTime;
+ }
+ return sf;
+}
+
+// Get the DST Status if LocalTime set via msecs
+static Q_DECL_RELAXED_CONSTEXPR inline
+QDateTimePrivate::DaylightStatus extractDaylightStatus(QDateTimePrivate::StatusFlags status)
+{
+ if (status & QDateTimePrivate::SetToDaylightTime)
+ return QDateTimePrivate::DaylightTime;
+ if (status & QDateTimePrivate::SetToStandardTime)
+ return QDateTimePrivate::StandardTime;
+ return QDateTimePrivate::UnknownDaylightTime;
+}
+
+static inline qint64 getMSecs(const QDateTimeData &d)
+{
+ if (d.isShort()) {
+ // same as, but producing better code
+ //return d.data.msecs;
+ return qintptr(d.d) >> 8;
+ }
+ return d->m_msecs;
+}
+
+static inline QDateTimePrivate::StatusFlags getStatus(const QDateTimeData &d)
+{
+ if (d.isShort()) {
+ // same as, but producing better code
+ //return StatusFlag(d.data.status);
+ return QDateTimePrivate::StatusFlag(qintptr(d.d) & 0xFF);
+ }
+ return d->m_status;
+}
+
+static inline Qt::TimeSpec getSpec(const QDateTimeData &d)
+{
+ return extractSpec(getStatus(d));
+}
+
+#if QT_CONFIG(timezone)
+void QDateTimePrivate::setUtcOffsetByTZ(qint64 atMSecsSinceEpoch)
+{
+ m_offsetFromUtc = m_timeZone.d->offsetFromUtc(atMSecsSinceEpoch);
+}
+#endif
+
+// Refresh the LocalTime validity and offset
+static void refreshDateTime(QDateTimeData &d)
+{
+ auto status = getStatus(d);
+ const auto spec = extractSpec(status);
+ const qint64 msecs = getMSecs(d);
+ qint64 epochMSecs = 0;
+ int offsetFromUtc = 0;
+ QDate testDate;
+ QTime testTime;
+ Q_ASSERT(spec == Qt::TimeZone || spec == Qt::LocalTime);
+
+#if QT_CONFIG(timezone)
+ // If not valid time zone then is invalid
+ if (spec == Qt::TimeZone) {
+ if (!d->m_timeZone.isValid()) {
+ status &= ~QDateTimePrivate::ValidDateTime;
+ } else {
+ epochMSecs = QDateTimePrivate::zoneMSecsToEpochMSecs(msecs, d->m_timeZone, extractDaylightStatus(status), &testDate, &testTime);
+ d->setUtcOffsetByTZ(epochMSecs);
+ }
+ }
+#endif // timezone
+
+ // If not valid date and time then is invalid
+ if (!(status & QDateTimePrivate::ValidDate) || !(status & QDateTimePrivate::ValidTime)) {
+ status &= ~QDateTimePrivate::ValidDateTime;
+ if (status & QDateTimePrivate::ShortData) {
+ d.data.status = status;
+ } else {
+ d->m_status = status;
+ d->m_offsetFromUtc = 0;
+ }
+ return;
+ }
+
+ // We have a valid date and time and a Qt::LocalTime or Qt::TimeZone that needs calculating
+ // LocalTime and TimeZone might fall into a "missing" DST transition hour
+ // Calling toEpochMSecs will adjust the returned date/time if it does
+ if (spec == Qt::LocalTime) {
+ auto dstStatus = extractDaylightStatus(status);
+ epochMSecs = localMSecsToEpochMSecs(msecs, &dstStatus, &testDate, &testTime);
+ }
+ if (timeToMSecs(testDate, testTime) == msecs) {
+ status |= QDateTimePrivate::ValidDateTime;
+ // Cache the offset to use in offsetFromUtc()
+ offsetFromUtc = (msecs - epochMSecs) / 1000;
+ } else {
+ status &= ~QDateTimePrivate::ValidDateTime;
+ }
+
+ if (status & QDateTimePrivate::ShortData) {
+ d.data.status = status;
+ } else {
+ d->m_status = status;
+ d->m_offsetFromUtc = offsetFromUtc;
+ }
+}
+
+// Check the UTC / offsetFromUTC validity
+static void checkValidDateTime(QDateTimeData &d)
+{
+ auto status = getStatus(d);
+ auto spec = extractSpec(status);
+ switch (spec) {
+ case Qt::OffsetFromUTC:
+ case Qt::UTC:
+ // for these, a valid date and a valid time imply a valid QDateTime
+ if ((status & QDateTimePrivate::ValidDate) && (status & QDateTimePrivate::ValidTime))
+ status |= QDateTimePrivate::ValidDateTime;
+ else
+ status &= ~QDateTimePrivate::ValidDateTime;
+ if (status & QDateTimePrivate::ShortData)
+ d.data.status = status;
+ else
+ d->m_status = status;
+ break;
+ case Qt::TimeZone:
+ case Qt::LocalTime:
+ // for these, we need to check whether the timezone is valid and whether
+ // the time is valid in that timezone. Expensive, but no other option.
+ refreshDateTime(d);
+ break;
+ }
+}
+
+static void setTimeSpec(QDateTimeData &d, Qt::TimeSpec spec, int offsetSeconds)
+{
+ auto status = getStatus(d);
+ status &= ~(QDateTimePrivate::ValidDateTime | QDateTimePrivate::DaylightMask |
+ QDateTimePrivate::TimeSpecMask);
+
+ switch (spec) {
+ case Qt::OffsetFromUTC:
+ if (offsetSeconds == 0)
+ spec = Qt::UTC;
+ break;
+ case Qt::TimeZone:
+ // Use system time zone instead
+ spec = Qt::LocalTime;
+ Q_FALLTHROUGH();
+ case Qt::UTC:
+ case Qt::LocalTime:
+ offsetSeconds = 0;
+ break;
+ }
+
+ status = mergeSpec(status, spec);
+ if (d.isShort() && offsetSeconds == 0) {
+ d.data.status = status;
+ } else {
+ d.detach();
+ d->m_status = status & ~QDateTimePrivate::ShortData;
+ d->m_offsetFromUtc = offsetSeconds;
+#if QT_CONFIG(timezone)
+ d->m_timeZone = QTimeZone();
+#endif // timezone
+ }
+}
+
+static void setDateTime(QDateTimeData &d, const QDate &date, const QTime &time)
+{
+ // If the date is valid and the time is not we set time to 00:00:00
+ QTime useTime = time;
+ if (!useTime.isValid() && date.isValid())
+ useTime = QTime::fromMSecsSinceStartOfDay(0);
+
+ QDateTimePrivate::StatusFlags newStatus = { };
+
+ // Set date value and status
+ qint64 days = 0;
+ if (date.isValid()) {
+ days = date.toJulianDay() - JULIAN_DAY_FOR_EPOCH;
+ newStatus = QDateTimePrivate::ValidDate;
+ }
+
+ // Set time value and status
+ int ds = 0;
+ if (useTime.isValid()) {
+ ds = useTime.msecsSinceStartOfDay();
+ newStatus |= QDateTimePrivate::ValidTime;
+ }
+
+ // Set msecs serial value
+ qint64 msecs = (days * MSECS_PER_DAY) + ds;
+ if (d.isShort()) {
+ // let's see if we can keep this short
+ if (msecsCanBeSmall(msecs)) {
+ // yes, we can
+ d.data.msecs = qintptr(msecs);
+ d.data.status &= ~(QDateTimePrivate::ValidityMask | QDateTimePrivate::DaylightMask);
+ d.data.status |= newStatus;
+ } else {
+ // nope...
+ d.detach();
+ }
+ }
+ if (!d.isShort()) {
+ d.detach();
+ d->m_msecs = msecs;
+ d->m_status &= ~(QDateTimePrivate::ValidityMask | QDateTimePrivate::DaylightMask);
+ d->m_status |= newStatus;
+ }
+
+ // Set if date and time are valid
+ checkValidDateTime(d);
+}
+
+static QPair<QDate, QTime> getDateTime(const QDateTimeData &d)
+{
+ QPair<QDate, QTime> result;
+ qint64 msecs = getMSecs(d);
+ auto status = getStatus(d);
+ msecsToTime(msecs, &result.first, &result.second);
+
+ if (!status.testFlag(QDateTimePrivate::ValidDate))
+ result.first = QDate();
+
+ if (!status.testFlag(QDateTimePrivate::ValidTime))
+ result.second = QTime();
+
+ return result;
+}
+
+/*****************************************************************************
+ QDateTime::Data member functions
+ *****************************************************************************/
+
+inline QDateTime::Data::Data()
+{
+ // default-constructed data has a special exception:
+ // it can be small even if CanBeSmall == false
+ // (optimization so we don't allocate memory in the default constructor)
+ quintptr value = quintptr(mergeSpec(QDateTimePrivate::ShortData, Qt::LocalTime));
+ d = reinterpret_cast<QDateTimePrivate *>(value);
+}
+
+inline QDateTime::Data::Data(Qt::TimeSpec spec)
+{
+ if (CanBeSmall && Q_LIKELY(specCanBeSmall(spec))) {
+ d = reinterpret_cast<QDateTimePrivate *>(quintptr(mergeSpec(QDateTimePrivate::ShortData, spec)));
+ } else {
+ // the structure is too small, we need to detach
+ d = new QDateTimePrivate;
+ d->ref.ref();
+ d->m_status = mergeSpec(nullptr, spec);
+ }
+}
+
+inline QDateTime::Data::Data(const Data &other)
+ : d(other.d)
+{
+ if (!isShort()) {
+ // check if we could shrink
+ if (specCanBeSmall(extractSpec(d->m_status)) && msecsCanBeSmall(d->m_msecs)) {
+ ShortData sd;
+ sd.msecs = qintptr(d->m_msecs);
+ sd.status = d->m_status | QDateTimePrivate::ShortData;
+ data = sd;
+ } else {
+ // no, have to keep it big
+ d->ref.ref();
+ }
+ }
+}
+
+inline QDateTime::Data::Data(Data &&other)
+ : d(other.d)
+{
+ // reset the other to a short state
+ Data dummy;
+ Q_ASSERT(dummy.isShort());
+ other.d = dummy.d;
+}
+
+inline QDateTime::Data &QDateTime::Data::operator=(const Data &other)
+{
+ if (d == other.d)
+ return *this;
+
+ auto x = d;
+ d = other.d;
+ if (!other.isShort()) {
+ // check if we could shrink
+ if (specCanBeSmall(extractSpec(other.d->m_status)) && msecsCanBeSmall(other.d->m_msecs)) {
+ ShortData sd;
+ sd.msecs = qintptr(other.d->m_msecs);
+ sd.status = other.d->m_status | QDateTimePrivate::ShortData;
+ data = sd;
+ } else {
+ // no, have to keep it big
+ other.d->ref.ref();
+ }
+ }
+
+ if (!(quintptr(x) & QDateTimePrivate::ShortData) && !x->ref.deref())
+ delete x;
+ return *this;
+}
+
+inline QDateTime::Data::~Data()
+{
+ if (!isShort() && !d->ref.deref())
+ delete d;
+}
+
+inline bool QDateTime::Data::isShort() const
+{
+ bool b = quintptr(d) & QDateTimePrivate::ShortData;
+
+ // sanity check:
+ Q_ASSERT(b || (d->m_status & QDateTimePrivate::ShortData) == 0);
+
+ // even if CanBeSmall = false, we have short data for a default-constructed
+ // QDateTime object. But it's unlikely.
+ if (CanBeSmall)
+ return Q_LIKELY(b);
+ return Q_UNLIKELY(b);
+}
+
+inline void QDateTime::Data::detach()
+{
+ QDateTimePrivate *x;
+ bool wasShort = isShort();
+ if (wasShort) {
+ // force enlarging
+ x = new QDateTimePrivate;
+ x->m_status = QDateTimePrivate::StatusFlag(data.status & ~QDateTimePrivate::ShortData);
+ x->m_msecs = data.msecs;
+ } else {
+ if (d->ref.loadRelaxed() == 1)
+ return;
+
+ x = new QDateTimePrivate(*d);
+ }
+
+ x->ref.storeRelaxed(1);
+ if (!wasShort && !d->ref.deref())
+ delete d;
+ d = x;
+}
+
+inline const QDateTimePrivate *QDateTime::Data::operator->() const
+{
+ Q_ASSERT(!isShort());
+ return d;
+}
+
+inline QDateTimePrivate *QDateTime::Data::operator->()
+{
+ // should we attempt to detach here?
+ Q_ASSERT(!isShort());
+ Q_ASSERT(d->ref.loadRelaxed() == 1);
+ return d;
+}
+
+/*****************************************************************************
+ QDateTimePrivate member functions
+ *****************************************************************************/
+
+Q_NEVER_INLINE
+QDateTime::Data QDateTimePrivate::create(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec,
+ int offsetSeconds)
+{
+ QDateTime::Data result(toSpec);
+ setTimeSpec(result, toSpec, offsetSeconds);
+ setDateTime(result, toDate, toTime);
+ return result;
+}
+
+#if QT_CONFIG(timezone)
+inline QDateTime::Data QDateTimePrivate::create(const QDate &toDate, const QTime &toTime,
+ const QTimeZone &toTimeZone)
+{
+ QDateTime::Data result(Qt::TimeZone);
+ Q_ASSERT(!result.isShort());
+
+ result.d->m_status = mergeSpec(result.d->m_status, Qt::TimeZone);
+ result.d->m_timeZone = toTimeZone;
+ setDateTime(result, toDate, toTime);
+ return result;
+}
+
+// Convert a TimeZone time expressed in zone msecs encoding into a UTC epoch msecs
+// DST transitions are disambiguated by hint.
+inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QTimeZone &zone,
+ DaylightStatus hint,
+ QDate *zoneDate, QTime *zoneTime)
+{
+ // Get the effective data from QTimeZone
+ QTimeZonePrivate::Data data = zone.d->dataForLocalTime(zoneMSecs, int(hint));
+ // Docs state any time before 1970-01-01 will *not* have any DST applied
+ // but all affected times afterwards will have DST applied.
+ if (data.atMSecsSinceEpoch < 0) {
+ msecsToTime(zoneMSecs, zoneDate, zoneTime);
+ return zoneMSecs - data.standardTimeOffset * 1000;
+ } else {
+ msecsToTime(data.atMSecsSinceEpoch + data.offsetFromUtc * 1000, zoneDate, zoneTime);
+ return data.atMSecsSinceEpoch;
+ }
+}
+#endif // timezone
+
+/*****************************************************************************
+ QDateTime member functions
+ *****************************************************************************/
+
+/*!
+ \class QDateTime
+ \inmodule QtCore
+ \ingroup shared
+ \reentrant
+ \brief The QDateTime class provides date and time functions.
+
+
+ A QDateTime object encodes a calendar date and a clock time (a
+ "datetime"). It combines features of the QDate and QTime classes.
+ It can read the current datetime from the system clock. It
+ provides functions for comparing datetimes and for manipulating a
+ datetime by adding a number of seconds, days, months, or years.
+
+ QDateTime can describe datetimes with respect to \l{Qt::LocalTime}{local
+ time}, to \l{Qt::UTC}{UTC}, to a specified \l{Qt::OffsetFromUTC}{offset from
+ UTC} or to a specified \l{Qt::TimeZone}{time zone}, in conjunction with the
+ QTimeZone class. For example, a time zone of "Europe/Berlin" will apply the
+ daylight-saving rules as used in Germany since 1970. In contrast, an offset
+ from UTC of +3600 seconds is one hour ahead of UTC (usually written in ISO
+ standard notation as "UTC+01:00"), with no daylight-saving offset or
+ changes. When using either local time or a specified time zone, time-zone
+ transitions such as the starts and ends of daylight-saving time (DST; but
+ see below) are taken into account. The choice of system used to represent a
+ datetime is described as its "timespec".
+
+ A QDateTime object is typically created either by giving a date and time
+ explicitly in the constructor, or by using a static function such as
+ currentDateTime() or fromMSecsSinceEpoch(). The date and time can be changed
+ with setDate() and setTime(). A datetime can also be set using the
+ setMSecsSinceEpoch() function that takes the time, in milliseconds, since
+ 00:00:00 on January 1, 1970. The fromString() function returns a QDateTime,
+ given a string and a date format used to interpret the date within the
+ string.
+
+ QDateTime::currentDateTime() returns a QDateTime that expresses the current
+ time with respect to local time. QDateTime::currentDateTimeUtc() returns a
+ QDateTime that expresses the current time with respect to UTC.
+
+ The date() and time() functions provide access to the date and
+ time parts of the datetime. The same information is provided in
+ textual format by the toString() function.
+
+ QDateTime provides a full set of operators to compare two
+ QDateTime objects, where smaller means earlier and larger means
+ later.
+
+ You can increment (or decrement) a datetime by a given number of
+ milliseconds using addMSecs(), seconds using addSecs(), or days using
+ addDays(). Similarly, you can use addMonths() and addYears(). The daysTo()
+ function returns the number of days between two datetimes, secsTo() returns
+ the number of seconds between two datetimes, and msecsTo() returns the
+ number of milliseconds between two datetimes. These operations are aware of
+ daylight-saving time (DST) and other time-zone transitions, where
+ applicable.
+
+ Use toTimeSpec() to express a datetime in local time or UTC,
+ toOffsetFromUtc() to express in terms of an offset from UTC, or toTimeZone()
+ to express it with respect to a general time zone. You can use timeSpec() to
+ find out what time-spec a QDateTime object stores its time relative to. When
+ that is Qt::TimeZone, you can use timeZone() to find out which zone it is
+ using.
+
+ \note QDateTime does not account for leap seconds.
+
+ \section1 Remarks
+
+ \section2 No Year 0
+
+ There is no year 0. Dates in that year are considered invalid. The
+ year -1 is the year "1 before Christ" or "1 before current era."
+ The day before 1 January 1 CE is 31 December 1 BCE.
+
+ \section2 Range of Valid Dates
+
+ The range of values that QDateTime can represent is dependent on the
+ internal storage implementation. QDateTime is currently stored in a qint64
+ as a serial msecs value encoding the date and time. This restricts the date
+ range to about +/- 292 million years, compared to the QDate range of +/- 2
+ billion years. Care must be taken when creating a QDateTime with extreme
+ values that you do not overflow the storage. The exact range of supported
+ values varies depending on the Qt::TimeSpec and time zone.
+
+ \section2 Use of Timezones
+
+ QDateTime uses the system's time zone information to determine the current
+ local time zone and its offset from UTC. If the system is not configured
+ correctly or not up-to-date, QDateTime will give wrong results.
+
+ QDateTime likewise uses system-provided information to determine the offsets
+ of other timezones from UTC. If this information is incomplete or out of
+ date, QDateTime will give wrong results. See the QTimeZone documentation for
+ more details.
+
+ On modern Unix systems, this means QDateTime usually has accurate
+ information about historical transitions (including DST, see below) whenever
+ possible. On Windows, where the system doesn't support historical timezone
+ data, historical accuracy is not maintained with respect to timezone
+ transitions, notably including DST.
+
+ \section2 Daylight-Saving Time (DST)
+
+ QDateTime takes into account transitions between Standard Time and
+ Daylight-Saving Time. For example, if the transition is at 2am and the clock
+ goes forward to 3am, then there is a "missing" hour from 02:00:00 to
+ 02:59:59.999 which QDateTime considers to be invalid. Any date arithmetic
+ performed will take this missing hour into account and return a valid
+ result. For example, adding one minute to 01:59:59 will get 03:00:00.
+
+ The range of valid dates taking DST into account is 1970-01-01 to the
+ present, and rules are in place for handling DST correctly until 2037-12-31,
+ but these could change. For dates after 2037, QDateTime makes a \e{best
+ guess} using the rules for year 2037, but we can't guarantee accuracy;
+ indeed, for \e{any} future date, the time-zone may change its rules before
+ that date comes around. For dates before 1970, QDateTime doesn't take DST
+ changes into account, even if the system's time zone database provides that
+ information, although it does take into account changes to the time-zone's
+ standard offset, where this information is available.
+
+ \section2 Offsets From UTC
+
+ There is no explicit size restriction on an offset from UTC, but there is an
+ implicit limit imposed when using the toString() and fromString() methods
+ which use a [+|-]hh:mm format, effectively limiting the range to +/- 99
+ hours and 59 minutes and whole minutes only. Note that currently no time
+ zone lies outside the range of +/- 14 hours.
+
+ \sa QDate, QTime, QDateTimeEdit, QTimeZone
+*/
+
+/*!
+ \since 5.14
+ \enum QDateTime::YearRange
+
+ This enumerated type describes the range of years (in the Gregorian
+ calendar) representable by QDateTime:
+
+ \value First The later parts of this year are representable
+ \value Last The earlier parts of this year are representable
+
+ All dates strictly between these two years are also representable.
+ Note, however, that the Gregorian Calendar has no year zero.
+
+ \note QDate can describe dates in a wider range of years. For most
+ purposes, this makes little difference, as the range of years that QDateTime
+ can support reaches 292 million years either side of 1970.
+
+ \sa isValid(), QDate
+*/
+
+/*!
+ Constructs a null datetime (i.e. null date and null time). A null
+ datetime is invalid, since the date is invalid.
+
+ \sa isValid()
+*/
+QDateTime::QDateTime() noexcept(Data::CanBeSmall)
+{
+}
+
+
+/*!
+ Constructs a datetime with the given \a date, a valid
+ time(00:00:00.000), and sets the timeSpec() to Qt::LocalTime.
+*/
+
+QDateTime::QDateTime(const QDate &date)
+ : d(QDateTimePrivate::create(date, QTime(0, 0), Qt::LocalTime, 0))
+{
+}
+
+/*!
+ Constructs a datetime with the given \a date and \a time, using
+ the time specification defined by \a spec.
+
+ If \a date is valid and \a time is not, the time will be set to midnight.
+
+ If \a spec is Qt::OffsetFromUTC then it will be set to Qt::UTC, i.e. an
+ offset of 0 seconds. To create a Qt::OffsetFromUTC datetime use the
+ correct constructor.
+
+ If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
+ i.e. the current system time zone. To create a Qt::TimeZone datetime
+ use the correct constructor.
+*/
+
+QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec)
+ : d(QDateTimePrivate::create(date, time, spec, 0))
+{
+}
+
+/*!
+ \since 5.2
+
+ Constructs a datetime with the given \a date and \a time, using
+ the time specification defined by \a spec and \a offsetSeconds seconds.
+
+ If \a date is valid and \a time is not, the time will be set to midnight.
+
+ If the \a spec is not Qt::OffsetFromUTC then \a offsetSeconds will be ignored.
+
+ If the \a spec is Qt::OffsetFromUTC and \a offsetSeconds is 0 then the
+ timeSpec() will be set to Qt::UTC, i.e. an offset of 0 seconds.
+
+ If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
+ i.e. the current system time zone. To create a Qt::TimeZone datetime
+ use the correct constructor.
+*/
+
+QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec, int offsetSeconds)
+ : d(QDateTimePrivate::create(date, time, spec, offsetSeconds))
+{
+}
+
+#if QT_CONFIG(timezone)
+/*!
+ \since 5.2
+
+ Constructs a datetime with the given \a date and \a time, using
+ the Time Zone specified by \a timeZone.
+
+ If \a date is valid and \a time is not, the time will be set to 00:00:00.
+
+ If \a timeZone is invalid then the datetime will be invalid.
+*/
+
+QDateTime::QDateTime(const QDate &date, const QTime &time, const QTimeZone &timeZone)
+ : d(QDateTimePrivate::create(date, time, timeZone))
+{
+}
+#endif // timezone
+
+/*!
+ Constructs a copy of the \a other datetime.
+*/
+QDateTime::QDateTime(const QDateTime &other) noexcept
+ : d(other.d)
+{
+}
+
+/*!
+ \since 5.8
+ Moves the content of the temporary \a other datetime to this object and
+ leaves \a other in an unspecified (but proper) state.
+*/
+QDateTime::QDateTime(QDateTime &&other) noexcept
+ : d(std::move(other.d))
+{
+}
+
+/*!
+ Destroys the datetime.
+*/
+QDateTime::~QDateTime()
+{
+}
+
+/*!
+ Makes a copy of the \a other datetime and returns a reference to the
+ copy.
+*/
+
+QDateTime &QDateTime::operator=(const QDateTime &other) noexcept
+{
+ d = other.d;
+ return *this;
+}
+/*!
+ \fn void QDateTime::swap(QDateTime &other)
+ \since 5.0
+
+ Swaps this datetime with \a other. This operation is very fast
+ and never fails.
+*/
+
+/*!
+ Returns \c true if both the date and the time are null; otherwise
+ returns \c false. A null datetime is invalid.
+
+ \sa QDate::isNull(), QTime::isNull(), isValid()
+*/
+
+bool QDateTime::isNull() const
+{
+ auto status = getStatus(d);
+ return !status.testFlag(QDateTimePrivate::ValidDate) &&
+ !status.testFlag(QDateTimePrivate::ValidTime);
+}
+
+/*!
+ Returns \c true if both the date and the time are valid and they are valid in
+ the current Qt::TimeSpec, otherwise returns \c false.
+
+ If the timeSpec() is Qt::LocalTime or Qt::TimeZone then the date and time are
+ checked to see if they fall in the Standard Time to Daylight-Saving Time transition
+ hour, i.e. if the transition is at 2am and the clock goes forward to 3am
+ then the time from 02:00:00 to 02:59:59.999 is considered to be invalid.
+
+ \sa QDateTime::YearRange, QDate::isValid(), QTime::isValid()
+*/
+
+bool QDateTime::isValid() const
+{
+ auto status = getStatus(d);
+ return status & QDateTimePrivate::ValidDateTime;
+}
+
+/*!
+ Returns the date part of the datetime.
+
+ \sa setDate(), time(), timeSpec()
+*/
+
+QDate QDateTime::date() const
+{
+ auto status = getStatus(d);
+ if (!status.testFlag(QDateTimePrivate::ValidDate))
+ return QDate();
+ QDate dt;
+ msecsToTime(getMSecs(d), &dt, nullptr);
+ return dt;
+}
+
+/*!
+ Returns the time part of the datetime.
+
+ \sa setTime(), date(), timeSpec()
+*/
+
+QTime QDateTime::time() const
+{
+ auto status = getStatus(d);
+ if (!status.testFlag(QDateTimePrivate::ValidTime))
+ return QTime();
+ QTime tm;
+ msecsToTime(getMSecs(d), nullptr, &tm);
+ return tm;
+}
+
+/*!
+ Returns the time specification of the datetime.
+
+ \sa setTimeSpec(), date(), time(), Qt::TimeSpec
+*/
+
+Qt::TimeSpec QDateTime::timeSpec() const
+{
+ return getSpec(d);
+}
+
+#if QT_CONFIG(timezone)
+/*!
+ \since 5.2
+
+ Returns the time zone of the datetime.
+
+ If the timeSpec() is Qt::LocalTime then an instance of the current system
+ time zone will be returned. Note however that if you copy this time zone
+ the instance will not remain in sync if the system time zone changes.
+
+ \sa setTimeZone(), Qt::TimeSpec
+*/
+
+QTimeZone QDateTime::timeZone() const
+{
+ switch (getSpec(d)) {
+ case Qt::UTC:
+ return QTimeZone::utc();
+ case Qt::OffsetFromUTC:
+ return QTimeZone(d->m_offsetFromUtc);
+ case Qt::TimeZone:
+ Q_ASSERT(d->m_timeZone.isValid());
+ return d->m_timeZone;
+ case Qt::LocalTime:
+ return QTimeZone::systemTimeZone();
+ }
+ return QTimeZone();
+}
+#endif // timezone
+
+/*!
+ \since 5.2
+
+ Returns this date-time's Offset From UTC in seconds.
+
+ The result depends on timeSpec():
+ \list
+ \li \c Qt::UTC The offset is 0.
+ \li \c Qt::OffsetFromUTC The offset is the value originally set.
+ \li \c Qt::LocalTime The local time's offset from UTC is returned.
+ \li \c Qt::TimeZone The offset used by the time-zone is returned.
+ \endlist
+
+ For the last two, the offset at this date and time will be returned, taking
+ account of Daylight-Saving Offset unless the date precedes the start of
+ 1970. The offset is the difference between the local time or time in the
+ given time-zone and UTC time; it is positive in time-zones ahead of UTC
+ (East of The Prime Meridian), negative for those behind UTC (West of The
+ Prime Meridian).
+
+ \sa setOffsetFromUtc()
+*/
+
+int QDateTime::offsetFromUtc() const
+{
+ if (!d.isShort())
+ return d->m_offsetFromUtc;
+ if (!isValid())
+ return 0;
+
+ auto spec = getSpec(d);
+ if (spec == Qt::LocalTime) {
+ // we didn't cache the value, so we need to calculate it now...
+ qint64 msecs = getMSecs(d);
+ return (msecs - toMSecsSinceEpoch()) / 1000;
+ }
+
+ Q_ASSERT(spec == Qt::UTC);
+ return 0;
+}
+
+/*!
+ \since 5.2
+
+ Returns the Time Zone Abbreviation for the datetime.
+
+ If the timeSpec() is Qt::UTC this will be "UTC".
+
+ If the timeSpec() is Qt::OffsetFromUTC this will be in the format
+ "UTC[+-]00:00".
+
+ If the timeSpec() is Qt::LocalTime then the host system is queried for the
+ correct abbreviation.
+
+ Note that abbreviations may or may not be localized.
+
+ Note too that the abbreviation is not guaranteed to be a unique value,
+ i.e. different time zones may have the same abbreviation.
+
+ \sa timeSpec()
+*/
+
+QString QDateTime::timeZoneAbbreviation() const
+{
+ if (!isValid())
+ return QString();
+
+ switch (getSpec(d)) {
+ case Qt::UTC:
+ return QLatin1String("UTC");
+ case Qt::OffsetFromUTC:
+ return QLatin1String("UTC") + toOffsetString(Qt::ISODate, d->m_offsetFromUtc);
+ case Qt::TimeZone:
+#if !QT_CONFIG(timezone)
+ break;
+#else
+ return d->m_timeZone.d->abbreviation(toMSecsSinceEpoch());
+#endif // timezone
+ case Qt::LocalTime: {
+ QString abbrev;
+ auto status = extractDaylightStatus(getStatus(d));
+ localMSecsToEpochMSecs(getMSecs(d), &status, nullptr, nullptr, &abbrev);
+ return abbrev;
+ }
+ }
+ return QString();
+}
+
+/*!
+ \since 5.2
+
+ Returns if this datetime falls in Daylight-Saving Time.
+
+ If the Qt::TimeSpec is not Qt::LocalTime or Qt::TimeZone then will always
+ return false.
+
+ \sa timeSpec()
+*/
+
+bool QDateTime::isDaylightTime() const
+{
+ if (!isValid())
+ return false;
+
+ switch (getSpec(d)) {
+ case Qt::UTC:
+ case Qt::OffsetFromUTC:
+ return false;
+ case Qt::TimeZone:
+#if !QT_CONFIG(timezone)
+ break;
+#else
+ return d->m_timeZone.d->isDaylightTime(toMSecsSinceEpoch());
+#endif // timezone
+ case Qt::LocalTime: {
+ auto status = extractDaylightStatus(getStatus(d));
+ if (status == QDateTimePrivate::UnknownDaylightTime)
+ localMSecsToEpochMSecs(getMSecs(d), &status);
+ return (status == QDateTimePrivate::DaylightTime);
+ }
+ }
+ return false;
+}
+
+/*!
+ Sets the date part of this datetime to \a date. If no time is set yet, it
+ is set to midnight. If \a date is invalid, this QDateTime becomes invalid.
+
+ \sa date(), setTime(), setTimeSpec()
+*/
+
+void QDateTime::setDate(const QDate &date)
+{
+ setDateTime(d, date, time());
+}
+
+/*!
+ Sets the time part of this datetime to \a time. If \a time is not valid,
+ this function sets it to midnight. Therefore, it's possible to clear any
+ set time in a QDateTime by setting it to a default QTime:
+
+ \code
+ QDateTime dt = QDateTime::currentDateTime();
+ dt.setTime(QTime());
+ \endcode
+
+ \sa time(), setDate(), setTimeSpec()
+*/
+
+void QDateTime::setTime(const QTime &time)
+{
+ setDateTime(d, date(), time);
+}
+
+/*!
+ Sets the time specification used in this datetime to \a spec.
+ The datetime will refer to a different point in time.
+
+ If \a spec is Qt::OffsetFromUTC then the timeSpec() will be set
+ to Qt::UTC, i.e. an effective offset of 0.
+
+ If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
+ i.e. the current system time zone.
+
+ Example:
+ \snippet code/src_corelib_tools_qdatetime.cpp 19
+
+ \sa timeSpec(), setDate(), setTime(), setTimeZone(), Qt::TimeSpec
+*/
+
+void QDateTime::setTimeSpec(Qt::TimeSpec spec)
+{
+ QT_PREPEND_NAMESPACE(setTimeSpec(d, spec, 0));
+ checkValidDateTime(d);
+}
+
+/*!
+ \since 5.2
+
+ Sets the timeSpec() to Qt::OffsetFromUTC and the offset to \a offsetSeconds.
+ The datetime will refer to a different point in time.
+
+ The maximum and minimum offset is 14 positive or negative hours. If
+ \a offsetSeconds is larger or smaller than that, then the result is
+ undefined.
+
+ If \a offsetSeconds is 0 then the timeSpec() will be set to Qt::UTC.
+
+ \sa isValid(), offsetFromUtc()
+*/
+
+void QDateTime::setOffsetFromUtc(int offsetSeconds)
+{
+ QT_PREPEND_NAMESPACE(setTimeSpec(d, Qt::OffsetFromUTC, offsetSeconds));
+ checkValidDateTime(d);
+}
+
+#if QT_CONFIG(timezone)
+/*!
+ \since 5.2
+
+ Sets the time zone used in this datetime to \a toZone.
+ The datetime will refer to a different point in time.
+
+ If \a toZone is invalid then the datetime will be invalid.
+
+ \sa timeZone(), Qt::TimeSpec
+*/
+
+void QDateTime::setTimeZone(const QTimeZone &toZone)
+{
+ d.detach(); // always detach
+ d->m_status = mergeSpec(d->m_status, Qt::TimeZone);
+ d->m_offsetFromUtc = 0;
+ d->m_timeZone = toZone;
+ refreshDateTime(d);
+}
+#endif // timezone
+
+/*!
+ \since 4.7
+
+ Returns the datetime as the number of milliseconds that have passed
+ since 1970-01-01T00:00:00.000, Coordinated Universal Time (Qt::UTC).
+
+ On systems that do not support time zones, this function will
+ behave as if local time were Qt::UTC.
+
+ The behavior for this function is undefined if the datetime stored in
+ this object is not valid. However, for all valid dates, this function
+ returns a unique value.
+
+ \sa toSecsSinceEpoch(), setMSecsSinceEpoch()
+*/
+qint64 QDateTime::toMSecsSinceEpoch() const
+{
+ switch (getSpec(d)) {
+ case Qt::UTC:
+ return getMSecs(d);
+
+ case Qt::OffsetFromUTC:
+ return d->m_msecs - (d->m_offsetFromUtc * 1000);
+
+ case Qt::LocalTime: {
+ // recalculate the local timezone
+ auto status = extractDaylightStatus(getStatus(d));
+ return localMSecsToEpochMSecs(getMSecs(d), &status);
+ }
+
+ case Qt::TimeZone:
+#if !QT_CONFIG(timezone)
+ return 0;
+#else
+ return QDateTimePrivate::zoneMSecsToEpochMSecs(d->m_msecs, d->m_timeZone,
+ extractDaylightStatus(getStatus(d)));
+#endif
+ }
+ Q_UNREACHABLE();
+ return 0;
+}
+
+/*!
+ \since 5.8
+
+ Returns the datetime as the number of seconds that have passed since
+ 1970-01-01T00:00:00.000, Coordinated Universal Time (Qt::UTC).
+
+ On systems that do not support time zones, this function will
+ behave as if local time were Qt::UTC.
+
+ The behavior for this function is undefined if the datetime stored in
+ this object is not valid. However, for all valid dates, this function
+ returns a unique value.
+
+ \sa toMSecsSinceEpoch(), setSecsSinceEpoch()
+*/
+qint64 QDateTime::toSecsSinceEpoch() const
+{
+ return toMSecsSinceEpoch() / 1000;
+}
+
+#if QT_DEPRECATED_SINCE(5, 8)
+/*!
+ \deprecated
+
+ Returns the datetime as the number of seconds that have passed
+ since 1970-01-01T00:00:00, Coordinated Universal Time (Qt::UTC).
+
+ On systems that do not support time zones, this function will
+ behave as if local time were Qt::UTC.
+
+ \note This function returns a 32-bit unsigned integer and is deprecated.
+
+ If the date is outside the range 1970-01-01T00:00:00 to
+ 2106-02-07T06:28:14, this function returns -1 cast to an unsigned integer
+ (i.e., 0xFFFFFFFF).
+
+ To get an extended range, use toMSecsSinceEpoch() or toSecsSinceEpoch().
+
+ \sa toSecsSinceEpoch(), toMSecsSinceEpoch(), setTime_t()
+*/
+
+uint QDateTime::toTime_t() const
+{
+ if (!isValid())
+ return uint(-1);
+ qint64 retval = toMSecsSinceEpoch() / 1000;
+ if (quint64(retval) >= Q_UINT64_C(0xFFFFFFFF))
+ return uint(-1);
+ return uint(retval);
+}
+#endif
+
+/*!
+ \since 4.7
+
+ Sets the date and time given the number of milliseconds \a msecs that have
+ passed since 1970-01-01T00:00:00.000, Coordinated Universal Time
+ (Qt::UTC). On systems that do not support time zones this function
+ will behave as if local time were Qt::UTC.
+
+ Note that passing the minimum of \c qint64
+ (\c{std::numeric_limits<qint64>::min()}) to \a msecs will result in
+ undefined behavior.
+
+ \sa toMSecsSinceEpoch(), setSecsSinceEpoch()
+*/
+void QDateTime::setMSecsSinceEpoch(qint64 msecs)
+{
+ const auto spec = getSpec(d);
+ auto status = getStatus(d);
+
+ status &= ~QDateTimePrivate::ValidityMask;
+ switch (spec) {
+ case Qt::UTC:
+ status = status
+ | QDateTimePrivate::ValidDate
+ | QDateTimePrivate::ValidTime
+ | QDateTimePrivate::ValidDateTime;
+ break;
+ case Qt::OffsetFromUTC:
+ msecs = msecs + (d->m_offsetFromUtc * 1000);
+ status = status
+ | QDateTimePrivate::ValidDate
+ | QDateTimePrivate::ValidTime
+ | QDateTimePrivate::ValidDateTime;
+ break;
+ case Qt::TimeZone:
+ Q_ASSERT(!d.isShort());
+#if QT_CONFIG(timezone)
+ // Docs state any LocalTime before 1970-01-01 will *not* have any DST applied
+ // but all affected times afterwards will have DST applied.
+ d.detach();
+ if (msecs >= 0) {
+ status = mergeDaylightStatus(status,
+ d->m_timeZone.d->isDaylightTime(msecs)
+ ? QDateTimePrivate::DaylightTime
+ : QDateTimePrivate::StandardTime);
+ d->m_offsetFromUtc = d->m_timeZone.d->offsetFromUtc(msecs);
+ } else {
+ status = mergeDaylightStatus(status, QDateTimePrivate::StandardTime);
+ d->m_offsetFromUtc = d->m_timeZone.d->standardTimeOffset(msecs);
+ }
+ msecs = msecs + (d->m_offsetFromUtc * 1000);
+ status = status
+ | QDateTimePrivate::ValidDate
+ | QDateTimePrivate::ValidTime
+ | QDateTimePrivate::ValidDateTime;
+#endif // timezone
+ break;
+ case Qt::LocalTime: {
+ QDate dt;
+ QTime tm;
+ QDateTimePrivate::DaylightStatus dstStatus;
+ epochMSecsToLocalTime(msecs, &dt, &tm, &dstStatus);
+ setDateTime(d, dt, tm);
+ msecs = getMSecs(d);
+ status = mergeDaylightStatus(getStatus(d), dstStatus);
+ break;
+ }
+ }
+
+ if (msecsCanBeSmall(msecs) && d.isShort()) {
+ // we can keep short
+ d.data.msecs = qintptr(msecs);
+ d.data.status = status;
+ } else {
+ d.detach();
+ d->m_status = status & ~QDateTimePrivate::ShortData;
+ d->m_msecs = msecs;
+ }
+
+ if (spec == Qt::LocalTime || spec == Qt::TimeZone)
+ refreshDateTime(d);
+}
+
+/*!
+ \since 5.8
+
+ Sets the date and time given the number of seconds \a secs that have
+ passed since 1970-01-01T00:00:00.000, Coordinated Universal Time
+ (Qt::UTC). On systems that do not support time zones this function
+ will behave as if local time were Qt::UTC.
+
+ \sa toSecsSinceEpoch(), setMSecsSinceEpoch()
+*/
+void QDateTime::setSecsSinceEpoch(qint64 secs)
+{
+ setMSecsSinceEpoch(secs * 1000);
+}
+
+#if QT_DEPRECATED_SINCE(5, 8)
+/*!
+ \fn void QDateTime::setTime_t(uint seconds)
+ \deprecated
+
+ Sets the date and time given the number of \a seconds that have
+ passed since 1970-01-01T00:00:00, Coordinated Universal Time
+ (Qt::UTC). On systems that do not support time zones this function
+ will behave as if local time were Qt::UTC.
+
+ \note This function is deprecated. For new code, use setSecsSinceEpoch().
+
+ \sa toTime_t()
+*/
+
+void QDateTime::setTime_t(uint secsSince1Jan1970UTC)
+{
+ setMSecsSinceEpoch((qint64)secsSince1Jan1970UTC * 1000);
+}
+#endif
+
+#if QT_CONFIG(datestring)
+/*!
+ \fn QString QDateTime::toString(Qt::DateFormat format) const
+
+ \overload
+
+ Returns the datetime as a string in the \a format given.
+
+ If the \a format is Qt::TextDate, the string is formatted in the default
+ way. The day and month names will be localized names using the system
+ locale, i.e. QLocale::system(). An example of this formatting is "Wed May 20
+ 03:40:13 1998".
+
+ If the \a format is Qt::ISODate, the string format corresponds
+ to the ISO 8601 extended specification for representations of
+ dates and times, taking the form yyyy-MM-ddTHH:mm:ss[Z|[+|-]HH:mm],
+ depending on the timeSpec() of the QDateTime. If the timeSpec()
+ is Qt::UTC, Z will be appended to the string; if the timeSpec() is
+ Qt::OffsetFromUTC, the offset in hours and minutes from UTC will
+ be appended to the string. To include milliseconds in the ISO 8601
+ date, use the \a format Qt::ISODateWithMs, which corresponds to
+ yyyy-MM-ddTHH:mm:ss.zzz[Z|[+|-]HH:mm].
+
+ If the \a format is Qt::SystemLocaleShortDate or
+ Qt::SystemLocaleLongDate, the string format depends on the locale
+ settings of the system. Identical to calling
+ QLocale::system().toString(datetime, QLocale::ShortFormat) or
+ QLocale::system().toString(datetime, QLocale::LongFormat).
+
+ If the \a format is Qt::DefaultLocaleShortDate or
+ Qt::DefaultLocaleLongDate, the string format depends on the
+ default application locale. This is the locale set with
+ QLocale::setDefault(), or the system locale if no default locale
+ has been set. Identical to calling QLocale().toString(datetime,
+ QLocale::ShortFormat) or QLocale().toString(datetime,
+ QLocale::LongFormat).
+
+ If the \a format is Qt::RFC2822Date, the string is formatted
+ following \l{RFC 2822}.
+
+ If the datetime is invalid, an empty string will be returned.
+
+ \warning The Qt::ISODate format is only valid for years in the
+ range 0 to 9999. This restriction may apply to locale-aware
+ formats as well, depending on the locale settings.
+
+ \sa fromString(), QDate::toString(), QTime::toString(),
+ QLocale::toString()
+*/
+
+QString QDateTime::toString(Qt::DateFormat format) const
+{
+ QString buf;
+ if (!isValid())
+ return buf;
+
+ switch (format) {
+ case Qt::SystemLocaleDate:
+ case Qt::SystemLocaleShortDate:
+ return QLocale::system().toString(*this, QLocale::ShortFormat);
+ case Qt::SystemLocaleLongDate:
+ return QLocale::system().toString(*this, QLocale::LongFormat);
+ case Qt::LocaleDate:
+ case Qt::DefaultLocaleShortDate:
+ return QLocale().toString(*this, QLocale::ShortFormat);
+ case Qt::DefaultLocaleLongDate:
+ return QLocale().toString(*this, QLocale::LongFormat);
+ case Qt::RFC2822Date: {
+ buf = QLocale::c().toString(*this, u"dd MMM yyyy hh:mm:ss ");
+ buf += toOffsetString(Qt::TextDate, offsetFromUtc());
+ return buf;
+ }
+ default:
+#if QT_CONFIG(textdate)
+ case Qt::TextDate: {
+ const QPair<QDate, QTime> p = getDateTime(d);
+ buf = p.first.toString(Qt::TextDate);
+ // Insert time between date's day and year:
+ buf.insert(buf.lastIndexOf(QLatin1Char(' ')),
+ QLatin1Char(' ') + p.second.toString(Qt::TextDate));
+ // Append zone/offset indicator, as appropriate:
+ switch (timeSpec()) {
+ case Qt::LocalTime:
+ break;
+# if QT_CONFIG(timezone)
+ case Qt::TimeZone:
+ buf += QLatin1Char(' ') + d->m_timeZone.abbreviation(*this);
+ break;
+# endif
+ default:
+ buf += QLatin1String(" GMT");
+ if (getSpec(d) == Qt::OffsetFromUTC)
+ buf += toOffsetString(Qt::TextDate, offsetFromUtc());
+ }
+ return buf;
+ }
+#endif
+ case Qt::ISODate:
+ case Qt::ISODateWithMs: {
+ const QPair<QDate, QTime> p = getDateTime(d);
+ const QDate &dt = p.first;
+ const QTime &tm = p.second;
+ buf = dt.toString(Qt::ISODate);
+ if (buf.isEmpty())
+ return QString(); // failed to convert
+ buf += QLatin1Char('T');
+ buf += tm.toString(format);
+ switch (getSpec(d)) {
+ case Qt::UTC:
+ buf += QLatin1Char('Z');
+ break;
+ case Qt::OffsetFromUTC:
+#if QT_CONFIG(timezone)
+ case Qt::TimeZone:
+#endif
+ buf += toOffsetString(Qt::ISODate, offsetFromUtc());
+ break;
+ default:
+ break;
+ }
+ return buf;
+ }
+ }
+}
+
+/*!
+ \fn QString QDateTime::toString(const QString &format) const
+ \fn QString QDateTime::toString(QStringView format) const
+
+ Returns the datetime as a string. The \a format parameter determines the
+ format of the result string. See QTime::toString() and QDate::toString() for
+ the supported specifiers for time and date, respectively.
+
+ Any sequence of characters enclosed in single quotes will be included
+ verbatim in the output string (stripped of the quotes), even if it contains
+ formatting characters. Two consecutive single quotes ("''") are replaced by
+ a single quote in the output. All other characters in the format string are
+ included verbatim in the output string.
+
+ Formats without separators (e.g. "ddMM") are supported but must be used with
+ care, as the resulting strings aren't always reliably readable (e.g. if "dM"
+ produces "212" it could mean either the 2nd of December or the 21st of
+ February).
+
+ Example format strings (assumed that the QDateTime is 21 May 2001
+ 14:13:09.120):
+
+ \table
+ \header \li Format \li Result
+ \row \li dd.MM.yyyy \li 21.05.2001
+ \row \li ddd MMMM d yy \li Tue May 21 01
+ \row \li hh:mm:ss.zzz \li 14:13:09.120
+ \row \li hh:mm:ss.z \li 14:13:09.12
+ \row \li h:m:s ap \li 2:13:9 pm
+ \endtable
+
+ If the datetime is invalid, an empty string will be returned.
+
+ \sa fromString(), QDate::toString(), QTime::toString(), QLocale::toString()
+*/
+QString QDateTime::toString(QStringView format) const
+{
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
+}
+
+#if QT_STRINGVIEW_LEVEL < 2
+QString QDateTime::toString(const QString &format) const
+{
+ return toString(qToStringViewIgnoringNull(format));
+}
+#endif
+
+#endif // datestring
+
+static inline void massageAdjustedDateTime(const QDateTimeData &d, QDate *date, QTime *time)
+{
+ /*
+ If we have just adjusted to a day with a DST transition, our given time
+ may lie in the transition hour (either missing or duplicated). For any
+ other time, telling mktime (deep in the bowels of localMSecsToEpochMSecs)
+ we don't know its DST-ness will produce no adjustment (just a decision as
+ to its DST-ness); but for a time in spring's missing hour it'll adjust the
+ time while picking a DST-ness. (Handling of autumn is trickier, as either
+ DST-ness is valid, without adjusting the time. We might want to propagate
+ the daylight status in that case, but it's hard to do so without breaking
+ (far more common) other cases; and it makes little difference, as the two
+ answers do then differ only in DST-ness.)
+ */
+ auto spec = getSpec(d);
+ if (spec == Qt::LocalTime) {
+ QDateTimePrivate::DaylightStatus status = QDateTimePrivate::UnknownDaylightTime;
+ localMSecsToEpochMSecs(timeToMSecs(*date, *time), &status, date, time);
+#if QT_CONFIG(timezone)
+ } else if (spec == Qt::TimeZone) {
+ QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time),
+ d->m_timeZone,
+ QDateTimePrivate::UnknownDaylightTime,
+ date, time);
+#endif // timezone
+ }
+}
+
+/*!
+ Returns a QDateTime object containing a datetime \a ndays days
+ later than the datetime of this object (or earlier if \a ndays is
+ negative).
+
+ If the timeSpec() is Qt::LocalTime and the resulting
+ date and time fall in the Standard Time to Daylight-Saving Time transition
+ hour then the result will be adjusted accordingly, i.e. if the transition
+ is at 2am and the clock goes forward to 3am and the result falls between
+ 2am and 3am then the result will be adjusted to fall after 3am.
+
+ \sa daysTo(), addMonths(), addYears(), addSecs()
+*/
+
+QDateTime QDateTime::addDays(qint64 ndays) const
+{
+ QDateTime dt(*this);
+ QPair<QDate, QTime> p = getDateTime(d);
+ QDate &date = p.first;
+ QTime &time = p.second;
+ date = date.addDays(ndays);
+ massageAdjustedDateTime(dt.d, &date, &time);
+ setDateTime(dt.d, date, time);
+ return dt;
+}
+
+/*!
+ Returns a QDateTime object containing a datetime \a nmonths months
+ later than the datetime of this object (or earlier if \a nmonths
+ is negative).
+
+ If the timeSpec() is Qt::LocalTime and the resulting
+ date and time fall in the Standard Time to Daylight-Saving Time transition
+ hour then the result will be adjusted accordingly, i.e. if the transition
+ is at 2am and the clock goes forward to 3am and the result falls between
+ 2am and 3am then the result will be adjusted to fall after 3am.
+
+ \sa daysTo(), addDays(), addYears(), addSecs()
+*/
+
+QDateTime QDateTime::addMonths(int nmonths) const
+{
+ QDateTime dt(*this);
+ QPair<QDate, QTime> p = getDateTime(d);
+ QDate &date = p.first;
+ QTime &time = p.second;
+ date = date.addMonths(nmonths);
+ massageAdjustedDateTime(dt.d, &date, &time);
+ setDateTime(dt.d, date, time);
+ return dt;
+}
+
+/*!
+ Returns a QDateTime object containing a datetime \a nyears years
+ later than the datetime of this object (or earlier if \a nyears is
+ negative).
+
+ If the timeSpec() is Qt::LocalTime and the resulting
+ date and time fall in the Standard Time to Daylight-Saving Time transition
+ hour then the result will be adjusted accordingly, i.e. if the transition
+ is at 2am and the clock goes forward to 3am and the result falls between
+ 2am and 3am then the result will be adjusted to fall after 3am.
+
+ \sa daysTo(), addDays(), addMonths(), addSecs()
+*/
+
+QDateTime QDateTime::addYears(int nyears) const
+{
+ QDateTime dt(*this);
+ QPair<QDate, QTime> p = getDateTime(d);
+ QDate &date = p.first;
+ QTime &time = p.second;
+ date = date.addYears(nyears);
+ massageAdjustedDateTime(dt.d, &date, &time);
+ setDateTime(dt.d, date, time);
+ return dt;
+}
+
+/*!
+ Returns a QDateTime object containing a datetime \a s seconds
+ later than the datetime of this object (or earlier if \a s is
+ negative).
+
+ If this datetime is invalid, an invalid datetime will be returned.
+
+ \sa addMSecs(), secsTo(), addDays(), addMonths(), addYears()
+*/
+
+QDateTime QDateTime::addSecs(qint64 s) const
+{
+ return addMSecs(s * 1000);
+}
+
+/*!
+ Returns a QDateTime object containing a datetime \a msecs miliseconds
+ later than the datetime of this object (or earlier if \a msecs is
+ negative).
+
+ If this datetime is invalid, an invalid datetime will be returned.
+
+ \sa addSecs(), msecsTo(), addDays(), addMonths(), addYears()
+*/
+QDateTime QDateTime::addMSecs(qint64 msecs) const
+{
+ if (!isValid())
+ return QDateTime();
+
+ QDateTime dt(*this);
+ auto spec = getSpec(d);
+ if (spec == Qt::LocalTime || spec == Qt::TimeZone) {
+ // Convert to real UTC first in case crosses DST transition
+ dt.setMSecsSinceEpoch(toMSecsSinceEpoch() + msecs);
+ } else {
+ // No need to convert, just add on
+ if (d.isShort()) {
+ // need to check if we need to enlarge first
+ msecs += dt.d.data.msecs;
+ if (msecsCanBeSmall(msecs)) {
+ dt.d.data.msecs = qintptr(msecs);
+ } else {
+ dt.d.detach();
+ dt.d->m_msecs = msecs;
+ }
+ } else {
+ dt.d.detach();
+ dt.d->m_msecs += msecs;
+ }
+ }
+ return dt;
+}
+
+/*!
+ Returns the number of days from this datetime to the \a other
+ datetime. The number of days is counted as the number of times
+ midnight is reached between this datetime to the \a other
+ datetime. This means that a 10 minute difference from 23:55 to
+ 0:05 the next day counts as one day.
+
+ If the \a other datetime is earlier than this datetime,
+ the value returned is negative.
+
+ Example:
+ \snippet code/src_corelib_tools_qdatetime.cpp 15
+
+ \sa addDays(), secsTo(), msecsTo()
+*/
+
+qint64 QDateTime::daysTo(const QDateTime &other) const
+{
+ return date().daysTo(other.date());
+}
+
+/*!
+ Returns the number of seconds from this datetime to the \a other
+ datetime. If the \a other datetime is earlier than this datetime,
+ the value returned is negative.
+
+ Before performing the comparison, the two datetimes are converted
+ to Qt::UTC to ensure that the result is correct if daylight-saving
+ (DST) applies to one of the two datetimes but not the other.
+
+ Returns 0 if either datetime is invalid.
+
+ Example:
+ \snippet code/src_corelib_tools_qdatetime.cpp 11
+
+ \sa addSecs(), daysTo(), QTime::secsTo()
+*/
+
+qint64 QDateTime::secsTo(const QDateTime &other) const
+{
+ return (msecsTo(other) / 1000);
+}
+
+/*!
+ Returns the number of milliseconds from this datetime to the \a other
+ datetime. If the \a other datetime is earlier than this datetime,
+ the value returned is negative.
+
+ Before performing the comparison, the two datetimes are converted
+ to Qt::UTC to ensure that the result is correct if daylight-saving
+ (DST) applies to one of the two datetimes and but not the other.
+
+ Returns 0 if either datetime is invalid.
+
+ \sa addMSecs(), daysTo(), QTime::msecsTo()
+*/
+
+qint64 QDateTime::msecsTo(const QDateTime &other) const
+{
+ if (!isValid() || !other.isValid())
+ return 0;
+
+ return other.toMSecsSinceEpoch() - toMSecsSinceEpoch();
+}
+
+/*!
+ \fn QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const
+
+ Returns a copy of this datetime converted to the given time
+ \a spec.
+
+ If \a spec is Qt::OffsetFromUTC then it is set to Qt::UTC. To set to a
+ spec of Qt::OffsetFromUTC use toOffsetFromUtc().
+
+ If \a spec is Qt::TimeZone then it is set to Qt::LocalTime,
+ i.e. the local Time Zone.
+
+ Example:
+ \snippet code/src_corelib_tools_qdatetime.cpp 16
+
+ \sa timeSpec(), toTimeZone(), toOffsetFromUtc()
+*/
+
+QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const
+{
+ if (getSpec(d) == spec && (spec == Qt::UTC || spec == Qt::LocalTime))
+ return *this;
+
+ if (!isValid()) {
+ QDateTime ret = *this;
+ ret.setTimeSpec(spec);
+ return ret;
+ }
+
+ return fromMSecsSinceEpoch(toMSecsSinceEpoch(), spec, 0);
+}
+
+/*!
+ \since 5.2
+
+ \fn QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const
+
+ Returns a copy of this datetime converted to a spec of Qt::OffsetFromUTC
+ with the given \a offsetSeconds.
+
+ If the \a offsetSeconds equals 0 then a UTC datetime will be returned
+
+ \sa setOffsetFromUtc(), offsetFromUtc(), toTimeSpec()
+*/
+
+QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const
+{
+ if (getSpec(d) == Qt::OffsetFromUTC
+ && d->m_offsetFromUtc == offsetSeconds)
+ return *this;
+
+ if (!isValid()) {
+ QDateTime ret = *this;
+ ret.setOffsetFromUtc(offsetSeconds);
+ return ret;
+ }
+
+ return fromMSecsSinceEpoch(toMSecsSinceEpoch(), Qt::OffsetFromUTC, offsetSeconds);
+}
+
+#if QT_CONFIG(timezone)
+/*!
+ \since 5.2
+
+ Returns a copy of this datetime converted to the given \a timeZone
+
+ \sa timeZone(), toTimeSpec()
+*/
+
+QDateTime QDateTime::toTimeZone(const QTimeZone &timeZone) const
+{
+ if (getSpec(d) == Qt::TimeZone && d->m_timeZone == timeZone)
+ return *this;
+
+ if (!isValid()) {
+ QDateTime ret = *this;
+ ret.setTimeZone(timeZone);
+ return ret;
+ }
+
+ return fromMSecsSinceEpoch(toMSecsSinceEpoch(), timeZone);
+}
+#endif // timezone
+
+/*!
+ Returns \c true if this datetime is equal to the \a other datetime;
+ otherwise returns \c false.
+
+ Since 5.14, all invalid datetimes are equal to one another and differ from
+ all other datetimes.
+
+ \sa operator!=()
+*/
+
+bool QDateTime::operator==(const QDateTime &other) const
+{
+ if (!isValid())
+ return !other.isValid();
+ if (!other.isValid())
+ return false;
+
+ if (getSpec(d) == Qt::LocalTime && getStatus(d) == getStatus(other.d))
+ return getMSecs(d) == getMSecs(other.d);
+
+ // Convert to UTC and compare
+ return toMSecsSinceEpoch() == other.toMSecsSinceEpoch();
+}
+
+/*!
+ \fn bool QDateTime::operator!=(const QDateTime &other) const
+
+ Returns \c true if this datetime is different from the \a other
+ datetime; otherwise returns \c false.
+
+ Two datetimes are different if either the date, the time, or the time zone
+ components are different. Since 5.14, any invalid datetime is less than all
+ valid datetimes.
+
+ \sa operator==()
+*/
+
+/*!
+ Returns \c true if this datetime is earlier than the \a other
+ datetime; otherwise returns \c false.
+*/
+
+bool QDateTime::operator<(const QDateTime &other) const
+{
+ if (!isValid())
+ return other.isValid();
+ if (!other.isValid())
+ return false;
+
+ if (getSpec(d) == Qt::LocalTime && getStatus(d) == getStatus(other.d))
+ return getMSecs(d) < getMSecs(other.d);
+
+ // Convert to UTC and compare
+ return toMSecsSinceEpoch() < other.toMSecsSinceEpoch();
+}
+
+/*!
+ \fn bool QDateTime::operator<=(const QDateTime &other) const
+
+ Returns \c true if this datetime is earlier than or equal to the
+ \a other datetime; otherwise returns \c false.
+*/
+
+/*!
+ \fn bool QDateTime::operator>(const QDateTime &other) const
+
+ Returns \c true if this datetime is later than the \a other datetime;
+ otherwise returns \c false.
+*/
+
+/*!
+ \fn bool QDateTime::operator>=(const QDateTime &other) const
+
+ Returns \c true if this datetime is later than or equal to the
+ \a other datetime; otherwise returns \c false.
+*/
+
+/*!
+ \fn QDateTime QDateTime::currentDateTime()
+ Returns the current datetime, as reported by the system clock, in
+ the local time zone.
+
+ \sa currentDateTimeUtc(), QDate::currentDate(), QTime::currentTime(), toTimeSpec()
+*/
+
+/*!
+ \fn QDateTime QDateTime::currentDateTimeUtc()
+ \since 4.7
+ Returns the current datetime, as reported by the system clock, in
+ UTC.
+
+ \sa currentDateTime(), QDate::currentDate(), QTime::currentTime(), toTimeSpec()
+*/
+
+/*!
+ \fn qint64 QDateTime::currentMSecsSinceEpoch()
+ \since 4.7
+
+ Returns the number of milliseconds since 1970-01-01T00:00:00 Universal
+ Coordinated Time. This number is like the POSIX time_t variable, but
+ expressed in milliseconds instead.
+
+ \sa currentDateTime(), currentDateTimeUtc(), toTime_t(), toTimeSpec()
+*/
+
+/*!
+ \fn qint64 QDateTime::currentSecsSinceEpoch()
+ \since 5.8
+
+ Returns the number of seconds since 1970-01-01T00:00:00 Universal
+ Coordinated Time.
+
+ \sa currentMSecsSinceEpoch()
+*/
+
+#if defined(Q_OS_WIN)
+static inline uint msecsFromDecomposed(int hour, int minute, int sec, int msec = 0)
+{
+ return MSECS_PER_HOUR * hour + MSECS_PER_MIN * minute + 1000 * sec + msec;
+}
+
+QDate QDate::currentDate()
+{
+ SYSTEMTIME st;
+ memset(&st, 0, sizeof(SYSTEMTIME));
+ GetLocalTime(&st);
+ return QDate(st.wYear, st.wMonth, st.wDay);
+}
+
+QTime QTime::currentTime()
+{
+ QTime ct;
+ SYSTEMTIME st;
+ memset(&st, 0, sizeof(SYSTEMTIME));
+ GetLocalTime(&st);
+ ct.setHMS(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
+ return ct;
+}
+
+QDateTime QDateTime::currentDateTime()
+{
+ QTime t;
+ SYSTEMTIME st;
+ memset(&st, 0, sizeof(SYSTEMTIME));
+ GetLocalTime(&st);
+ QDate d(st.wYear, st.wMonth, st.wDay);
+ t.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
+ return QDateTime(d, t);
+}
+
+QDateTime QDateTime::currentDateTimeUtc()
+{
+ QTime t;
+ SYSTEMTIME st;
+ memset(&st, 0, sizeof(SYSTEMTIME));
+ GetSystemTime(&st);
+ QDate d(st.wYear, st.wMonth, st.wDay);
+ t.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
+ return QDateTime(d, t, Qt::UTC);
+}
+
+qint64 QDateTime::currentMSecsSinceEpoch() noexcept
+{
+ SYSTEMTIME st;
+ memset(&st, 0, sizeof(SYSTEMTIME));
+ GetSystemTime(&st);
+ const qint64 daysAfterEpoch = QDate(1970, 1, 1).daysTo(QDate(st.wYear, st.wMonth, st.wDay));
+
+ return msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds) +
+ daysAfterEpoch * Q_INT64_C(86400000);
+}
+
+qint64 QDateTime::currentSecsSinceEpoch() noexcept
+{
+ SYSTEMTIME st;
+ memset(&st, 0, sizeof(SYSTEMTIME));
+ GetSystemTime(&st);
+ const qint64 daysAfterEpoch = QDate(1970, 1, 1).daysTo(QDate(st.wYear, st.wMonth, st.wDay));
+
+ return st.wHour * SECS_PER_HOUR + st.wMinute * SECS_PER_MIN + st.wSecond +
+ daysAfterEpoch * Q_INT64_C(86400);
+}
+
+#elif defined(Q_OS_UNIX)
+QDate QDate::currentDate()
+{
+ return QDateTime::currentDateTime().date();
+}
+
+QTime QTime::currentTime()
+{
+ return QDateTime::currentDateTime().time();
+}
+
+QDateTime QDateTime::currentDateTime()
+{
+ return fromMSecsSinceEpoch(currentMSecsSinceEpoch(), Qt::LocalTime);
+}
+
+QDateTime QDateTime::currentDateTimeUtc()
+{
+ return fromMSecsSinceEpoch(currentMSecsSinceEpoch(), Qt::UTC);
+}
+
+qint64 QDateTime::currentMSecsSinceEpoch() noexcept
+{
+ // posix compliant system
+ // we have milliseconds
+ struct timeval tv;
+ gettimeofday(&tv, nullptr);
+ return qint64(tv.tv_sec) * Q_INT64_C(1000) + tv.tv_usec / 1000;
+}
+
+qint64 QDateTime::currentSecsSinceEpoch() noexcept
+{
+ struct timeval tv;
+ gettimeofday(&tv, nullptr);
+ return qint64(tv.tv_sec);
+}
+#else
+#error "What system is this?"
+#endif
+
+#if QT_DEPRECATED_SINCE(5, 8)
+/*!
+ \since 4.2
+ \deprecated
+
+ Returns a datetime whose date and time are the number of \a seconds
+ that have passed since 1970-01-01T00:00:00, Coordinated Universal
+ Time (Qt::UTC) and converted to Qt::LocalTime. On systems that do not
+ support time zones, the time will be set as if local time were Qt::UTC.
+
+ \note This function is deprecated. Please use fromSecsSinceEpoch() in new
+ code.
+
+ \sa toTime_t(), setTime_t()
+*/
+QDateTime QDateTime::fromTime_t(uint seconds)
+{
+ return fromMSecsSinceEpoch((qint64)seconds * 1000, Qt::LocalTime);
+}
+
+/*!
+ \since 5.2
+ \deprecated
+
+ Returns a datetime whose date and time are the number of \a seconds
+ that have passed since 1970-01-01T00:00:00, Coordinated Universal
+ Time (Qt::UTC) and converted to the given \a spec.
+
+ If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be
+ ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0
+ then the spec will be set to Qt::UTC, i.e. an offset of 0 seconds.
+
+ \note This function is deprecated. Please use fromSecsSinceEpoch() in new
+ code.
+
+ \sa toTime_t(), setTime_t()
+*/
+QDateTime QDateTime::fromTime_t(uint seconds, Qt::TimeSpec spec, int offsetSeconds)
+{
+ return fromMSecsSinceEpoch((qint64)seconds * 1000, spec, offsetSeconds);
+}
+
+#if QT_CONFIG(timezone)
+/*!
+ \since 5.2
+ \deprecated
+
+ Returns a datetime whose date and time are the number of \a seconds
+ that have passed since 1970-01-01T00:00:00, Coordinated Universal
+ Time (Qt::UTC) and with the given \a timeZone.
+
+ \note This function is deprecated. Please use fromSecsSinceEpoch() in new
+ code.
+
+ \sa toTime_t(), setTime_t()
+*/
+QDateTime QDateTime::fromTime_t(uint seconds, const QTimeZone &timeZone)
+{
+ return fromMSecsSinceEpoch((qint64)seconds * 1000, timeZone);
+}
+#endif
+#endif // QT_DEPRECATED_SINCE(5, 8)
+
+/*!
+ \since 4.7
+
+ Returns a datetime whose date and time are the number of milliseconds, \a msecs,
+ that have passed since 1970-01-01T00:00:00.000, Coordinated Universal
+ Time (Qt::UTC), and converted to Qt::LocalTime. On systems that do not
+ support time zones, the time will be set as if local time were Qt::UTC.
+
+ Note that there are possible values for \a msecs that lie outside the valid
+ range of QDateTime, both negative and positive. The behavior of this
+ function is undefined for those values.
+
+ \sa toMSecsSinceEpoch(), setMSecsSinceEpoch()
+*/
+QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs)
+{
+ return fromMSecsSinceEpoch(msecs, Qt::LocalTime);
+}
+
+/*!
+ \since 5.2
+
+ Returns a datetime whose date and time are the number of milliseconds \a msecs
+ that have passed since 1970-01-01T00:00:00.000, Coordinated Universal
+ Time (Qt::UTC) and converted to the given \a spec.
+
+ Note that there are possible values for \a msecs that lie outside the valid
+ range of QDateTime, both negative and positive. The behavior of this
+ function is undefined for those values.
+
+ If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be
+ ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0
+ then the spec will be set to Qt::UTC, i.e. an offset of 0 seconds.
+
+ If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
+ i.e. the current system time zone.
+
+ \sa toMSecsSinceEpoch(), setMSecsSinceEpoch()
+*/
+QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, Qt::TimeSpec spec, int offsetSeconds)
+{
+ QDateTime dt;
+ QT_PREPEND_NAMESPACE(setTimeSpec(dt.d, spec, offsetSeconds));
+ dt.setMSecsSinceEpoch(msecs);
+ return dt;
+}
+
+/*!
+ \since 5.8
+
+ Returns a datetime whose date and time are the number of seconds \a secs
+ that have passed since 1970-01-01T00:00:00.000, Coordinated Universal
+ Time (Qt::UTC) and converted to the given \a spec.
+
+ Note that there are possible values for \a secs that lie outside the valid
+ range of QDateTime, both negative and positive. The behavior of this
+ function is undefined for those values.
+
+ If the \a spec is not Qt::OffsetFromUTC then the \a offsetSeconds will be
+ ignored. If the \a spec is Qt::OffsetFromUTC and the \a offsetSeconds is 0
+ then the spec will be set to Qt::UTC, i.e. an offset of 0 seconds.
+
+ If \a spec is Qt::TimeZone then the spec will be set to Qt::LocalTime,
+ i.e. the current system time zone.
+
+ \sa toSecsSinceEpoch(), setSecsSinceEpoch()
+*/
+QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec, int offsetSeconds)
+{
+ return fromMSecsSinceEpoch(secs * 1000, spec, offsetSeconds);
+}
+
+#if QT_CONFIG(timezone)
+/*!
+ \since 5.2
+
+ Returns a datetime whose date and time are the number of milliseconds \a msecs
+ that have passed since 1970-01-01T00:00:00.000, Coordinated Universal
+ Time (Qt::UTC) and with the given \a timeZone.
+
+ \sa fromSecsSinceEpoch()
+*/
+QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone)
+{
+ QDateTime dt;
+ dt.setTimeZone(timeZone);
+ dt.setMSecsSinceEpoch(msecs);
+ return dt;
+}
+
+/*!
+ \since 5.8
+
+ Returns a datetime whose date and time are the number of seconds \a secs
+ that have passed since 1970-01-01T00:00:00.000, Coordinated Universal
+ Time (Qt::UTC) and with the given \a timeZone.
+
+ \sa fromMSecsSinceEpoch()
+*/
+QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, const QTimeZone &timeZone)
+{
+ return fromMSecsSinceEpoch(secs * 1000, timeZone);
+}
+#endif
+
+#if QT_DEPRECATED_SINCE(5, 2)
+/*!
+ \since 4.4
+ \internal
+ \obsolete
+
+ This method was added in 4.4 but never documented as public. It was replaced
+ in 5.2 with public method setOffsetFromUtc() for consistency with QTimeZone.
+
+ This method should never be made public.
+
+ \sa setOffsetFromUtc()
+ */
+void QDateTime::setUtcOffset(int seconds)
+{
+ setOffsetFromUtc(seconds);
+}
+
+/*!
+ \since 4.4
+ \internal
+ \obsolete
+
+ This method was added in 4.4 but never documented as public. It was replaced
+ in 5.1 with public method offsetFromUTC() for consistency with QTimeZone.
+
+ This method should never be made public.
+
+ \sa offsetFromUTC()
+*/
+int QDateTime::utcOffset() const
+{
+ return offsetFromUtc();
+}
+#endif // QT_DEPRECATED_SINCE
+
+#if QT_CONFIG(datestring)
+
+/*!
+ Returns the QDateTime represented by the \a string, using the
+ \a format given, or an invalid datetime if this is not possible.
+
+ Note for Qt::TextDate: It is recommended that you use the
+ English short month names (e.g. "Jan"). Although localized month
+ names can also be used, they depend on the user's locale settings.
+
+ \sa toString(), QLocale::toDateTime()
+*/
+QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format)
+{
+ if (string.isEmpty())
+ return QDateTime();
+
+ switch (format) {
+ case Qt::SystemLocaleDate:
+ case Qt::SystemLocaleShortDate:
+ return QLocale::system().toDateTime(string, QLocale::ShortFormat);
+ case Qt::SystemLocaleLongDate:
+ return QLocale::system().toDateTime(string, QLocale::LongFormat);
+ case Qt::LocaleDate:
+ case Qt::DefaultLocaleShortDate:
+ return QLocale().toDateTime(string, QLocale::ShortFormat);
+ case Qt::DefaultLocaleLongDate:
+ return QLocale().toDateTime(string, QLocale::LongFormat);
+ case Qt::RFC2822Date: {
+ const ParsedRfcDateTime rfc = rfcDateImpl(string);
+
+ if (!rfc.date.isValid() || !rfc.time.isValid())
+ return QDateTime();
+
+ QDateTime dateTime(rfc.date, rfc.time, Qt::UTC);
+ dateTime.setOffsetFromUtc(rfc.utcOffset);
+ return dateTime;
+ }
+ case Qt::ISODate:
+ case Qt::ISODateWithMs: {
+ const int size = string.size();
+ if (size < 10)
+ return QDateTime();
+
+ QDate date = QDate::fromString(string.left(10), Qt::ISODate);
+ if (!date.isValid())
+ return QDateTime();
+ if (size == 10)
+ return QDateTime(date);
+
+ Qt::TimeSpec spec = Qt::LocalTime;
+ QStringRef isoString(&string);
+ isoString = isoString.mid(10); // trim "yyyy-MM-dd"
+
+ // Must be left with T and at least one digit for the hour:
+ if (isoString.size() < 2
+ || !(isoString.startsWith(QLatin1Char('T'))
+ // FIXME: QSql relies on QVariant::toDateTime() accepting a space here:
+ || isoString.startsWith(QLatin1Char(' ')))) {
+ return QDateTime();
+ }
+ isoString = isoString.mid(1); // trim 'T' (or space)
+
+ int offset = 0;
+ // Check end of string for Time Zone definition, either Z for UTC or [+-]HH:mm for Offset
+ if (isoString.endsWith(QLatin1Char('Z'))) {
+ spec = Qt::UTC;
+ isoString.chop(1); // trim 'Z'
+ } else {
+ // the loop below is faster but functionally equal to:
+ // const int signIndex = isoString.indexOf(QRegExp(QStringLiteral("[+-]")));
+ int signIndex = isoString.size() - 1;
+ Q_ASSERT(signIndex >= 0);
+ bool found = false;
+ {
+ const QChar plus = QLatin1Char('+');
+ const QChar minus = QLatin1Char('-');
+ do {
+ QChar character(isoString.at(signIndex));
+ found = character == plus || character == minus;
+ } while (!found && --signIndex >= 0);
+ }
+
+ if (found) {
+ bool ok;
+ offset = fromOffsetString(isoString.mid(signIndex), &ok);
+ if (!ok)
+ return QDateTime();
+ isoString = isoString.left(signIndex);
+ spec = Qt::OffsetFromUTC;
+ }
+ }
+
+ // Might be end of day (24:00, including variants), which QTime considers invalid.
+ // ISO 8601 (section 4.2.3) says that 24:00 is equivalent to 00:00 the next day.
+ bool isMidnight24 = false;
+ QTime time = fromIsoTimeString(isoString, format, &isMidnight24);
+ if (!time.isValid())
+ return QDateTime();
+ if (isMidnight24)
+ date = date.addDays(1);
+ return QDateTime(date, time, spec, offset);
+ }
+#if QT_CONFIG(textdate)
+ case Qt::TextDate: {
+ QVector<QStringRef> parts = string.splitRef(QLatin1Char(' '), QString::SkipEmptyParts);
+
+ if ((parts.count() < 5) || (parts.count() > 6))
+ return QDateTime();
+
+ // Accept "Sun Dec 1 13:02:00 1974" and "Sun 1. Dec 13:02:00 1974"
+
+ // Year and time can be in either order.
+ // Guess which by looking for ':' in the time
+ int yearPart = 3;
+ int timePart = 3;
+ if (parts.at(3).contains(QLatin1Char(':')))
+ yearPart = 4;
+ else if (parts.at(4).contains(QLatin1Char(':')))
+ timePart = 4;
+ else
+ return QDateTime();
+
+ int month = 0;
+ int day = 0;
+ bool ok = false;
+
+ int year = parts.at(yearPart).toInt(&ok);
+ if (!ok || year == 0)
+ return QDateTime();
+
+ // Next try month then day
+ month = fromShortMonthName(parts.at(1), year);
+ if (month)
+ day = parts.at(2).toInt(&ok);
+
+ // If failed, try day then month
+ if (!ok || !month || !day) {
+ month = fromShortMonthName(parts.at(2), year);
+ if (month) {
+ QStringRef dayStr = parts.at(1);
+ if (dayStr.endsWith(QLatin1Char('.'))) {
+ dayStr = dayStr.left(dayStr.size() - 1);
+ day = dayStr.toInt(&ok);
+ }
+ }
+ }
+
+ // If both failed, give up
+ if (!ok || !month || !day)
+ return QDateTime();
+
+ QDate date(year, month, day);
+ if (!date.isValid())
+ return QDateTime();
+
+ QVector<QStringRef> timeParts = parts.at(timePart).split(QLatin1Char(':'));
+ if (timeParts.count() < 2 || timeParts.count() > 3)
+ return QDateTime();
+
+ int hour = timeParts.at(0).toInt(&ok);
+ if (!ok)
+ return QDateTime();
+
+ int minute = timeParts.at(1).toInt(&ok);
+ if (!ok)
+ return QDateTime();
+
+ int second = 0;
+ int millisecond = 0;
+ if (timeParts.count() > 2) {
+ const QVector<QStringRef> secondParts = timeParts.at(2).split(QLatin1Char('.'));
+ if (secondParts.size() > 2) {
+ return QDateTime();
+ }
+
+ second = secondParts.first().toInt(&ok);
+ if (!ok) {
+ return QDateTime();
+ }
+
+ if (secondParts.size() > 1) {
+ millisecond = secondParts.last().toInt(&ok);
+ if (!ok) {
+ return QDateTime();
+ }
+ }
+ }
+
+ QTime time(hour, minute, second, millisecond);
+ if (!time.isValid())
+ return QDateTime();
+
+ if (parts.count() == 5)
+ return QDateTime(date, time, Qt::LocalTime);
+
+ QStringRef tz = parts.at(5);
+ if (!tz.startsWith(QLatin1String("GMT"), Qt::CaseInsensitive))
+ return QDateTime();
+ tz = tz.mid(3);
+ if (!tz.isEmpty()) {
+ int offset = fromOffsetString(tz, &ok);
+ if (!ok)
+ return QDateTime();
+ return QDateTime(date, time, Qt::OffsetFromUTC, offset);
+ } else {
+ return QDateTime(date, time, Qt::UTC);
+ }
+ }
+#endif // textdate
+ }
+
+ return QDateTime();
+}
+
+/*!
+ Returns the QDateTime represented by the \a string, using the \a
+ format given, or an invalid datetime if the string cannot be parsed.
+
+ Uses the calendar \a cal if supplied, else Gregorian.
+
+ See QDate::fromString() and QTime::fromString() for the expressions
+ recognized in the format string to represent parts of the date and time.
+ All other input characters will be treated as text. Any sequence of
+ characters that are enclosed in single quotes will also be treated as text
+ and not be used as an expression.
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 12
+
+ If the format is not satisfied, an invalid QDateTime is returned.
+ The expressions that don't have leading zeroes (d, M, h, m, s, z) will be
+ greedy. This means that they will use two digits even if this will
+ put them outside the range and/or leave too few digits for other
+ sections.
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 13
+
+ This could have meant 1 January 00:30.00 but the M will grab
+ two digits.
+
+ Incorrectly specified fields of the \a string will cause an invalid
+ QDateTime to be returned. For example, consider the following code,
+ where the two digit year 12 is read as 1912 (see the table below for all
+ field defaults); the resulting datetime is invalid because 23 April 1912
+ was a Tuesday, not a Monday:
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 20
+
+ The correct code is:
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 21
+
+ For any field that is not represented in the format, the following
+ defaults are used:
+
+ \table
+ \header \li Field \li Default value
+ \row \li Year \li 1900
+ \row \li Month \li 1 (January)
+ \row \li Day \li 1
+ \row \li Hour \li 0
+ \row \li Minute \li 0
+ \row \li Second \li 0
+ \endtable
+
+ For example:
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 14
+
+ \sa toString(), QDate::fromString(), QTime::fromString(),
+ QLocale::toDateTime()
+*/
+
+QDateTime QDateTime::fromString(const QString &string, const QString &format, QCalendar cal)
+{
+#if QT_CONFIG(datetimeparser)
+ QTime time;
+ QDate date;
+
+ QDateTimeParser dt(QVariant::DateTime, QDateTimeParser::FromString, cal);
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
+ if (dt.parseFormat(format) && dt.fromString(string, &date, &time))
+ return QDateTime(date, time);
+#else
+ Q_UNUSED(string);
+ Q_UNUSED(format);
+ Q_UNUSED(cal);
+#endif
+ return QDateTime();
+}
+
+/*
+ \overload
+*/
+
+QDateTime QDateTime::fromString(const QString &string, const QString &format)
+{
+ return fromString(string, format, QCalendar());
+}
+
+#endif // datestring
+/*!
+ \fn QDateTime QDateTime::toLocalTime() const
+
+ Returns a datetime containing the date and time information in
+ this datetime, but specified using the Qt::LocalTime definition.
+
+ Example:
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 17
+
+ \sa toTimeSpec()
+*/
+
+/*!
+ \fn QDateTime QDateTime::toUTC() const
+
+ Returns a datetime containing the date and time information in
+ this datetime, but specified using the Qt::UTC definition.
+
+ Example:
+
+ \snippet code/src_corelib_tools_qdatetime.cpp 18
+
+ \sa toTimeSpec()
+*/
+
+/*****************************************************************************
+ Date/time stream functions
+ *****************************************************************************/
+
+#ifndef QT_NO_DATASTREAM
+/*!
+ \relates QDate
+
+ Writes the \a date to stream \a out.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator<<(QDataStream &out, const QDate &date)
+{
+ if (out.version() < QDataStream::Qt_5_0)
+ return out << quint32(date.jd);
+ else
+ return out << qint64(date.jd);
+}
+
+/*!
+ \relates QDate
+
+ Reads a date from stream \a in into the \a date.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator>>(QDataStream &in, QDate &date)
+{
+ if (in.version() < QDataStream::Qt_5_0) {
+ quint32 jd;
+ in >> jd;
+ // Older versions consider 0 an invalid jd.
+ date.jd = (jd != 0 ? jd : QDate::nullJd());
+ } else {
+ qint64 jd;
+ in >> jd;
+ date.jd = jd;
+ }
+
+ return in;
+}
+
+/*!
+ \relates QTime
+
+ Writes \a time to stream \a out.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator<<(QDataStream &out, const QTime &time)
+{
+ if (out.version() >= QDataStream::Qt_4_0) {
+ return out << quint32(time.mds);
+ } else {
+ // Qt3 had no support for reading -1, QTime() was valid and serialized as 0
+ return out << quint32(time.isNull() ? 0 : time.mds);
+ }
+}
+
+/*!
+ \relates QTime
+
+ Reads a time from stream \a in into the given \a time.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator>>(QDataStream &in, QTime &time)
+{
+ quint32 ds;
+ in >> ds;
+ if (in.version() >= QDataStream::Qt_4_0) {
+ time.mds = int(ds);
+ } else {
+ // Qt3 would write 0 for a null time
+ time.mds = (ds == 0) ? QTime::NullTime : int(ds);
+ }
+ return in;
+}
+
+/*!
+ \relates QDateTime
+
+ Writes \a dateTime to the \a out stream.
+
+ \sa {Serializing Qt Data Types}
+*/
+QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime)
+{
+ QPair<QDate, QTime> dateAndTime;
+
+ if (out.version() >= QDataStream::Qt_5_2) {
+
+ // In 5.2 we switched to using Qt::TimeSpec and added offset support
+ dateAndTime = getDateTime(dateTime.d);
+ out << dateAndTime << qint8(dateTime.timeSpec());
+ if (dateTime.timeSpec() == Qt::OffsetFromUTC)
+ out << qint32(dateTime.offsetFromUtc());
+#if QT_CONFIG(timezone)
+ else if (dateTime.timeSpec() == Qt::TimeZone)
+ out << dateTime.timeZone();
+#endif // timezone
+
+ } else if (out.version() == QDataStream::Qt_5_0) {
+
+ // In Qt 5.0 we incorrectly serialised all datetimes as UTC.
+ // This approach is wrong and should not be used again; it breaks
+ // the guarantee that a deserialised local datetime is the same time
+ // of day, regardless of which timezone it was serialised in.
+ dateAndTime = getDateTime((dateTime.isValid() ? dateTime.toUTC() : dateTime).d);
+ out << dateAndTime << qint8(dateTime.timeSpec());
+
+ } else if (out.version() >= QDataStream::Qt_4_0) {
+
+ // From 4.0 to 5.1 (except 5.0) we used QDateTimePrivate::Spec
+ dateAndTime = getDateTime(dateTime.d);
+ out << dateAndTime;
+ switch (dateTime.timeSpec()) {
+ case Qt::UTC:
+ out << (qint8)QDateTimePrivate::UTC;
+ break;
+ case Qt::OffsetFromUTC:
+ out << (qint8)QDateTimePrivate::OffsetFromUTC;
+ break;
+ case Qt::TimeZone:
+ out << (qint8)QDateTimePrivate::TimeZone;
+ break;
+ case Qt::LocalTime:
+ out << (qint8)QDateTimePrivate::LocalUnknown;
+ break;
+ }
+
+ } else { // version < QDataStream::Qt_4_0
+
+ // Before 4.0 there was no TimeSpec, only Qt::LocalTime was supported
+ dateAndTime = getDateTime(dateTime.d);
+ out << dateAndTime;
+
+ }
+
+ return out;
+}
+
+/*!
+ \relates QDateTime
+
+ Reads a datetime from the stream \a in into \a dateTime.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator>>(QDataStream &in, QDateTime &dateTime)
+{
+ QDate dt;
+ QTime tm;
+ qint8 ts = 0;
+ Qt::TimeSpec spec = Qt::LocalTime;
+ qint32 offset = 0;
+#if QT_CONFIG(timezone)
+ QTimeZone tz;
+#endif // timezone
+
+ if (in.version() >= QDataStream::Qt_5_2) {
+
+ // In 5.2 we switched to using Qt::TimeSpec and added offset support
+ in >> dt >> tm >> ts;
+ spec = static_cast<Qt::TimeSpec>(ts);
+ if (spec == Qt::OffsetFromUTC) {
+ in >> offset;
+ dateTime = QDateTime(dt, tm, spec, offset);
+#if QT_CONFIG(timezone)
+ } else if (spec == Qt::TimeZone) {
+ in >> tz;
+ dateTime = QDateTime(dt, tm, tz);
+#endif // timezone
+ } else {
+ dateTime = QDateTime(dt, tm, spec);
+ }
+
+ } else if (in.version() == QDataStream::Qt_5_0) {
+
+ // In Qt 5.0 we incorrectly serialised all datetimes as UTC
+ in >> dt >> tm >> ts;
+ spec = static_cast<Qt::TimeSpec>(ts);
+ dateTime = QDateTime(dt, tm, Qt::UTC);
+ dateTime = dateTime.toTimeSpec(spec);
+
+ } else if (in.version() >= QDataStream::Qt_4_0) {
+
+ // From 4.0 to 5.1 (except 5.0) we used QDateTimePrivate::Spec
+ in >> dt >> tm >> ts;
+ switch ((QDateTimePrivate::Spec)ts) {
+ case QDateTimePrivate::UTC:
+ spec = Qt::UTC;
+ break;
+ case QDateTimePrivate::OffsetFromUTC:
+ spec = Qt::OffsetFromUTC;
+ break;
+ case QDateTimePrivate::TimeZone:
+ spec = Qt::TimeZone;
+#if QT_CONFIG(timezone)
+ // FIXME: need to use a different constructor !
+#endif
+ break;
+ case QDateTimePrivate::LocalUnknown:
+ case QDateTimePrivate::LocalStandard:
+ case QDateTimePrivate::LocalDST:
+ spec = Qt::LocalTime;
+ break;
+ }
+ dateTime = QDateTime(dt, tm, spec, offset);
+
+ } else { // version < QDataStream::Qt_4_0
+
+ // Before 4.0 there was no TimeSpec, only Qt::LocalTime was supported
+ in >> dt >> tm;
+ dateTime = QDateTime(dt, tm, spec, offset);
+
+ }
+
+ return in;
+}
+#endif // QT_NO_DATASTREAM
+
+/*****************************************************************************
+ Date / Time Debug Streams
+*****************************************************************************/
+
+#if !defined(QT_NO_DEBUG_STREAM) && QT_CONFIG(datestring)
+QDebug operator<<(QDebug dbg, const QDate &date)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace() << "QDate(";
+ if (date.isValid())
+ dbg.nospace() << date.toString(Qt::ISODate);
+ else
+ dbg.nospace() << "Invalid";
+ dbg.nospace() << ')';
+ return dbg;
+}
+
+QDebug operator<<(QDebug dbg, const QTime &time)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace() << "QTime(";
+ if (time.isValid())
+ dbg.nospace() << time.toString(u"HH:mm:ss.zzz");
+ else
+ dbg.nospace() << "Invalid";
+ dbg.nospace() << ')';
+ return dbg;
+}
+
+QDebug operator<<(QDebug dbg, const QDateTime &date)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace() << "QDateTime(";
+ if (date.isValid()) {
+ const Qt::TimeSpec ts = date.timeSpec();
+ dbg.noquote() << date.toString(u"yyyy-MM-dd HH:mm:ss.zzz t")
+ << ' ' << ts;
+ switch (ts) {
+ case Qt::UTC:
+ break;
+ case Qt::OffsetFromUTC:
+ dbg.space() << date.offsetFromUtc() << 's';
+ break;
+ case Qt::TimeZone:
+#if QT_CONFIG(timezone)
+ dbg.space() << date.timeZone().id();
+#endif // timezone
+ break;
+ case Qt::LocalTime:
+ break;
+ }
+ } else {
+ dbg.nospace() << "Invalid";
+ }
+ return dbg.nospace() << ')';
+}
+#endif // debug_stream && datestring
+
+/*! \fn uint qHash(const QDateTime &key, uint seed = 0)
+ \relates QHash
+ \since 5.0
+
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+*/
+uint qHash(const QDateTime &key, uint seed)
+{
+ // Use to toMSecsSinceEpoch instead of individual qHash functions for
+ // QDate/QTime/spec/offset because QDateTime::operator== converts both arguments
+ // to the same timezone. If we don't, qHash would return different hashes for
+ // two QDateTimes that are equivalent once converted to the same timezone.
+ return key.isValid() ? qHash(key.toMSecsSinceEpoch(), seed) : seed;
+}
+
+/*! \fn uint qHash(const QDate &key, uint seed = 0)
+ \relates QHash
+ \since 5.0
+
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+*/
+uint qHash(const QDate &key, uint seed) noexcept
+{
+ return qHash(key.toJulianDay(), seed);
+}
+
+/*! \fn uint qHash(const QTime &key, uint seed = 0)
+ \relates QHash
+ \since 5.0
+
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+*/
+uint qHash(const QTime &key, uint seed) noexcept
+{
+ return qHash(key.msecsSinceStartOfDay(), seed);
+}
+
+QT_END_NAMESPACE