summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2021-09-24 14:12:04 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-10-12 22:26:14 +0000
commit832b561b4549016c8409f05fda5a9fc3d4f31144 (patch)
tree2e3128e783d872c3e0b5ea13d3cef6c4e547fd7d
parent33517b8069edb697c98e7e36fddf9a6b6eb21f4b (diff)
Fix handling of time-zone gap in QTimeZonePrivate::dataForLocalTime()
This was handled correctly when the backend supplies transitions bracketing the time in question, but the fallback code tried to use the DST offset at the time with larger offset from UTC; this did not work when the gap was due to a change in standard time. Discovered by ANS1 parsing of a date-time with two-digit year, for which the date-time parser tried to use 1921-05-01T00:00 local time when filling in the fields it had parsed; but, when run in Europe/Helsinki, there is no such time due to the 20m 11s skipped when joining EET from the prior local solar mean time. Correct the calculation to use the actual change in offset from UTC, as used in the (far better tested) between-transitions branch of the code, rather than the DST offset after the transition. Add a test-case based on the ASN.1 certificate date whose parsing revealed the issue. Although it seems nothing in Coin can reproduce the issue, the reporter has verified that the test does indeed fail on the system where the bug was found and the fix does fix it. Fixes: QTBUG-96861 Change-Id: I12b02bad01daca2073d1a356452cd573684aa688 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> (cherry picked from commit ba23507960a80367d918468d9d7da39c92a09fbf) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/corelib/time/qtimezoneprivate.cpp6
-rw-r--r--tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp12
2 files changed, 16 insertions, 2 deletions
diff --git a/src/corelib/time/qtimezoneprivate.cpp b/src/corelib/time/qtimezoneprivate.cpp
index fc22aa7aee..f1c127b5a6 100644
--- a/src/corelib/time/qtimezoneprivate.cpp
+++ b/src/corelib/time/qtimezoneprivate.cpp
@@ -473,8 +473,10 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs,
utcEpochMSecs = forStd;
} else {
// Invalid forLocalMSecs: in spring-forward gap.
- const int dstStep = daylightTimeOffset(early < late ? imminent : recent) * 1000;
- Q_ASSERT(dstStep); // There can't be a transition without it !
+ const int dstStep = (offsetInDst - offsetInStd) * 1000;
+ // That'll typically be the DST offset at imminent, but changes to
+ // standard time have zero DST offset both before and after.
+ Q_ASSERT(dstStep > 0); // There can't be a gap without it !
utcEpochMSecs = (hint > 0) ? forStd - dstStep : forDst + dstStep;
}
}
diff --git a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
index 6e68b4af05..d528361bb9 100644
--- a/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
+++ b/tests/auto/corelib/time/qdatetime/tst_qdatetime.cpp
@@ -2917,6 +2917,18 @@ void tst_QDateTime::fromStringStringFormat_localTimeZone_data()
<< QString("2008-10-13 GMT 11.50") << QString("yyyy-MM-dd t hh.mm")
<< QDateTime(QDate(2008, 10, 13), QTime(11, 50), gmt);
}
+ QTimeZone helsinki("Europe/Helsinki");
+ if (helsinki.isValid()) {
+ // QTBUG-96861: QAsn1Element::toDateTime() tripped over an assert in
+ // QTimeZonePrivate::dataForLocalTime() on macOS and iOS.
+ // The first 20m 11s of 1921-05-01 were skipped, so the parser's attempt
+ // to construct a local time after scanning yyMM tripped up on the start
+ // of the day, when the zone backend lacked transition data.
+ QTest::newRow("Helsinki-joins-EET")
+ << QByteArrayLiteral("Europe/Helsinki")
+ << QString("210506000000Z") << QString("yyMMddHHmmsst")
+ << QDateTime(QDate(1921, 5, 6), QTime(0, 0), Qt::UTC);
+ }
#endif
}