📄 datedb.c
字号:
{
// 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;
}
// 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);
}
*/
/***********************************************************************
*
* FUNCTION: IsException
*
* DESCRIPTION: This routine returns true the date passed is in a
* repeating appointment's exception list.
*
* PARAMETERS: apptRec - a pointer to an appointment record
* date - date to check
*
* RETURNED: true if the date is an exception date.
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* art 6/14/95 Initial Revision
*
***********************************************************************/
static Boolean IsException (ApptDBRecordPtr apptRec, DateType date)
{
int i;
DatePtr exceptions;
if (apptRec->exceptions)
{
exceptions = &apptRec->exceptions->exception;
for (i = 0; i < apptRec->exceptions->numExceptions; i++)
{
if (DateCompare (date, exceptions[i]) == 0)
return (true);
}
}
return (false);
}
/***********************************************************************
*
* FUNCTION: ApptNextRepeat
*
* DESCRIPTION: This routine computes the next occurrence of a
* repeating appointment.
*
* PARAMETERS: apptRec - a pointer to an appointment record
* dateP - passed: date to start from
* returned: date of next occurrence
* searchForward - true if searching for next occurrence
* - false if searching for most recent
*
* RETURNED: true if there is an occurrence of the appointment
* between the date passed and the appointment's end date
* (if searching forward) or start date (if searching
* backwards)
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* art 6/20/95 Initial Revision
* gap 9/25/00 Add capability to search backwards for the most
* recent occurrence of the event (needed for attention
* manager support)
*
***********************************************************************/
Boolean ApptNextRepeat (ApptDBRecordPtr apptRec, DatePtr dateP, Boolean searchForward)
{
DateType date;
date = *dateP;
while (true)
{
// Compute the next time the appointment repeats.
if (! FindNextRepeat (apptRec, &date, searchForward))
return (false);
// Check if the date computed is in the exceptions list.
if (! IsException (apptRec, date))
{
*dateP = date;
return (true);
}
DateAdjust (&date, (searchForward) ? 1 : -1);
}
}
/***********************************************************************
*
* FUNCTION: UnDayOfMonth
*
* DESCRIPTION: Inverse of DayOfMonth routine. Takes a month and year
* and a dayOfMonth value (e.g., dom1stSun, domLastFri, etc.) and computes
* what date that day is for that month.
*
* PARAMETERS: month
* year - a year (1904, etc.)
* dayOfMonth - a dayOfMonth, like those returned from DayOfMonth
*
* RETURNED: date in month
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* grant 3/1/99 Initial Revision
*
***********************************************************************/
static UInt16 UnDayOfMonth(UInt16 month, UInt16 year, UInt16 dayOfMonth)
{
Int16 dayOfWeek;
Int16 firstDayOfWeek;
Int16 week;
Int16 day;
dayOfWeek = dayOfMonth % daysInWeek;
week = dayOfMonth / daysInWeek;
firstDayOfWeek = DayOfWeek(month, 1, year);
day = (dayOfWeek - firstDayOfWeek + daysInWeek) % daysInWeek + 1 + week * daysInWeek;
// adjust for last-fooday in months with only 4 foodays
while (day > DaysInMonth(month, year))
day -= daysInWeek;
return day;
}
/***********************************************************************
*
* FUNCTION: CountTotalRepeats
*
* DESCRIPTION: Counts the total number of times a repeating event occurs.
* Returns apptNoEndDate (-1) if the event has no end date (repeats forever).
* The default value returned is 1, since an appointment that repeats on 0
* days is not allowed.
*
* PARAMETERS: apptRecP - pointer to an appointment record
*
* RETURNED: number of times the appointment repeats
*
* REVISION HISTORY:
* Name Date Description
* ---- ---- -----------
* grant 3/1/99 Initial Revision
*
***********************************************************************/
static Int32 CountTotalRepeats(ApptDBRecordPtr apptRecP)
{
DateType start;
DateType end;
UInt16 daysTotal;
UInt16 freq;
UInt16 weeks;
UInt16 months;
UInt16 years;
UInt16 dayOfWeek;
UInt16 startDOW;
UInt16 endDOW;
UInt16 daycount;
UInt16 repeatOnDay;
UInt32 startInDays;
UInt32 endInDays;
UInt32 firstSunday;
UInt32 lastSaturday;
UInt32 numDays;
ErrFatalDisplayIf(apptRecP == NULL, "no appointment");
ErrFatalDisplayIf(apptRecP->repeat == NULL, "appointment does not repeat");
ErrFatalDisplayIf(apptRecP->when == NULL, "appointment has no date");
ErrFatalDisplayIf(apptRecP->repeat->repeatFrequency == 0, "zero repeat frequency");
// Get the frequency of occurrence (ex: every 2nd day, every 3rd month, etc).
freq = apptRecP->repeat->repeatFrequency;
// Get the date of the first occurrence of the appointment.
start = apptRecP->when->date;
// Get the date of the last occurrence of the appointment.
end = apptRecP->repeat->repeatEndDate;
// Does the appointment repeat forever?
if (DateToInt(end) == apptNoEndDate)
return (apptNoEndDate);
// if the end date is somehow before the start date, just return 1
if (DateCompare(end, start) < 0)
return 1;
daysTotal = 0;
switch (apptRecP->repeat->repeatType)
{
// Daily repeating appointment.
case repeatDaily:
startInDays = DateToDays(start);
endInDays = DateToDays(end);
daysTotal = ((endInDays - startInDays) / freq) + 1;
break;
// Weekly repeating appointment (ex: every Monday and Friday).
// The strategy is to break the time period into 3 fragments that
// are easily dealt with - days before the first sunday, whole weeks
// from the first sunday to the last saturday, and days after the
// last saturday.
// Yes, weekly repeating appointment can occur more then once a
// week.
case repeatWeekly:
startInDays = DateToDays(start);
endInDays = DateToDays(end);
startDOW = DayOfWeek(start.month, start.day, start.year + firstYear);
endDOW = DayOfWeek(end.month, end.day, end.year + firstYear);
numDays = endInDays - startInDays + 1;
// find firstSunday and lastSaturday
if (startDOW != sunday)
{
firstSunday = startInDays - startDOW + daysInWeek;
}
else
{
firstSunday = startInDays;
}
if (endDOW != saturday)
{
lastSaturday = endInDays - endDOW - 1;
}
else
{
lastSaturday = endInDays;
}
// compute number of full sunday-to-saturday weeks
if (lastSaturday > firstSunday)
weeks = (lastSaturday - firstSunday + 1) / daysInWeek;
else
weeks = 0;
// count number of times appt repeats in a full week
daycount = 0;
for (dayOfWeek = sunday; dayOfWeek < daysInWeek; dayOfWeek++)
{
//if repeat on dayOfWeek, daycount++
if (RepeatOnDOW(apptRecP->repeat, dayOfWeek))
daycount++;
}
// Now we are ready to total the repetitions.
daysTotal = 0;
// fragment 1 - before firstSunday
if (startDOW != sunday)
{
for (dayOfWeek = startDOW; (dayOfWeek < daysInWeek) && (daysTotal < numDays); dayOfWeek++)
{
// if repeat on dayOfWeek, daysTotal++
if (RepeatOnDOW(apptRecP->repeat, dayOfWeek))
daysTotal++;
}
}
// fragment 2 - full weeks from firstSunday to lastSaturday
daysTotal += (daycount * (weeks / freq));
// fragment 3 - after lastSaturday
if (endDOW != saturday)
{
for (dayOfWeek = sunday; (dayOfWeek <= endDOW) && (daysTotal < numDays); dayOfWeek++)
{
// if repeat of dayOfWeek, daysTotal++
if (RepeatOnDOW(apptRecP->repeat, dayOfWeek))
daysTotal++;
}
}
break;
// Monthly-by-day repeating appointment
case repeatMonthlyByDay:
// Compute the number of months
months = ((end.year - start.year) * monthsInYear) + (end.month - start.month);
// if the end day is too early in the last month, don't include that month
repeatOnDay = UnDayOfMonth(end.month, end.year + firstYear,
apptRecP->repeat->repeatOn);
if (end.day < repeatOnDay)
months--;
daysTotal = months / freq + 1; // repeats once every freq months
break;
// Monthly-by-date repeating appointment
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -