23 #include "recurrencerule.h"
26 #include <tdeglobal.h>
27 #include <tqdatetime.h>
28 #include <tqstringlist.h>
36 const int LOOP_LIMIT = 10000;
60 long long ownSecsTo(
const TQDateTime &dt1,
const TQDateTime &dt2 )
62 long long res =
static_cast<long long>( dt1.date().daysTo( dt2.date() ) ) * 24*3600;
63 res += dt1.time().secsTo( dt2.time() );
77 static TQString dayName(
short day );
79 static TQDate getNthWeek(
int year,
int weeknumber,
short weekstart = 1 );
80 static int weekNumbersInYear(
int year,
short weekstart = 1 );
81 static int getWeekNumber(
const TQDate &date,
short weekstart,
int *year = 0 );
82 static int getWeekNumberNeg(
const TQDate &date,
short weekstart,
int *year = 0 );
87 TQString DateHelper::dayName(
short day )
90 case 1:
return "MO";
break;
91 case 2:
return "TU";
break;
92 case 3:
return "WE";
break;
93 case 4:
return "TH";
break;
94 case 5:
return "FR";
break;
95 case 6:
return "SA";
break;
96 case 7:
return "SU";
break;
103 TQDate DateHelper::getNthWeek(
int year,
int weeknumber,
short weekstart )
105 if ( weeknumber == 0 )
return TQDate();
107 TQDate dt( year, 1, 4 );
108 int adjust = -(7 + dt.dayOfWeek() - weekstart) % 7;
109 if ( weeknumber > 0 ) {
110 dt = dt.addDays( 7 * (weeknumber-1) + adjust );
111 }
else if ( weeknumber < 0 ) {
112 dt = dt.addYears( 1 );
113 dt = dt.addDays( 7 * weeknumber + adjust );
119 int DateHelper::getWeekNumber(
const TQDate &date,
short weekstart,
int *year )
122 if ( year ) *year = date.year();
123 TQDate dt( date.year(), 1, 4 );
124 dt = dt.addDays( -(7 + dt.dayOfWeek() - weekstart) % 7 );
125 TQDate dtn( date.year()+1, 1, 4 );
126 dtn = dtn.addDays( -(7 + dtn.dayOfWeek() - weekstart) % 7 );
128 int daysto = dt.daysTo( date );
129 int dayston = dtn.daysTo( date );
131 if ( year ) *year = date.year()-1;
132 dt = TQDate( date.year()-1, 1, 4 );
133 dt = dt.addDays( -(7 + dt.dayOfWeek() - weekstart) % 7 );
134 daysto = dt.daysTo( date );
135 }
else if ( dayston >= 0 ) {
137 if ( year ) *year = date.year() + 1;
141 return daysto / 7 + 1;
144 int DateHelper::weekNumbersInYear(
int year,
short weekstart )
146 TQDate dt( year, 1, weekstart );
147 TQDate dt1( year + 1, 1, weekstart );
148 return dt.daysTo( dt1 ) / 7;
152 int DateHelper::getWeekNumberNeg(
const TQDate &date,
short weekstart,
int *year )
154 int weekpos = getWeekNumber( date, weekstart, year );
155 return weekNumbersInYear( *year, weekstart ) - weekpos - 1;
167 RecurrenceRule::Constraint::Constraint(
int wkst )
173 RecurrenceRule::Constraint::Constraint(
const TQDateTime &preDate, PeriodType type,
int wkst )
176 readDateTime( preDate, type );
179 void RecurrenceRule::Constraint::clear()
198 if ( weeknumber == 0 ) {
199 if ( year > 0 && year != dt.year() )
return false;
202 if ( weeknumber > 0 &&
203 weeknumber != DateHelper::getWeekNumber( dt, weekstart, &y ) )
return false;
204 if ( weeknumber < 0 &&
205 weeknumber != DateHelper::getWeekNumberNeg( dt, weekstart, &y ) )
return false;
206 if ( year > 0 && year != y )
return false;
209 if ( month > 0 && month != dt.month() )
return false;
210 if ( day > 0 && day != dt.day() )
return false;
211 if ( day < 0 && dt.day() != (dt.daysInMonth() + day + 1 ) )
return false;
213 if ( weekday != dt.dayOfWeek() )
return false;
214 if ( weekdaynr != 0 ) {
217 bool inMonth = (type == rMonthly) || ( type == rYearly && month > 0 );
219 if ( weekdaynr > 0 && inMonth &&
220 weekdaynr != (dt.day() - 1)/7 + 1 )
return false;
221 if ( weekdaynr < 0 && inMonth &&
222 weekdaynr != -((dt.daysInMonth() - dt.day() )/7 + 1 ) )
225 if ( weekdaynr > 0 && !inMonth &&
226 weekdaynr != (dt.dayOfYear() - 1)/7 + 1 )
return false;
227 if ( weekdaynr < 0 && !inMonth &&
228 weekdaynr != -((dt.daysInYear() - dt.dayOfYear() )/7 + 1 ) )
232 if ( yearday > 0 && yearday != dt.dayOfYear() )
return false;
233 if ( yearday < 0 && yearday != dt.daysInYear() - dt.dayOfYear() + 1 )
240 if ( !matches( dt.date(), type ) )
return false;
241 if ( hour >= 0 && hour != dt.time().hour() )
return false;
242 if ( minute >= 0 && minute != dt.time().minute() )
return false;
243 if ( second >= 0 && second != dt.time().second() )
return false;
247 bool RecurrenceRule::Constraint::isConsistent( PeriodType )
const
256 dt.setTime( TQTime( 0, 0, 0 ) );
257 dt.setDate( TQDate( year, (month>0)?month:1, (day>0)?day:1 ) );
259 dt = dt.addDays( dt.date().daysInMonth() + day );
262 dt.setTime( TQTime( hour, minute, second ) );
break;
264 dt.setTime( TQTime( hour, minute, 1 ) );
break;
266 dt.setTime( TQTime( hour, 1, 1 ) );
break;
270 dt = DateHelper::getNthWeek( year, weeknumber, weekstart );
break;
272 dt.setDate( TQDate( year, month, 1 ) );
break;
274 dt.setDate( TQDate( year, 1, 1 ) );
break;
305 TQTime tm( hour, minute, second );
306 if ( !isConsistent( type ) )
return result;
308 if ( !done && day > 0 && month > 0 ) {
309 TQDateTime dt( TQDate( year, month, day ), tm );
310 if ( dt.isValid() ) result.append( dt );
313 if ( !done && day < 0 && month > 0 ) {
314 TQDateTime dt( TQDate( year, month, 1 ), tm );
315 dt = dt.addDays( dt.date().daysInMonth() + day );
316 if ( dt.isValid() ) result.append( dt );
321 if ( !done && weekday == 0 && weeknumber == 0 && yearday == 0 ) {
323 uint mstart = (month>0) ? month : 1;
324 uint mend = (month <= 0) ? 12 : month;
325 for ( uint m = mstart; m <= mend; ++m ) {
329 }
else if ( day < 0 ) {
330 TQDate date( year, month, 1 );
331 dstart = dend = date.daysInMonth() + day + 1;
333 TQDate date( year, month, 1 );
335 dend = date.daysInMonth();
337 for ( uint d = dstart; d <= dend; ++d ) {
338 TQDateTime dt( TQDate( year, m, d ), tm );
339 if ( dt.isValid() ) result.append( dt );
347 if ( !done && yearday != 0 ) {
349 TQDate d( year + ((yearday>0)?0:1), 1, 1 );
350 d = d.addDays( yearday - ((yearday>0)?1:0) );
351 result.append( TQDateTime( d, tm ) );
356 if ( !done && weeknumber != 0 ) {
357 TQDate wst( DateHelper::getNthWeek( year, weeknumber, weekstart ) );
358 if ( weekday != 0 ) {
359 wst = wst.addDays( (7 + weekday - weekstart ) % 7 );
360 result.append( TQDateTime( wst, tm ) );
362 for (
int i = 0; i < 7; ++i ) {
363 result.append( TQDateTime( wst, tm ) );
364 wst = wst.addDays( 1 );
371 if ( !done && weekday != 0 ) {
372 TQDate dt( year, 1, 1 );
376 bool inMonth = ( type == rMonthly) || ( type == rYearly && month > 0 );
377 if ( inMonth && month > 0 ) {
378 dt = TQDate( year, month, 1 );
381 if ( weekdaynr < 0 ) {
384 dt = dt.addMonths( 1 );
386 dt = dt.addYears( 1 );
388 int adj = ( 7 + weekday - dt.dayOfWeek() ) % 7;
389 dt = dt.addDays( adj );
391 if ( weekdaynr > 0 ) {
392 dt = dt.addDays( ( weekdaynr - 1 ) * 7 );
393 result.append( TQDateTime( dt, tm ) );
394 }
else if ( weekdaynr < 0 ) {
395 dt = dt.addDays( weekdaynr * 7 );
396 result.append( TQDateTime( dt, tm ) );
399 for (
int i = 0; i < maxloop; ++i ) {
400 result.append( TQDateTime( dt, tm ) );
401 dt = dt.addDays( 7 );
409 DateTimeList::Iterator it;
410 for ( it = result.begin(); it != result.end(); ++it ) {
411 if ( matches( *it, type ) ) valid.append( *it );
423 TQDateTime dt( intervalDateTime( type ) );
428 dt = dt.addSecs( freq );
break;
430 dt = dt.addSecs( 60*freq );
break;
432 dt = dt.addSecs( 3600 * freq );
break;
434 dt = dt.addDays( freq );
break;
436 dt = dt.addDays( 7*freq );
break;
438 dt = dt.addMonths( freq );
break;
440 dt = dt.addYears( freq );
break;
445 readDateTime( dt, type );
450 bool RecurrenceRule::Constraint::readDateTime(
const TQDateTime &preDate, PeriodType type )
456 second = preDate.time().second();
458 minute = preDate.time().minute();
460 hour = preDate.time().hour();
462 day = preDate.date().day();
464 month = preDate.date().month();
466 year = preDate.date().year();
471 weeknumber = DateHelper::getWeekNumber( preDate.date(), weekstart, &year );
480 RecurrenceRule::RecurrenceRule( )
481 : mPeriod( rNone ), mFrequency( 0 ), mIsReadOnly( false ),
491 mDateStart = r.mDateStart;
492 mDuration = r.mDuration;
493 mDateEnd = r.mDateEnd;
494 mFrequency = r.mFrequency;
496 mIsReadOnly = r.mIsReadOnly;
497 mFloating = r.mFloating;
499 mBySeconds = r.mBySeconds;
500 mByMinutes = r.mByMinutes;
501 mByHours = r.mByHours;
503 mByMonthDays = r.mByMonthDays;
504 mByYearDays = r.mByYearDays;
505 mByWeekNumbers = r.mByWeekNumbers;
506 mByMonths = r.mByMonths;
507 mBySetPos = r.mBySetPos;
508 mWeekStart = r.mWeekStart;
513 RecurrenceRule::~RecurrenceRule()
519 if ( mPeriod != r.mPeriod )
return false;
520 if ( mDateStart != r.mDateStart )
return false;
521 if ( mDuration != r.mDuration )
return false;
522 if ( mDateEnd != r.mDateEnd )
return false;
523 if ( mFrequency != r.mFrequency )
return false;
525 if ( mIsReadOnly != r.mIsReadOnly )
return false;
526 if ( mFloating != r.mFloating )
return false;
528 if ( mBySeconds != r.mBySeconds )
return false;
529 if ( mByMinutes != r.mByMinutes )
return false;
530 if ( mByHours != r.mByHours )
return false;
531 if ( mByDays != r.mByDays )
return false;
532 if ( mByMonthDays != r.mByMonthDays )
return false;
533 if ( mByYearDays != r.mByYearDays )
return false;
534 if ( mByWeekNumbers != r.mByWeekNumbers )
return false;
535 if ( mByMonths != r.mByMonths )
return false;
536 if ( mBySetPos != r.mBySetPos )
return false;
537 if ( mWeekStart != r.mWeekStart )
return false;
544 if ( !mObservers.contains( observer ) )
545 mObservers.append( observer );
550 if ( mObservers.contains( observer ) )
551 mObservers.remove( observer );
556 void RecurrenceRule::setRecurrenceType( PeriodType period )
565 if ( result ) *result =
false;
566 if ( mPeriod == rNone )
return TQDateTime();
567 if ( mDuration < 0 )
return TQDateTime();
568 if ( mDuration == 0 ) {
569 if ( result ) *result =
true;
575 if ( !buildCache() )
return TQDateTime();
577 if ( result ) *result =
true;
578 return mCachedDateEnd;
611 mByMonthDays.clear();
613 mByWeekNumbers.clear();
621 void RecurrenceRule::setDirty()
623 mConstraints.clear();
627 mCachedDates.clear();
628 for ( TQValueList<Observer*>::ConstIterator it = mObservers.begin();
629 it != mObservers.end(); ++it ) {
630 if ( (*it) ) (*it)->recurrenceChanged(
this );
648 void RecurrenceRule::setBySeconds(
const TQValueList<int> bySeconds )
651 mBySeconds = bySeconds;
655 void RecurrenceRule::setByMinutes(
const TQValueList<int> byMinutes )
658 mByMinutes = byMinutes;
662 void RecurrenceRule::setByHours(
const TQValueList<int> byHours )
670 void RecurrenceRule::setByDays(
const TQValueList<WDayPos> byDays )
677 void RecurrenceRule::setByMonthDays(
const TQValueList<int> byMonthDays )
680 mByMonthDays = byMonthDays;
684 void RecurrenceRule::setByYearDays(
const TQValueList<int> byYearDays )
687 mByYearDays = byYearDays;
691 void RecurrenceRule::setByWeekNumbers(
const TQValueList<int> byWeekNumbers )
694 mByWeekNumbers = byWeekNumbers;
698 void RecurrenceRule::setByMonths(
const TQValueList<int> byMonths )
701 mByMonths = byMonths;
705 void RecurrenceRule::setBySetPos(
const TQValueList<int> bySetPos )
708 mBySetPos = bySetPos;
712 void RecurrenceRule::setWeekStart(
short weekStart )
715 mWeekStart = weekStart;
777 void RecurrenceRule::buildConstraints()
779 mTimedRepetition = 0;
780 mNoByRules = mBySetPos.isEmpty();
781 mConstraints.clear();
783 if ( mWeekStart > 0 ) con.weekstart = mWeekStart;
784 mConstraints.append( con );
786 Constraint::List tmp;
787 Constraint::List::const_iterator it;
788 TQValueList<int>::const_iterator intit;
790 #define intConstraint( list, element ) \
791 if ( !list.isEmpty() ) { \
792 mNoByRules = false; \
793 for ( it = mConstraints.constBegin(); it != mConstraints.constEnd(); ++it ) { \
794 for ( intit = list.constBegin(); intit != list.constEnd(); ++intit ) { \
796 con.element = (*intit); \
800 mConstraints = tmp; \
804 intConstraint( mBySeconds, second );
805 intConstraint( mByMinutes, minute );
806 intConstraint( mByHours, hour );
807 intConstraint( mByMonthDays, day );
808 intConstraint( mByMonths, month );
809 intConstraint( mByYearDays, yearday );
810 intConstraint( mByWeekNumbers, weeknumber );
813 if ( !mByDays.isEmpty() ) {
815 for ( it = mConstraints.constBegin(); it != mConstraints.constEnd(); ++it ) {
816 TQValueList<WDayPos>::const_iterator dayit;
817 for ( dayit = mByDays.constBegin(); dayit != mByDays.constEnd(); ++dayit ) {
819 con.weekday = (*dayit).day();
820 con.weekdaynr = (*dayit).pos();
828 #define fixConstraint( element, value ) \
831 for ( it = mConstraints.constBegin(); it != mConstraints.constEnd(); ++it ) { \
832 con = (*it); con.element = value; tmp.append( con ); \
834 mConstraints = tmp; \
840 if ( mPeriod == rWeekly && mByDays.isEmpty() ) {
841 fixConstraint( weekday, mDateStart.date().dayOfWeek() );
848 if ( mByDays.isEmpty() && mByWeekNumbers.isEmpty() && mByYearDays.isEmpty() && mByMonths.isEmpty() ) {
849 fixConstraint( month, mDateStart.date().month() );
852 if ( mByDays.isEmpty() && mByWeekNumbers.isEmpty() && mByYearDays.isEmpty() && mByMonthDays.isEmpty() ) {
853 fixConstraint( day, mDateStart.date().day() );
858 if ( mByHours.isEmpty() ) {
859 fixConstraint( hour, mDateStart.time().hour() );
862 if ( mByMinutes.isEmpty() ) {
863 fixConstraint( minute, mDateStart.time().minute() );
866 if ( mBySeconds.isEmpty() ) {
867 fixConstraint( second, mDateStart.time().second() );
878 mTimedRepetition = mFrequency * 3600;
881 mTimedRepetition = mFrequency * 60;
884 mTimedRepetition = mFrequency;
890 Constraint::List::Iterator conit = mConstraints.begin();
891 while ( conit != mConstraints.end() ) {
892 if ( (*conit).isConsistent( mPeriod ) ) {
895 conit = mConstraints.remove( conit );
901 bool RecurrenceRule::buildCache()
const
903 kdDebug(5800) <<
" RecurrenceRule::buildCache: " << endl;
906 Constraint interval( getNextValidDateInterval(
startDt(), recurrenceType() ) );
909 DateTimeList dts = datesForInterval( interval, recurrenceType() );
910 DateTimeList::Iterator it = dts.begin();
913 while ( it != dts.end() ) {
914 if ( (*it) <
startDt() ) it = dts.remove( it );
921 int dtnr = dts.count();
924 while ( loopnr < 10000 && dtnr < mDuration ) {
925 interval.increase( recurrenceType(),
frequency() );
927 dts += datesForInterval( interval, recurrenceType() );
931 if (
int(dts.count()) > mDuration ) {
933 it = dts.at( mDuration );
934 while ( it != dts.end() ) it = dts.remove( it );
939 kdDebug(5800) <<
" Finished Building Cache, cache has " << dts.count() <<
" entries:" << endl;
945 if (
int(dts.count()) == mDuration ) {
946 mCachedDateEnd = dts.last();
949 mCachedDateEnd = TQDateTime();
957 for ( Constraint::List::ConstIterator it = mConstraints.begin();
958 it!=mConstraints.end(); ++it ) {
959 match = match || ( (*it).matches( qdt, recurrenceType() ) );
969 if ( qd < mDateStart.date() ) {
974 if ( mDuration >= 0 ) {
975 endDate =
endDt().date();
976 if ( qd > endDate ) {
984 for ( i = 0, iend = mConstraints.count(); i < iend && !match; ++i ) {
985 match = mConstraints[i].matches( qd, recurrenceType() );
991 TQDateTime start( qd, TQTime( 0, 0, 0 ) );
992 Constraint interval( getNextValidDateInterval( start, recurrenceType() ) );
995 if ( !interval.matches( qd, recurrenceType() ) ) {
1001 TQDateTime end = start.addDays(1);
1003 DateTimeList dts = datesForInterval( interval, recurrenceType() );
1004 for ( i = 0, iend = dts.count(); i < iend; ++i ) {
1005 if ( dts[i].date() >= qd ) {
1006 return dts[i].date() == qd;
1009 interval.increase( recurrenceType(),
frequency() );
1010 }
while ( interval.intervalDateTime( recurrenceType() ) < end );
1015 TQDateTime start( qd, TQTime( 0, 0, 0 ) );
1016 TQDateTime end = start.addDays( 1 );
1017 if ( end < mDateStart ) {
1020 if ( start < mDateStart ) {
1025 if ( mDuration >= 0 ) {
1026 TQDateTime endRecur =
endDt();
1027 if ( endRecur.isValid() ) {
1028 if ( start > endRecur ) {
1031 if ( end > endRecur ) {
1037 if ( mTimedRepetition ) {
1039 int n =
static_cast<int>( ( mDateStart.secsTo( start ) - 1 ) % mTimedRepetition );
1040 return start.addSecs( mTimedRepetition - n ) < end;
1044 TQDate startDay = start.date();
1045 TQDate endDay = end.addSecs( -1 ).date();
1046 int dayCount = startDay.daysTo( endDay ) + 1;
1051 for ( i = 0, iend = mConstraints.count(); i < iend && !match; ++i ) {
1052 match = mConstraints[i].matches( startDay, recurrenceType() );
1053 for (
int day = 1; day < dayCount && !match; ++day ) {
1054 match = mConstraints[i].matches( startDay.addDays( day ), recurrenceType() );
1061 Constraint interval( getNextValidDateInterval( start, recurrenceType() ) );
1065 Constraint intervalm = interval;
1067 match = intervalm.matches( startDay, recurrenceType() );
1068 for (
int day = 1; day < dayCount && !match; ++day ) {
1069 match = intervalm.matches( startDay.addDays( day ), recurrenceType() );
1074 intervalm.increase( recurrenceType(),
frequency() );
1075 }
while ( intervalm.intervalDateTime( recurrenceType() ) < end );
1084 DateTimeList dts = datesForInterval( interval, recurrenceType() );
1085 int i = findGE( dts, start, 0 );
1087 return dts[i] < end;
1089 interval.increase( recurrenceType(),
frequency() );
1090 }
while ( interval.intervalDateTime( recurrenceType() ) < end );
1100 if ( dt < mDateStart ) {
1104 if ( mDuration >= 0 && dt >
endDt() ) {
1108 if ( mTimedRepetition ) {
1110 return !( mDateStart.secsTo( dt ) % mTimedRepetition );
1120 Constraint interval( getNextValidDateInterval( dt, recurrenceType() ) );
1122 if ( interval.matches( dt, recurrenceType() ) ) {
1134 TQDateTime start( date, TQTime( 0, 0, 0 ) );
1135 TQDateTime end = start.addDays( 1 ).addSecs( -1 );
1137 for (
int i = 0, iend = dts.count(); i < iend; ++i ) {
1138 lst += dts[i].time();
1149 if ( dt <
startDt() )
return 0;
1152 if ( mDuration > 0 && dt >=
endDt() )
return mDuration;
1156 while ( next.isValid() && next <= dt ) {
1169 return TQDateTime();
1173 if ( mDuration > 0 ) {
1174 if ( !mCached ) buildCache();
1175 DateTimeList::ConstIterator it = mCachedDates.begin();
1176 while ( it != mCachedDates.end() && (*it) < afterDate ) {
1180 if ( prev.isValid() && prev < afterDate )
return prev;
1181 else return TQDateTime();
1186 if ( mDuration >= 0 &&
endDt().isValid() && afterDate >
endDt() )
1187 prev =
endDt().addSecs( 1 );
1189 Constraint interval( getPreviousValidDateInterval( prev, recurrenceType() ) );
1192 DateTimeList dts = datesForInterval( interval, recurrenceType() );
1193 DateTimeList::Iterator dtit = dts.end();
1194 if ( dtit != dts.begin() ) {
1197 }
while ( dtit != dts.begin() && (*dtit) >= prev );
1198 if ( (*dtit) < prev ) {
1199 if ( (*dtit) >=
startDt() )
return (*dtit);
1200 else return TQDateTime();
1205 while ( interval.intervalDateTime( recurrenceType() ) >
startDt() ) {
1206 interval.increase( recurrenceType(), -
frequency() );
1210 DateTimeList dts = datesForInterval( interval, recurrenceType() );
1212 if ( dts.count() > 0 ) {
1214 if ( prev.isValid() && prev >=
startDt() )
return prev;
1215 else return TQDateTime();
1218 return TQDateTime();
1226 if ( mDuration >= 0 &&
endDt().isValid() && preDate >=
endDt() )
1227 return TQDateTime();
1230 TQDateTime adjustedPreDate;
1232 adjustedPreDate =
startDt().addSecs( -1 );
1234 adjustedPreDate = preDate;
1236 if ( mDuration > 0 ) {
1237 if ( !mCached ) buildCache();
1238 DateTimeList::ConstIterator it = mCachedDates.begin();
1239 while ( it != mCachedDates.end() && (*it) <= adjustedPreDate ) ++it;
1240 if ( it != mCachedDates.end() ) {
1247 Constraint interval( getNextValidDateInterval( adjustedPreDate, recurrenceType() ) );
1248 DateTimeList dts = datesForInterval( interval, recurrenceType() );
1249 DateTimeList::Iterator dtit = dts.begin();
1250 while ( dtit != dts.end() && (*dtit) <= adjustedPreDate ) ++dtit;
1251 if ( dtit != dts.end() ) {
1252 if ( mDuration >= 0 && (*dtit) >
endDt() )
return TQDateTime();
1253 else return (*dtit);
1260 while ( loopnr < 10000 ) {
1261 interval.increase( recurrenceType(),
frequency() );
1262 DateTimeList dts = datesForInterval( interval, recurrenceType() );
1263 if ( dts.count() > 0 ) {
1264 TQDateTime ret( dts.first() );
1265 if ( mDuration >= 0 && ret >
endDt() )
return TQDateTime();
1270 return TQDateTime();
1274 const TQDateTime &dtEnd )
const
1276 TQDateTime start = dtStart;
1277 TQDateTime end = dtEnd;
1278 DateTimeList result;
1279 if ( end < mDateStart ) {
1282 TQDateTime enddt = end;
1283 if ( mDuration >= 0 ) {
1284 TQDateTime endRecur =
endDt();
1285 if ( endRecur.isValid() ) {
1286 if ( start > endRecur ) {
1289 if ( end > endRecur ) {
1295 if ( mTimedRepetition ) {
1297 int n =
static_cast<int>( ( mDateStart.secsTo( start ) - 1 ) % mTimedRepetition );
1298 TQDateTime dt = start.addSecs( mTimedRepetition - n );
1300 n =
static_cast<int>( ( dt.secsTo( enddt ) - 1 ) / mTimedRepetition ) + 1;
1302 n = TQMIN( n, LOOP_LIMIT );
1303 for (
int i = 0; i < n; dt = dt.addSecs( mTimedRepetition ), ++i ) {
1310 TQDateTime st = start;
1312 if ( mDuration > 0 ) {
1316 if ( mCachedDateEnd.isValid() && start > mCachedDateEnd ) {
1319 int i = findGE( mCachedDates, start, 0 );
1321 int iend = findGT( mCachedDates, enddt, i );
1323 iend = mCachedDates.count();
1327 while ( i < iend ) {
1328 result += mCachedDates[i++];
1331 if ( mCachedDateEnd.isValid() ) {
1333 }
else if ( !result.isEmpty() ) {
1334 result += TQDateTime();
1341 st = mCachedLastDate.addSecs( 1 );
1344 Constraint interval( getNextValidDateInterval( st, recurrenceType() ) );
1347 DateTimeList dts = datesForInterval( interval, recurrenceType() );
1349 int iend = dts.count();
1351 i = findGE( dts, st, 0 );
1356 int j = findGT( dts, enddt, i );
1361 while ( i < iend ) {
1365 interval.increase( recurrenceType(),
frequency() );
1366 }
while ( ++loop < LOOP_LIMIT &&
1367 interval.intervalDateTime( recurrenceType() ) < end );
1371 RecurrenceRule::Constraint RecurrenceRule::getPreviousValidDateInterval(
const TQDateTime &preDate, PeriodType type )
const
1375 TQDateTime nextValid =
startDt();
1378 TQDateTime toDate( preDate );
1389 case rHourly: modifier *= 60;
1390 case rMinutely: modifier *= 60;
1392 periods = ownSecsTo( start, toDate ) / modifier;
1395 nextValid = start.addSecs( modifier * periods );
1399 toDate = toDate.addDays( -(7 + toDate.date().dayOfWeek() - mWeekStart) % 7 );
1400 start = start.addDays( -(7 + start.date().dayOfWeek() - mWeekStart) % 7 );
1403 periods = start.daysTo( toDate ) / modifier;
1406 nextValid = start.addDays( modifier * periods );
1410 periods = 12*( toDate.date().year() - start.date().year() ) +
1411 ( toDate.date().month() - start.date().month() );
1416 start.setDate( TQDate( start.date().year(), start.date().month(), 1 ) );
1417 nextValid.setDate( start.date().addMonths( periods ) );
1420 periods = ( toDate.date().year() - start.date().year() );
1423 nextValid.setDate( start.date().addYears( periods ) );
1430 return Constraint( nextValid, type, mWeekStart );
1433 RecurrenceRule::Constraint RecurrenceRule::getNextValidDateInterval(
const TQDateTime &preDate, PeriodType type )
const
1436 kdDebug(5800) <<
" (o) getNextValidDateInterval after " << preDate <<
", type=" << type << endl;
1439 TQDateTime nextValid( start );
1441 TQDateTime toDate( preDate );
1452 case rHourly: modifier *= 60;
1453 case rMinutely: modifier *= 60;
1455 periods = ownSecsTo( start, toDate ) / modifier;
1456 periods = TQMAX( 0, periods);
1459 nextValid = start.addSecs( modifier * periods );
1464 toDate = toDate.addDays( -(7 + toDate.date().dayOfWeek() - mWeekStart) % 7 );
1465 start = start.addDays( -(7 + start.date().dayOfWeek() - mWeekStart) % 7 );
1468 periods = start.daysTo( toDate ) / modifier;
1469 periods = TQMAX( 0, periods);
1472 nextValid = start.addDays( modifier * periods );
1476 periods = 12*( toDate.date().year() - start.date().year() ) +
1477 ( toDate.date().month() - start.date().month() );
1478 periods = TQMAX( 0, periods);
1483 start.setDate( TQDate( start.date().year(), start.date().month(), 1 ) );
1484 nextValid.setDate( start.date().addMonths( periods ) );
1487 periods = ( toDate.date().year() - start.date().year() );
1488 periods = TQMAX( 0, periods);
1491 nextValid.setDate( start.date().addYears( periods ) );
1498 return Constraint( nextValid, type, mWeekStart );
1501 bool RecurrenceRule::mergeIntervalConstraint( Constraint *merged,
1502 const Constraint &conit,
const Constraint &interval )
const
1504 Constraint result( interval );
1506 #define mergeConstraint( name, cmparison ) \
1507 if ( conit.name cmparison ) { \
1508 if ( !(result.name cmparison) || result.name == conit.name ) { \
1509 result.name = conit.name; \
1510 } else return false;\
1513 mergeConstraint( year, > 0 );
1514 mergeConstraint( month, > 0 );
1515 mergeConstraint( day, != 0 );
1516 mergeConstraint( hour, >= 0 );
1517 mergeConstraint( minute, >= 0 );
1518 mergeConstraint( second, >= 0 );
1520 mergeConstraint( weekday, != 0 );
1521 mergeConstraint( weekdaynr, != 0 );
1522 mergeConstraint( weeknumber, != 0 );
1523 mergeConstraint( yearday, != 0 );
1525 #undef mergeConstraint
1526 if ( merged ) *merged = result;
1531 DateTimeList RecurrenceRule::datesForInterval(
const Constraint &interval, PeriodType type )
const
1542 Constraint::List::ConstIterator conit = mConstraints.begin();
1543 for ( ; conit != mConstraints.end(); ++conit ) {
1545 bool mergeok = mergeIntervalConstraint( &merged, *conit, interval );
1547 if ( merged.year <= 0 || merged.hour < 0 || merged.minute < 0 || merged.second < 0 )
1554 DateTimeList lstnew = merged.dateTimes( type );
1571 if ( !mBySetPos.isEmpty() ) {
1572 DateTimeList tmplst = lst;
1574 TQValueList<int>::ConstIterator it;
1575 for ( it = mBySetPos.begin(); it != mBySetPos.end(); ++it ) {
1577 if ( pos > 0 ) --pos;
1578 if ( pos < 0 ) pos += tmplst.count();
1579 if ( pos >= 0 && uint(pos) < tmplst.count() ) {
1580 lst.append( tmplst[pos] );
1593 kdDebug(5800) <<
"RecurrenceRule::dump():" << endl;
1594 if ( !mRRule.isEmpty() )
1595 kdDebug(5800) <<
" RRULE=" << mRRule << endl;
1596 kdDebug(5800) <<
" Read-Only: " <<
isReadOnly() <<
1597 ", dirty: " << mDirty << endl;
1599 kdDebug(5800) <<
" Period type: " << recurrenceType() <<
", frequency: " <<
frequency() << endl;
1600 kdDebug(5800) <<
" #occurrences: " <<
duration() << endl;
1601 kdDebug(5800) <<
" start date: " <<
startDt() <<
", end date: " <<
endDt() << endl;
1604 #define dumpByIntList(list,label) \
1605 if ( !list.isEmpty() ) {\
1607 for ( TQValueList<int>::ConstIterator it = list.begin();\
1608 it != list.end(); ++it ) {\
1609 lst.append( TQString::number( *it ) );\
1611 kdDebug(5800) << " " << label << lst.join(", ") << endl;\
1613 dumpByIntList( mBySeconds,
"BySeconds: " );
1614 dumpByIntList( mByMinutes,
"ByMinutes: " );
1615 dumpByIntList( mByHours,
"ByHours: " );
1616 if ( !mByDays.isEmpty() ) {
1618 for ( TQValueList<WDayPos>::ConstIterator it = mByDays.begin();
1619 it != mByDays.end(); ++it ) {
1620 lst.append( ( ((*it).pos()!=0) ? TQString::number( (*it).pos() ) :
"" ) +
1621 DateHelper::dayName( (*it).day() ) );
1623 kdDebug(5800) <<
" ByDays: " << lst.join(
", ") << endl;
1625 dumpByIntList( mByMonthDays,
"ByMonthDays:" );
1626 dumpByIntList( mByYearDays,
"ByYearDays: " );
1627 dumpByIntList( mByWeekNumbers,
"ByWeekNr: " );
1628 dumpByIntList( mByMonths,
"ByMonths: " );
1629 dumpByIntList( mBySetPos,
"BySetPos: " );
1630 #undef dumpByIntList
1632 kdDebug(5800) <<
" Week start: " << DateHelper::dayName( mWeekStart ) << endl;
1634 kdDebug(5800) <<
" Constraints:" << endl;
1636 for ( Constraint::List::ConstIterator it = mConstraints.begin();
1637 it!=mConstraints.end(); ++it ) {
1643 void RecurrenceRule::Constraint::dump()
const
1645 kdDebug(5800) <<
" ~> Y="<<year<<
", M="<<month<<
", D="<<day<<
", H="<<hour<<
", m="<<minute<<
", S="<<second<<
", wd="<<weekday<<
",#wd="<<weekdaynr<<
", #w="<<weeknumber<<
", yd="<<yearday<<endl;
This class represents a recurrence rule for a calendar incidence.
TQDateTime getPreviousDate(const TQDateTime &afterDateTime) const
Returns the date and time of the last previous recurrence, before the specified date/time.
TQDateTime endDt(bool *result=0) const
Returns the date and time of the last recurrence.
TimeList recurTimesOn(const TQDate &date) const
Returns a list of the times on the specified date at which the recurrence will occur.
void clear()
Turns off recurrence for the event.
void setDuration(int duration)
Sets the total number of times the event is to occur, including both the first and last.
int durationTo(const TQDateTime &) const
Returns the number of recurrences up to and including the date/time specified.
void dump() const
Debug output.
TQDateTime startDt() const
Return the start of the recurrence.
bool recursOn(const TQDate &qd) const
Returns true if the date specified is one on which the event will recur.
void setFrequency(int freq)
Sets the frequency of recurrence, in terms of the recurrence time period type.
void removeObserver(Observer *observer)
Removes an observer that was added with addObserver.
void setFloats(bool floats)
Sets whether the dtstart is a floating time (i.e.
void setEndDt(const TQDateTime &endDateTime)
Sets the date and time of the last recurrence.
bool recursAt(const TQDateTime &) const
Returns true if the date/time specified is one at which the event will recur.
uint frequency() const
Returns frequency of recurrence, in terms of the recurrence time period type.
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
bool dateMatchesRules(const TQDateTime &qdt) const
Returns true if the date matches the rules.
void addObserver(Observer *observer)
Installs an observer.
bool doesFloat() const
Returns whether the start date has no time associated.
PeriodType
enum for describing the frequency how an event recurs, if at all.
bool isReadOnly() const
Returns true if the recurrence is read-only, or false if it can be changed.
TQDateTime getNextDate(const TQDateTime &preDateTime) const
Returns the date and time of the next recurrence, after the specified date/time.
DateTimeList timesInInterval(const TQDateTime &start, const TQDateTime &end) const
Returns a list of all the times at which the recurrence will occur between two specified times.
void setStartDt(const TQDateTime &start)
Set start of recurrence, as a date and time.
Namespace KCal is for global classes, objects and/or functions in libkcal.