Fix date parsing when local time lacks the start of the day

The case where a parsed date-time fell in a transition, but only
because the default value for some field lead it there, only dealt
with the case of parsing a date-time, which is the only time it should
be relevant. However, since the date and time do get combined as a
date-time (even when only one of them is relevant) the same problem
could arise when parsing a date (on which the current time-zone
happened to make a transition at the start of the day) or a time (if
the default date happens to be one on which the current zone had a
transition).

So handle both of those cases, as well as the date-time case.

Fixes: QTBUG-91120
Change-Id: I565d115eb85cd2ee69fa500fcd40b05bcf8f6fff
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit f9469990d0fb1ae9444d415390ec8be483ec4ab3)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Edward Welbourne 2021-06-01 17:41:40 +02:00 committed by Qt Cherry-pick Bot
parent eda9ff2bc4
commit 02c7b658f6

View File

@ -1385,21 +1385,34 @@ QDateTimeParser::scanString(const QDateTime &defaultValue, bool fixup) const
// 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 == QMetaType::QDateTime && !(isSet & HourSectionMask) && !when.isValid()) {
qint64 msecs = when.toMSecsSinceEpoch();
// Fortunately, that gets a useful answer, even though when is invalid ...
const QDateTime replace =
if (!(isSet & HourSectionMask) && !when.isValid()) {
switch (parserType) {
case QMetaType::QDateTime: {
qint64 msecs = when.toMSecsSinceEpoch();
// Fortunately, that gets a useful answer, even though when is invalid ...
const QDateTime replace =
#if QT_CONFIG(timezone)
tspec == Qt::TimeZone
? QDateTime::fromMSecsSinceEpoch(msecs, 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);
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);
}
} break;
case QMetaType::QDate:
// Don't care about time, so just use start of day (and ignore spec):
return StateNode(date.startOfDay(Qt::UTC), state, padding, conflicts);
break;
case QMetaType::QTime:
// Don't care about date or spec, so pick a safe spec:
return StateNode(QDateTime(date, time, Qt::UTC), state, padding, conflicts);
default:
Q_UNREACHABLE();
return StateNode();
}
}