Insurance Date Calculations
(*
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 *)