diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2023-01-12 10:04:49 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2023-01-17 21:58:32 +0100 |
commit | 5bc63de8819448e7342f3cb0ac08af667ccc81e5 (patch) | |
tree | b68b1bc0945743e1b9f0924b9538f872875ac63e /src | |
parent | 330c3e91eeed631e084b68454c3fbc248a1b4bb1 (diff) |
QML: Add more overloads to Qt.format{Date|Time|DateTime}()
Since JavaScript has no concept of time or date separate from the Date
object that contains both, and since we implicitly (via
QVariant::convert) or explicitly accept string arguments to all these
methods, we should really accept string coercions of Date objects.
We should also make all the string overloads explicit. Converting
strings to QDateTime is a really obscure feature of the metatype system.
We should not rely on it.
Furthermore, we need to accept QDateTime, as the native representation
of the JavaScript Date object, as argument to formatDate() and
formatTime(). Otherwise there are two ambiguous paths to calling
formatTime() or formatDate() using a Date object: Either coerce the Date
into a string and call the string overload or coerce it into a QTime or
QDate and call the QTime or QDate overload. The QML engine special cases
this and prefers the QTime/QDate way, but this just needlessly
complicates the overload resolution.
Interestingly, tst_qqmlqt already tests most of those variants. We just
have to add the JS string coercions.
Task-number: QTBUG-109380
Change-Id: I880e622256fe115dade32bde880605df2031ff2f
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/jsruntime/qv4dateobject.cpp | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4dateobject_p.h | 1 | ||||
-rw-r--r-- | src/qml/qml/qqmlbuiltinfunctions.cpp | 146 | ||||
-rw-r--r-- | src/qml/qml/qqmlbuiltinfunctions_p.h | 16 |
4 files changed, 168 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 98d930eece..ed64493d9a 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -719,6 +719,11 @@ QString DateObject::dateTimeToString(const QDateTime &dateTime, ExecutionEngine return ToString(TimeClip(dateTime.toMSecsSinceEpoch()), engine->localTZA); } +QDateTime DateObject::stringToDateTime(const QString &string, ExecutionEngine *engine) +{ + return ToDateTime(ParseString(string, engine->localTZA), QTimeZone::LocalTime); +} + QDate DateObject::dateTimeToDate(const QDateTime &dateTime) { // If the Date object was parse()d from a string with no time part diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index 147638744d..ad5b51f063 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -207,6 +207,7 @@ struct DateObject: ReferenceObject { static QString dateTimeToString(const QDateTime &dateTime, ExecutionEngine *engine); static QDate dateTimeToDate(const QDateTime &dateTime); + static QDateTime stringToDateTime(const QString &string, ExecutionEngine *engine); }; template<> diff --git a/src/qml/qml/qqmlbuiltinfunctions.cpp b/src/qml/qml/qqmlbuiltinfunctions.cpp index 2ae58f2178..3807db7456 100644 --- a/src/qml/qml/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/qqmlbuiltinfunctions.cpp @@ -757,6 +757,11 @@ QString formatDateTimeObjectUsingDateFormat(T formatThis, Qt::DateFormat format) } } +static QTime dateTimeToTime(const QDateTime &dateTime) +{ + return dateTime.toLocalTime().time(); +} + /*! \qmlmethod string Qt::formatDate(datetime date, variant format, variant localeFormatOption) @@ -773,6 +778,36 @@ default locale. \sa Locale */ +static std::optional<QDate> dateFromString(const QString &string, QV4::ExecutionEngine *engine) +{ + { + const QDate date = QDate::fromString(string, Qt::ISODate); + if (date.isValid()) + return date; + } + + { + // For historical reasons, the string argument is parsed as datetime, not as only date + const QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate); + if (dateTime.isValid()) { + qCWarning(lcRootProperties()) + << string << "is a date/time string being passed to formatDate()." + << "You should only pass date strings to formatDate()."; + return dateTime.date(); + } + } + + { + // Since we can coerce QDate to QString, allow the resulting string format here. + const QDateTime dateTime = DateObject::stringToDateTime(string, engine); + if (dateTime.isValid()) + return DateObject::dateTimeToDate(dateTime); + } + + engine->throwError(QStringLiteral("Invalid argument passed to formatDate(): %1").arg(string)); + return std::nullopt; +} + QString QtObject::formatDate(const QDate &date, const QString &format) const { return date.toString(format); @@ -783,12 +818,53 @@ QString QtObject::formatDate(const QDate &date, Qt::DateFormat format) const return formatDateTimeObjectUsingDateFormat(date, format); } +QString QtObject::formatDate(const QDateTime &dateTime, const QString &format) const +{ + return DateObject::dateTimeToDate(dateTime).toString(format); +} + +QString QtObject::formatDate(const QString &string, const QString &format) const +{ + if (const auto qDate = dateFromString(string, v4Engine())) + return formatDate(qDate.value(), format); + + return QString(); +} + +QString QtObject::formatDate(const QDateTime &dateTime, Qt::DateFormat format) const +{ + return formatDateTimeObjectUsingDateFormat(DateObject::dateTimeToDate(dateTime), format); +} + +QString QtObject::formatDate(const QString &string, Qt::DateFormat format) const +{ + if (const auto qDate = dateFromString(string, v4Engine())) + return formatDate(qDate.value(), format); + + return QString(); +} + #if QT_CONFIG(qml_locale) QString QtObject::formatDate(const QDate &date, const QLocale &locale, QLocale::FormatType formatType) const { return locale.toString(date, formatType); } + +QString QtObject::formatDate(const QDateTime &dateTime, const QLocale &locale, + QLocale::FormatType formatType) const +{ + return locale.toString(DateObject::dateTimeToDate(dateTime), formatType); +} + +QString QtObject::formatDate(const QString &string, const QLocale &locale, + QLocale::FormatType formatType) const +{ + if (const auto qDate = dateFromString(string, v4Engine())) + return locale.toString(qDate.value(), formatType); + + return QString(); +} #endif /*! @@ -826,6 +902,13 @@ static std::optional<QTime> timeFromString(const QString &string, QV4::Execution } } + { + // Since we can coerce QTime to QString, allow the resulting string format here. + const QDateTime dateTime = DateObject::stringToDateTime(string, engine); + if (dateTime.isValid()) + return dateTimeToTime(dateTime); + } + engine->throwError(QStringLiteral("Invalid argument passed to formatTime(): %1").arg(string)); return std::nullopt; } @@ -835,6 +918,11 @@ QString QtObject::formatTime(const QTime &time, const QString &format) const return time.toString(format); } +QString QtObject::formatTime(const QDateTime &dateTime, const QString &format) const +{ + return dateTimeToTime(dateTime).toString(format); +} + QString QtObject::formatTime(const QString &time, const QString &format) const { @@ -849,6 +937,11 @@ QString QtObject::formatTime(const QTime &time, Qt::DateFormat format) const return formatDateTimeObjectUsingDateFormat(time, format); } +QString QtObject::formatTime(const QDateTime &dateTime, Qt::DateFormat format) const +{ + return formatDateTimeObjectUsingDateFormat(dateTimeToTime(dateTime), format); +} + QString QtObject::formatTime(const QString &time, Qt::DateFormat format) const { if (auto qTime = timeFromString(time, v4Engine())) @@ -864,6 +957,12 @@ QString QtObject::formatTime(const QTime &time, const QLocale &locale, return locale.toString(time, formatType); } +QString QtObject::formatTime(const QDateTime &dateTime, const QLocale &locale, + QLocale::FormatType formatType) const +{ + return locale.toString(dateTimeToTime(dateTime), formatType); +} + QString QtObject::formatTime(const QString &time, const QLocale &locale, QLocale::FormatType formatType) const { @@ -972,22 +1071,69 @@ with the \a format values below to produce the following results: \sa Locale */ +static std::optional<QDateTime> dateTimeFromString(const QString &string, QV4::ExecutionEngine *engine) +{ + { + const QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate); + if (dateTime.isValid()) + return dateTime; + } + + { + // Since we can coerce QDateTime to QString, allow the resulting string format here. + const QDateTime dateTime = DateObject::stringToDateTime(string, engine); + if (dateTime.isValid()) + return dateTime; + } + + engine->throwError(QStringLiteral("Invalid argument passed to formatDateTime(): %1").arg(string)); + return std::nullopt; +} + QString QtObject::formatDateTime(const QDateTime &dateTime, const QString &format) const { return dateTime.toString(format); } +QString QtObject::formatDateTime(const QString &string, const QString &format) const +{ + + if (const auto qDateTime = dateTimeFromString(string, v4Engine())) + return formatDateTime(qDateTime.value(), format); + + return QString(); +} + QString QtObject::formatDateTime(const QDateTime &dateTime, Qt::DateFormat format) const { return formatDateTimeObjectUsingDateFormat(dateTime, format); } +QString QtObject::formatDateTime(const QString &string, Qt::DateFormat format) const +{ + + if (const auto qDateTime = dateTimeFromString(string, v4Engine())) + return formatDateTime(qDateTime.value(), format); + + return QString(); +} + #if QT_CONFIG(qml_locale) QString QtObject::formatDateTime(const QDateTime &dateTime, const QLocale &locale, QLocale::FormatType formatType) const { return locale.toString(dateTime, formatType); } + +QString QtObject::formatDateTime(const QString &string, const QLocale &locale, + QLocale::FormatType formatType) const +{ + + if (const auto qDateTime = dateTimeFromString(string, v4Engine())) + return formatDateTime(qDateTime.value(), locale, formatType); + + return QString(); +} #endif /*! diff --git a/src/qml/qml/qqmlbuiltinfunctions_p.h b/src/qml/qml/qqmlbuiltinfunctions_p.h index 2739524516..46c4f415e3 100644 --- a/src/qml/qml/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/qqmlbuiltinfunctions_p.h @@ -86,25 +86,41 @@ public: Q_INVOKABLE QVariant tint(const QJSValue &baseColor, const QJSValue &tintColor) const; Q_INVOKABLE QString formatDate(const QDate &date, const QString &format) const; + Q_INVOKABLE QString formatDate(const QDateTime &dateTime, const QString &format) const; + Q_INVOKABLE QString formatDate(const QString &string, const QString &format) const; Q_INVOKABLE QString formatDate(const QDate &date, Qt::DateFormat format) const; + Q_INVOKABLE QString formatDate(const QDateTime &dateTime, Qt::DateFormat format) const; + Q_INVOKABLE QString formatDate(const QString &string, Qt::DateFormat format) const; Q_INVOKABLE QString formatTime(const QTime &time, const QString &format) const; + Q_INVOKABLE QString formatTime(const QDateTime &dateTime, const QString &format) const; Q_INVOKABLE QString formatTime(const QString &time, const QString &format) const; Q_INVOKABLE QString formatTime(const QTime &time, Qt::DateFormat format) const; + Q_INVOKABLE QString formatTime(const QDateTime &dateTime, Qt::DateFormat format) const; Q_INVOKABLE QString formatTime(const QString &time, Qt::DateFormat format) const; Q_INVOKABLE QString formatDateTime(const QDateTime &date, const QString &format) const; + Q_INVOKABLE QString formatDateTime(const QString &string, const QString &format) const; Q_INVOKABLE QString formatDateTime(const QDateTime &date, Qt::DateFormat format) const; + Q_INVOKABLE QString formatDateTime(const QString &string, Qt::DateFormat format) const; #if QT_CONFIG(qml_locale) Q_INVOKABLE QString formatDate(const QDate &date, const QLocale &locale = QLocale(), QLocale::FormatType formatType = QLocale::ShortFormat) const; + Q_INVOKABLE QString formatDate(const QDateTime &dateTime, const QLocale &locale = QLocale(), + QLocale::FormatType formatType = QLocale::ShortFormat) const; + Q_INVOKABLE QString formatDate(const QString &string, const QLocale &locale = QLocale(), + QLocale::FormatType formatType = QLocale::ShortFormat) const; Q_INVOKABLE QString formatTime(const QTime &time, const QLocale &locale = QLocale(), QLocale::FormatType formatType = QLocale::ShortFormat) const; + Q_INVOKABLE QString formatTime(const QDateTime &dateTime, const QLocale &locale = QLocale(), + QLocale::FormatType formatType = QLocale::ShortFormat) const; Q_INVOKABLE QString formatTime(const QString &time, const QLocale &locale = QLocale(), QLocale::FormatType formatType = QLocale::ShortFormat) const; Q_INVOKABLE QString formatDateTime(const QDateTime &date, const QLocale &locale = QLocale(), QLocale::FormatType formatType = QLocale::ShortFormat) const; + Q_INVOKABLE QString formatDateTime(const QString &string, const QLocale &locale = QLocale(), + QLocale::FormatType formatType = QLocale::ShortFormat) const; Q_INVOKABLE QLocale locale() const; Q_INVOKABLE QLocale locale(const QString &name) const; #endif |