Commit 3d267297 authored by David Jarvie's avatar David Jarvie
Browse files

Bug 461713: Fix handling of times which repeat during DST -> standard time shift

The daylight savings flag in QDateTime values was not taken account of
by KADateTime. This fix ensures that the first and second occurrences
of times during a daylight savings time -> standard time shift are
handled correctly, and that the KADateTime::secondOccurrence()
value corresponds with the QDateTime::isDaylightTime() value.
parent ba6758f5
Pipeline #269697 passed with stage
in 1 minute and 53 seconds
......@@ -2,7 +2,7 @@
This file is part of kalarmcal library, which provides access to KAlarm
calendar data.
SPDX-FileCopyrightText: 2005-2021 David Jarvie <djarvie@kde.org>
SPDX-FileCopyrightText: 2005-2022 David Jarvie <djarvie@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
......@@ -2572,39 +2572,49 @@ void KADateTimeTest::dstShifts()
QDateTime qdt(QDate(2005, 10, 29), QTime(23, 59, 59), Qt::UTC);
KADateTime dt(qdt, london);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
QCOMPARE(dt.date(), QDate(2005, 10, 30));
QCOMPARE(dt.time(), QTime(0, 59, 59));
dt = KADateTime(QDateTime(QDate(2005, 10, 30), QTime(0, 0, 0), Qt::UTC), london);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
QCOMPARE(dt.date(), QDate(2005, 10, 30));
QCOMPARE(dt.time(), QTime(1, 0, 0));
dt = KADateTime(QDateTime(QDate(2005, 10, 30), QTime(0, 59, 59), Qt::UTC), london);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
QCOMPARE(dt.date(), QDate(2005, 10, 30));
QCOMPARE(dt.time(), QTime(1, 59, 59));
dt = KADateTime(QDateTime(QDate(2005, 10, 30), QTime(1, 0, 0), Qt::UTC), london);
QVERIFY(dt.isSecondOccurrence());
QVERIFY(!dt.qDateTime().isDaylightTime());
QCOMPARE(dt.date(), QDate(2005, 10, 30));
QCOMPARE(dt.time(), QTime(1, 0, 0));
dt = KADateTime(QDateTime(QDate(2005, 10, 30), QTime(1, 59, 59), Qt::UTC), london);
QVERIFY(dt.isSecondOccurrence());
QVERIFY(!dt.qDateTime().isDaylightTime());
QCOMPARE(dt.date(), QDate(2005, 10, 30));
QCOMPARE(dt.time(), QTime(1, 59, 59));
dt = KADateTime(QDateTime(QDate(2005, 10, 30), QTime(2, 0, 0), Qt::UTC), london);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(!dt.qDateTime().isDaylightTime());
QCOMPARE(dt.date(), QDate(2005, 10, 30));
QCOMPARE(dt.time(), QTime(2, 0, 0));
dt = KADateTime(QDate(2005, 10, 30), QTime(0, 59, 59), london);
dt.setSecondOccurrence(true); // this has no effect
QVERIFY(dt.qDateTime().isDaylightTime());
QCOMPARE(dt.toUtc().date(), QDate(2005, 10, 29));
QCOMPARE(dt.toUtc().time(), QTime(23, 59, 59));
dt = KADateTime(QDate(2005, 10, 30), QTime(1, 0, 0), london);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
QCOMPARE(dt.toUtc().date(), QDate(2005, 10, 30));
QCOMPARE(dt.toUtc().time(), QTime(0, 0, 0));
dt = KADateTime(QDate(2005, 10, 30), QTime(1, 59, 59), london);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
QCOMPARE(dt.toUtc().date(), QDate(2005, 10, 30));
QCOMPARE(dt.toUtc().time(), QTime(0, 59, 59));
dt = KADateTime(QDate(2005, 10, 30), QTime(1, 0, 0), london);
......@@ -2612,34 +2622,170 @@ void KADateTimeTest::dstShifts()
QCOMPARE(dt.toUtc().date(), QDate(2005, 10, 30));
QCOMPARE(dt.toUtc().time(), QTime(1, 0, 0));
QVERIFY(dt.isSecondOccurrence());
QVERIFY(!dt.qDateTime().isDaylightTime());
dt = KADateTime(QDate(2005, 10, 30), QTime(1, 59, 59), london);
dt.setSecondOccurrence(true);
QCOMPARE(dt.toUtc().date(), QDate(2005, 10, 30));
QCOMPARE(dt.toUtc().time(), QTime(1, 59, 59));
QVERIFY(dt.isSecondOccurrence());
QVERIFY(!dt.qDateTime().isDaylightTime());
dt = KADateTime(QDate(2005, 10, 30), QTime(2, 0, 0), london);
dt.setSecondOccurrence(true); // this has no effect
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(!dt.qDateTime().isDaylightTime());
QCOMPARE(dt.toUtc().date(), QDate(2005, 10, 30));
QCOMPARE(dt.toUtc().time(), QTime(2, 0, 0));
dt = KADateTime(QDate(2005, 10, 30), QTime(0, 59, 59), london);
KADateTime dt1 = dt.addSecs(1); // local time 01:00:00
QVERIFY(!dt1.isSecondOccurrence());
QVERIFY(dt1.qDateTime().isDaylightTime());
dt1 = dt.addSecs(3600); // local time 01:59:59
QVERIFY(!dt1.isSecondOccurrence());
QVERIFY(dt1.qDateTime().isDaylightTime());
dt1 = dt.addSecs(3601); // local time 01:00:00
QVERIFY(dt1.isSecondOccurrence());
QVERIFY(!dt1.qDateTime().isDaylightTime());
dt1 = dt.addSecs(7200); // local time 01:59:59
QVERIFY(dt1.isSecondOccurrence());
QVERIFY(!dt1.qDateTime().isDaylightTime());
dt1 = dt.addSecs(7201); // local time 02:00:00
QVERIFY(!dt1.isSecondOccurrence());
QVERIFY(!dt1.qDateTime().isDaylightTime());
QVERIFY(KADateTime(QDate(2005, 10, 29), london) == KADateTime(QDate(2005, 10, 29), KADateTime::Spec::OffsetFromUTC(3600)));
QVERIFY(KADateTime(QDate(2005, 10, 30), london) != KADateTime(QDate(2005, 10, 30), KADateTime::Spec::OffsetFromUTC(3600)));
QVERIFY(KADateTime(QDate(2005, 10, 30), london) != KADateTime(QDate(2005, 10, 30), KADateTime::Spec::OffsetFromUTC(0)));
QVERIFY(KADateTime(QDate(2005, 10, 31), london) == KADateTime(QDate(2005, 10, 31), KADateTime::Spec::OffsetFromUTC(0)));
// Constructor (QDateTime)
qdt = QDateTime(QDate(2005, 10, 30), QTime(0, 59, 59), london);
bool dst = qdt.isDaylightTime();
dt = KADateTime(qdt);
QVERIFY(!dt.isSecondOccurrence());
QCOMPARE(dt.qDateTime().isDaylightTime(), dst);
qdt = QDateTime(QDate(2005, 10, 30), QTime(1, 0, 0), london);
dst = qdt.isDaylightTime();
dt = KADateTime(qdt);
QCOMPARE(dt.isSecondOccurrence(), !dst);
QCOMPARE(dt.qDateTime().isDaylightTime(), dst);
qdt = QDateTime(QDate(2005, 10, 30), QTime(1, 59, 59), london);
dst = qdt.isDaylightTime();
dt = KADateTime(qdt);
QCOMPARE(dt.isSecondOccurrence(), !dst);
QCOMPARE(dt.qDateTime().isDaylightTime(), dst);
qdt = QDateTime(QDate(2005, 10, 30), QTime(2, 0, 0), london);
dst = qdt.isDaylightTime();
dt = KADateTime(qdt);
QVERIFY(!dt.isSecondOccurrence());
QCOMPARE(dt.qDateTime().isDaylightTime(), dst);
// Set local time to London
qputenv("TZ", ":Europe/London");
::tzset();
qdt = QDateTime(QDate(2005, 10, 30), QTime(0, 59, 59), Qt::LocalTime);
dst = qdt.isDaylightTime();
dt = KADateTime(qdt);
QVERIFY(!dt.isSecondOccurrence());
QCOMPARE(dt.qDateTime().isDaylightTime(), dst);
qdt = QDateTime(QDate(2005, 10, 30), QTime(1, 0, 0), Qt::LocalTime);
dst = qdt.isDaylightTime();
dt = KADateTime(qdt);
QCOMPARE(dt.isSecondOccurrence(), !dst);
QCOMPARE(dt.qDateTime().isDaylightTime(), dst);
qdt = QDateTime(QDate(2005, 10, 30), QTime(1, 59, 59), Qt::LocalTime);
dst = qdt.isDaylightTime();
dt = KADateTime(qdt);
QCOMPARE(dt.isSecondOccurrence(), !dst);
QCOMPARE(dt.qDateTime().isDaylightTime(), dst);
qdt = QDateTime(QDate(2005, 10, 30), QTime(2, 0, 0), Qt::LocalTime);
dst = qdt.isDaylightTime();
dt = KADateTime(qdt);
QVERIFY(!dt.isSecondOccurrence());
QCOMPARE(dt.qDateTime().isDaylightTime(), dst);
// setDate()
dt = KADateTime(QDate(2005, 10, 29), QTime(1, 59, 59), london);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt.setDate(QDate(2005, 10, 30));
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt = KADateTime(QDate(2005, 10, 30), QTime(1, 59, 59), london);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt.setDate(QDate(2005, 10, 31));
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(!dt.qDateTime().isDaylightTime());
dt = KADateTime(QDate(2005, 10, 30), QTime(1, 59, 59), london);
dt.setSecondOccurrence(true);
QVERIFY(dt.isSecondOccurrence());
QVERIFY(!dt.qDateTime().isDaylightTime());
dt.setDate(QDate(2005, 10, 31));
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(!dt.qDateTime().isDaylightTime());
// setTime()
dt = KADateTime(QDate(2005, 10, 29), QTime(1, 59, 59), london);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt.setTime(QTime(5, 30, 25));
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt = KADateTime(QDate(2005, 10, 30), QTime(1, 59, 59), london);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt.setTime(QTime(1, 30, 25));
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt = KADateTime(QDate(2005, 10, 30), QTime(1, 59, 59), london);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt.setTime(QTime(5, 30, 25));
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(!dt.qDateTime().isDaylightTime());
dt = KADateTime(QDate(2005, 10, 30), QTime(1, 59, 59), london);
dt.setSecondOccurrence(true);
QVERIFY(dt.isSecondOccurrence());
QVERIFY(!dt.qDateTime().isDaylightTime());
dt.setTime(QTime(1, 30, 25));
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt = KADateTime(QDate(2005, 10, 30), QTime(1, 59, 59), london);
dt.setSecondOccurrence(true);
QVERIFY(dt.isSecondOccurrence());
QVERIFY(!dt.qDateTime().isDaylightTime());
dt.setTime(QTime(5, 30, 25));
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(!dt.qDateTime().isDaylightTime());
// setDateOnly()
dt = KADateTime(QDate(2005, 10, 29), QTime(1, 59, 59), london);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt.setDateOnly(true);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt = KADateTime(QDate(2005, 10, 30), QTime(1, 59, 59), london);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt.setDateOnly(true);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt = KADateTime(QDate(2005, 10, 30), QTime(1, 59, 59), london);
dt.setSecondOccurrence(true);
QVERIFY(dt.isSecondOccurrence());
QVERIFY(!dt.qDateTime().isDaylightTime());
dt.setDateOnly(true);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt = KADateTime(QDate(2005, 10, 30), london);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
dt.setDateOnly(false);
QVERIFY(!dt.isSecondOccurrence());
QVERIFY(dt.qDateTime().isDaylightTime());
// Restore the original local time zone
if (originalZone.isEmpty()) {
unsetenv("TZ");
......
This diff is collapsed.
......@@ -685,6 +685,16 @@ public:
*/
bool isSecondOccurrence() const;
/**
* Returns whether the date/time falls within daylight savings time in its
* time zone.
*
* @return @c true if daylight savings time applies;
* @c false if standard time applies, or if timeSpec() is not
* TimeZone or LocalZone.
*/
bool isDaylightTime() const;
/**
* Returns the time converted to UTC. The converted time has a UTC offset
* of zero.
......@@ -789,6 +799,9 @@ public:
* value. If its status is changed to date-only, its time is set to
* 00:00:00.
*
* If the resultant date/time occurs twice due to a daylight savings time
* shift, it is set to the first occurrence (before the time shift).
*
* @param dateOnly @c true to set to date-only, @c false to set to date
* and time.
* @see isDateOnly(), setTime()
......@@ -798,6 +811,9 @@ public:
/**
* Sets the date part of the date/time.
*
* If the resultant date/time occurs twice due to a daylight savings time
* shift, it is set to the first occurrence (before the time shift).
*
* @param date new date value
* @see date(), setTime(), setTimeSpec(), setSecsSinceEpoch(), setDateOnly()
*/
......@@ -807,6 +823,9 @@ public:
* Sets the time part of the date/time. If the instance was date-only, it
* is changed to being a date and time value.
*
* If the resultant date/time occurs twice due to a daylight savings time
* shift, it is set to the first occurrence (before the time shift).
*
* @param time new time value
* @see time(), setDate(), setTimeSpec(), setSecsSinceEpoch()
*/
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment