QDateTimeParser: avoid using an invalid hour by default

When a time-zone does a spring-forward, skipping an hour (either to
start DST or to move its standard time), there's an hour that doesn't
exist on the day in question.  That hour can be the first hour of the
day, in which case using 0:0 as the default time is broken.  So catch
this case and use the first time that day that makes sense.

Fixes: QTBUG-70823
Change-Id: I23dae9320a3cdd2c988841a7db1b111edb945730
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Edward Welbourne 2018-10-01 20:01:54 +02:00
parent 5a295a1009
commit ced34cb3d5
2 changed files with 33 additions and 4 deletions

View File

@ -1341,12 +1341,33 @@ QDateTimeParser::scanString(const QDateTime &defaultValue,
const QDate date(year, month, day);
const QTime time(hour, minute, second, msec);
return StateNode(
const QDateTime when =
#if QT_CONFIG(timezone)
tspec == Qt::TimeZone ? QDateTime(date, time, timeZone) :
tspec == Qt::TimeZone ? QDateTime(date, time, timeZone) :
#endif
QDateTime(date, time, tspec, zoneOffset),
state, padding, conflicts);
QDateTime(date, time, tspec, zoneOffset);
// If hour wasn't specified, check the default we're using exists on the
// given date (which might be a spring-forward, skipping an hour).
if (parserType == QVariant::DateTime && !(isSet & HourSectionMask) && !when.isValid()) {
qint64 msecs = when.toMSecsSinceEpoch();
// Fortunately, that gets a useful answer ...
const QDateTime replace =
#if QT_CONFIG(timezone)
tspec == Qt::TimeZone
? QDateTime::fromMSecsSinceEpoch(msecs, timeZone) :
#endif
QDateTime::fromMSecsSinceEpoch(msecs, tspec, zoneOffset);
const QTime tick = replace.time();
if (replace.date() == date
&& (!(isSet & MinuteSection) || tick.minute() == minute)
&& (!(isSet & SecondSection) || tick.second() == second)
&& (!(isSet & MSecSection) || tick.msec() == msec)) {
return StateNode(replace, state, padding, conflicts);
}
}
return StateNode(when, state, padding, conflicts);
}
/*!

View File

@ -2390,6 +2390,14 @@ void tst_QDateTime::fromStringStringFormat_data()
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);
#if QT_CONFIG(timezone)
QTimeZone southBrazil("America/Sao_Paulo");
if (southBrazil.isValid()) {
QTest::newRow("spring-forward-midnight")
<< QString("2008-10-19 23:45.678 America/Sao_Paulo") << QString("yyyy-MM-dd mm:ss.zzz t")
<< QDateTime(QDate(2008, 10, 19), QTime(1, 23, 45, 678), southBrazil);
}
#endif
QTest::newRow("late") << QString("9999-12-31T23:59:59.999Z")
<< QString("yyyy-MM-ddThh:mm:ss.zZ")
<< QDateTime(QDate(9999, 12, 31), QTime(23, 59, 59, 999));