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.cpp145
1 files changed, 83 insertions, 62 deletions
diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp
index a2816e87f4..f881d47284 100644
--- a/src/corelib/time/qdatetime.cpp
+++ b/src/corelib/time/qdatetime.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
@@ -75,6 +75,7 @@
#include "qcalendar.h"
#include "qgregoriancalendar_p.h"
+#include "private/qnumeric_p.h"
QT_BEGIN_NAMESPACE
@@ -1429,9 +1430,11 @@ 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);
+ qint64 r;
+ if (Q_UNLIKELY(add_overflow(jd, ndays, &r)))
+ return QDate();
+ else
+ return fromJulianDay(r);
}
/*!
@@ -1701,22 +1704,25 @@ QT_WARNING_POP
return rfcDateImpl(string).date;
default:
case Qt::TextDate: {
+ // Accept only "ddd MMM d yyyy" form (in contrast with QDateTime), e.g. "Sun Dec 1 1974"
QVector<QStringRef> parts = string.splitRef(QLatin1Char(' '), Qt::SkipEmptyParts);
-
- if (parts.count() != 4)
+ const int count = parts.count();
+ bool ok = count > 3;
+ int year = ok ? parts.at(count - 1).toInt(&ok) : 0;
+ int day = ok ? parts.at(count - 2).toInt(&ok) : 0;
+ if (!ok || !day || !year)
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);
+ // Some locales have multi-word month names:
+ int i = count - 3;
+ QString monthName = parts.at(i).toString();
+ while (i > 0) {
+ const int month = fromShortMonthName(monthName, year);
+ if (month > 0) // Month name matches an English or localised name.
+ return QDate(year, month, day);
+ monthName = parts.at(--i) + QLatin1Char(' ') + monthName;
+ }
+ return QDate();
}
case Qt::ISODate:
// Semi-strict parsing, must be long enough and have punctuators as separators
@@ -2612,6 +2618,8 @@ bool QTime::isValid(int h, int m, int s, int ms)
#if QT_DEPRECATED_SINCE(5, 14) // ### Qt 6: remove
/*!
+ \deprecated
+
Sets this time to the current time. This is practical for timing:
\snippet code/src_corelib_tools_qdatetime.cpp 10
@@ -2655,6 +2663,8 @@ int QTime::restart()
}
/*!
+ \deprecated
+
Returns the number of milliseconds that have elapsed since the
last time start() or restart() was called.
@@ -4541,9 +4551,9 @@ static inline void massageAdjustedDateTime(const QDateTimeData &d, QDate *date,
QDateTimePrivate::DaylightStatus status = QDateTimePrivate::UnknownDaylightTime;
localMSecsToEpochMSecs(timeToMSecs(*date, *time), &status, date, time);
#if QT_CONFIG(timezone)
- } else if (spec == Qt::TimeZone && d->m_timeZone.isValid()) {
+ } else if (spec == Qt::TimeZone && d.d->m_timeZone.isValid()) {
QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time),
- d->m_timeZone,
+ d.d->m_timeZone,
QDateTimePrivate::UnknownDaylightTime,
date, time);
#endif // timezone
@@ -4644,7 +4654,7 @@ QDateTime QDateTime::addSecs(qint64 s) const
}
/*!
- Returns a QDateTime object containing a datetime \a msecs miliseconds
+ Returns a QDateTime object containing a datetime \a msecs milliseconds
later than the datetime of this object (or earlier if \a msecs is
negative).
@@ -5374,49 +5384,66 @@ QT_WARNING_POP
case Qt::TextDate: {
QVector<QStringRef> parts = string.splitRef(QLatin1Char(' '), Qt::SkipEmptyParts);
- if ((parts.count() < 5) || (parts.count() > 6))
+ const int count = parts.count();
+ if (count < 5)
return QDateTime();
- // Accept "Sun Dec 1 13:02:00 1974" and "Sun 1. Dec 13:02:00 1974"
+ // Accept "Sun Dec 1 13:02:00 1974" and "Sun 1. Dec 13:02:00 1974" with
+ // optional GMT-based zone-suffix, with time and year in either order;
+ // and some locales have spaces even in short names of months and days.
+ int tail = count - 1, zonePart = 0;
+ if (parts.at(tail).startsWith(QLatin1String("GMT"), Qt::CaseInsensitive))
+ zonePart = tail--;
// 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;
+ int yearPart = tail;
+ int timePart = tail;
+ if (parts.at(timePart).contains(QLatin1Char(':')))
+ yearPart--;
+ else if (parts.at(timePart - 1).contains(QLatin1Char(':')))
+ timePart--;
else
return QDateTime();
- int month = 0;
- int day = 0;
- bool ok = false;
+ int dayPart = tail - 2; // but may be earlier, with a comma after:
+ for (int i = 1; i < dayPart; i++) {
+ if (parts.at(i).endsWith(QLatin1Char('.')))
+ dayPart = i; // exits the loop
+ }
+ bool ok = false;
int year = parts.at(yearPart).toInt(&ok);
- if (!ok || year == 0)
+ int day = 0;
+
+ if (ok && year) {
+ QStringRef dayStr = parts.at(dayPart);
+ if (dayStr.endsWith(QLatin1Char('.')))
+ dayStr.chop(1);
+ day = dayStr.toInt(&ok);
+ }
+ if (!ok || !year || !day)
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);
- }
+ int month = 0;
+ if (dayPart < tail - 2) {
+ // Easy case, month is the parts from dayPart + 1 to count - 3
+ int i = dayPart + 1;
+ QString monthName = parts.at(i).toString();
+ while (++i < tail - 1)
+ monthName += QLatin1Char(' ') + parts.at(i);
+ month = fromShortMonthName(monthName, year);
+ } else {
+ int i = dayPart - 1;
+ QString monthName = parts.at(i).toString();
+ while (i > 0) {
+ month = fromShortMonthName(monthName, year);
+ if (month > 0)
+ break;
+ monthName = parts.at(--i) + QLatin1Char(' ') + monthName;
}
}
-
- // If both failed, give up
- if (!ok || !month || !day)
+ if (month <= 0)
return QDateTime();
QDate date(year, month, day);
@@ -5460,21 +5487,15 @@ QT_WARNING_POP
if (!time.isValid())
return QDateTime();
- if (parts.count() == 5)
+ if (!zonePart)
return QDateTime(date, time, Qt::LocalTime);
- QStringView 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 {
+ const QStringView tz = parts.at(zonePart).mid(3);
+ if (tz.isEmpty())
return QDateTime(date, time, Qt::UTC);
- }
+
+ int offset = fromOffsetString(tz, &ok);
+ return ok ? QDateTime(date, time, Qt::OffsetFromUTC, offset) : QDateTime();
}
}
@@ -5573,7 +5594,7 @@ QDateTime QDateTime::fromString(const QString &string, const QString &format, QC
return QDateTime();
}
-/*
+/*!
\overload
*/