//////////////////////////////////////////////////////////////////////// // FUNCTION: DateAdjust // // DESCRIPTION: This routine return a new date +/- the days adjustment. // // PARAMETERS: (DatePtr) dateP - A DateType structure with the date to // be adjusted. // (Int32) adjustment - The Adjustment in number of days. // // RETURNED: Returns nothing. // // REVISION HISTORY: // Name Date Description // ---- ---- ----------- // Jerry 5/10/01 Initial Revision //////////////////////////////////////////////////////////////////////// void DateAdjust (DatePtr dateP, Int32 adjustment) { UInt32 days; days = DateToDays (*dateP); days += adjustment; DateDaysToDate (days, dateP); }
//////////////////////////////////////////////////////////////////////// // FUNCTION: TimSecondsToDateTime // // DESCRIPTION: This routine returns the date and time, given seconds. // // PARAMETERS: (UInt32) seconds - Seconds since 1/1/1904. // (DateTimePtr) dateTimeP - Pointer to DateTimeType structure. // // RETURNED: Returns nothing. // // REVISION HISTORY: // Name Date Description // ---- ---- ----------- // Jerry 5/10/01 Initial Revision // Jerry 7/05/01 Completed weekDay //////////////////////////////////////////////////////////////////////// void TimSecondsToDateTime (UInt32 seconds, DateTimePtr dateTimeP) { UInt32 days = (UInt32)(seconds/secondsInADay); DateType date; DateDaysToDate (days, &date); dateTimeP->year = date.year+SYSSTARTYEAR; dateTimeP->month = date.month; dateTimeP->day = date.day; #ifdef LINUX dateTimeP->weekDay = (Int16)(((days-1)+4)%7); // 1970/1/1 is Thursday(4). #else dateTimeP->weekDay = (Int16)(((days-1)+5)%7); // 1904/1/1 is Friday(5). #endif seconds = seconds % secondsInADay; dateTimeP->hour = (Int16) (seconds/secondsInAHour); seconds = seconds % secondsInAHour; dateTimeP->minute = (Int16) seconds/secondsInAMinute; dateTimeP->second = (Int16) seconds % secondsInAMinute; }
//////////////////////////////////////////////////////////////////////// // FUNCTION: DateSecondsToDate // // DESCRIPTION: This routine returns the date, given seconds. // // PARAMETERS: (UInt32) seconds - seconds since 1/1/1904. // (DatePtr) date - Pointer to DateType structure. // // RETURNED: Returns nothing. // // REVISION HISTORY: // Name Date Description // ---- ---- ----------- // Jerry 5/10/01 Initial Revision //////////////////////////////////////////////////////////////////////// void DateSecondsToDate (UInt32 seconds, DatePtr date) { UInt32 days = seconds/secondsInADay; DateDaysToDate (days, date); }
/*********************************************************************** * * FUNCTION: NextRepeat * * DESCRIPTION: This routine computes the date of the next * occurrence of a repeating appointment. * * PARAMETERS: rec - a pointer to a DiddleBug record * date - passed: date to start from * returned: date of next occurrence * * RETURNED: true if the appointment occurs again * ***********************************************************************/ Boolean NextRepeat(DiddleBugRecordType* rec, DateTimeType* dateP) { /* ** Get the frequency on occurrence **(ex: every 2nd day, every 3rd month, etc). */ const UInt16 freq = rec->repeatInfo.repeatFrequency; Int16 i = 0; UInt16 day; UInt16 year; UInt16 adjust; UInt16 weeksDiff; UInt16 monthsDiff; UInt16 daysInMonth; UInt16 dayOfWeek; UInt16 apptWeekDay; UInt16 firstDayOfWeek; UInt16 daysTilNext; UInt16 monthsTilNext; UInt32 dateInDays; UInt32 startInDays; DateType start, date, when, next; DateTimeType nextReal; UInt32 startSecs, nextSecs; DateSecondsToDate(TimDateTimeToSeconds(dateP), &date); TimSecondsToDateTime(rec->alarmSecs, &nextReal); nextReal.year = dateP->year; nextReal.month = dateP->month; nextReal.day = dateP->day; nextReal.weekDay = dateP->weekDay; /* Calculate alarm date */ DateSecondsToDate(rec->alarmSecs, &when); /* Is the date passed after the end date of the appointment? */ if (DateCompare(date, rec->repeatInfo.repeatEndDate) > 0) return false; /* Is the date passed before the start date of the appointment? */ if (DateCompare(date, when) < 0) date = when; /* Get the date of the first occurrecne of the appointment. */ start = when; switch (rec->repeatInfo.repeatType) { /* Hourly repeating appointment */ case repeatHourly: startSecs = TimDateTimeToSeconds(dateP); nextSecs = rec->alarmSecs; while (nextSecs < startSecs) nextSecs += freq * hoursInSeconds; TimSecondsToDateTime(nextSecs, &nextReal); DateSecondsToDate(nextSecs, &next); break; /* Daily repeating appointment. */ case repeatDaily: dateInDays = DateToDays(date); startInDays = DateToDays(start); daysTilNext = (dateInDays - startInDays + freq - 1) / freq * freq; if (startInDays + daysTilNext > (UInt32) maxDays) return false; DateDaysToDate (startInDays + daysTilNext, &next); break; /* ** Weekly repeating appointment (ex: every Monday and Friday). ** Yes, weekly repeating appointment can occur more then once a ** week. */ case repeatWeekly: dateInDays = DateToDays(date); startInDays = DateToDays(start); firstDayOfWeek = (DayOfWeek (1, 1, firstYear) - rec->repeatInfo.repeatStartOfWeek + daysInWeek) % daysInWeek; dayOfWeek = DayOfWeek(date.month, date.day, date.year+firstYear); apptWeekDay = (dayOfWeek - rec->repeatInfo.repeatStartOfWeek + daysInWeek) % daysInWeek; /* ** Are we in a week in which the appointment occurrs, if not ** move to that start of the next week in which the appointment ** does occur. */ weeksDiff = (((dateInDays + firstDayOfWeek) / daysInWeek) - ((startInDays + firstDayOfWeek) / daysInWeek)) % freq; if (weeksDiff) { adjust = ((freq - weeksDiff) * daysInWeek) - apptWeekDay; apptWeekDay = 0; dayOfWeek = (dayOfWeek + adjust) % daysInWeek; } else { adjust = 0; } /* Find the next day on which the appointment repeats. */ for (; i < daysInWeek; i++) { if (rec->repeatInfo.repeatOn & (1 << dayOfWeek)) break; adjust++; if (++dayOfWeek == daysInWeek) dayOfWeek = 0; if (++apptWeekDay == daysInWeek) adjust += (freq - 1) * daysInWeek; } if (dateInDays + adjust > (UInt32) maxDays) return false; DateDaysToDate (dateInDays + adjust, &next); break; /* ** Monthly-by-day repeating appointment ** (ex: the 3rd Friday of every month). */ case repeatMonthlyByDay: /* Compute the number of month until the appointment repeats again. */ monthsTilNext = ((((date.year - start.year) * monthsInYear) + (date.month - start.month)) + freq - 1) / freq * freq; while (true) { year = start.year + (start.month - 1 + monthsTilNext) / monthsInYear; if (year >= numberOfYears) return false; next.year = year; next.month = (start.month - 1 + monthsTilNext) % monthsInYear + 1; dayOfWeek = DayOfWeek (next.month, 1, next.year+firstYear); if ((rec->repeatInfo.repeatOn % daysInWeek) >= dayOfWeek) day = rec->repeatInfo.repeatOn - dayOfWeek + 1; else day = rec->repeatInfo.repeatOn + daysInWeek - dayOfWeek + 1; /* ** If repeat-on day is between the last sunday and the last ** saturday, make sure we're not passed the end of the month. */ if ( (rec->repeatInfo.repeatOn >= domLastSun) && (day > DaysInMonth (next.month, next.year+firstYear))) { day -= daysInWeek; } next.day = day; /* ** Its posible that "next date" calculated above is ** before the date passed. If so, move forward ** by the length of the repeat freguency and preform ** the calculation again. */ if (DateToInt(date) > DateToInt(next)) monthsTilNext += freq; else break; } break; /* ** Monthly-by-date repeating appointment ** (ex: the 15th of every month). */ case repeatMonthlyByDate: /* Compute the number of month until the appointment repeats again. */ monthsDiff = (date.year - start.year) * monthsInYear + date.month - start.month; monthsTilNext = (monthsDiff + freq - 1) / freq * freq; if (date.day > start.day && !(monthsDiff % freq)) monthsTilNext += freq; year = start.year + (start.month - 1 + monthsTilNext) / monthsInYear; if (year >= numberOfYears) return false; next.year = year; next.month = (start.month - 1 + monthsTilNext) % monthsInYear + 1; next.day = start.day; /* Make sure we're not passed the last day of the month. */ daysInMonth = DaysInMonth(next.month, next.year+firstYear); if (next.day > daysInMonth) next.day = daysInMonth; break; /* Yearly repeating appointment. */ case repeatYearly: next.day = start.day; next.month = start.month; year = start.year + ((date.year - start.year + freq - 1) / freq * freq); if (date.month > start.month || (date.month == start.month && date.day > start.day)) year += freq; /* Specal leap day processing. */ if (next.month == february && next.day == 29 && next.day > DaysInMonth(next.month, year+firstYear)) { next.day = DaysInMonth (next.month, year+firstYear); } if (year >= numberOfYears) return false; next.year = year; break; default: /* ignore */ } /* Is the next occurrence after the end date of the appointment? */ if (DateCompare(next, rec->repeatInfo.repeatEndDate) > 0) return false; dateP->day = next.day; dateP->month = next.month; dateP->year = next.year + firstYear; dateP->hour = nextReal.hour; dateP->minute = nextReal.minute; dateP->second = nextReal.second; return true; }
Boolean NextRepeat (ApptDBRecordPtr apptRec, DatePtr dateP) { Int16 i; UInt16 day; UInt16 freq; UInt16 year; UInt16 adjust; UInt16 weeksDiff; UInt16 monthsDiff; UInt16 daysInMonth; UInt16 dayOfWeek; UInt16 apptWeekDay; UInt16 firstDayOfWeek; UInt16 daysTilNext; UInt16 monthsTilNext; UInt32 dateInDays; UInt32 startInDays; DateType start; DateType date; DateType next; date = *dateP; // Is the date passed after the end date of the appointment? if (DateCompare (date, apptRec->repeat->repeatEndDate) > 0) return (false); // Is the date passed before the start date of the appointment? if (DateCompare (date, apptRec->when->date) < 0) date = apptRec->when->date; // Get the frequency on occurrecne (ex: every 2nd day, every 3rd month, etc). freq = apptRec->repeat->repeatFrequency; // Get the date of the first occurrecne of the appointment. start = apptRec->when->date; switch (apptRec->repeat->repeatType) { // Daily repeating appointment. case repeatDaily: dateInDays = DateToDays (date); startInDays = DateToDays (start); daysTilNext = (dateInDays - startInDays + freq - 1) / freq * freq; if (startInDays + daysTilNext > (UInt32) maxDays) return (false); DateDaysToDate (startInDays + daysTilNext, &next); break; // Weekly repeating appointment (ex: every Monday and Friday). // Yes, weekly repeating appointment can occur more then once a // week. case repeatWeekly: dateInDays = DateToDays (date); startInDays = DateToDays (start); firstDayOfWeek = (DayOfWeek (1, 1, firstYear) - apptRec->repeat->repeatStartOfWeek + daysInWeek) % daysInWeek; dayOfWeek = DayOfWeek (date.month, date.day, date.year+firstYear); apptWeekDay = (dayOfWeek - apptRec->repeat->repeatStartOfWeek + daysInWeek) % daysInWeek; // Are we in a week in which the appointment occurrs, if not // move to that start of the next week in which the appointment // does occur. weeksDiff = (((dateInDays + firstDayOfWeek) / daysInWeek) - ((startInDays + firstDayOfWeek) / daysInWeek)) %freq; if (weeksDiff) { adjust = ((freq - weeksDiff) * daysInWeek)- apptWeekDay; apptWeekDay = 0; dayOfWeek = (dayOfWeek + adjust) % daysInWeek; } else adjust = 0; // Find the next day on which the appointment repeats. for (i = 0; i < daysInWeek; i++) { if (apptRec->repeat->repeatOn & (1 << dayOfWeek)) break; adjust++; if (++dayOfWeek == daysInWeek) dayOfWeek = 0; if (++apptWeekDay == daysInWeek) adjust += (freq - 1) * daysInWeek; } if (dateInDays + adjust > (UInt32) maxDays) return (false); DateDaysToDate (dateInDays + adjust, &next); // next = date; // DateAdjust (&next, adjust); break; // Monthly-by-day repeating appointment (ex: the 3rd Friday of every // month). case repeatMonthlyByDay: // Compute the number of month until the appointment repeats again. monthsTilNext = (date.month - start.month); monthsTilNext = ((((date.year - start.year) * monthsInYear) + (date.month - start.month)) + freq - 1) / freq * freq; while (true) { year = start.year + (start.month - 1 + monthsTilNext) / monthsInYear; if (year >= numberOfYears) return (false); next.year = year; next.month = (start.month - 1 + monthsTilNext) % monthsInYear + 1; dayOfWeek = DayOfWeek (next.month, 1, next.year+firstYear); if ((apptRec->repeat->repeatOn % daysInWeek) >= dayOfWeek) day = apptRec->repeat->repeatOn - dayOfWeek + 1; else day = apptRec->repeat->repeatOn + daysInWeek - dayOfWeek + 1; // If repeat-on day is between the last sunday and the last // saturday, make sure we're not passed the end of the month. if ( (apptRec->repeat->repeatOn >= domLastSun) && (day > DaysInMonth (next.month, next.year+firstYear))) { day -= daysInWeek; } next.day = day; // Its posible that "next date" calculated above is // before the date passed. If so, move forward // by the length of the repeat freguency and preform // the calculation again. if ( DateToInt(date) > DateToInt (next)) monthsTilNext += freq; else break; } break; // Monthly-by-date repeating appointment (ex: the 15th of every // month). case repeatMonthlyByDate: // Compute the number of month until the appointment repeats again. monthsDiff = ((date.year - start.year) * monthsInYear) + (date.month - start.month); monthsTilNext = (monthsDiff + freq - 1) / freq * freq; if ((date.day > start.day) && (!(monthsDiff % freq))) monthsTilNext += freq; year = start.year + (start.month - 1 + monthsTilNext) / monthsInYear; if (year >= numberOfYears) return (false); next.year = year; next.month = (start.month - 1 + monthsTilNext) % monthsInYear + 1; next.day = start.day; // Make sure we're not passed the last day of the month. daysInMonth = DaysInMonth (next.month, next.year+firstYear); if (next.day > daysInMonth) next.day = daysInMonth; break; // Yearly repeating appointment. case repeatYearly: next.day = start.day; next.month = start.month; year = start.year + ((date.year - start.year + freq - 1) / freq * freq); if ((date.month > start.month) || ((date.month == start.month) && (date.day > start.day))) year += freq; // Specal leap day processing. if ( (next.month == february) && (next.day == 29) && (next.day > DaysInMonth (next.month, year+firstYear))) { next.day = DaysInMonth (next.month, year+firstYear); } if (year >= numberOfYears) return (false); next.year = year; break; default: break; } // Is the next occurrence after the end date of the appointment? if (DateCompare (next, apptRec->repeat->repeatEndDate) > 0) return (false); ErrFatalDisplayIf ((DateToInt (next) < DateToInt (*dateP)), "Calculation error"); *dateP = next; return (true); }