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;