Introduction
This
article describes an approach to assessing the difference between a specified
beginning and end date. The example was written in the context of comparing a
birth date to a specific end date but the same approach could be used to
calculate the number of years, months, and days between a specified start and
end date.
Figure 1: Test Application Main Form
Getting Started:
In order
to get started, unzip the included project and open the solution in the Visual
Studio 2008 environment. In the solution explorer, you should note these files
(Figure 2):
Figure 2: Solution Explorer
The
solution contains a single project called DateAgeCalculation. This project
contains a class entitled AgeEvaluator that is used to perform the date related
calculations and a single form class used to test the AgeEvalator class. The
form contains to date picker controls which are used to set the date of birth
and the end date (used to simulate today as any day of the year).
Code: AgeEvaluator.vb
The
AgeEvaluator class contains a couple of methods used to calculate either the
total number of years the subject has been alive, or used to calculate the
number of years, months, and days the subject has been alive. Further, the
class determines whether or not the subject’s birthday will occur within 30,
60, or 90 days of the specified end date.
The
class begins with the default imports:
Imports
System
Imports
System.Text
The next section contains the class declaration. There is
no specified default constructor for the class as both contained methods are
static.
'''
<summary>
''' Class
used to determine a person's age
''' based
upon a date of birth and a specific
''' end date
'''
</summary>
'''
<remarks></remarks>
Public
Class AgeEvaluator
The
first method contained in this class is used to calculate the person’s age in
years only. This method accepts the person’s date of birth as an argument and
all calculations are based upon comparing the date of birth to the current
date. The return type is specified as a nullable integer so that, if the method
is passed a birthday that is greater than the current date, the method may
return a null. The code in this method is annotated and you can follow what the
method does by reading that annotation.
'''
<summary>
''' Return a person's age in years based
''' upon that person's date of birth
''' </summary>
''' <param
name="birthDay"></param>
'''
<returns></returns>
'''
<remarks></remarks>
Public Shared
Function GetAgeInYears(ByVal
birthDay As DateTime)
As
Nullable(Of
Integer)
' return null if the date of birth
' greater than the current date
If (birthDay > DateTime.Now)
Then
Return Nothing
End If
' get the basic number of years
Dim years As
Integer = DateTime.Now.Year - birthDay.Year
' adjust the years against this year's
' birthday
If (DateTime.Now.Month < birthDay.Month
Or _
(DateTime.Now.Month = birthDay.Month And _
DateTime.Now.Day < birthDay.Day)) Then
years -= 1
End If
' don't return a negative number
' for years alive
If (years >= 0) Then
Return years
Else
Return 0
End
If
End Function
That
next method contained in the class is used to calculate the time a person has
been alive in years, months, and days. The method returns an AgeBag class
instance; this class will be described in the next section of this document but
in general, it is a property bag used to hold the number of years, months, and
days a person has been alive coupled with three Boolean values used to determine
whether or not a person’s next birthday will fall within 30, 60, or 90 days of
the end date specified in the methods arguments. This method is annotated and
you may read what each section of the code does by following the annotation.
''' <summary>
''' Calculate the time a person has been alive in
''' days, months, and years, and return values
''' in an instance of the age bag class
''' </summary>
''' <param name="birthDate"></param>
''' <param name="endDate"></param>
'''
<returns></returns>
'''
<remarks></remarks>
Public Shared
Function GetTimeAlive(ByVal
birthDate As DateTime, _
ByVal
endDate As DateTime)
As AgeBag
If (endDate < birthDate)
Then
System.Windows.Forms.MessageBox.Show("Invalid end
date", "Error")
Return New
AgeBag()
End If
Dim years As
Integer = endDate.Year - birthDate.Year
Dim months As
Integer = endDate.Month - birthDate.Month
Dim days As
Integer = endDate.Day - birthDate.Day
' use the original days value
' to adjust the month where the
' day has passed
If (days < 0) Then
months -= 1
End If
' adjust month and years where
' month has passed
While (months < 0)
months += 12
years -= 1
End While
' adjust days for the current year
Dim timeSpan As
TimeSpan = endDate â€"
birthDate.AddYears(years).AddMonths(months)
' dispose of fractional portion of total days
days =
Convert.ToInt32(Math.Round(timeSpan.TotalDays))
' create and populate an instance of
' the age bag class to keep the values
' calculated for the birth date
Dim ab = New
AgeBag()
ab.AgeDays = days
ab.AgeMonths =
months
'
get rid of negative number of years
If (years >= 1) Then
ab.AgeYears =
years
Else
ab.AgeYears = 0
End If
' get the timespan between the date of birth and end
date
Dim dtThisBirthday =
New DateTime(DateTime.Now.Year, _
birthDate.Month, birthDate.Day)
Dim ts As
TimeSpan = dtThisBirthday - endDate
' round off the fractional days portion and set
' the agebag property used to hold the days remaining
' before the next birthday
ab.DaysToBirthday =
Convert.ToInt32(Math.Round(ts.TotalDays))
' if the days until the next birthday in
' a negative number (already passed), recalculate the
days
' until the next birthday using the future birthday
If (ab.DaysToBirthday < 0)
Then
Dim nextBirthday =
New DateTime(endDate.Year + 1,
birthDate.Month, birthDate.Day)
Dim tsNext As
TimeSpan = nextBirthday - endDate
ab.DaysToBirthday = Convert.ToInt32(Math.Round(tsNext.TotalDays))
' determine whether or not the subject's next
' birthday is between 61 and 90 days away
If (ab.DaysToBirthday <= 90
And ab.DaysToBirthday > 60)
Then
ab.BirthdayIn90Days = True
End If
Else
ab.BirthdayIn90Days = False
' determine whether or not the subject's next
' birthday is between 60 and 31 days
If (ab.DaysToBirthday <= 60
And ab.DaysToBirthday > 30)
Then
ab.BirthdayIn60Days = True
Else
ab.BirthdayIn60Days = False
' determine whether or not the subject's next
' birthday will fall within the next 30 days
If (ab.DaysToBirthday <= 30
And ab.DaysToBirthday >= 0)
Then
ab.BirthdayIn30Days = True
Else
ab.BirthdayIn30Days = False
End If
End If
End If
'
return the populated airbag class instance
' to the caller
Return ab
End Function
End
Class
The bit of code in the project is a class entitled
“AgeBagâ€. This class is nothing more than a property bag used to contain
the years, months, and days a person has been alive coupled with the Booleans
indicating whether or not a person’s next birthday will occur within the
following 30, 60, or 90 days.
'''
<summary>
''' A class
containing age related properties
'''
describing the time alive, the days
''' remaining
before the next birthday, and
'''
indications as to whether or not the
''' next
birthday will fall within 90,
''' 60, or 30
days
'''
</summary>
'''
<remarks></remarks>
Public
Class AgeBag
Public Sub
New()
'
do nothing
End Sub
' member variables
Private mYears As
Integer
Private mMonths As
Integer
Private mDays As
Integer
Private mDaysToBirthday
As Integer
Private mBirthdayIn90Days
As Boolean
Private mBirthdayIn60Days
As Boolean
Private mBirthdayIn30Days
As Boolean
' public properties
Public Property
AgeYears() As Integer
Get
Return mYears
End Get
Set(ByVal
value As Integer)
mYears = value
End Set
End
Property
Public Property
AgeMonths() As
Integer
Get
Return mMonths
End Get
Set(ByVal
value As Integer)
mMonths = value
End Set
End Property
Public Property
AgeDays() As Integer
Get
Return mDays
End Get
Set(ByVal
value As Integer)
mDays = value
End Set
End Property
Public Property
BirthdayIn90Days() As
Boolean
Get
Return mBirthdayIn90Days
End Get
Set(ByVal
value As Boolean)
mBirthdayIn90Days = value
End Set
End Property
Public Property
BirthdayIn60Days() As
Boolean
Get
Return mBirthdayIn60Days
End Get
Set(ByVal
value As Boolean)
mBirthdayIn60Days = value
End Set
End Property
Public Property
BirthdayIn30Days() As
Boolean
Get
Return mBirthdayIn30Days
End Get
Set(ByVal
value As Boolean)
mBirthdayIn30Days = value
End Set
End Property
Public Property
DaysToBirthday() As
Integer
Get
Return mDaysToBirthday
End Get
Set(ByVal
value As Integer)
mDaysToBirthday
= value
End Set
End Property
End
Class
Code: frmTestEmailer.vb
This
form class is the only class contained in the test application; it provides a
simple interface for testing the AgeEvaluator class using a specified birth date
coupled with an arbitrary end date (simulating the current date as any date).
The
class begins with the default imports.
Imports
System.Text
Imports
System.Environment
The next section contains the class declaration and
default constructor.
'''
<summary>
'''
Application used to test the
'''
AgeEvaluator Class
'''
</summary>
'''
<remarks></remarks>
Public
Class Form1
''' <summary>
''' Default Constructor
''' </summary>
'''
<remarks></remarks>
Public Sub
New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the
InitializeComponent() call.
End Sub
The next
bit of code in the application is a method entitled “ShowYourAgeâ€; this
method creates and populates an AgeBag class instance based upon the results
returned from the AgeEvaluator class GetTimeAlive method. The method displays a
message box containing the results returned in the age bag. The method is
annotated and you can follow what is going on within the method by reading he
annotation.
''' <summary>
''' Method uses ManageAgeCalcs Class to
''' determine the age of the subject along with
''' additional information about the subject's
''' next birthday
''' </summary>
Private Sub
ShowYourAge()
Try
' create a new AgeBag to collect the birth and age
related
' information
Dim ab As
New AgeBag()
' get the subject's time alive based upon the
' date of birth and the end value date
ab =
AgeEvaluator.GetTimeAlive(dtpBirthDate.Value, _
dtpEndDate.Value)
' display information about the subject's age and
date
' of birth
Dim sb As
New StringBuilder()
sb.Append("Time
Alive (Days/Months/Years): " + NewLine)
sb.Append("Years
Alive: " + ab.AgeYears.ToString() + NewLine)
sb.Append("Months
Alive: " + ab.AgeMonths.ToString() + NewLine)
sb.Append("Days
Alive: " + ab.AgeDays.ToString() + NewLine +
NewLine)
sb.Append("Pending
Birthday: " + NewLine)
sb.Append("Birthday
Is Within The Next 90 Days: " + _
ab.BirthdayIn90Days.ToString() + NewLine)
sb.Append("Birthday
Is Within The Next 60 Days: " + _
ab.BirthdayIn60Days.ToString() + NewLine)
sb.Append("Birthday
Is Within The Next 30 Days: " + _
ab.BirthdayIn30Days.ToString() + NewLine + NewLine)
sb.Append("Days
Until Next Birthday: " + _
ab.DaysToBirthday.ToString() + NewLine)
' display the age and birth day information
MessageBox.Show("Birth Information" +
NewLine + _
NewLine + sb.ToString(), "Birthday Test")
Catch ex As
Exception
MessageBox.Show(ex.Message, "Error")
End Try
End Sub
The last bit of code in the form class is the button click
event handler used to handle the test button’s click event. The handler
merely calls the ShowYourAge method defined in the previous section of this
document.
''' <summary>
''' Test button click event handler;
''' calls the ShowYourAge method
''' </summary>
''' <param
name="sender"></param>
''' <param
name="e"></param>
'''
<remarks></remarks>
Private Sub
btnTestDates_Click(ByVal sender
As System.Object, _
ByVal e
As System.EventArgs) _
Handles
btnTestDates.Click
ShowYourAge()
End Sub
Summary
The
article provide a simple class that may be used to determine the exact age of a
person, or to determine the exact amount of time in years, months, and days that
has passed between a specific start and end date. Further, the class will
indicate whether or not the person’s next birthday will occur within the
following 30, 60, or 90 days.