summaryrefslogtreecommitdiffstats
path: root/src/corelib/time/qdatetime.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/time/qdatetime.cpp')
-rw-r--r--src/corelib/time/qdatetime.cpp236
1 files changed, 156 insertions, 80 deletions
diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp
index b3a12a4a46..e9fe34110a 100644
--- a/src/corelib/time/qdatetime.cpp
+++ b/src/corelib/time/qdatetime.cpp
@@ -51,7 +51,6 @@
#if QT_CONFIG(timezone)
#include "qtimezoneprivate_p.h"
#endif
-#include "qregexp.h"
#include "qdebug.h"
#ifndef Q_OS_WIN
#include <locale.h>
@@ -135,8 +134,6 @@ static int qt_monthNumberFromShortName(QStringView shortName)
}
return -1;
}
-static int qt_monthNumberFromShortName(const QString &shortName)
-{ return qt_monthNumberFromShortName(QStringView(shortName)); }
static int fromShortMonthName(QStringView monthName, int year)
{
@@ -153,43 +150,144 @@ static int fromShortMonthName(QStringView monthName, int year)
}
#endif // textdate
-#if QT_CONFIG(datestring)
+#if QT_CONFIG(datestring) // depends on, so implies, textdate
struct ParsedRfcDateTime {
QDate date;
QTime time;
int utcOffset;
};
+static int shortDayFromName(QStringView name)
+{
+ const char16_t shortDayNames[] = u"MonTueWedThuFriSatSun";
+ for (int i = 0; i < 7; i++) {
+ if (name == QStringView(shortDayNames + 3 * i, 3))
+ return i + 1;
+ }
+ return 0;
+}
+
static ParsedRfcDateTime rfcDateImpl(const QString &s)
{
+ // Matches "[ddd,] dd MMM yyyy[ hh:mm[:ss]] [±hhmm]" - correct RFC 822, 2822, 5322 format -
+ // or "ddd MMM dd[ hh:mm:ss] yyyy [±hhmm]" - permissive RFC 850, 1036 (read only)
ParsedRfcDateTime result;
- // Matches "[ddd,] dd MMM yyyy[ hh:mm[:ss]] [±hhmm]" - correct RFC 822, 2822, 5322 format
- QRegExp rex(QStringLiteral("^[ \\t]*(?:[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 "ddd MMM dd[ hh:mm:ss] yyyy [±hhmm]" - permissive RFC 850, 1036 (read only)
- QRegExp rex(QStringLiteral("^[ \\t]*[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));
+ auto words = s.splitRef(QLatin1Char(' '), Qt::SkipEmptyParts);
+ if (words.size() < 3 || words.size() > 6)
+ return result;
+ const QChar colon(QLatin1Char(':'));
+ const QLocale C = QLocale::c();
+ bool ok = true;
+ QDate date;
+
+ const auto isShortName = [](QStringView name) {
+ return (name.length() == 3 && name.at(0).isUpper()
+ && name.at(1).isLower() && name.at(2).isLower());
+ };
+
+ /* Reject entirely (return) if the string is malformed; however, if the date
+ * is merely invalid, (break, so as to) go on to parsing of the time.
+ */
+ int yearIndex;
+ do { // "loop" so that we can use break on merely invalid, but "right shape" date.
+ QStringView dayName;
+ bool rfcX22 = true;
+ if (words.at(0).endsWith(QLatin1Char(','))) {
+ dayName = words.takeFirst().chopped(1);
+ } else if (!words.at(0).at(0).isDigit()) {
+ dayName = words.takeFirst();
+ rfcX22 = false;
+ } // else: dayName is not specified (so we can only be RFC *22)
+ if (words.size() < 3 || words.size() > 5)
+ return result;
+
+ // Don't break before setting yearIndex.
+ int dayIndex, monthIndex;
+ if (rfcX22) {
+ // dd MMM yyyy [hh:mm[:ss]] [±hhmm]
+ dayIndex = 0;
+ monthIndex = 1;
+ yearIndex = 2;
+ } else {
+ // MMM dd[ hh:mm:ss] yyyy [±hhmm]
+ dayIndex = 1;
+ monthIndex = 0;
+ yearIndex = words.size() > 3 && words.at(2).contains(colon) ? 3 : 2;
+ }
+
+ int dayOfWeek = 0;
+ if (!dayName.isEmpty()) {
+ if (!isShortName(dayName))
+ return result;
+ dayOfWeek = shortDayFromName(dayName);
+ if (!dayOfWeek)
+ break;
}
+
+ const int day = words.at(dayIndex).toInt(&ok);
+ if (!ok)
+ return result;
+ const int year = words.at(yearIndex).toInt(&ok);
+ if (!ok)
+ return result;
+ const QStringView monthName = words.at(monthIndex);
+ if (!isShortName(monthName))
+ return result;
+ int month = fromShortMonthName(monthName, year);
+ if (month < 0)
+ break;
+
+ date = QDate(year, month, day);
+ if (dayOfWeek && date.dayOfWeek() != dayOfWeek)
+ date = QDate();
+ } while (false);
+ words.remove(yearIndex);
+ words.remove(0, 2); // month and day-of-month, in some order
+
+ // Time: [hh:mm[:ss]]
+ QTime time;
+ if (words.size() && words.at(0).contains(colon)) {
+ const QStringView when = words.takeFirst();
+ if (when.at(2) != colon || (when.size() == 8 ? when.at(5) != colon : when.size() > 5))
+ return result;
+ const int hour = C.toInt(when.left(2), &ok);
+ if (!ok)
+ return result;
+ const int minute = C.toInt(when.mid(3, 2), &ok);
+ if (!ok)
+ return result;
+ const auto secs = when.size() == 8 ? C.toInt(when.right(2), &ok) : 0;
+ if (!ok)
+ return result;
+ time = QTime(hour, minute, secs);
}
+ // Offset: [±hhmm]
+ int offset = 0;
+ if (words.size()) {
+ const QStringView zone = words.takeFirst();
+ if (words.size() || !(zone.size() == 3 || zone.size() == 5))
+ return result;
+ bool negate = false;
+ if (zone.at(0) == QLatin1Char('-'))
+ negate = true;
+ else if (zone.at(0) != QLatin1Char('+'))
+ return result;
+ const int hour = C.toInt(zone.mid(1, 2), &ok);
+ if (!ok)
+ return result;
+ const auto minute = zone.size() > 3 ? C.toInt(zone.mid(3, 2), &ok) : 0;
+ if (!ok)
+ return result;
+ offset = (hour * 60 + minute) * 60;
+ if (negate)
+ offset = -offset;
+ }
+
+ result.date = date;
+ result.time = time;
+ result.utcOffset = offset;
return result;
}
#endif // datestring
@@ -1561,7 +1659,7 @@ QDate QDate::addYears(int nyears) const
\sa addDays()
*/
-qint64 QDate::daysTo(const QDate &d) const
+qint64 QDate::daysTo(QDate d) const
{
if (isNull() || d.isNull())
return 0;
@@ -1572,7 +1670,7 @@ qint64 QDate::daysTo(const QDate &d) const
/*!
- \fn bool QDate::operator==(const QDate &d) const
+ \fn bool QDate::operator==(QDate d) const
Returns \c true if this date is equal to \a d; otherwise returns
false.
@@ -1580,35 +1678,35 @@ qint64 QDate::daysTo(const QDate &d) const
*/
/*!
- \fn bool QDate::operator!=(const QDate &d) const
+ \fn bool QDate::operator!=(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
+ \fn bool QDate::operator<(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
+ \fn bool QDate::operator<=(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
+ \fn bool QDate::operator>(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
+ \fn bool QDate::operator>=(QDate d) const
Returns \c true if this date is later than or equal to \a d;
otherwise returns \c false.
@@ -2219,7 +2317,7 @@ QTime QTime::addSecs(int s) const
\sa addSecs(), QDateTime::secsTo()
*/
-int QTime::secsTo(const QTime &t) const
+int QTime::secsTo(QTime t) const
{
if (!isValid() || !t.isValid())
return 0;
@@ -2271,7 +2369,7 @@ QTime QTime::addMSecs(int ms) const
\sa secsTo(), addMSecs(), QDateTime::msecsTo()
*/
-int QTime::msecsTo(const QTime &t) const
+int QTime::msecsTo(QTime t) const
{
if (!isValid() || !t.isValid())
return 0;
@@ -2280,38 +2378,38 @@ int QTime::msecsTo(const QTime &t) const
/*!
- \fn bool QTime::operator==(const QTime &t) const
+ \fn bool QTime::operator==(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
+ \fn bool QTime::operator!=(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
+ \fn bool QTime::operator<(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
+ \fn bool QTime::operator<=(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
+ \fn bool QTime::operator>(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
+ \fn bool QTime::operator>=(QTime t) const
Returns \c true if this time is later than or equal to \a t;
otherwise returns \c false.
@@ -3437,7 +3535,7 @@ inline QDateTimePrivate *QDateTime::Data::operator->()
*****************************************************************************/
Q_NEVER_INLINE
-QDateTime::Data QDateTimePrivate::create(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec,
+QDateTime::Data QDateTimePrivate::create(QDate toDate, QTime toTime, Qt::TimeSpec toSpec,
int offsetSeconds)
{
QDateTime::Data result(toSpec);
@@ -3447,7 +3545,7 @@ QDateTime::Data QDateTimePrivate::create(const QDate &toDate, const QTime &toTim
}
#if QT_CONFIG(timezone)
-inline QDateTime::Data QDateTimePrivate::create(const QDate &toDate, const QTime &toTime,
+inline QDateTime::Data QDateTimePrivate::create(QDate toDate, QTime toTime,
const QTimeZone &toTimeZone)
{
QDateTime::Data result(Qt::TimeZone);
@@ -3652,7 +3750,7 @@ QDateTime::QDateTime() noexcept(Data::CanBeSmall)
\sa QDate::startOfDay()
*/
-QDateTime::QDateTime(const QDate &date)
+QDateTime::QDateTime(QDate date)
: QDateTime(date.startOfDay(Qt::LocalTime, 0))
{
}
@@ -3660,28 +3758,6 @@ QDateTime::QDateTime(const QDate &date)
/*!
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.
@@ -3696,7 +3772,7 @@ QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec)
use the correct constructor.
*/
-QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec, int offsetSeconds)
+QDateTime::QDateTime(QDate date, QTime time, Qt::TimeSpec spec, int offsetSeconds)
: d(QDateTimePrivate::create(date, time, spec, offsetSeconds))
{
}
@@ -3713,7 +3789,7 @@ QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec, in
If \a timeZone is invalid then the datetime will be invalid.
*/
-QDateTime::QDateTime(const QDate &date, const QTime &time, const QTimeZone &timeZone)
+QDateTime::QDateTime(QDate date, QTime time, const QTimeZone &timeZone)
: d(QDateTimePrivate::create(date, time, timeZone))
{
}
@@ -4001,7 +4077,7 @@ bool QDateTime::isDaylightTime() const
\sa date(), setTime(), setTimeSpec()
*/
-void QDateTime::setDate(const QDate &date)
+void QDateTime::setDate(QDate date)
{
setDateTime(d, date, time());
}
@@ -4019,7 +4095,7 @@ void QDateTime::setDate(const QDate &date)
\sa time(), setDate(), setTimeSpec()
*/
-void QDateTime::setTime(const QTime &time)
+void QDateTime::setTime(QTime time)
{
setDateTime(d, date(), time);
}
@@ -5307,7 +5383,7 @@ QT_WARNING_POP
isoString.chop(1); // trim 'Z'
} else {
// the loop below is faster but functionally equal to:
- // const int signIndex = isoString.indexOf(QRegExp(QStringLiteral("[+-]")));
+ // const int signIndex = isoString.indexOf(QRegulargExpression(QStringLiteral("[+-]")));
int signIndex = isoString.size() - 1;
Q_ASSERT(signIndex >= 0);
bool found = false;
@@ -5575,7 +5651,7 @@ QDateTime QDateTime::fromString(const QString &string, const QString &format)
\sa {Serializing Qt Data Types}
*/
-QDataStream &operator<<(QDataStream &out, const QDate &date)
+QDataStream &operator<<(QDataStream &out, QDate date)
{
if (out.version() < QDataStream::Qt_5_0)
return out << quint32(date.jd);
@@ -5615,7 +5691,7 @@ QDataStream &operator>>(QDataStream &in, QDate &date)
\sa {Serializing Qt Data Types}
*/
-QDataStream &operator<<(QDataStream &out, const QTime &time)
+QDataStream &operator<<(QDataStream &out, QTime time)
{
if (out.version() >= QDataStream::Qt_4_0) {
return out << quint32(time.mds);
@@ -5795,7 +5871,7 @@ QDataStream &operator>>(QDataStream &in, QDateTime &dateTime)
*****************************************************************************/
#if !defined(QT_NO_DEBUG_STREAM) && QT_CONFIG(datestring)
-QDebug operator<<(QDebug dbg, const QDate &date)
+QDebug operator<<(QDebug dbg, QDate date)
{
QDebugStateSaver saver(dbg);
dbg.nospace() << "QDate(";
@@ -5807,7 +5883,7 @@ QDebug operator<<(QDebug dbg, const QDate &date)
return dbg;
}
-QDebug operator<<(QDebug dbg, const QTime &time)
+QDebug operator<<(QDebug dbg, QTime time)
{
QDebugStateSaver saver(dbg);
dbg.nospace() << "QTime(";
@@ -5863,24 +5939,24 @@ uint qHash(const QDateTime &key, uint seed)
return key.isValid() ? qHash(key.toMSecsSinceEpoch(), seed) : seed;
}
-/*! \fn uint qHash(const QDate &key, uint seed = 0)
+/*! \fn uint qHash(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
+uint qHash(QDate key, uint seed) noexcept
{
return qHash(key.toJulianDay(), seed);
}
-/*! \fn uint qHash(const QTime &key, uint seed = 0)
+/*! \fn uint qHash(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
+uint qHash(QTime key, uint seed) noexcept
{
return qHash(key.msecsSinceStartOfDay(), seed);
}