summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Adams <chris.adams@jollamobile.com>2015-11-02 19:45:48 +1000
committerChristopher Adams <chris.adams@jollamobile.com>2015-11-12 03:08:13 +0000
commit56ac971415fee9bdaa01fc052246ce91fc4374e9 (patch)
tree954b6648bd328fc0f510108317245fb1b6516acc
parent480303e8ee89fb1d39b4f00f77559f3021e2ccae (diff)
QtOrganizer: fix date-only value handling to avoid UTC conversion
Some functions take JS Date parameters which can be either intended to be QDate or QDateTime values. Previously these functions had always assumed that the Date parameter was a fully-specified datetime and performed a toUtc() conversion before extracting the date part. For example, new Date("January 1, 1986") would be converted to a QDateTime and then have the local-to-UTC timezone transformation applied, which could result in an incorrect date. This commit ensures that in those cases, we detect whether the Date was most likely constructed as a date-only Date, and in those cases we immediately extract the date part without performing a toUtc() conversion. Change-Id: I8f76cccc2fc27df2115965c78288e16185b1a0c8 Reviewed-by: Matthew Vogt <matthew.vogt@qinetic.com.au> Reviewed-by: Renato Araujo Oliveira Filho <renato.filho@canonical.com> Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
-rw-r--r--src/imports/organizer/qdeclarativeorganizeritemdetail.cpp67
-rw-r--r--tests/auto/organizer/qmlorganizer/testcases/tst_organizeritemdetail.qml35
2 files changed, 81 insertions, 21 deletions
diff --git a/src/imports/organizer/qdeclarativeorganizeritemdetail.cpp b/src/imports/organizer/qdeclarativeorganizeritemdetail.cpp
index 58d9d2461..40474b44e 100644
--- a/src/imports/organizer/qdeclarativeorganizeritemdetail.cpp
+++ b/src/imports/organizer/qdeclarativeorganizeritemdetail.cpp
@@ -662,7 +662,16 @@ bool QDeclarativeOrganizerItemParent::setValue(int field, const QVariant &value)
void QDeclarativeOrganizerItemParent::setOriginalDate(const QDateTime &date)
{
if (date != originalDate()) {
- m_detail.setValue(QOrganizerItemParent::FieldOriginalDate, date.date());
+ // If the value was likely set as a QDate, then assume that the time info can be ignored.
+ // This is to ensure that dates like "2002-01-01" don't get interpretted as being
+ // "2002-01-01T00:00:00+10:00" if the local timezone is GMT+10, and then being converted
+ // to "2001-31-12T14:00:00Z" in UTC before having the (different) date "2001-31-12"
+ // extracted for insertion into the FieldResponseDeadline value.
+ if (date.timeSpec() == Qt::LocalTime && date.time() == QTime(0,0,0,0)) {
+ m_detail.setValue(QOrganizerItemParent::FieldOriginalDate, date.date());
+ } else {
+ m_detail.setValue(QOrganizerItemParent::FieldOriginalDate, date.toUTC().date());
+ }
emit valueChanged();
}
}
@@ -908,9 +917,20 @@ void QDeclarativeOrganizerItemRecurrence::setRecurrenceDates(const QVariantList
if (dates != recurrenceDates()) {
QSet<QDate> dateSet;
QVariant dateSetVariant;
- foreach (QVariant date, dates) {
- if (date.canConvert(QVariant::DateTime))
- dateSet.insert(date.toDateTime().toUTC().date());
+ Q_FOREACH (const QVariant &date, dates) {
+ if (date.canConvert(QVariant::DateTime)) {
+ QDateTime dt = date.toDateTime();
+ // If the value was likely set as a QDate, then assume that the time info can be ignored.
+ // This is to ensure that dates like "2002-01-01" don't get interpretted as being
+ // "2002-01-01T00:00:00+10:00" if the local timezone is GMT+10, and then being converted
+ // to "2001-31-12T14:00:00Z" in UTC before having the (different) date "2001-31-12"
+ // extracted for insertion into the dateSet.
+ if (dt.timeSpec() == Qt::LocalTime && dt.time() == QTime(0,0,0,0)) {
+ dateSet.insert(dt.date());
+ } else {
+ dateSet.insert(dt.toUTC().date());
+ }
+ }
}
dateSetVariant.setValue(dateSet);
m_detail.setValue(QOrganizerItemRecurrence::FieldRecurrenceDates, dateSetVariant);
@@ -940,9 +960,20 @@ void QDeclarativeOrganizerItemRecurrence::setExceptionDates(const QVariantList&
if (dates != exceptionDates()) {
QSet<QDate> dateSet;
QVariant dateSetVariant;
- foreach (QVariant date, dates) {
- if (date.canConvert(QVariant::DateTime))
- dateSet.insert(date.toDateTime().toUTC().date());
+ Q_FOREACH (const QVariant &date, dates) {
+ if (date.canConvert(QVariant::DateTime)) {
+ QDateTime dt = date.toDateTime();
+ // If the value was likely set as a QDate, then assume that the time info can be ignored.
+ // This is to ensure that dates like "2002-01-01" don't get interpretted as being
+ // "2002-01-01T00:00:00+10:00" if the local timezone is GMT+10, and then being converted
+ // to "2001-31-12T14:00:00Z" in UTC before having the (different) date "2001-31-12"
+ // extracted for insertion into the dateSet.
+ if (dt.timeSpec() == Qt::LocalTime && dt.time() == QTime(0,0,0,0)) {
+ dateSet.insert(dt.date());
+ } else {
+ dateSet.insert(dt.toUTC().date());
+ }
+ }
}
dateSetVariant.setValue(dateSet);
m_detail.setValue(QOrganizerItemRecurrence::FieldExceptionDates, dateSetVariant);
@@ -2188,7 +2219,16 @@ QDeclarativeOrganizerEventRsvp::ResponseRequirement QDeclarativeOrganizerEventRs
void QDeclarativeOrganizerEventRsvp::setResponseDeadline(const QDateTime &date)
{
if (responseDeadline() != date) {
- m_detail.setValue(QOrganizerEventRsvp::FieldResponseDeadline, date.toUTC().date());
+ // If the value was likely set as a QDate, then assume that the time info can be ignored.
+ // This is to ensure that dates like "2002-01-01" don't get interpretted as being
+ // "2002-01-01T00:00:00+10:00" if the local timezone is GMT+10, and then being converted
+ // to "2001-31-12T14:00:00Z" in UTC before having the (different) date "2001-31-12"
+ // extracted for insertion into the FieldResponseDeadline value.
+ if (date.timeSpec() == Qt::LocalTime && date.time() == QTime(0,0,0,0)) {
+ m_detail.setValue(QOrganizerEventRsvp::FieldResponseDeadline, date.date());
+ } else {
+ m_detail.setValue(QOrganizerEventRsvp::FieldResponseDeadline, date.toUTC().date());
+ }
emit valueChanged();
}
}
@@ -2207,7 +2247,16 @@ QDateTime QDeclarativeOrganizerEventRsvp::responseDeadline() const
void QDeclarativeOrganizerEventRsvp::setResponseDate(const QDateTime &date)
{
if (responseDate() != date) {
- m_detail.setValue(QOrganizerEventRsvp::FieldResponseDate, date.toUTC().date());
+ // If the value was likely set as a QDate, then assume that the time info can be ignored.
+ // This is to ensure that dates like "2002-01-01" don't get interpretted as being
+ // "2002-01-01T00:00:00+10:00" if the local timezone is GMT+10, and then being converted
+ // to "2001-31-12T14:00:00Z" in UTC before having the (different) date "2001-31-12"
+ // extracted for insertion into the FieldResponseDate value.
+ if (date.timeSpec() == Qt::LocalTime && date.time() == QTime(0,0,0,0)) {
+ m_detail.setValue(QOrganizerEventRsvp::FieldResponseDate, date.date());
+ } else {
+ m_detail.setValue(QOrganizerEventRsvp::FieldResponseDate, date.toUTC().date());
+ }
emit valueChanged();
}
}
diff --git a/tests/auto/organizer/qmlorganizer/testcases/tst_organizeritemdetail.qml b/tests/auto/organizer/qmlorganizer/testcases/tst_organizeritemdetail.qml
index cc1ad37e2..76de34396 100644
--- a/tests/auto/organizer/qmlorganizer/testcases/tst_organizeritemdetail.qml
+++ b/tests/auto/organizer/qmlorganizer/testcases/tst_organizeritemdetail.qml
@@ -178,16 +178,19 @@ TestCase {
function test_recurrenceDateArrays_data() {
return [
{tag: "basic date object", testValue: [new Date(2012, 2, 16, 11, 00, 00)]},
- {tag: "date object from string", testValue: [new Date("January 1, 1986")]},
+ {tag: "date object from string", testValue: [new Date("January 1, 1986")], expectedValue: ['1986-01-01']},
{tag: "date object from ISO date", testValue: [new Date('2014-01-01')]},
{tag: "datetime object from string", testValue: [new Date("October 13, 1975 11:13:00")]},
- // {tag: "date string", testValue: ['2013-01-01']}, // TODO fix conversion to UTC from string
- // {tag: "datetime string", testValue: ['2013-10-23T23:55:00']}, // TODO fix conversion to UTC from string
+ {tag: "date string at year boundary lower", testValue: ['2013-01-01']},
+ {tag: "date string at year boundary upper", testValue: ['2013-12-31']},
+ {tag: "datetime string", testValue: ['2013-10-23T23:55:00']},
{tag: "datetime string ISO 8601 Z", testValue: ['1997-07-16T19:20:30.45Z']},
{tag: "datetime string ISO 8601 +01", testValue: ['1997-07-16T19:20:30.45+01:00']},
{tag: "datetime string ISO 8601 +10", testValue: ['1997-07-16T19:20:30.45+10:00']},
{tag: "datetime string ISO 8601 -01", testValue: ['1997-07-16T19:20:30.45-01:00']},
- {tag: "datetime string ISO 8601 -10", testValue: ['1997-07-16T19:20:30.45-10:00']}
+ {tag: "datetime string ISO 8601 -10", testValue: ['1997-07-16T19:20:30.45-10:00']},
+ {tag: "datetime string ISO 8601 +10 at boundary", testValue: ['1997-01-01T00:00:01.45+10:00']},
+ {tag: "datetime string ISO 8601 -10 at boundary", testValue: ['1997-12-31T23:59:59.45-10:00']}
]
}
function test_recurrenceDateArrays(data) {
@@ -199,7 +202,8 @@ TestCase {
detailChangedSpy.signalName = "detailChanged"
var testDate = (typeof data.testValue[0] == 'string') ? new Date(data.testValue[0]) : data.testValue[0];
- var testDateUTCMidnight = utility.toUTCMidnight(testDate);;
+ var expectedDate = (data.hasOwnProperty('expectedValue') && typeof data.expectedValue[0] == 'string') ? new Date(data.expectedValue[0]) : testDate;
+ var testDateUTCMidnight = utility.toUTCMidnight(expectedDate);
if (isNaN(testDate.getTime())) {
warn("test \"" + data.tag + "\" contains incorrect date");
@@ -457,8 +461,6 @@ TestCase {
function test_parent() {
compare(parent.type, Detail.Parent)
- skip('TODO should be fixed conversion between local time and UTC to avoid a double conversion')
-
compare(parent.value(Parent.FieldOriginalDate), undefined)
var originalDate = new Date("2008-12-28")
parent.originalDate = originalDate
@@ -474,6 +476,11 @@ TestCase {
parent.setValue(Parent.FieldOriginalDate, "2008-01-01")
compare(parent.originalDate, originalDate2UTC)
compare(parent.value(Parent.FieldOriginalDate), originalDate2UTC)
+
+ var originalDate3 = new Date("January 1, 2008")
+ parent.setValue(Parent.FieldOriginalDate, originalDate3)
+ compare(parent.originalDate, originalDate2UTC)
+ compare(parent.value(Parent.FieldOriginalDate), originalDate2UTC)
}
function test_location() {
@@ -662,16 +669,19 @@ TestCase {
function test_rsvpDateProperties_data() {
return [
{tag: "basic date object", testValue: new Date(2012, 2, 16, 11, 00, 00)},
- {tag: "date object from string", testValue: new Date("January 1, 1986")},
+ {tag: "date object from string", testValue: new Date("January 1, 1986"), expectedValue: '1986-01-01'},
{tag: "date object from ISO date", testValue: new Date('2014-01-01')},
{tag: "datetime object from string", testValue: new Date("October 13, 1975 11:13:00")},
- // {tag: "date string", testValue: '2013-01-01'}, // TODO test fails for TZ=EET
- // {tag: "datetime string", testValue: '2013-10-23T23:55:00'}, // TODO test fails for TZ=HST
+ {tag: "date string at year boundary lower", testValue: '2013-01-01'},
+ {tag: "date string at year boundary upper", testValue: '2013-12-31'},
+ {tag: "datetime string", testValue: '2013-10-23T23:55:00'},
{tag: "datetime string ISO 8601 Z", testValue: '1997-07-16T19:20:30.45Z'},
{tag: "datetime string ISO 8601 +01", testValue: '1997-07-16T19:20:30.45+01:00'},
{tag: "datetime string ISO 8601 +10", testValue: '1997-07-16T19:20:30.45+10:00'},
{tag: "datetime string ISO 8601 -01", testValue: '1997-07-16T19:20:30.45-01:00'},
- {tag: "datetime string ISO 8601 -10", testValue: '1997-07-16T19:20:30.45-10:00'}
+ {tag: "datetime string ISO 8601 -10", testValue: '1997-07-16T19:20:30.45-10:00'},
+ {tag: "datetime string ISO 8601 +10 at boundary", testValue: '1997-01-01T00:00:01.45+10:00'},
+ {tag: "datetime string ISO 8601 -10 at boundary", testValue: '1997-12-31T23:59:59.45-10:00'}
]
}
function test_rsvpDateProperties(data) {
@@ -684,7 +694,8 @@ TestCase {
detailChangedSpy.signalName = "detailChanged"
var testDate = (typeof data.testValue == 'string') ? new Date(data.testValue) : data.testValue;
- var testDateUTCMidnight = utility.toUTCMidnight(testDate);
+ var expectedDate = (data.hasOwnProperty('expectedValue') && typeof data.expectedValue == 'string') ? new Date(data.expectedValue) : testDate;
+ var testDateUTCMidnight = utility.toUTCMidnight(expectedDate);
if (isNaN(testDate.getTime())) {
warn("test \"" + data.tag + "\" contains incorrect date");