QTimeZone - Fix dateForLocalTime() to check validity of next transition

The private method dateForLocalTime() was not checking that transitions
were valid, resulting in infinite looping when a time zone didn't have
any future transitions.

Change-Id: I0e5d07063861778dd86056a80c36fdd9f9d36133
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
John Layt 2013-11-02 18:53:32 +01:00 committed by The Qt Project
parent 8e6258f059
commit 6ad97bfa73
3 changed files with 16 additions and 3 deletions

View File

@ -264,7 +264,8 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs)
// If the local msecs is less than the real local time of the transition
// then get the previous transition to use instead
if (forLocalMSecs < tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000)) {
while (forLocalMSecs < tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000)) {
while (tran.atMSecsSinceEpoch != invalidMSecs()
&& forLocalMSecs < tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000)) {
nextTran = tran;
tran = previousTransition(tran.atMSecsSinceEpoch);
}
@ -272,7 +273,8 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs)
// The zone msecs is after the transition, so check it is before the next tran
// If not try use the next transition instead
nextTran = nextTransition(tran.atMSecsSinceEpoch);
while (forLocalMSecs >= nextTran.atMSecsSinceEpoch + (nextTran.offsetFromUtc * 1000)) {
while (nextTran.atMSecsSinceEpoch != invalidMSecs()
&& forLocalMSecs >= nextTran.atMSecsSinceEpoch + (nextTran.offsetFromUtc * 1000)) {
tran = nextTran;
nextTran = nextTransition(tran.atMSecsSinceEpoch);
}
@ -292,7 +294,8 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs)
// then use the prev tran as we default to the FirstOccurrence
// TODO Check if faster to just always get prev tran, or if faster using 6 hour check.
Data dstTran = previousTransition(tran.atMSecsSinceEpoch);
if (dstTran.daylightTimeOffset > 0 && diffPrevTran < (dstTran.daylightTimeOffset * 1000))
if (dstTran.atMSecsSinceEpoch != invalidMSecs()
&& dstTran.daylightTimeOffset > 0 && diffPrevTran < (dstTran.daylightTimeOffset * 1000))
tran = dstTran;
} else if (diffNextTran >= 0 && diffNextTran <= (nextTran.daylightTimeOffset * 1000)) {
// If time falls within last hour of standard time then is actually the missing hour

View File

@ -2903,6 +2903,12 @@ void tst_QDateTime::timeZones() const
// - Test 03:00:00 = 1 hour after tran
hourAfterStd = QDateTime(QDate(2013, 10, 27), QTime(3, 0, 0), cet);
QCOMPARE(hourAfterStd.toMSecsSinceEpoch(), dstToStdMSecs + 3600000);
// Test Time Zone that has transitions but no future transitions afer a given date
QTimeZone sgt("Asia/Singapore");
QDateTime future(QDate(2015, 1, 1), QTime(0, 0, 0), sgt);
QVERIFY(future.isValid());
QCOMPARE(future.offsetFromUtc(), 28800);
}
void tst_QDateTime::invalid() const

View File

@ -409,6 +409,10 @@ void tst_QTimeZone::stressTest()
qDebug() << "Stress test calculating transistions for" << testZone.id();
testZone.transitions(lowDate1, highDate1);
}
testDate.setTimeZone(testZone);
testDate.isValid();
testDate.offsetFromUtc();
testDate.timeZoneAbbreviation();
}
}