diff options
author | Edward Welbourne <edward.welbourne@qt.io> | 2021-05-12 11:05:16 +0200 |
---|---|---|
committer | Edward Welbourne <edward.welbourne@qt.io> | 2021-05-18 16:24:13 +0200 |
commit | 0a673d257a02b34450d4bbeb43346d993cf3a109 (patch) | |
tree | 9f1fc54b6a3a86033d80fec897487546a555e180 /src/qml/jsruntime | |
parent | 6f1ed8b46abed1a2190c12f8d7b272b075efa0e8 (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.cpp | 29 |
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: |