mirror of https://github.com/qt/qtbase.git
5791 lines
179 KiB
C++
5791 lines
179 KiB
C++
/****************************************************************************
|
|
**
|
|
** 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"
|
|
|
|
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);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
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)
|
|
{
|
|
*this = QCalendar().dateFromParts(y, m, d);
|
|
}
|
|
|
|
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
|
|
{
|
|
return year(QCalendar());
|
|
}
|
|
|
|
/*!
|
|
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
|
|
{
|
|
return month(QCalendar());
|
|
}
|
|
|
|
/*!
|
|
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
|
|
{
|
|
return day(QCalendar());
|
|
}
|
|
|
|
/*!
|
|
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 dayOfWeek(QCalendar());
|
|
}
|
|
|
|
/*!
|
|
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
|
|
{
|
|
return dayOfYear(QCalendar());
|
|
}
|
|
|
|
/*!
|
|
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
|
|
{
|
|
return daysInMonth(QCalendar());
|
|
}
|
|
|
|
/*!
|
|
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 daysInYear(QCalendar());
|
|
}
|
|
|
|
/*!
|
|
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 number without a leading zero (1 to 31)
|
|
\row \li dd \li the day as 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 number without a leading zero (1 to 12)
|
|
\row \li MM \li the month as 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 two digit number (00 to 99)
|
|
\row \li yyyy \li the year as four digit number. If the year is negative,
|
|
a minus sign is prepended in addition.
|
|
\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)
|
|
{
|
|
return setDate(year, month, day, QCalendar());
|
|
}
|
|
|
|
/*!
|
|
\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 = QCalendar().partsFromDate(*this);
|
|
|
|
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);
|
|
}
|
|
|
|
/*!
|
|
\override
|
|
*/
|
|
|
|
QDate QDate::addMonths(int nmonths) const
|
|
{
|
|
return addMonths(nmonths, QCalendar());
|
|
}
|
|
|
|
/*!
|
|
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);
|
|
}
|
|
|
|
/*!
|
|
\override
|
|
*/
|
|
|
|
QDate QDate::addYears(int nyears) const
|
|
{
|
|
return addYears(nyears, QCalendar());
|
|
}
|
|
|
|
/*!
|
|
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 two digit number (00 to 99)
|
|
\row \li yyyy \li The year as four digit number. If the year is negative,
|
|
a minus sign is prepended in addition.
|
|
\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 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 QCalendar().isDateValid(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 QCalendar().isLeapYear(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 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
|
|
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 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
|
|
\li interpret as an AM/PM time. \e AP must be either "AM" or "PM".
|
|
\row \li ap
|
|
\li Interpret as an AM/PM time. \e ap must be either "am" or "pm".
|
|
\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) 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 falling outside that range, QDateTime
|
|
makes a \e{best guess} using the rules for year 1970 or 2037, but we can't
|
|
guarantee accuracy. This means QDateTime doesn't take into account changes
|
|
in a time zone before 1970, even if the system's time zone database provides
|
|
that information.
|
|
|
|
\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
|
|
*/
|
|
|
|
/*!
|
|
\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 the current Offset From UTC in seconds.
|
|
|
|
If the timeSpec() is Qt::OffsetFromUTC this will be the value originally set.
|
|
|
|
If the timeSpec() is Qt::TimeZone this will be the offset effective in the
|
|
Time Zone including any Daylight-Saving Offset.
|
|
|
|
If the timeSpec() is Qt::LocalTime this will be the difference between the
|
|
Local Time and UTC including any Daylight-Saving Offset.
|
|
|
|
If the timeSpec() is Qt::UTC this will be 0.
|
|
|
|
\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
|
|
{
|
|
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
|
|
{
|
|
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.
|
|
|
|
These expressions may be used for the date:
|
|
|
|
\table
|
|
\header \li Expression \li Output
|
|
\row \li d \li the day as number without a leading zero (1 to 31)
|
|
\row \li dd \li the day as 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 number without a leading zero (1-12)
|
|
\row \li MM \li the month as number with a leading zero (01-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 two digit number (00-99)
|
|
\row \li yyyy \li the year as four digit number
|
|
\endtable
|
|
|
|
These expressions may be used for the time:
|
|
|
|
\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 a 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 either "AM" or "PM".
|
|
\row \li ap or a
|
|
\li use am/pm display. \e a/ap will be replaced by either "am" or "pm".
|
|
\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 (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.
|
|
|
|
\sa operator!=()
|
|
*/
|
|
|
|
bool QDateTime::operator==(const QDateTime &other) const
|
|
{
|
|
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.
|
|
|
|
\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 (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. The illustrative
|
|
values and ranges below are given for the latter; other calendars may have
|
|
different ranges or values.
|
|
|
|
These expressions may be used for the date part of the format string:
|
|
|
|
\table
|
|
\header \li Expression \li Output
|
|
\row \li d \li the day as number without a leading zero (1 to 31)
|
|
\row \li dd \li the day as number with a leading zero (01 to 31)
|
|
\row \li ddd
|
|
\li the abbreviated localized day name (e.g. 'Mon' to 'Sun').
|
|
\row \li dddd
|
|
\li the long localized day name (e.g. 'Monday' to 'Sunday').
|
|
\row \li M \li the month as number without a leading zero (1-12)
|
|
\row \li MM \li the month as number with a leading zero (01-12)
|
|
\row \li MMM
|
|
\li the abbreviated localized month name (e.g. 'Jan' to 'Dec').
|
|
\row \li MMMM
|
|
\li the long localized month name (e.g. 'January' to 'December').
|
|
\row \li yy \li the year as two digit number (00-99)
|
|
\row \li yyyy \li the year as four digit number
|
|
\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.
|
|
|
|
These expressions may be used for the time part of the format string:
|
|
|
|
\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 a 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 AP must be either "AM" or "PM".
|
|
\row \li ap or a
|
|
\li Interpret as an AM/PM time. \e ap must be either "am" or "pm".
|
|
\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 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 qHash(key.toMSecsSinceEpoch(), 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
|