Skip to content
This repository has been archived by the owner on Nov 11, 2021. It is now read-only.

Commit

Permalink
Fixed the recurrence calculation
Browse files Browse the repository at this point in the history
This is a cherry-pick of 87f869098862d43793025445cd2d72d04ffd0e91
from upstream
  • Loading branch information
cmollekopf authored and Chris Adams committed Oct 8, 2019
1 parent 2ee568f commit de179ab
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 6 deletions.
19 changes: 13 additions & 6 deletions kcalcore/recurrencerule.cpp
Expand Up @@ -1761,13 +1761,20 @@ DateTimeList RecurrenceRule::timesInInterval( const KDateTime &dtStart,

if ( d->mTimedRepetition ) {
// It's a simple sub-daily recurrence with no constraints
int n = static_cast<int>( ( d->mDateStart.secsTo_long( start ) - 1 ) % d->mTimedRepetition );
KDateTime dt = start.addSecs( d->mTimedRepetition - n );
if ( dt < enddt ) {
n = static_cast<int>( ( dt.secsTo_long( enddt ) - 1 ) / d->mTimedRepetition ) + 1;

//Seconds to add to interval start, to get first occurrence which is within interval
qint64 offsetFromNextOccurrence;
if (d->mDateStart < start) {
offsetFromNextOccurrence = d->mTimedRepetition - (d->mDateStart.secsTo_long( start ) % d->mTimedRepetition);
} else {
offsetFromNextOccurrence = -(d->mDateStart.secsTo_long( start ) % d->mTimedRepetition);
}
KDateTime dt = start.addSecs( offsetFromNextOccurrence );
if ( dt <= enddt ) {
int numberOfOccurrencesWithinInterval = static_cast<int>( dt.secsTo_long( enddt ) / d->mTimedRepetition ) + 1;
// limit n by a sane value else we can "explode".
n = qMin( n, LOOP_LIMIT );
for ( int i = 0; i < n; dt = dt.addSecs( d->mTimedRepetition ), ++i ) {
numberOfOccurrencesWithinInterval = qMin( numberOfOccurrencesWithinInterval, LOOP_LIMIT );
for ( int i = 0; i < numberOfOccurrencesWithinInterval; dt = dt.addSecs( d->mTimedRepetition ), ++i ) {
result += dt;
}
}
Expand Down
70 changes: 70 additions & 0 deletions kcalcore/tests/testtimesininterval.cpp
Expand Up @@ -83,3 +83,73 @@ void TimesInIntervalTest::test()
//------------------------------------------------------------------------------------------------
}

//Test that interval start and end are inclusive
void TimesInIntervalTest::testSubDailyRecurrenceIntervalInclusive()
{
const KDateTime start(QDate(2013, 03, 10), QTime(10, 0, 0), KDateTime::UTC);
const KDateTime end(QDate(2013, 03, 10), QTime(11, 0, 0), KDateTime::UTC);

KCalCore::Event::Ptr event(new KCalCore::Event());
event->setUid("event");
event->setDtStart(start);
event->recurrence()->setHourly(1);
event->recurrence()->setDuration(2);

QList<KDateTime> expectedEventOccurrences;
expectedEventOccurrences << start << start.addSecs(60*60);

const DateTimeList timesInInterval = event->recurrence()->timesInInterval(start, end);
// kDebug() << "timesInInterval " << timesInInterval;
foreach (const KDateTime &dt, timesInInterval) {
// kDebug() << dt;
QCOMPARE(expectedEventOccurrences.removeAll(dt), 1);
}
QCOMPARE(expectedEventOccurrences.size(), 0);
}

//Test that the recurrence dtStart is used for calculation and not the interval start date
void TimesInIntervalTest::testSubDailyRecurrence2()
{
const KDateTime start(QDate(2013, 03, 10), QTime(10, 2, 3), KDateTime::UTC);
const KDateTime end(QDate(2013, 03, 10), QTime(13, 4, 5), KDateTime::UTC);

KCalCore::Event::Ptr event(new KCalCore::Event());
event->setUid("event");
event->setDtStart(start);
event->recurrence()->setHourly(1);
event->recurrence()->setDuration(2);

QList<KDateTime> expectedEventOccurrences;
expectedEventOccurrences << start << start.addSecs(60*60);

const DateTimeList timesInInterval = event->recurrence()->timesInInterval(start.addSecs(-20), end.addSecs(20));
// kDebug() << "timesInInterval " << timesInInterval;
foreach (const KDateTime &dt, timesInInterval) {
// kDebug() << dt;
QCOMPARE(expectedEventOccurrences.removeAll(dt), 1);
}
QCOMPARE(expectedEventOccurrences.size(), 0);
}

void TimesInIntervalTest::testSubDailyRecurrenceIntervalLimits()
{
const KDateTime start(QDate(2013, 03, 10), QTime(10, 2, 3), KDateTime::UTC);
const KDateTime end(QDate(2013, 03, 10), QTime(12, 2, 3), KDateTime::UTC);

KCalCore::Event::Ptr event(new KCalCore::Event());
event->setUid("event");
event->setDtStart(start);
event->recurrence()->setHourly(1);
event->recurrence()->setDuration(3);

QList<KDateTime> expectedEventOccurrences;
expectedEventOccurrences << start.addSecs(60*60);

const DateTimeList timesInInterval = event->recurrence()->timesInInterval(start.addSecs(1), end.addSecs(-1));
// kDebug() << "timesInInterval " << timesInInterval;
foreach (const KDateTime &dt, timesInInterval) {
// kDebug() << dt;
QCOMPARE(expectedEventOccurrences.removeAll(dt), 1);
}
QCOMPARE(expectedEventOccurrences.size(), 0);
}
3 changes: 3 additions & 0 deletions kcalcore/tests/testtimesininterval.h
Expand Up @@ -30,6 +30,9 @@ class TimesInIntervalTest : public QObject
Q_OBJECT
private Q_SLOTS:
void test();
void testSubDailyRecurrenceIntervalInclusive();
void testSubDailyRecurrence2();
void testSubDailyRecurrenceIntervalLimits();
};

#endif

0 comments on commit de179ab

Please sign in to comment.