A
Adrian
I hit on this problem converting a VB.NET insurance application to C#.
Age next birthday calculated from date of birth is often needed in
insurance premium calculations.
Originally done using DateDiff in VB.NET which is only available in C#
if you don't mind linking in Microsoft.VisualBasic.dll to your C#
application.
I wanted to avoid this so set about a pure C# solution which uses a
combination of TimeSpan in whole days and the
System.Globalizarion.Calendar class GetDaysInYear() function to work
it out.
The added advantage here over DateDiff is this function should work
with all the different System.Globalization.Calendar types (Japanese
etc.), however I have only tested it with GregorianCalendar.
Here is the C# source code which includes a console application test
harness.
To get "Age" rather than "Age next birthday" just subtract 1 from this
result (sorry for pointing out the obvious!)
<code>
using System;
namespace WorkbenchCSConsole
{
/// <summary>
/// Summary description for AgeNextBirtdatCalculator.
/// </summary>
class AgeNextBirtdatCalculator
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
//
// Test harness for AgeNextBirthday function
//
int AgeNextBirthday;
DateTime DOB;
DateTime DateNow;
System.Globalization.Calendar MyCalendar = new
System.Globalization.GregorianCalendar(); // should work with other
calendars
DateNow = DateTime.Now;
System.Console.WriteLine("Calendar independant date of birth to
age NEXT birtday function (commonly required in the insurance
industry) for C# written by Adrian Hilder, Camdaw Limited
www.camdaw.net. You are free to use and distribute this function in
your applications, you may not sell it for profit as a stand alone
utility without prior consent from Camdaw Limited.\nThis function is
provided as is in the hope it is usefull with no warrantee of any
kind. You should test this function to your satisfaction before using
it in your applications.\nIf you do find any faults please tell
me!\nIf you use this please tell me, I'm interested to know if anyone
uses it (it was about 3 hours work). (contact details at
www.camdaw.net)\n\n");
DOB = DateTime.MinValue;
DOB = DOB.AddYears(1970-1);
DOB = DOB.AddMonths(DateNow.Month-1);
DOB = DOB.AddDays(DateNow.Day-2);
System.Console.WriteLine("Calendar type: " +
MyCalendar.ToString() + "\n");
System.Console.WriteLine("Testing with todays date " +
DateNow.Day + "/" + DateNow.Month + "/" + DateNow.Year + "
(dd/mm/yyyy)\n");
Console.WriteLine("Test with DOB yesterdays date in 1970");
System.Console.WriteLine("DOB entered: " + DOB.Day + "/" +
DOB.Month + "/" + DOB.Year + " (dd/mm/yyyy)");
AgeNextBirthday = DOBToAgeNextBirthday(DOB, MyCalendar);
System.Console.WriteLine("AgeNextBirthdayYears=" +
AgeNextBirthday + "\n");
Console.WriteLine("Test with DOB tommorrows date in 1970");
DOB = DateTime.MinValue;
DOB = DOB.AddYears(1970-1);
DOB = DOB.AddMonths(DateNow.Month-1);
DOB = DOB.AddDays(DateNow.Day);
System.Console.WriteLine("DOB entered: " + DOB.Day + "/" +
DOB.Month + "/" + DOB.Year + " (dd/mm/yyyy)");
AgeNextBirthday = DOBToAgeNextBirthday(DOB, MyCalendar);
System.Console.WriteLine("AgeNextBirthdayYears=" +
AgeNextBirthday + "\n");
Console.WriteLine("Test with DOB this day in 1970");
DOB = DateTime.MinValue;
DOB = DOB.AddYears(1970-1);
DOB = DOB.AddMonths(DateNow.Month-1);
DOB = DOB.AddDays(DateNow.Day-1);
System.Console.WriteLine("DOB entered: " + DOB.Day + "/" +
DOB.Month + "/" + DOB.Year + " (dd/mm/yyyy) ... Happy Birthday!");
AgeNextBirthday = DOBToAgeNextBirthday(DOB, MyCalendar);
System.Console.WriteLine("AgeNextBirthdayYears=" +
AgeNextBirthday + "\n");
while(!(MyCalendar.IsLeapYear(DateNow.Year)))
DateNow = DateNow.AddYears(1);
System.Console.WriteLine("Testing with the next leap year date "
+ DateNow.Day + "/" + DateNow.Month + "/" + DateNow.Year + "
(dd/mm/yyyy)\n");
System.Console.WriteLine("Note: this DOBToAgeNextBirthday
function and test harness was written 3rd August 2004, which was a
leap year.");
Console.WriteLine("Test with DOB yesterdays date in 1970");
System.Console.WriteLine("DOB entered: " + DOB.Day + "/" +
DOB.Month + "/" + DOB.Year + " (dd/mm/yyyy)");
AgeNextBirthday = DOBToAgeNextBirthday(DOB, MyCalendar);
System.Console.WriteLine("AgeNextBirthdayYears=" +
AgeNextBirthday + "\n");
Console.WriteLine("Test with DOB tommorrows date in 1970");
DOB = DateTime.MinValue;
DOB = DOB.AddYears(1970-1);
DOB = DOB.AddMonths(DateNow.Month-1);
DOB = DOB.AddDays(DateNow.Day);
System.Console.WriteLine("DOB entered: " + DOB.Day + "/" +
DOB.Month + "/" + DOB.Year + " (dd/mm/yyyy)");
AgeNextBirthday = DOBToAgeNextBirthday(DOB, MyCalendar);
System.Console.WriteLine("AgeNextBirthdayYears=" +
AgeNextBirthday + "\n");
Console.WriteLine("Test with DOB this day in 1970");
DOB = DateTime.MinValue;
DOB = DOB.AddYears(1970-1);
DOB = DOB.AddMonths(DateNow.Month-1);
DOB = DOB.AddDays(DateNow.Day-1);
System.Console.WriteLine("DOB entered: " + DOB.Day + "/" +
DOB.Month + "/" + DOB.Year + " (dd/mm/yyyy) ... Happy Birthday!");
AgeNextBirthday = DOBToAgeNextBirthday(DOB, MyCalendar);
System.Console.WriteLine("AgeNextBirthdayYears=" +
AgeNextBirthday + "\n");
}
private static int DOBToAgeNextBirthday(DateTime DOB,
System.Globalization.Calendar ThisCalendar)
{
int DaysPassedInYear;
DateTime Now;
int YearIndex;
int DiffDays;
Now = DateTime.Now;
DiffDays = (int)Now.Subtract(DOB).TotalDays;
YearIndex = 0;
DaysPassedInYear = CalcDaysPassedInYear(Now, DOB, YearIndex,
ThisCalendar);
while(DiffDays > DaysPassedInYear)
{
DiffDays = DiffDays - DaysPassedInYear;
YearIndex++; // on to next year
DaysPassedInYear = CalcDaysPassedInYear(Now, DOB, YearIndex,
ThisCalendar);
}
// Now handle last part year
if (DiffDays > 0) // if still some days to account for
{
int DaysPassedToBirthday;
DaysPassedInYear = CalcDaysPassedInYear(Now, DOB, -1,
ThisCalendar);
DaysPassedToBirthday =
CalcDaysPassedInYear(DOB.AddYears(YearIndex), DOB, -1, ThisCalendar);
if (DaysPassedInYear >= DaysPassedToBirthday)
YearIndex++; // birthday has passed this year
}
return YearIndex;
}
private static int CalcDaysPassedInYear(DateTime Now, DateTime
DOB, int YearIndex, System.Globalization.Calendar ThisCalendar)
{
DateTime PartYearStartDate; // 1st Jan <PartYear>
int YearDaysPassed;
int DaysPassedInYear;
if (YearIndex == 0) // days in starting (DOB) part year
{
PartYearStartDate = DateTime.MinValue;
PartYearStartDate = PartYearStartDate.AddYears(DOB.Year-1);
YearDaysPassed =
(int)DOB.Subtract(PartYearStartDate).TotalDays;
DaysPassedInYear = ThisCalendar.GetDaysInYear(DOB.Year) -
YearDaysPassed;
}
else if (YearIndex == -1) // -1 used to indicate last year in
period, i.e. Now.Year
{
PartYearStartDate = DateTime.MinValue;
PartYearStartDate.AddYears(Now.Year);
DaysPassedInYear =
(int)Now.Subtract(PartYearStartDate).TotalDays;
}
else // a year within the period
{
DaysPassedInYear = ThisCalendar.GetDaysInYear(DOB.Year +
YearIndex);
}
return DaysPassedInYear;
}
}
}
</code>
Age next birthday calculated from date of birth is often needed in
insurance premium calculations.
Originally done using DateDiff in VB.NET which is only available in C#
if you don't mind linking in Microsoft.VisualBasic.dll to your C#
application.
I wanted to avoid this so set about a pure C# solution which uses a
combination of TimeSpan in whole days and the
System.Globalizarion.Calendar class GetDaysInYear() function to work
it out.
The added advantage here over DateDiff is this function should work
with all the different System.Globalization.Calendar types (Japanese
etc.), however I have only tested it with GregorianCalendar.
Here is the C# source code which includes a console application test
harness.
To get "Age" rather than "Age next birthday" just subtract 1 from this
result (sorry for pointing out the obvious!)
<code>
using System;
namespace WorkbenchCSConsole
{
/// <summary>
/// Summary description for AgeNextBirtdatCalculator.
/// </summary>
class AgeNextBirtdatCalculator
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
//
// Test harness for AgeNextBirthday function
//
int AgeNextBirthday;
DateTime DOB;
DateTime DateNow;
System.Globalization.Calendar MyCalendar = new
System.Globalization.GregorianCalendar(); // should work with other
calendars
DateNow = DateTime.Now;
System.Console.WriteLine("Calendar independant date of birth to
age NEXT birtday function (commonly required in the insurance
industry) for C# written by Adrian Hilder, Camdaw Limited
www.camdaw.net. You are free to use and distribute this function in
your applications, you may not sell it for profit as a stand alone
utility without prior consent from Camdaw Limited.\nThis function is
provided as is in the hope it is usefull with no warrantee of any
kind. You should test this function to your satisfaction before using
it in your applications.\nIf you do find any faults please tell
me!\nIf you use this please tell me, I'm interested to know if anyone
uses it (it was about 3 hours work). (contact details at
www.camdaw.net)\n\n");
DOB = DateTime.MinValue;
DOB = DOB.AddYears(1970-1);
DOB = DOB.AddMonths(DateNow.Month-1);
DOB = DOB.AddDays(DateNow.Day-2);
System.Console.WriteLine("Calendar type: " +
MyCalendar.ToString() + "\n");
System.Console.WriteLine("Testing with todays date " +
DateNow.Day + "/" + DateNow.Month + "/" + DateNow.Year + "
(dd/mm/yyyy)\n");
Console.WriteLine("Test with DOB yesterdays date in 1970");
System.Console.WriteLine("DOB entered: " + DOB.Day + "/" +
DOB.Month + "/" + DOB.Year + " (dd/mm/yyyy)");
AgeNextBirthday = DOBToAgeNextBirthday(DOB, MyCalendar);
System.Console.WriteLine("AgeNextBirthdayYears=" +
AgeNextBirthday + "\n");
Console.WriteLine("Test with DOB tommorrows date in 1970");
DOB = DateTime.MinValue;
DOB = DOB.AddYears(1970-1);
DOB = DOB.AddMonths(DateNow.Month-1);
DOB = DOB.AddDays(DateNow.Day);
System.Console.WriteLine("DOB entered: " + DOB.Day + "/" +
DOB.Month + "/" + DOB.Year + " (dd/mm/yyyy)");
AgeNextBirthday = DOBToAgeNextBirthday(DOB, MyCalendar);
System.Console.WriteLine("AgeNextBirthdayYears=" +
AgeNextBirthday + "\n");
Console.WriteLine("Test with DOB this day in 1970");
DOB = DateTime.MinValue;
DOB = DOB.AddYears(1970-1);
DOB = DOB.AddMonths(DateNow.Month-1);
DOB = DOB.AddDays(DateNow.Day-1);
System.Console.WriteLine("DOB entered: " + DOB.Day + "/" +
DOB.Month + "/" + DOB.Year + " (dd/mm/yyyy) ... Happy Birthday!");
AgeNextBirthday = DOBToAgeNextBirthday(DOB, MyCalendar);
System.Console.WriteLine("AgeNextBirthdayYears=" +
AgeNextBirthday + "\n");
while(!(MyCalendar.IsLeapYear(DateNow.Year)))
DateNow = DateNow.AddYears(1);
System.Console.WriteLine("Testing with the next leap year date "
+ DateNow.Day + "/" + DateNow.Month + "/" + DateNow.Year + "
(dd/mm/yyyy)\n");
System.Console.WriteLine("Note: this DOBToAgeNextBirthday
function and test harness was written 3rd August 2004, which was a
leap year.");
Console.WriteLine("Test with DOB yesterdays date in 1970");
System.Console.WriteLine("DOB entered: " + DOB.Day + "/" +
DOB.Month + "/" + DOB.Year + " (dd/mm/yyyy)");
AgeNextBirthday = DOBToAgeNextBirthday(DOB, MyCalendar);
System.Console.WriteLine("AgeNextBirthdayYears=" +
AgeNextBirthday + "\n");
Console.WriteLine("Test with DOB tommorrows date in 1970");
DOB = DateTime.MinValue;
DOB = DOB.AddYears(1970-1);
DOB = DOB.AddMonths(DateNow.Month-1);
DOB = DOB.AddDays(DateNow.Day);
System.Console.WriteLine("DOB entered: " + DOB.Day + "/" +
DOB.Month + "/" + DOB.Year + " (dd/mm/yyyy)");
AgeNextBirthday = DOBToAgeNextBirthday(DOB, MyCalendar);
System.Console.WriteLine("AgeNextBirthdayYears=" +
AgeNextBirthday + "\n");
Console.WriteLine("Test with DOB this day in 1970");
DOB = DateTime.MinValue;
DOB = DOB.AddYears(1970-1);
DOB = DOB.AddMonths(DateNow.Month-1);
DOB = DOB.AddDays(DateNow.Day-1);
System.Console.WriteLine("DOB entered: " + DOB.Day + "/" +
DOB.Month + "/" + DOB.Year + " (dd/mm/yyyy) ... Happy Birthday!");
AgeNextBirthday = DOBToAgeNextBirthday(DOB, MyCalendar);
System.Console.WriteLine("AgeNextBirthdayYears=" +
AgeNextBirthday + "\n");
}
private static int DOBToAgeNextBirthday(DateTime DOB,
System.Globalization.Calendar ThisCalendar)
{
int DaysPassedInYear;
DateTime Now;
int YearIndex;
int DiffDays;
Now = DateTime.Now;
DiffDays = (int)Now.Subtract(DOB).TotalDays;
YearIndex = 0;
DaysPassedInYear = CalcDaysPassedInYear(Now, DOB, YearIndex,
ThisCalendar);
while(DiffDays > DaysPassedInYear)
{
DiffDays = DiffDays - DaysPassedInYear;
YearIndex++; // on to next year
DaysPassedInYear = CalcDaysPassedInYear(Now, DOB, YearIndex,
ThisCalendar);
}
// Now handle last part year
if (DiffDays > 0) // if still some days to account for
{
int DaysPassedToBirthday;
DaysPassedInYear = CalcDaysPassedInYear(Now, DOB, -1,
ThisCalendar);
DaysPassedToBirthday =
CalcDaysPassedInYear(DOB.AddYears(YearIndex), DOB, -1, ThisCalendar);
if (DaysPassedInYear >= DaysPassedToBirthday)
YearIndex++; // birthday has passed this year
}
return YearIndex;
}
private static int CalcDaysPassedInYear(DateTime Now, DateTime
DOB, int YearIndex, System.Globalization.Calendar ThisCalendar)
{
DateTime PartYearStartDate; // 1st Jan <PartYear>
int YearDaysPassed;
int DaysPassedInYear;
if (YearIndex == 0) // days in starting (DOB) part year
{
PartYearStartDate = DateTime.MinValue;
PartYearStartDate = PartYearStartDate.AddYears(DOB.Year-1);
YearDaysPassed =
(int)DOB.Subtract(PartYearStartDate).TotalDays;
DaysPassedInYear = ThisCalendar.GetDaysInYear(DOB.Year) -
YearDaysPassed;
}
else if (YearIndex == -1) // -1 used to indicate last year in
period, i.e. Now.Year
{
PartYearStartDate = DateTime.MinValue;
PartYearStartDate.AddYears(Now.Year);
DaysPassedInYear =
(int)Now.Subtract(PartYearStartDate).TotalDays;
}
else // a year within the period
{
DaysPassedInYear = ThisCalendar.GetDaysInYear(DOB.Year +
YearIndex);
}
return DaysPassedInYear;
}
}
}
</code>