aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2023-01-12 10:04:49 +0100
committerUlf Hermann <ulf.hermann@qt.io>2023-01-17 21:58:32 +0100
commit5bc63de8819448e7342f3cb0ac08af667ccc81e5 (patch)
treeb68b1bc0945743e1b9f0924b9538f872875ac63e /src/qml
parent330c3e91eeed631e084b68454c3fbc248a1b4bb1 (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/qml')
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp5
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h1
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions.cpp146
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions_p.h16
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