(* Class: InsureDate Package: com.waysysweb.util Author: W. Shaffer Date: 07-Jan-2007 Description: This structure specifies various date calculations useful in insurance applications. Maintenance: Date Author Description ----------- ------ ----------------------------------------------------------- 07-Jan-2007 Shaffer File created *) structure INSUREDATE = struct (*============ Exceptions ==============================================*) exception InsureDateError; (*============ Imports =============================================*) (* Date Imports *) type WayDate = WAYDATE.WayDate; type Month = WAYDATE.Month; type Day = WAYDATE.Day; type Year = WAYDATE.Year; fun getDay(date : WayDate) : Day = WAYDATE.getDay(date); fun getMonth(date : WayDate) : Month = WAYDATE.getMonth(date); fun getYear(date : WayDate) : Year = WAYDATE.getYear(date); fun compare(date1 : WayDate, date2 : WayDate) : order = WAYDATE.compare(date1, date2); fun daysInMonth(mnth : Month, yr : Year) : Day = WAYDATE.daysInMonth(mnth, yr); fun difference(date1 : WayDate, date2 : WayDate) : int = WAYDATE.difference(date1, date2); (*============ Types =============================================*) (*============ Constants ==============================================*) val MaxDate = WAYDATE.MaxDate; val MinDate = WAYDATE.MinDate; val MaxYear = WAYDATE.MaxYear; val MinYear = WAYDATE.MinYear; (*============ Properties ==============================================*) (*============ Attributes =============================================*) (*============ Invariant =============================================*) (*============ Initialization ==========================================*) (* Create a date *) (* Precondition: (none) *) fun create(mnth : Month, dy : Day, yr : Year) : WayDate = WAYDATE.create(mnth, dy, yr); (*============ Operations =============================================*) (* Return the age *) fun age(laterDate : WayDate, earlierDate : WayDate) : int = if (compare(laterDate, earlierDate) = LESS) then raise InsureDateError else let val laterMonth = getMonth(laterDate); val laterDay = getDay(laterDate); val earlierMonth = getMonth(earlierDate); val earlierDay = getDay(earlierDate); val laterYear = getYear(laterDate); val earlierYear = getYear(earlierDate) in if laterMonth > earlierMonth then laterYear - earlierYear else if (laterMonth = earlierMonth) andalso (laterDay >= earlierDay) then laterYear - earlierYear else laterYear - earlierYear - 1 end; (* add one month to a date *) fun nextMonth(date : WayDate) : WayDate = if getMonth(date) = 12 andalso getYear(date) = MaxYear then raise InsureDateError else let val day = getDay(date); val month = getMonth(date); val year = getYear(date); val nextMonth = if month = 12 then 1 else month + 1; val nextYear = if month = 12 then year + 1 else year; val daysInMonth = daysInMonth(nextMonth, nextYear); val nextDay = int.min(day, daysInMonth) in create(nextMonth, nextDay, nextYear) end; (* Return a date after adding a number of months *) fun addMonths(date : WayDate, months : int) : WayDate = if months < 0 then raise InsureDateError else if months = 0 then date else addMonths(nextMonth(date), months - 1); (* add a number of years to a date *) (* NOTE: the date cannot be a leap day *) fun addYears(date : WayDate, years : int) : WayDate = let val month = getMonth(date); val day = getDay(date); val year = getYear(date); in if year + years > MaxYear then raise InsureDateError else if year + years < MinYear then raise InsureDateError else if month = 2 andalso day = 29 then raise InsureDateError else create(month, day, year + years) end; (* return the number of days in a year a certain number of years from *) (* a beginning date (e.g. issue date) *) fun daysInPolicyYear(effectiveDate : WayDate, polYear : int) : int = let val beginPolYear = addYears(effectiveDate, polYear); val endPolYear = addYears(beginPolYear, 1) in difference(endPolYear, beginPolYear) end; (* return the number of days in the month *) fun daysInPolicyMonth(monthaversary : WayDate) : int = let val next = nextMonth(monthaversary) in difference(next, monthaversary) end; (* return the number of months between a base date and a new date *) fun diffMonths(newDate : WayDate, baseDate : WayDate) : int = let val ord = compare(baseDate, newDate) in if ord = LESS then 1 + diffMonths(newDate, nextMonth(baseDate)) else if ord = EQUAL then 0 else ~1 end; (* return the number of years between a base date and a new date *) fun diffYears(newDate : WayDate, baseDate : WayDate) : int = let val comp = compare(baseDate, newDate) in case comp of LESS => 1 + diffYears(newDate, addYears(baseDate, 1)) | EQUAL => 0 | GREATER => ~1 end; (* return the current birth date *) fun getCurrentBirthdate(birthdate : WayDate, current : WayDate) : WayDate = create(getMonth(birthdate), getDay(birthdate), getYear(current)); (* return the date closest to the target date *) fun selectClosestDate(date1 : WayDate, date2 : WayDate, date3 : WayDate, target : WayDate) : WayDate = let fun absDiff(later : WayDate, earlier : WayDate) : int = abs(difference(later, earlier)); val diff1 = absDiff(date1, target); val diff2 = absDiff(date2, target); val diff3 = absDiff(date3, target) in if diff1 <= diff2 andalso diff1 <= diff3 then date1 else if diff2 <= diff3 then date2 else date3 end; (* return the birthdate nearest to the current date *) fun getNearestBirthdate(current : WayDate, birthdate : WayDate) : WayDate = let val currentBirthdate = getCurrentBirthdate(birthdate, current); val prevBirthdate = addYears(currentBirthdate, ~1); val nextBirthdate = addYears(currentBirthdate, 1) in selectClosestDate(prevBirthdate, currentBirthdate, nextBirthdate, current) end; (* return the age nearest birthday *) fun ageNearestBirthday(current : WayDate, birthdate : WayDate) : int = let val nearestBirthdate = getNearestBirthdate(current, birthdate) in age(nearestBirthdate, birthdate) end; (* Return true if a date is the anniversary of the effective date *) fun isAnniversary(date : WayDate, effectiveDate : WayDate) : bool = getDay(date) = getDay(effectiveDate) andalso getMonth(date) = getMonth(effectiveDate); (* Return the greatest anniversary date less than or equal to the current*) (* date *) fun getLastAnniversary(current : WayDate, effective : WayDate) : WayDate = let val years = diffYears(current, effective) in addYears(effective, years) end; (* Return true if a date is a monthaversary based on the base date *) fun isMonthaversary(date : WayDate, baseDate : WayDate) : bool = getDay(date) = getDay(baseDate); (* Return the last monthaversary less than or equal a date given an *) (* initial date *) fun getLastMonthaversary(current : WayDate, initial : WayDate) : WayDate = let val months = diffMonths(current, initial) in addMonths(initial, months) end; end (* INSUREDATE *)