Skip to content

Commit

Permalink
[mkcal] Fix some issues related to ClockTime handling. Contributes to…
Browse files Browse the repository at this point in the history
… JB#43708

When expanding events (to determine whether an event or its occurrences
should be returned within a given date-time range) we need to handle
both clock-time ranges, and clock-time events, specially.

That is, if an event is clock-time 10 am until clock-time 11 am, then
that event should be returned for any range covering 10 am -> 11 am,
regardless of what timezone is specified for that range.
  • Loading branch information
Chris Adams committed Nov 25, 2019
1 parent a86b0ab commit b285899
Show file tree
Hide file tree
Showing 4 changed files with 748 additions and 48 deletions.
85 changes: 60 additions & 25 deletions src/extendedcalendar.cpp
Expand Up @@ -52,6 +52,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 +950,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
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 b285899

Please sign in to comment.