Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge branch 'jb43708v3' into 'master'
[mkcal] Fix some issues related to ClockTime handling. Contributes to JB#43708

See merge request mer-core/mkcal!31
  • Loading branch information
chriadam committed Nov 27, 2019
2 parents a86b0ab + 9ee48a6 commit 9e4ec96
Show file tree
Hide file tree
Showing 7 changed files with 990 additions and 55 deletions.
87 changes: 62 additions & 25 deletions src/extendedcalendar.cpp
Expand Up @@ -5,6 +5,8 @@
Copyright (c) 2001,2003,2004 Cornelius Schumacher <schumacher@kde.org>
Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
Copyright (c) 2009 Alvaro Manera <alvaro.manera@nokia.com>
Copyright (c) 2014-2019 Jolla Ltd.
Copyright (c) 2019 Open Mobile Platform LLC.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
Expand Down Expand Up @@ -52,6 +54,23 @@ using namespace KCalCore;
// #ifdef to control expensive/spammy debug stmts
#undef DEBUG_EXPANSION

namespace {
// KDateTime::toClockTime() has the semantic that the input is first
// converted to the local system timezone, before having its timezone
// information stripped.
// In many cases in mkcal, we use clock-time to mean "floating"
// i.e. irrespective of timezone, and thus when converting to or from
// clock time, we don't want any conversion to the local system timezone
// to occur as part of that operation.
KDateTime kdatetimeAsTimeSpec(const KDateTime &input, const KDateTime::Spec &spec) {
if (input.isClockTime() || spec.type() == KDateTime::ClockTime) {
return KDateTime(input.date(), input.time(), spec);
} else {
return input.toTimeSpec(spec);
}
}
}

using namespace mKCal;
/**
Private class that helps to provide binary compatibility between releases.
Expand Down Expand Up @@ -933,47 +952,65 @@ ExtendedCalendar::ExpandedIncidenceList ExtendedCalendar::rawExpandedEvents(cons

KDateTime::Spec ts = timespec.isValid() ? timespec : timeSpec();
KDateTime ksdt(start, ts);
KDateTime kedt = KDateTime(end, QTime(23, 59, 59), ts);
KDateTime kedt = KDateTime(end.addDays(1), QTime(0, 0, 0), ts);

// Iterate over all events. Look for recurring events that occur on this date
QHashIterator<QString, Event::Ptr>i(d->mEvents);
while (i.hasNext()) {
i.next();
ev = i.value();
if (isVisible(ev)) {
const bool asClockTime = ev->dtStart().isClockTime() || ts.type() == KDateTime::ClockTime;
const KDateTime startTime = ev->dtStart();
const KDateTime endTime = ev->dtEnd();
const KDateTime rangeStartTime = (ev->allDay() && asClockTime)
? KDateTime(ksdt.date(), QTime(), KDateTime::ClockTime)
: ev->allDay() ? ksdt
: KDateTime(ksdt.date(), QTime(0,0,0), ksdt.timeSpec());
const KDateTime rangeEndTime = (ev->allDay() && asClockTime)
? KDateTime(kedt.date(), QTime(), KDateTime::ClockTime)
: kedt;
const KDateTime tsRangeStartTime = kdatetimeAsTimeSpec(rangeStartTime, ts);
const KDateTime tsRangeEndTime = kdatetimeAsTimeSpec(rangeEndTime, ts);
if (ev->recurs()) {

DateTimeList times;

int extraDays = (ev->isMultiDay() && !startInclusive) ?
ev->dtStart().date().daysTo(ev->dtEnd().date()) : 0;
times = ev->recurrence()->timesInInterval(ksdt.addDays(-extraDays), kedt);

for (int ii = 0; ii < times.count(); ++ii) {
KDateTime endDateTime = Duration(ev->dtStart(), ev->dtEnd()).end(times.at(ii));
if (endDateTime < ksdt || (endInclusive && endDateTime > kedt))
int extraDays = (ev->isMultiDay() && !startInclusive)
? startTime.date().daysTo(endTime.date())
: (ev->allDay() ? 1 : 0);
const KDateTime tsAdjustedRangeStartTime(tsRangeStartTime.addDays(-extraDays));
const DateTimeList times = ev->recurrence()->timesInInterval(tsAdjustedRangeStartTime, tsRangeEndTime);
for (const KDateTime &timeInInterval : times) {
const KDateTime tsStartTime = kdatetimeAsTimeSpec(timeInInterval, ts);
const KDateTime tsEndTime = Duration(startTime, endTime).end(tsStartTime);
if (tsStartTime >= tsRangeEndTime
|| tsEndTime <= tsAdjustedRangeStartTime
|| (endInclusive && (tsEndTime > tsRangeEndTime))) {
continue;
ExpandedIncidenceValidity eiv = { times.at(ii).toTimeSpec(ts).dateTime(),
endDateTime.toTimeSpec(ts).dateTime()
};
}
ExpandedIncidenceValidity eiv = {
tsStartTime.dateTime(),
tsEndTime.dateTime()
};
eventList.append(qMakePair(eiv, ev.dynamicCast<Incidence>()));
}

} else {
const KDateTime tsStartTime = kdatetimeAsTimeSpec(startTime, ts);
const KDateTime tsEndTime = kdatetimeAsTimeSpec(endTime, ts);
if (ev->isMultiDay()) {
if ((startInclusive == false || ev->dtStart() >= ksdt) &&
ev->dtStart() <= kedt && ev->dtEnd() >= ksdt &&
(endInclusive == false || ev->dtEnd() <= kedt)) {
ExpandedIncidenceValidity eiv = { ev->dtStart().toTimeSpec(ts).dateTime(),
ev->dtEnd().toTimeSpec(ts).dateTime()
};
if ((startInclusive == false || tsStartTime >= tsRangeStartTime) &&
tsStartTime <= tsRangeEndTime && tsEndTime >= tsRangeStartTime &&
(endInclusive == false || tsEndTime <= tsRangeEndTime)) {
ExpandedIncidenceValidity eiv = {
tsStartTime.dateTime(),
tsEndTime.dateTime()
};
eventList.append(qMakePair(eiv, ev.dynamicCast<Incidence>()));
}
} else {
if (ev->dtStart() >= ksdt && ev->dtStart() <= kedt) {
ExpandedIncidenceValidity eiv = { ev->dtStart().toTimeSpec(ts).dateTime(),
ev->dtEnd().toTimeSpec(ts).dateTime()
};
if (tsStartTime >= tsRangeStartTime && tsStartTime <= tsRangeEndTime) {
ExpandedIncidenceValidity eiv = {
tsStartTime.dateTime(),
tsEndTime.dateTime()
};
eventList.append(qMakePair(eiv, ev.dynamicCast<Incidence>()));
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/sqliteformat.cpp
Expand Up @@ -2,7 +2,8 @@
This file is part of the mkcal library.
Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
Contact: Alvaro Manera <alvaro.manera@nokia.com>
Copyright (c) 2014-2019 Jolla Ltd.
Copyright (c) 2019 Open Mobile Platform LLC.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
Expand Down Expand Up @@ -1114,6 +1115,12 @@ static KDateTime getDateTime(SqliteStorage *storage, sqlite3_stmt *stmt, int ind
} else {
date = sqlite3_column_int64(stmt, index);
dateTime = storage->fromOriginTime(date, timezone);
if (!dateTime.isValid()) {
// timezone is specified but invalid?
// fall back to local seconds from origin as clock time.
date = sqlite3_column_int64(stmt, index + 1);
dateTime = storage->fromLocalOriginTime(date);
}
}
if (isDate) {
QTime localTime(dateTime.toLocalZone().time());
Expand Down
16 changes: 11 additions & 5 deletions src/sqlitestorage.cpp
Expand Up @@ -2,7 +2,8 @@
This file is part of the mkcal library.
Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
Contact: Alvaro Manera <alvaro.manera@nokia.com>
Copyright (c) 2014-2019 Jolla Ltd.
Copyright (c) 2019 Open Mobile Platform LLC.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
Expand Down Expand Up @@ -3020,6 +3021,13 @@ sqlite3_int64 SqliteStorage::toLocalOriginTime(KDateTime dt)
+ dt1.time().secsTo(dt2.time());
}

KDateTime SqliteStorage::fromLocalOriginTime(sqlite3_int64 seconds)
{
// Note: don't call toClockTime() as that implies a conversion first to the local time zone.
KDateTime local(d->mOriginTime.addSecs(seconds));
return KDateTime(local.date(), local.time(), KDateTime::ClockTime);
}

KDateTime SqliteStorage::fromOriginTime(sqlite3_int64 seconds)
{
//qCDebug(lcMkcal) << "fromOriginTime" << seconds << d->mOriginTime.addSecs( seconds ).toUtc();
Expand All @@ -3041,12 +3049,10 @@ KDateTime SqliteStorage::fromOriginTime(sqlite3_int64 seconds, QString zonename)
// Then try calendar specific zones.
ICalTimeZones::ZoneMap zones = d->mCalendar->timeZones()->zones();
ICalTimeZone icaltimezone = zones.value(zonename);
if (icaltimezone.isValid()) {
const QByteArray emptyTz = "BEGIN:VTIMEZONE\r\nTZID:" + zonename.toUtf8() + "\r\nEND:VTIMEZONE\r\n";
if (icaltimezone.isValid() && icaltimezone.vtimezone() != emptyTz) {
dt =
d->mOriginTime.addSecs(seconds).toUtc().toTimeSpec(KDateTime::Spec(icaltimezone));
} else {
// Invalid zone, fall back to UTC.
dt = d->mOriginTime.addSecs(seconds).toUtc();
}
}
} else {
Expand Down
10 changes: 9 additions & 1 deletion src/sqlitestorage.h
Expand Up @@ -2,7 +2,8 @@
This file is part of the mkcal library.
Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
Contact: Alvaro Manera <alvaro.manera@nokia.com>
Copyright (c) 2014-2019 Jolla Ltd.
Copyright (c) 2019 Open Mobile Platform LLC.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
Expand Down Expand Up @@ -360,6 +361,13 @@ class MKCAL_EXPORT SqliteStorage : public ExtendedStorage
*/
sqlite3_int64 toLocalOriginTime(KDateTime dt);

/**
Convert seconds from the origin to clock time.
@param seconds relative to origin.
@return clocktime datetime.
*/
KDateTime fromLocalOriginTime(sqlite3_int64 seconds);

/**
Convert seconds from the origin to UTC datetime.
@param seconds relative to origin.
Expand Down
2 changes: 1 addition & 1 deletion src/src.pro
Expand Up @@ -6,7 +6,7 @@ TARGET = mkcal-qt5

DEFINES += TIMED_SUPPORT

CONFIG += link_pkgconfig create_pc create_prl no_install_prl
CONFIG += link_pkgconfig create_pc create_prl no_install_prl c++11
PKGCONFIG += sqlite3 \
libkcalcoren-qt5 \
timed-qt5
Expand Down

0 comments on commit 9e4ec96

Please sign in to comment.