aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2021-05-12 11:05:16 +0200
committerEdward Welbourne <edward.welbourne@qt.io>2021-05-18 16:24:13 +0200
commit0a673d257a02b34450d4bbeb43346d993cf3a109 (patch)
tree9f1fc54b6a3a86033d80fec897487546a555e180 /src/qml/jsruntime
parent6f1ed8b46abed1a2190c12f8d7b272b075efa0e8 (diff)
Make QDate handling consistent in its use of UTC
Due to the quirk of ECMAScript's Date.parse() spec [0] stipulating the use of UTC for date-only strings, in contrast to most other ways of creating a Date using local time, reasonable users get surprised by the behavior of QDate properties initialized from strings. This can't be avoided without breaking other uses of Date, so document the work-around needed to cope with it (use UTC-specific methods to access the Date object). [0] https://tc39.es/ecma262/#sec-date.parse Make conversions back to QDate from Date work round the possibility that the Date, seen as a QDateTime(,, LocalTime), needs to be handled as UTC when extracting the date, and catch two more places that conversion from QDate neglected to use UTC's start of day, for consistency. Revised tests to call UTC-specific methods instead of the local-time ones, where appropriate. Drive-by: some tests were (entirely bogusly) constructing a fresh Date using the UTC-fields of the Date they had, in order to then test the non-UTC fields of this fresh Date; instead, simply test that the UTC fields are as expected. [ChangeLog][QML][Behavior change] Where a QDate is represented in QML's JavaScript as a Date, it is now more consistently associated with the start of the UTC day it describes. Previously cases where it was represented as the start of local time's day could lead to a Date turning into a QDate for the preceding day. Inconsistencies in the specified behavior of Date preclude eliminating such problems entirely, but they should now be limited to cases where (perversely for a date property or parameter) the date is specified with a local time late enough to make it coincide with the start of the next UTC day (in which case that next day's QDate will be its C++ representation). Fixes: QTBUG-92466 Change-Id: I2306dd9ecef0d5c2d59b562762392e51bb6d66ca Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/qv4engine.cpp29
1 files changed, 25 insertions, 4 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 567ef03428..5247fda6c9 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -1639,8 +1639,16 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, QMet
if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>())
return *ld->d()->locale;
#endif
- if (const QV4::DateObject *d = value.as<DateObject>())
- return d->toQDateTime();
+ if (const QV4::DateObject *d = value.as<DateObject>()) {
+ auto dt = d->toQDateTime();
+ // See ExecutionEngine::metaTypeFromJS()'s handling of QMetaType::Date:
+ if (typeHint == QMetaType::QDate) {
+ const auto utc = dt.toUTC();
+ if (utc.date() != dt.date() && utc.addSecs(-1).date() == dt.date())
+ dt = utc;
+ }
+ return dt;
+ }
if (const QV4::UrlObject *d = value.as<UrlObject>())
return d->toQUrl();
if (const ArrayBuffer *d = value.as<ArrayBuffer>())
@@ -2320,7 +2328,20 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
} break;
case QMetaType::QDate:
if (const QV4::DateObject *d = value.as<DateObject>()) {
- *reinterpret_cast<QDate *>(data) = d->toQDateTime().date();
+ // If the Date object was parse()d from a string with no time part
+ // or zone specifier it's really the UTC start of the relevant day,
+ // but it's here represented as a local time, which may fall in the
+ // preceding day. See QTBUG-92466 for the gory details.
+ QDateTime dt = d->toQDateTime();
+ const QDateTime utc = dt.toUTC();
+ if (utc.date() != dt.date() && utc.addMSecs(-1).date() == dt.date())
+ dt = utc;
+ // This may, of course, be The Wrong Thing if the date was
+ // constructed as a full local date-time that happens to coincide
+ // with the start of a UTC day; however, that would be an odd value
+ // to give to something that, apparently, someone thinks belongs in
+ // a QDate.
+ *reinterpret_cast<QDate *>(data) = dt.date();
return true;
} break;
case QMetaType::QUrl: