Verify that QML can reliably receive datetime info from C++
authorMatthew Vogt <matthew.vogt@nokia.com>
Mon, 23 Apr 2012 05:14:42 +0000 (15:14 +1000)
committerQt by Nokia <qt-info@nokia.com>
Mon, 23 Apr 2012 22:33:25 +0000 (00:33 +0200)
Since a JavaScript Date object does not contain any information about
the timezone in which it is specified, a C++ module that exports
datetime information to QML must also provide the relevant timezone
data so that clients can correctly interpret the datetime value.

Provide an example of exporting datetime information to QML, verifying
that the data can be correctly interpreted in JS.

Task-number: QTBUG-25262
Change-Id: I732797da225861470e6b034f2e3d89a43df36cf7
Reviewed-by: Andrew den Exter <andrew.den-exter@nokia.com>
tests/auto/qml/qqmlecmascript/data/exportDate.2.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/exportDate.3.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/exportDate.4.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/exportDate.5.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/exportDate.6.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/exportDate.7.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/exportDate.8.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/data/exportDate.qml [new file with mode: 0644]
tests/auto/qml/qqmlecmascript/testtypes.h
tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp

diff --git a/tests/auto/qml/qqmlecmascript/data/exportDate.2.qml b/tests/auto/qml/qqmlecmascript/data/exportDate.2.qml
new file mode 100644 (file)
index 0000000..8ad75aa
--- /dev/null
@@ -0,0 +1,33 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyTypeObject {
+    boolProperty: false
+
+    Component.onCompleted: {
+        var dt = datetimeExporter.getDateTime()
+        var offset = datetimeExporter.getDateTimeOffset()
+        var date = datetimeExporter.getDate()
+        var timespec = datetimeExporter.getTimeSpec()
+
+        // The test date is 2009-5-12 23:59:59 (local time)
+        var compare = new Date(2009, 5-1, 12, 23, 59, 59)
+        var compareOffset = new Date().getTimezoneOffset()
+
+        // The date is already in local time, so we can use the partial values directly
+        var dtAdjusted = dt
+
+        boolProperty = (dt.getTime() == compare.getTime()) &&
+                       (offset == compareOffset) &&
+                       (timespec == 'LocalTime') &&
+                       (dtAdjusted.getFullYear() == 2009) &&
+                       (dtAdjusted.getMonth() == 5-1) &&
+                       (dtAdjusted.getDate() == 12) &&
+                       (dtAdjusted.getHours() == 23) &&
+                       (dtAdjusted.getMinutes() == 59) &&
+                       (dtAdjusted.getSeconds() == 59) &&
+                       (date.getFullYear() == 2009) &&
+                       (date.getMonth() == 5-1) &&
+                       (date.getDate() == 12)
+    }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/exportDate.3.qml b/tests/auto/qml/qqmlecmascript/data/exportDate.3.qml
new file mode 100644 (file)
index 0000000..2ba1cc6
--- /dev/null
@@ -0,0 +1,39 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyTypeObject {
+    boolProperty: false
+
+    Component.onCompleted: {
+        var dt = datetimeExporter.getDateTime()
+        var offset = datetimeExporter.getDateTimeOffset()
+        var date = datetimeExporter.getDate()
+        var timespec = datetimeExporter.getTimeSpec()
+
+        // The test date is 2009-5-12 00:00:01 (UTC)
+        var compare = new Date(Date.UTC(2009, 5-1, 12, 0, 0, 1))
+        var compareOffset = 0
+
+        // Adjust for timezone to extract correct partial values
+        var dtAdjusted = new Date(dt.getUTCFullYear(),
+                                  dt.getUTCMonth(),
+                                  dt.getUTCDate(),
+                                  dt.getUTCHours(),
+                                  dt.getUTCMinutes(),
+                                  dt.getUTCSeconds(),
+                                  dt.getUTCMilliseconds())
+
+        boolProperty = (dt.getTime() == compare.getTime()) &&
+                       (offset == compareOffset) &&
+                       (timespec == 'UTC') &&
+                       (dtAdjusted.getFullYear() == 2009) &&
+                       (dtAdjusted.getMonth() == 5-1) &&
+                       (dtAdjusted.getDate() == 12) &&
+                       (dtAdjusted.getHours() == 0) &&
+                       (dtAdjusted.getMinutes() == 0) &&
+                       (dtAdjusted.getSeconds() == 1) &&
+                       (date.getFullYear() == 2009) &&
+                       (date.getMonth() == 5-1) &&
+                       (date.getDate() == 12)
+    }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/exportDate.4.qml b/tests/auto/qml/qqmlecmascript/data/exportDate.4.qml
new file mode 100644 (file)
index 0000000..c5b2388
--- /dev/null
@@ -0,0 +1,39 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyTypeObject {
+    boolProperty: false
+
+    Component.onCompleted: {
+        var dt = datetimeExporter.getDateTime()
+        var offset = datetimeExporter.getDateTimeOffset()
+        var date = datetimeExporter.getDate()
+        var timespec = datetimeExporter.getTimeSpec()
+
+        // The test date is 2009-5-12 23:59:59 (UTC)
+        var compare = new Date(Date.UTC(2009, 5-1, 12, 23, 59, 59))
+        var compareOffset = 0
+
+        // Adjust for timezone to extract correct partial values
+        var dtAdjusted = new Date(dt.getUTCFullYear(),
+                                  dt.getUTCMonth(),
+                                  dt.getUTCDate(),
+                                  dt.getUTCHours(),
+                                  dt.getUTCMinutes(),
+                                  dt.getUTCSeconds(),
+                                  dt.getUTCMilliseconds())
+
+        boolProperty = (dt.getTime() == compare.getTime()) &&
+                       (offset == compareOffset) &&
+                       (timespec == 'UTC') &&
+                       (dtAdjusted.getFullYear() == 2009) &&
+                       (dtAdjusted.getMonth() == 5-1) &&
+                       (dtAdjusted.getDate() == 12) &&
+                       (dtAdjusted.getHours() == 23) &&
+                       (dtAdjusted.getMinutes() == 59) &&
+                       (dtAdjusted.getSeconds() == 59) &&
+                       (date.getFullYear() == 2009) &&
+                       (date.getMonth() == 5-1) &&
+                       (date.getDate() == 12)
+    }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/exportDate.5.qml b/tests/auto/qml/qqmlecmascript/data/exportDate.5.qml
new file mode 100644 (file)
index 0000000..6da3a4a
--- /dev/null
@@ -0,0 +1,39 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyTypeObject {
+    boolProperty: false
+
+    Component.onCompleted: {
+        var dt = datetimeExporter.getDateTime()
+        var offset = datetimeExporter.getDateTimeOffset()
+        var date = datetimeExporter.getDate()
+        var timespec = datetimeExporter.getTimeSpec()
+
+        // The test date is 2009-5-12 00:00:01 (UTC+11:30)
+        var compare = new Date('2009-05-12T00:00:01+11:30')
+
+        // Adjust for timezone to extract correct partial values
+        var dtUtc = new Date(dt.getTime() + (offset * 60000))
+        var dtAdjusted = new Date(dtUtc.getUTCFullYear(),
+                                  dtUtc.getUTCMonth(),
+                                  dtUtc.getUTCDate(),
+                                  dtUtc.getUTCHours(),
+                                  dtUtc.getUTCMinutes(),
+                                  dtUtc.getUTCSeconds(),
+                                  dtUtc.getUTCMilliseconds())
+
+        boolProperty = (dt.getTime() == compare.getTime()) &&
+                       (offset == ((11 * 60) + 30)) &&
+                       (timespec == '+11:30') &&
+                       (dtAdjusted.getFullYear() == 2009) &&
+                       (dtAdjusted.getMonth() == 5-1) &&
+                       (dtAdjusted.getDate() == 12) &&
+                       (dtAdjusted.getHours() == 0) &&
+                       (dtAdjusted.getMinutes() == 0) &&
+                       (dtAdjusted.getSeconds() == 1) &&
+                       (date.getFullYear() == 2009) &&
+                       (date.getMonth() == 5-1) &&
+                       (date.getDate() == 12)
+    }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/exportDate.6.qml b/tests/auto/qml/qqmlecmascript/data/exportDate.6.qml
new file mode 100644 (file)
index 0000000..9980af4
--- /dev/null
@@ -0,0 +1,39 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyTypeObject {
+    boolProperty: false
+
+    Component.onCompleted: {
+        var dt = datetimeExporter.getDateTime()
+        var offset = datetimeExporter.getDateTimeOffset()
+        var date = datetimeExporter.getDate()
+        var timespec = datetimeExporter.getTimeSpec()
+
+        // The test date is 2009-5-12 23:59:59 (UTC+11:30)
+        var compare = new Date('2009-05-12T23:59:59+11:30')
+
+        // Adjust for timezone to extract correct partial values
+        var dtUtc = new Date(dt.getTime() + (offset * 60000))
+        var dtAdjusted = new Date(dtUtc.getUTCFullYear(),
+                                  dtUtc.getUTCMonth(),
+                                  dtUtc.getUTCDate(),
+                                  dtUtc.getUTCHours(),
+                                  dtUtc.getUTCMinutes(),
+                                  dtUtc.getUTCSeconds(),
+                                  dtUtc.getUTCMilliseconds())
+
+        boolProperty = (dt.getTime() == compare.getTime()) &&
+                       (offset == ((11 * 60) + 30)) &&
+                       (timespec == '+11:30') &&
+                       (dtAdjusted.getFullYear() == 2009) &&
+                       (dtAdjusted.getMonth() == 5-1) &&
+                       (dtAdjusted.getDate() == 12) &&
+                       (dtAdjusted.getHours() == 23) &&
+                       (dtAdjusted.getMinutes() == 59) &&
+                       (dtAdjusted.getSeconds() == 59) &&
+                       (date.getFullYear() == 2009) &&
+                       (date.getMonth() == 5-1) &&
+                       (date.getDate() == 12)
+    }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/exportDate.7.qml b/tests/auto/qml/qqmlecmascript/data/exportDate.7.qml
new file mode 100644 (file)
index 0000000..d1de970
--- /dev/null
@@ -0,0 +1,39 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyTypeObject {
+    boolProperty: false
+
+    Component.onCompleted: {
+        var dt = datetimeExporter.getDateTime()
+        var offset = datetimeExporter.getDateTimeOffset()
+        var date = datetimeExporter.getDate()
+        var timespec = datetimeExporter.getTimeSpec()
+
+        // The test date is 2009-5-12 00:00:01 (UTC-11:30)
+        var compare = new Date('2009-05-12T00:00:01-11:30')
+
+        // Adjust for timezone to extract correct partial values
+        var dtUtc = new Date(dt.getTime() + (offset * 60000))
+        var dtAdjusted = new Date(dtUtc.getUTCFullYear(),
+                                  dtUtc.getUTCMonth(),
+                                  dtUtc.getUTCDate(),
+                                  dtUtc.getUTCHours(),
+                                  dtUtc.getUTCMinutes(),
+                                  dtUtc.getUTCSeconds(),
+                                  dtUtc.getUTCMilliseconds())
+
+        boolProperty = (dt.getTime() == compare.getTime()) &&
+                       (offset == -((11 * 60) + 30)) &&
+                       (timespec == '-11:30') &&
+                       (dtAdjusted.getFullYear() == 2009) &&
+                       (dtAdjusted.getMonth() == 5-1) &&
+                       (dtAdjusted.getDate() == 12) &&
+                       (dtAdjusted.getHours() == 0) &&
+                       (dtAdjusted.getMinutes() == 0) &&
+                       (dtAdjusted.getSeconds() == 1) &&
+                       (date.getFullYear() == 2009) &&
+                       (date.getMonth() == 5-1) &&
+                       (date.getDate() == 12)
+    }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/exportDate.8.qml b/tests/auto/qml/qqmlecmascript/data/exportDate.8.qml
new file mode 100644 (file)
index 0000000..6459ca8
--- /dev/null
@@ -0,0 +1,39 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyTypeObject {
+    boolProperty: false
+
+    Component.onCompleted: {
+        var dt = datetimeExporter.getDateTime()
+        var offset = datetimeExporter.getDateTimeOffset()
+        var date = datetimeExporter.getDate()
+        var timespec = datetimeExporter.getTimeSpec()
+
+        // The test date is 2009-5-12 23:59:59 (UTC-11:30)
+        var compare = new Date('2009-05-12T23:59:59-11:30')
+
+        // Adjust for timezone to extract correct partial values
+        var dtUtc = new Date(dt.getTime() + (offset * 60000))
+        var dtAdjusted = new Date(dtUtc.getUTCFullYear(),
+                                  dtUtc.getUTCMonth(),
+                                  dtUtc.getUTCDate(),
+                                  dtUtc.getUTCHours(),
+                                  dtUtc.getUTCMinutes(),
+                                  dtUtc.getUTCSeconds(),
+                                  dtUtc.getUTCMilliseconds())
+
+        boolProperty = (dt.getTime() == compare.getTime()) &&
+                       (offset == -((11 * 60) + 30)) &&
+                       (timespec == '-11:30') &&
+                       (dtAdjusted.getFullYear() == 2009) &&
+                       (dtAdjusted.getMonth() == 5-1) &&
+                       (dtAdjusted.getDate() == 12) &&
+                       (dtAdjusted.getHours() == 23) &&
+                       (dtAdjusted.getMinutes() == 59) &&
+                       (dtAdjusted.getSeconds() == 59) &&
+                       (date.getFullYear() == 2009) &&
+                       (date.getMonth() == 5-1) &&
+                       (date.getDate() == 12)
+    }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/exportDate.qml b/tests/auto/qml/qqmlecmascript/data/exportDate.qml
new file mode 100644 (file)
index 0000000..13b35a9
--- /dev/null
@@ -0,0 +1,33 @@
+import Qt.test 1.0
+import QtQuick 2.0
+
+MyTypeObject {
+    boolProperty: false
+
+    Component.onCompleted: {
+        var dt = datetimeExporter.getDateTime()
+        var offset = datetimeExporter.getDateTimeOffset()
+        var date = datetimeExporter.getDate()
+        var timespec = datetimeExporter.getTimeSpec()
+
+        // The test date is 2009-5-12 00:00:01 (local time)
+        var compare = new Date(2009, 5-1, 12, 0, 0, 1)
+        var compareOffset = new Date().getTimezoneOffset()
+
+        // The date is already in local time, so we can use the partial values directly
+        var dtAdjusted = dt
+
+        boolProperty = (dt.getTime() == compare.getTime()) &&
+                       (offset == compareOffset) &&
+                       (timespec == 'LocalTime') &&
+                       (dtAdjusted.getFullYear() == 2009) &&
+                       (dtAdjusted.getMonth() == 5-1) &&
+                       (dtAdjusted.getDate() == 12) &&
+                       (dtAdjusted.getHours() == 0) &&
+                       (dtAdjusted.getMinutes() == 0) &&
+                       (dtAdjusted.getSeconds() == 1) &&
+                       (date.getFullYear() == 2009) &&
+                       (date.getMonth() == 5-1) &&
+                       (date.getDate() == 12)
+    }
+}
index b0d7e0f..502c65d 100644 (file)
@@ -1332,6 +1332,43 @@ private:
     MyQmlObject *m_nestedObject;
 };
 
+class DateTimeExporter : public QObject
+{
+    Q_OBJECT
+
+public:
+    DateTimeExporter(const QDateTime &dt) : m_datetime(dt), m_offset(0), m_timespec("UTC")
+    {
+        switch (m_datetime.timeSpec()) {
+        case Qt::LocalTime:
+            {
+            QDateTime utc(m_datetime.toUTC());
+            utc.setTimeSpec(Qt::LocalTime);
+            m_offset = m_datetime.secsTo(utc) / 60;
+            m_timespec = "LocalTime";
+            }
+            break;
+        case Qt::OffsetFromUTC:
+            m_offset = m_datetime.utcOffset() / 60;
+            m_timespec = QString("%1%2:%3").arg(m_offset < 0 ? '-' : '+')
+                                           .arg(abs(m_offset) / 60)
+                                           .arg(abs(m_offset) % 60);
+        default:
+            break;
+        }
+    }
+
+    Q_INVOKABLE QDate getDate() const { return m_datetime.date(); }
+    Q_INVOKABLE QDateTime getDateTime() const { return m_datetime; }
+    Q_INVOKABLE int getDateTimeOffset() const { return m_offset; }
+    Q_INVOKABLE QString getTimeSpec() const { return m_timespec; }
+
+private:
+    QDateTime m_datetime;
+    int m_offset;
+    QString m_timespec;
+};
+
 void registerTypes();
 
 #endif // TESTTYPES_H
index 4e7da76..b66427e 100644 (file)
@@ -73,6 +73,8 @@ private slots:
     void assignBasicTypes();
     void assignDate_data();
     void assignDate();
+    void exportDate_data();
+    void exportDate();
     void idShortcutInvalidates();
     void boolPropertiesEvaluateAsBool();
     void methods();
@@ -362,6 +364,62 @@ void tst_qqmlecmascript::assignDate()
     QCOMPARE(object->boolProperty(), true);
 }
 
+void tst_qqmlecmascript::exportDate_data()
+{
+    QTest::addColumn<QUrl>("source");
+    QTest::addColumn<QDateTime>("datetime");
+
+    // Verify that we can export datetime information to QML and that consumers can access
+    // the data correctly provided they know the TZ info associated with the value
+
+    const QDate date(2009, 5, 12);
+    const QTime early(0, 0, 1);
+    const QTime late(23, 59, 59);
+    const int offset(((11 * 60) + 30) * 60);
+
+    QTest::newRow("Localtime early") << testFileUrl("exportDate.qml") << QDateTime(date, early, Qt::LocalTime);
+    QTest::newRow("Localtime late") << testFileUrl("exportDate.2.qml") << QDateTime(date, late, Qt::LocalTime);
+    QTest::newRow("UTC early") << testFileUrl("exportDate.3.qml") << QDateTime(date, early, Qt::UTC);
+    QTest::newRow("UTC late") << testFileUrl("exportDate.4.qml") << QDateTime(date, late, Qt::UTC);
+    {
+        QDateTime dt(date, early, Qt::OffsetFromUTC);
+        dt.setUtcOffset(offset);
+        QTest::newRow("+11:30 early") << testFileUrl("exportDate.5.qml") << dt;
+    }
+    {
+        QDateTime dt(date, late, Qt::OffsetFromUTC);
+        dt.setUtcOffset(offset);
+        QTest::newRow("+11:30 late") << testFileUrl("exportDate.6.qml") << dt;
+    }
+    {
+        QDateTime dt(date, early, Qt::OffsetFromUTC);
+        dt.setUtcOffset(-offset);
+        QTest::newRow("-11:30 early") << testFileUrl("exportDate.7.qml") << dt;
+    }
+    {
+        QDateTime dt(date, late, Qt::OffsetFromUTC);
+        dt.setUtcOffset(-offset);
+        QTest::newRow("-11:30 late") << testFileUrl("exportDate.8.qml") << dt;
+    }
+}
+
+void tst_qqmlecmascript::exportDate()
+{
+    QFETCH(QUrl, source);
+    QFETCH(QDateTime, datetime);
+
+    DateTimeExporter exporter(datetime);
+
+    QQmlEngine e;
+    e.rootContext()->setContextProperty("datetimeExporter", &exporter);
+
+    QQmlComponent component(&e, source);
+    QScopedPointer<QObject> obj(component.create());
+    MyTypeObject *object = qobject_cast<MyTypeObject *>(obj.data());
+    QVERIFY(object != 0);
+    QCOMPARE(object->boolProperty(), true);
+}
+
 void tst_qqmlecmascript::idShortcutInvalidates()
 {
     {