summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/time/qdatetime.cpp4
-rw-r--r--src/corelib/time/qdatetimeparser.cpp193
-rw-r--r--src/corelib/time/qdatetimeparser_p.h4
-rw-r--r--tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp131
4 files changed, 270 insertions, 62 deletions
diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp
index 9c10e7fe39..50825182a9 100644
--- a/src/corelib/time/qdatetime.cpp
+++ b/src/corelib/time/qdatetime.cpp
@@ -2382,7 +2382,7 @@ static QString qt_tzname(QDateTimePrivate::DaylightStatus daylightStatus)
#endif // Q_OS_WIN
}
-#if QT_CONFIG(datetimeparser) && QT_CONFIG(timezone)
+#if QT_CONFIG(datetimeparser)
/*
\internal
Implemented here to share qt_tzname()
@@ -2400,7 +2400,7 @@ int QDateTimeParser::startsWithLocalTimeZone(const QStringRef name)
}
return 0;
}
-#endif // datetimeparser && timezone
+#endif // datetimeparser
// 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
diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp
index 5bd2821827..e5242b43eb 100644
--- a/src/corelib/time/qdatetimeparser.cpp
+++ b/src/corelib/time/qdatetimeparser.cpp
@@ -218,9 +218,11 @@ int QDateTimeParser::absoluteMax(int s, const QDateTime &cur) const
{
const SectionNode &sn = sectionNode(s);
switch (sn.type) {
-#if QT_CONFIG(timezone)
case TimeZoneSection:
+#if QT_CONFIG(timezone)
return QTimeZone::MaxUtcOffsetSecs;
+#else
+ return +14 * 3600; // NB: copied from QTimeZone
#endif
case Hour24Section:
case Hour12Section:
@@ -263,8 +265,11 @@ int QDateTimeParser::absoluteMin(int s) const
{
const SectionNode &sn = sectionNode(s);
switch (sn.type) {
+ case TimeZoneSection:
#if QT_CONFIG(timezone)
- case TimeZoneSection: return QTimeZone::MinUtcOffsetSecs;
+ return QTimeZone::MinUtcOffsetSecs;
+#else
+ return -14 * 3600; // NB: copied from QTimeZone
#endif
case Hour24Section:
case Hour12Section:
@@ -1200,24 +1205,29 @@ QDateTimeParser::scanString(const QDateTime &defaultValue,
case TimeZoneSection:
current = &zoneOffset;
if (sect.used > 0) {
-#if QT_CONFIG(timezone) // Synchronize with what findTimeZone() found:
+ // Synchronize with what findTimeZone() found:
QStringRef zoneName = input->midRef(pos, sect.used);
Q_ASSERT(!zoneName.isEmpty()); // sect.used > 0
- const QByteArray latinZone(zoneName == QLatin1String("Z")
- ? QByteArray("UTC") : zoneName.toLatin1());
- if (latinZone.startsWith("UTC") &&
- (latinZone.size() == 3 || latinZone.at(3) == '+' || latinZone.at(3) == '-' )) {
- timeZone = QTimeZone(sect.value);
+
+ const QStringRef offsetStr = zoneName.startsWith(QLatin1String("UTC"))
+ ? zoneName.mid(3) : zoneName;
+ const bool isUtcOffset = offsetStr.startsWith(QLatin1Char('+'))
+ || offsetStr.startsWith(QLatin1Char('-'));
+ const bool isUtc = zoneName == QLatin1String("Z")
+ || zoneName == QLatin1String("UTC");
+
+ if (isUtc || isUtcOffset) {
tspec = sect.value ? Qt::OffsetFromUTC : Qt::UTC;
} else {
- timeZone = QTimeZone(latinZone);
+#if QT_CONFIG(timezone)
+ timeZone = QTimeZone(zoneName.toLatin1());
tspec = timeZone.isValid()
? Qt::TimeZone
: (Q_ASSERT(startsWithLocalTimeZone(zoneName)), Qt::LocalTime);
- }
#else
- tspec = Qt::LocalTime;
+ tspec = Qt::LocalTime;
#endif
+ }
}
break;
case Hour24Section: current = &hour; break;
@@ -1640,61 +1650,104 @@ int QDateTimeParser::findDay(const QString &str1, int startDay, int sectionIndex
/*!
\internal
+ Return's .value is UTC offset in seconds.
+ The caller must verify that the offset is within a valid range.
+ */
+QDateTimeParser::ParsedSection QDateTimeParser::findUtcOffset(QStringRef str) const
+{
+ const bool startsWithUtc = str.startsWith(QLatin1String("UTC"));
+ // Get rid of UTC prefix if it exists
+ if (startsWithUtc)
+ str = str.mid(3);
+
+ const bool negativeSign = str.startsWith(QLatin1Char('-'));
+ // Must start with a sign:
+ if (!negativeSign && !str.startsWith(QLatin1Char('+')))
+ return ParsedSection();
+ str = str.mid(1); // drop sign
+
+ const int colonPosition = str.indexOf(QLatin1Char(':'));
+ // Colon that belongs to offset is at most at position 2 (hh:mm)
+ bool hasColon = (colonPosition >= 0 && colonPosition < 3);
+
+ // We deal only with digits at this point (except ':'), so collect them
+ const int digits = hasColon ? colonPosition + 3 : 4;
+ int i = 0;
+ for (const int offsetLength = qMin(digits, str.size()); i < offsetLength; ++i) {
+ if (i != colonPosition && !str.at(i).isDigit())
+ break;
+ }
+ const int hoursLength = qMin(i, hasColon ? colonPosition : 2);
+ if (hoursLength < 1)
+ return ParsedSection();
+ // Field either ends with hours or also has two digits of minutes
+ if (i < digits) {
+ // Only allow single-digit hours with UTC prefix or :mm suffix
+ if (!startsWithUtc && hoursLength != 2)
+ return ParsedSection();
+ i = hoursLength;
+ hasColon = false;
+ }
+ str.truncate(i); // The rest of the string is not part of the UTC offset
+
+ bool isInt = false;
+ const int hours = str.mid(0, hoursLength).toInt(&isInt);
+ if (!isInt)
+ return ParsedSection();
+ const QStringRef minutesStr = str.mid(hasColon ? colonPosition + 1 : 2, 2);
+ const int minutes = minutesStr.isEmpty() ? 0 : minutesStr.toInt(&isInt);
+ if (!isInt)
+ return ParsedSection();
+
+ // Keep in sync with QTimeZone::maxUtcOffset hours (14 at most). Also, user
+ // could be in the middle of updating the offset (e.g. UTC+14:23) which is
+ // an intermediate state
+ const State status = (hours > 14 || minutes >= 60) ? Invalid
+ : (hours == 14 && minutes > 0) ? Intermediate : Acceptable;
+
+ int offset = 3600 * hours + 60 * minutes;
+ if (negativeSign)
+ offset = -offset;
+
+ // Used: UTC, sign, hours, colon, minutes
+ const int usedSymbols = (startsWithUtc ? 3 : 0) + 1 + hoursLength + (hasColon ? 1 : 0)
+ + minutesStr.size();
+
+ return ParsedSection(status, offset, usedSymbols);
+}
+
+/*!
+ \internal
+
Return's .value is zone's offset, zone time - UTC time, in seconds.
+ The caller must verify that the offset is within a valid range.
See QTimeZonePrivate::isValidId() for the format of zone names.
*/
QDateTimeParser::ParsedSection
-QDateTimeParser::findTimeZone(QStringRef str, const QDateTime &when,
- int maxVal, int minVal) const
+QDateTimeParser::findTimeZoneName(QStringRef str, const QDateTime &when) const
{
-#if QT_CONFIG(timezone)
int index = startsWithLocalTimeZone(str);
- int offset;
+ if (index > 0) // won't actually use the offset, but need it to be valid
+ return ParsedSection(Acceptable, when.toLocalTime().offsetFromUtc(), index);
- if (index > 0) {
- // We won't actually use this, but we need a valid return:
- offset = QDateTime(when.date(), when.time(), Qt::LocalTime).offsetFromUtc();
- } else {
- int size = str.length();
- offset = std::numeric_limits<int>::max(); // deliberately out of range
- Q_ASSERT(offset > QTimeZone::MaxUtcOffsetSecs); // cf. absoluteMax()
-
- // Collect up plausibly-valid characters; let QTimeZone work out what's truly valid.
- while (index < size) {
- const auto here = str[index].unicode();
- if (here < 127
- && (QChar::isLetterOrNumber(here)
- || here == '/' || here == '-'
- || here == '_' || here == '.'
- || here == '+' || here == ':'))
- index++;
- else
- break;
- }
+#if QT_CONFIG(timezone)
+ const int size = str.length();
- while (index > 0) {
- str.truncate(index);
- if (str == QLatin1String("Z")) {
- offset = 0; // "Zulu" time - a.k.a. UTC
- break;
- }
- QTimeZone zone(str.toLatin1());
- if (zone.isValid()) {
- offset = zone.offsetFromUtc(when);
- break;
- }
- index--; // maybe we collected too much ...
- }
+ // Collect up plausibly-valid characters; let QTimeZone work out what's
+ // truly valid.
+ for (; index < size; ++index) {
+ const QChar here = str[index];
+ if (here >= 127 || (!here.isLetterOrNumber() && !QLatin1String("/-_.+:").contains(here)))
+ break;
}
- if (index > 0 && maxVal >= offset && offset >= minVal)
- return ParsedSection(Acceptable, offset, index);
-
-#else // timezone
- Q_UNUSED(str);
- Q_UNUSED(when);
- Q_UNUSED(maxVal);
- Q_UNUSED(minVal);
+ while (index > 0) {
+ str.truncate(index);
+ QTimeZone zone(str.toLatin1());
+ if (zone.isValid())
+ return ParsedSection(Acceptable, zone.offsetFromUtc(when), index);
+ index--; // maybe we collected too much ...
+ }
#endif
return ParsedSection();
}
@@ -1702,6 +1755,34 @@ QDateTimeParser::findTimeZone(QStringRef str, const QDateTime &when,
/*!
\internal
+ Return's .value is zone's offset, zone time - UTC time, in seconds.
+ See QTimeZonePrivate::isValidId() for the format of zone names.
+ */
+QDateTimeParser::ParsedSection
+QDateTimeParser::findTimeZone(QStringRef str, const QDateTime &when,
+ int maxVal, int minVal) const
+{
+ ParsedSection section = findUtcOffset(str);
+ if (section.used <= 0) // if nothing used, try time zone parsing
+ section = findTimeZoneName(str, when);
+ // It can be a well formed time zone specifier, but with value out of range
+ if (section.state == Acceptable && (section.value < minVal || section.value > maxVal))
+ section.state = Intermediate;
+ if (section.used > 0)
+ return section;
+
+ // Check if string is UTC or alias to UTC, after all other options
+ if (str.startsWith(QLatin1String("UTC")))
+ return ParsedSection(Acceptable, 0, 3);
+ if (str.startsWith(QLatin1Char('Z')))
+ return ParsedSection(Acceptable, 0, 1);
+
+ return ParsedSection();
+}
+
+/*!
+ \internal
+
Compares str to the am/pm texts returned by getAmPmText().
Returns AM or PM if str is one of those texts. Failing that, it looks to see
whether, ignoring spaces and case, each character of str appears in one of
diff --git a/src/corelib/time/qdatetimeparser_p.h b/src/corelib/time/qdatetimeparser_p.h
index caef0403bc..535069b7b2 100644
--- a/src/corelib/time/qdatetimeparser_p.h
+++ b/src/corelib/time/qdatetimeparser_p.h
@@ -220,12 +220,12 @@ private:
int year, QString *monthName = nullptr, int *used = nullptr) const;
int findDay(const QString &str1, int intDaystart, int sectionIndex,
QString *dayName = nullptr, int *used = nullptr) const;
+ ParsedSection findUtcOffset(QStringRef str) const;
+ ParsedSection findTimeZoneName(QStringRef str, const QDateTime &when) const;
ParsedSection findTimeZone(QStringRef str, const QDateTime &when,
int maxVal, int minVal) const;
-#if QT_CONFIG(timezone)
// Implemented in qdatetime.cpp:
static int startsWithLocalTimeZone(const QStringRef name);
-#endif
enum AmPmFinder {
Neither = -1,
diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
index a3fe6faead..ccae0dc3c4 100644
--- a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
+++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
@@ -2511,11 +2511,136 @@ void tst_QDateTime::fromStringStringFormat_data()
QTest::newRow("data13") << QString("30.02.2004") << QString("dd.MM.yyyy") << invalidDateTime();
QTest::newRow("data14") << QString("32.01.2004") << QString("dd.MM.yyyy") << invalidDateTime();
QTest::newRow("data15") << QString("Thu January 2004") << QString("ddd MMMM yyyy") << QDateTime(QDate(2004, 1, 1), QTime());
-#if QT_CONFIG(timezone)
- // Qt::UTC and Qt::OffsetFromUTC not supported without timezone: QTBUG-83844
QTest::newRow("data16") << QString("2005-06-28T07:57:30.001Z")
<< QString("yyyy-MM-ddThh:mm:ss.zt")
<< QDateTime(QDate(2005, 06, 28), QTime(07, 57, 30, 1), Qt::UTC);
+ QTest::newRow("utc-time-spec-as:UTC+0")
+ << QString("2005-06-28T07:57:30.001UTC+0") << QString("yyyy-MM-ddThh:mm:ss.zt")
+ << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), Qt::UTC);
+ QTest::newRow("utc-time-spec-as:UTC-0")
+ << QString("2005-06-28T07:57:30.001UTC-0") << QString("yyyy-MM-ddThh:mm:ss.zt")
+ << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), Qt::UTC);
+ QTest::newRow("offset-from-utc:UTC+1")
+ << QString("2001-09-13T07:33:01.001 UTC+1") << QString("yyyy-MM-ddThh:mm:ss.z t")
+ << QDateTime(QDate(2001, 9, 13), QTime(7, 33, 1, 1), Qt::OffsetFromUTC, 3600);
+ QTest::newRow("offset-from-utc:UTC-11:01")
+ << QString("2008-09-13T07:33:01.001 UTC-11:01") << QString("yyyy-MM-ddThh:mm:ss.z t")
+ << QDateTime(QDate(2008, 9, 13), QTime(7, 33, 1, 1), Qt::OffsetFromUTC, -39660);
+ QTest::newRow("offset-from-utc:UTC+02:57")
+ << QString("2001-09-15T09:33:01.001UTC+02:57") << QString("yyyy-MM-ddThh:mm:ss.zt")
+ << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1), Qt::OffsetFromUTC, 10620);
+ QTest::newRow("offset-from-utc:-03:00") // RFC 3339 offset format
+ << QString("2001-09-15T09:33:01.001-03:00") << QString("yyyy-MM-ddThh:mm:ss.zt")
+ << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1), Qt::OffsetFromUTC, -10800);
+ QTest::newRow("offset-from-utc:+0205") // ISO 8601 basic offset format
+ << QString("2001-09-15T09:33:01.001+0205") << QString("yyyy-MM-ddThh:mm:ss.zt")
+ << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1), Qt::OffsetFromUTC, 7500);
+ QTest::newRow("offset-from-utc:-0401") // ISO 8601 basic offset format
+ << QString("2001-09-15T09:33:01.001-0401") << QString("yyyy-MM-ddThh:mm:ss.zt")
+ << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1), Qt::OffsetFromUTC, -14460);
+ QTest::newRow("offset-from-utc:+10") // ISO 8601 basic (hour-only) offset format
+ << QString("2001-09-15T09:33:01.001 +10") << QString("yyyy-MM-ddThh:mm:ss.z t")
+ << QDateTime(QDate(2001, 9, 15), QTime(9, 33, 1, 1), Qt::OffsetFromUTC, 36000);
+ QTest::newRow("offset-from-utc:UTC+10:00") // Time-spec specifier at the beginning
+ << QString("UTC+10:00 2008-10-13T07:33") << QString("t yyyy-MM-ddThh:mm")
+ << QDateTime(QDate(2008, 10, 13), QTime(7, 33), Qt::OffsetFromUTC, 36000);
+ QTest::newRow("offset-from-utc:UTC-03:30") // Time-spec specifier in the middle
+ << QString("2008-10-13 UTC-03:30 11.50") << QString("yyyy-MM-dd t hh.mm")
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, -12600);
+ QTest::newRow("offset-from-utc:UTC-2") // Time-spec specifier joined with text/time
+ << QString("2008-10-13 UTC-2Z11.50") << QString("yyyy-MM-dd tZhh.mm")
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, -7200);
+ QTest::newRow("offset-from-utc:followed-by-colon")
+ << QString("2008-10-13 UTC-0100:11.50") << QString("yyyy-MM-dd t:hh.mm")
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, -3600);
+ QTest::newRow("offset-from-utc:late-colon")
+ << QString("2008-10-13 UTC+05T:11.50") << QString("yyyy-MM-dd tT:hh.mm")
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, 18000);
+ QTest::newRow("offset-from-utc:merged-with-time")
+ << QString("2008-10-13 UTC+010011.50") << QString("yyyy-MM-dd thh.mm")
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, 3600);
+ QTest::newRow("offset-from-utc:double-colon-delimiter")
+ << QString("2008-10-13 UTC+12::11.50") << QString("yyyy-MM-dd t::hh.mm")
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, 43200);
+ QTest::newRow("offset-from-utc:3-digit-with-colon")
+ << QString("2008-10-13 -4:30 11.50") << QString("yyyy-MM-dd t hh.mm")
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, -16200);
+ QTest::newRow("offset-from-utc:merged-with-time")
+ << QString("2008-10-13 UTC+010011.50") << QString("yyyy-MM-dd thh.mm")
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, 3600);
+ QTest::newRow("offset-from-utc:with-colon-merged-with-time")
+ << QString("2008-10-13 UTC+01:0011.50") << QString("yyyy-MM-dd thh.mm")
+ << QDateTime(QDate(2008, 10, 13), QTime(11, 50), Qt::OffsetFromUTC, 3600);
+ QTest::newRow("invalid-offset-from-utc:out-of-range")
+ << QString("2001-09-15T09:33:01.001-50") << QString("yyyy-MM-ddThh:mm:ss.zt")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:single-digit-format")
+ << QString("2001-09-15T09:33:01.001+5") << QString("yyyy-MM-ddThh:mm:ss.zt")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:three-digit-format")
+ << QString("2001-09-15T09:33:01.001-701") << QString("yyyy-MM-ddThh:mm:ss.zt")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:three-digit-minutes")
+ << QString("2001-09-15T09:33:01.001+11:570") << QString("yyyy-MM-ddThh:mm:ss.zt")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:single-digit-minutes")
+ << QString("2001-09-15T09:33:01.001+11:5") << QString("yyyy-MM-ddThh:mm:ss.zt")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:invalid-sign-symbol")
+ << QString("2001-09-15T09:33:01.001 ~11:30") << QString("yyyy-MM-ddThh:mm:ss.z t")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:symbol-in-hours")
+ << QString("2001-09-15T09:33:01.001 UTC+o8:30") << QString("yyyy-MM-ddThh:mm:ss.z t")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:symbol-in-minutes")
+ << QString("2001-09-15T09:33:01.001 UTC+08:3i") << QString("yyyy-MM-ddThh:mm:ss.z t")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:UTC+123") // Invalid offset (UTC and 3 digit format)
+ << QString("2001-09-15T09:33:01.001 UTC+123") << QString("yyyy-MM-ddThh:mm:ss.z t")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:UTC+00005") // Invalid offset with leading zeroes
+ << QString("2001-09-15T09:33:01.001 UTC+00005") << QString("yyyy-MM-ddThh:mm:ss.z t")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:three-digit-with-colon-delimiter")
+ << QString("2008-10-13 +123:11.50") << QString("yyyy-MM-dd t:hh.mm")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:double-colon-as-part-of-offset")
+ << QString("2008-10-13 UTC+12::11.50") << QString("yyyy-MM-dd thh.mm")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:single-colon-as-part-of-offset")
+ << QString("2008-10-13 UTC+12::11.50") << QString("yyyy-MM-dd t:hh.mm")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:starts-with-colon")
+ << QString("2008-10-13 UTC+:59 11.50") << QString("yyyy-MM-dd t hh.mm")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:empty-offset")
+ << QString("2008-10-13 UTC+ 11.50") << QString("yyyy-MM-dd t hh.mm")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:time-section-instead-of-offset")
+ << QString("2008-10-13 UTC+11.50") << QString("yyyy-MM-dd thh.mm")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:missing-minutes-if-colon")
+ << QString("2008-10-13 +05: 11.50") << QString("yyyy-MM-dd t hh.mm")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:1-digit-minutes-if-colon")
+ << QString("2008-10-13 UTC+05:1 11.50") << QString("yyyy-MM-dd t hh.mm")
+ << invalidDateTime();
+ QTest::newRow("invalid-time-spec:random-symbol")
+ << QString("2001-09-15T09:33:01.001 $") << QString("yyyy-MM-ddThh:mm:ss.z t")
+ << invalidDateTime();
+ QTest::newRow("invalid-time-spec:random-digit")
+ << QString("2001-09-15T09:33:01.001 1") << QString("yyyy-MM-ddThh:mm:ss.z t")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:merged-with-time")
+ << QString("2008-10-13 UTC+0111.50") << QString("yyyy-MM-dd thh.mm")
+ << invalidDateTime();
+ QTest::newRow("invalid-offset-from-utc:with-colon-3-digit-merged-with-time")
+ << QString("2008-10-13 UTC+01:011.50") << QString("yyyy-MM-dd thh.mm")
+ << invalidDateTime();
+ QTest::newRow("invalid-time-spec:empty")
+ << QString("2001-09-15T09:33:01.001 ") << QString("yyyy-MM-ddThh:mm:ss.z t")
+ << invalidDateTime();
+#if QT_CONFIG(timezone)
QTimeZone southBrazil("America/Sao_Paulo");
if (southBrazil.isValid()) {
QTest::newRow("spring-forward-midnight")
@@ -2556,6 +2681,8 @@ void tst_QDateTime::fromStringStringFormat()
if (expected.timeSpec() == Qt::TimeZone)
QCOMPARE(dt.timeZone(), expected.timeZone());
#endif
+ // OffsetFromUTC needs an offset check - we may as well do it for all:
+ QCOMPARE(dt.offsetFromUtc(), expected.offsetFromUtc());
}
QCOMPARE(dt, expected);
}