diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp index e5242b43eb..68ec73f471 100644 --- a/src/corelib/time/qdatetimeparser.cpp +++ b/src/corelib/time/qdatetimeparser.cpp @@ -1726,29 +1726,26 @@ QDateTimeParser::ParsedSection QDateTimeParser::findUtcOffset(QStringRef str) co QDateTimeParser::ParsedSection QDateTimeParser::findTimeZoneName(QStringRef str, const QDateTime &when) const { - int index = startsWithLocalTimeZone(str); - if (index > 0) // won't actually use the offset, but need it to be valid - return ParsedSection(Acceptable, when.toLocalTime().offsetFromUtc(), index); - + const int systemLength = startsWithLocalTimeZone(str); #if QT_CONFIG(timezone) - const int size = str.length(); - // 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; - } + const auto invalidZoneNameCharacter = [] (const QChar &c) { + return c.unicode() >= 127u + || (!c.isLetterOrNumber() && !QLatin1String("+-./:_").contains(c)); + }; + int index = std::distance(str.cbegin(), + std::find_if(str.cbegin(), str.cend(), invalidZoneNameCharacter)); - while (index > 0) { + for (; index > systemLength; --index) { // Find longest match str.truncate(index); QTimeZone zone(str.toLatin1()); if (zone.isValid()) return ParsedSection(Acceptable, zone.offsetFromUtc(when), index); - index--; // maybe we collected too much ... } #endif + if (systemLength > 0) // won't actually use the offset, but need it to be valid + return ParsedSection(Acceptable, when.toLocalTime().offsetFromUtc(), systemLength); return ParsedSection(); } diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp index ccae0dc3c4..23a99e2f47 100644 --- a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp @@ -119,6 +119,8 @@ private slots: void fromStringDateFormat(); void fromStringStringFormat_data(); void fromStringStringFormat(); + void fromStringStringFormat_localTimeZone_data(); + void fromStringStringFormat_localTimeZone(); #if defined(Q_OS_WIN) && QT_CONFIG(textdate) void fromString_LOCALE_ILDATE(); #endif @@ -2675,6 +2677,7 @@ void tst_QDateTime::fromStringStringFormat() QDateTime dt = QDateTime::fromString(string, format); + QCOMPARE(dt, expected); if (expected.isValid()) { QCOMPARE(dt.timeSpec(), expected.timeSpec()); #if QT_CONFIG(timezone) @@ -2684,7 +2687,42 @@ void tst_QDateTime::fromStringStringFormat() // OffsetFromUTC needs an offset check - we may as well do it for all: QCOMPARE(dt.offsetFromUtc(), expected.offsetFromUtc()); } - QCOMPARE(dt, expected); +} + +void tst_QDateTime::fromStringStringFormat_localTimeZone_data() +{ + QTest::addColumn("localTimeZone"); + QTest::addColumn("string"); + QTest::addColumn("format"); + QTest::addColumn("expected"); + +#if QT_CONFIG(timezone) + QTimeZone etcGmtWithOffset("Etc/GMT+3"); + if (etcGmtWithOffset.isValid()) { + QTest::newRow("local-timezone-with-offset:Etc/GMT+3") << QByteArrayLiteral("GMT") + << QString("2008-10-13 Etc/GMT+3 11.50") << QString("yyyy-MM-dd t hh.mm") + << QDateTime(QDate(2008, 10, 13), QTime(11, 50), etcGmtWithOffset); + } + QTimeZone gmtWithOffset("GMT-2"); + if (gmtWithOffset.isValid()) { + QTest::newRow("local-timezone-with-offset:GMT-2") << QByteArrayLiteral("GMT") + << QString("2008-10-13 GMT-2 11.50") << QString("yyyy-MM-dd t hh.mm") + << QDateTime(QDate(2008, 10, 13), QTime(11, 50), gmtWithOffset); + } + QTimeZone gmt("GMT"); + if (gmt.isValid()) { + QTest::newRow("local-timezone-with-offset:GMT") << QByteArrayLiteral("GMT") + << QString("2008-10-13 GMT 11.50") << QString("yyyy-MM-dd t hh.mm") + << QDateTime(QDate(2008, 10, 13), QTime(11, 50), gmt); + } +#endif +} + +void tst_QDateTime::fromStringStringFormat_localTimeZone() +{ + QFETCH(QByteArray, localTimeZone); + TimeZoneRollback useZone(localTimeZone); // enforce test's time zone + fromStringStringFormat(); // call basic fromStringStringFormat test } #if defined(Q_OS_WIN) && QT_CONFIG(textdate)