diff options
author | Edward Welbourne <edward.welbourne@qt.io> | 2021-08-31 16:48:37 +0200 |
---|---|---|
committer | Edward Welbourne <edward.welbourne@qt.io> | 2021-09-02 09:58:06 +0200 |
commit | 87b5d77aeaf9aaa9530d546f728cc8cffc9a0523 (patch) | |
tree | 146cbf0b944b6bd66e1a3bde4ecc4c3efb909deb | |
parent | ef0f04d1da3790a7f89db5e9556e799dc5114c61 (diff) |
Fix corner case in QTimeZonePrivate::dataForLocalTime()
If the local time for which we want data is after the last known
transition, the two transitions we get to bracket it are the last
known and an invalid one. The code checked the former was valid, but
neglected to check the latter, leading to nonsense arithmetic later in
the function. In this situation we unequivocally want the last known
transition, so the problem is easily solved.
Fixes: QTBUG-96152
Change-Id: I6fc830ce538e8a572093cd8dfe832e10689bf904
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
(cherry picked from commit b656cea5deccab352b7c4c56d7023f5108578654)
-rw-r--r-- | src/corelib/time/qtimezoneprivate.cpp | 32 |
1 files changed, 19 insertions, 13 deletions
diff --git a/src/corelib/time/qtimezoneprivate.cpp b/src/corelib/time/qtimezoneprivate.cpp index 832f8f3e59..530d5eac9f 100644 --- a/src/corelib/time/qtimezoneprivate.cpp +++ b/src/corelib/time/qtimezoneprivate.cpp @@ -356,26 +356,33 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs, // Check we do *really* have transitions for this zone: if (tran.atMSecsSinceEpoch != invalidMSecs()) { - - /* - So now tran is definitely before and nextTran is either after or only - slightly before. One is standard time; we interpret the other as DST - (although the transition might in fact by a change in standard offset). Our - hint tells us which of those to use (defaulting to standard if no hint): try - it first; if that fails, try the other; if both fail, life's tricky. - */ + /* So now tran is definitely before ... */ Q_ASSERT(forLocalMSecs < 0 || forLocalMSecs - tran.offsetFromUtc * 1000 > tran.atMSecsSinceEpoch); + // Work out the UTC value it would make sense to return if using tran: + tran.atMSecsSinceEpoch = forLocalMSecs - tran.offsetFromUtc * 1000; + // If we know of no transition after it, the answer is easy: const qint64 nextStart = nextTran.atMSecsSinceEpoch; - // Work out the UTC values it might make sense to return: + if (nextStart == invalidMSecs()) + return tran; + + /* + ... and nextTran is either after or only slightly before. We're + going to interpret one as standard time, the other as DST + (although the transition might in fact be a change in standard + offset, or a change in DST offset, e.g. to/from double-DST). Our + hint tells us which of those to use (defaulting to standard if no + hint): try it first; if that fails, try the other; if both fail, + life's tricky. + */ + // Work out the UTC value it would make sense to return if using nextTran: nextTran.atMSecsSinceEpoch = forLocalMSecs - nextTran.offsetFromUtc * 1000; - tran.atMSecsSinceEpoch = forLocalMSecs - tran.offsetFromUtc * 1000; // If both or neither have zero DST, treat the one with lower offset as standard: const bool nextIsDst = !nextTran.daylightTimeOffset == !tran.daylightTimeOffset ? tran.offsetFromUtc < nextTran.offsetFromUtc : nextTran.daylightTimeOffset; // If that agrees with hint > 0, our first guess is to use nextTran; else tran. - const bool nextFirst = nextIsDst == (hint > 0) && nextStart != invalidMSecs(); + const bool nextFirst = nextIsDst == (hint > 0); for (int i = 0; i < 2; i++) { /* On the first pass, the case we consider is what hint told us to expect @@ -384,12 +391,11 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs, by which time the second case, that we're trying, is likely right. */ if (nextFirst ? i == 0 : i) { - Q_ASSERT(nextStart != invalidMSecs()); if (nextStart <= nextTran.atMSecsSinceEpoch) return nextTran; } else { // If next is invalid, nextFirst is false, to route us here first: - if (nextStart == invalidMSecs() || nextStart > tran.atMSecsSinceEpoch) + if (nextStart > tran.atMSecsSinceEpoch) return tran; } } |