Assessing Dates of Birth Using C#

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.

date diff in C# 

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):

date diff in C# 

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.cs

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: 

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;   

The next section contains the namespace and class declarations.  There is no specified default constructor for the class as both contained methods are static. 

  1. namespace DateAgeCalculation  
  2. {  
  3.           public class AgeEvaluator  
  4.           {  

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.

  1. /// <summary>  
  2. /// Returns the years alive only based upon  
  3. /// the date of birth  
  4. /// </summary>  
  5. /// <param name="birthDay"></param>  
  6. /// <returns>int?</returns>  
  7. public static int? GetAgeInYears(DateTime birthDay)  
  8. {  
  9.     //return null if the date of birth  
  10.     //greater than the current date  
  11.     if (birthDay > DateTime.Now)  
  12.         return null;  
  13.     // get the basic number of years  
  14.     int years = DateTime.Now.Year - birthDay.Year;  
  15.     // adjust the years against this year's  
  16.     // birthday  
  17.     if (DateTime.Now.Month < birthDay.Month ||  
  18.        (DateTime.Now.Month == birthDay.Month &&  
  19.         DateTime.Now.Day < birthDay.Day))  
  20.     {  
  21.         years--;  
  22.     }  
  23.     // Don't return a negative number  
  24.     // for years alive  
  25.     if (years >= 0)  
  26.         return years;  
  27.     else  
  28.         return 0;  
  29.  

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

  1.     /// <summary>    
  2.     /// Get the years, months, and days alive between    
  3.     /// the date of birth and a specified end date;    
  4.     /// use current date for the end date in normal    
  5.     /// calculations    
  6.     /// </summary>    
  7.     /// <param name="birthDate"></param>    
  8.     /// <param name="endDate"></param>    
  9.     /// <returns></returns>    
  10.     public static AgeBag GetTimeAlive(DateTime birthDate, DateTime    
  11.     endDate)    
  12.     {    
  13.         if (endDate < birthDate)    
  14.         {    
  15.             System.Windows.Forms.MessageBox.Show("Invalid end date""Error");    
  16.             return new AgeBag();    
  17.         }    
  18.         int years = endDate.Year - birthDate.Year;    
  19.         int months = endDate.Month - birthDate.Month;    
  20.         int days = endDate.Day - birthDate.Day;    
  21.         // use the original days value    
  22.         // to adjust the month where the    
  23.         // day has passed    
  24.         if (days < 0)    
  25.             months -= 1;    
  26.         // adjust month and years where    
  27.         // month has passed    
  28.         while (months < 0)    
  29.         {    
  30.             months += 12;    
  31.             years -= 1;    
  32.         }    
  33.         // adjust days for the current year    
  34.         TimeSpan timeSpan = endDate - birthDate.AddYears(years).AddMonths(months);    
  35.         // dispose of fractional portion of total days    
  36.         days = Convert.ToInt32(Math.Round(timeSpan.TotalDays));    
  37.         // create and populate an instance of    
  38.         // the age bag class to keep the values    
  39.         // calculated for the birth date    
  40.         AgeBag ab = new AgeBag();    
  41.         ab.AgeDays = days;    
  42.         ab.AgeMonths = months;    
  43.         // get rid of negative number of years    
  44.         if (years >= 1)    
  45.             ab.AgeYears = years;    
  46.         else    
  47.             ab.AgeYears = 0;    
  48.         // get the timespan between the date of birth and end date    
  49.         DateTime dtThisBirthday = new DateTime(DateTime.Now.Year,birthDate.Month, birthDate.Day);    
  50.         TimeSpan ts = dtThisBirthday - endDate;    
  51.         // round off the fractional days portion and set    
  52.         // the agebag property used to hold the days remaining    
  53.         // before the next birthday    
  54.         ab.DaysToBirthday = (int)Math.Round(ts.TotalDays);    
  55.         // if the days until the next birthday in    
  56.         // a negative number (already passed), recalculate the days    
  57.         // until the next birthday using the future birthday    
  58.         if (ab.DaysToBirthday < 0)    
  59.         {    
  60.             DateTime nextBirthday = new DateTime(endDate.Year + 1,birthDate.Month, birthDate.Day);    
  61.             TimeSpan tsNext = nextBirthday - endDate;    
  62.             ab.DaysToBirthday = Convert.ToInt32(Math.Round(tsNext.TotalDays));    
  63.         }    
  64.         // determine whether or not the subject's next    
  65.         // birthday is between 61 and 90 days away    
  66.         if (ab.DaysToBirthday <= 90 && ab.DaysToBirthday > 60)    
  67.             ab.BirthdayIn90Days = true;  
  68.         else  
  69.             ab.BirthdayIn90Days = false;  
  70.         // determine whether or not the subject's next    
  71.         // birthday is between 60 and 31 days  
  72.         if (ab.DaysToBirthday <= 60 && ab.DaysToBirthday > 30)    
  73.             ab.BirthdayIn60Days = true;    
  74.         else    
  75.             ab.BirthdayIn60Days = false;    
  76.         // determine whether or not the subject's next    
  77.         // birthday will fall within the next 30 days    
  78.         if (ab.DaysToBirthday <= 30 && ab.DaysToBirthday >= 0)    
  79.             ab.BirthdayIn30Days = true;    
  80.         else    
  81.             ab.BirthdayIn30Days = false;  
  82.         // return the populated airbag class instance    
  83.         // to the caller    
  84.         return ab;    
  85.     } 

The bit of code in this class is a nested 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.

  1.     /// <summary>  
  2.     /// A property bag for holding the years, months, and days since  
  3.     /// between a birth date  
  4.     /// </summary>  
  5.     public class AgeBag  
  6.     {  
  7.         public AgeBag()  
  8.         {  
  9.         }  
  10.         // member variables  
  11.         private int mYears;  
  12.         private int mMonths;  
  13.         private int mDays;  
  14.         private int mDaysToBirthday;  
  15.         private bool mBirthdayIn90Days;  
  16.         private bool mBirthdayIn60Days;  
  17.         private bool mBirthdayIn30Days;  
  18.         // public properties  
  19.         public int AgeYears  
  20.         {  
  21.             get  
  22.             {  
  23.                 return mYears;  
  24.             }  
  25.             set  
  26.             {  
  27.                 mYears = value;  
  28.             }  
  29.         }  
  30.         public int AgeMonths  
  31.         {  
  32.             get  
  33.             {  
  34.                 return mMonths;  
  35.             }  
  36.             set  
  37.             {  
  38.                 mMonths = value;  
  39.             }  
  40.         }  
  41.         public int AgeDays  
  42.         {  
  43.             get  
  44.             {  
  45.                 return mDays;  
  46.             }  
  47.             set  
  48.             {  
  49.                 mDays = value;  
  50.             }  
  51.         }  
  52.         public bool BirthdayIn90Days  
  53.         {  
  54.             get  
  55.             {  
  56.                 return mBirthdayIn90Days;  
  57.             }  
  58.             set  
  59.             {  
  60.                 mBirthdayIn90Days = value;  
  61.             }  
  62.         }  
  63.         public bool BirthdayIn60Days  
  64.         {  
  65.             get  
  66.             {  
  67.                 return mBirthdayIn60Days;  
  68.             }  
  69.             set  
  70.             {  
  71.                 mBirthdayIn60Days = value;  
  72.             }  
  73.         }  
  74.         public bool BirthdayIn30Days  
  75.         {  
  76.             get  
  77.             {  
  78.                 return mBirthdayIn30Days;  
  79.             }  
  80.             set  
  81.             {  
  82.                 mBirthdayIn30Days = value;  
  83.             }  
  84.         }  
  85.         public int DaysToBirthday  
  86.         {  
  87.             get  
  88.             {  
  89.                 return mDaysToBirthday;  
  90.             }  
  91.             set  
  92.             {  
  93.                 mDaysToBirthday = value;  
  94.             }  
  95.         }  
  96.     }  
  97. }   

Code:  frmTestEmailer.cs

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. 

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.ComponentModel;  
  4. using System.Data;  
  5. using System.Drawing;  
  6. using System.Linq;  
  7. using System.Text;  
  8. using System.Windows.Forms;  
The next section contains the namespace and class declarations, and default constructor.
  1. namespace DateAgeCalculation  
  2. {  
  3.     /// <summary>  
  4.     /// Demo application used to test the ManageAgeCalcs  
  5.     /// class  
  6.     /// </summary>  
  7.     public partial class Form1 : Form  
  8.     {  
  9.         // default constructor  
  10.         public Form1()  
  11.         {  
  12.             InitializeComponent();  
  13.         }  
  14.     }  
  15. }

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 the annotation.

  1. /// <summary>  
  2. /// Method uses AgeEvaluator Class to  
  3. /// determine the age of the subject along with  
  4. /// additional information about the subject's  
  5. /// next birthday  
  6. /// </summary>  
  7. private void ShowYourAge()  
  8. {  
  9.     try  
  10.     {
  11.         // create a new AgeBag to collect the birth and age related  
  12.         // information  
  13.         AgeEvaluator.AgeBag ab = new AgeEvaluator.AgeBag();  
  14.         // get the subject's time alive based upon the  
  15.         // date of birth and the end value date
  16.         ab = AgeEvaluator.GetTimeAlive(dtpBirthDate.Value,dtpEndDate.Value);  
  17.         // display information about the subject's age and date  
  18.         // of birth  
  19.         StringBuilder sb = new StringBuilder();  
  20.         sb.Append("The amount of time the subject as lived in days,months and Years: "  + Environment.NewLine); 
  21.         sb.Append("Years Alive: " + ab.AgeYears + Environment.NewLine);  
  22.         sb.Append("Months Alive: " + ab.AgeMonths +  Environment.NewLine);  
  23.         sb.Append("Days Alive: " + ab.AgeDays + Environment.NewLine  + Environment.NewLine);
  24.         sb.Append("Pending Birthday: " + Environment.NewLine);  
  25.         sb.Append("Birthday Is Within The Next 90 Days: "  + ab.BirthdayIn90Days.ToString() + Environment.NewLine);  
  26.         sb.Append("Birthday Is Within The Next 60 Days: "  + ab.BirthdayIn60Days.ToString() + Environment.NewLine);  
  27.         sb.Append("Birthday Is Within The Next 30 Days: "  + ab.BirthdayIn30Days.ToString() + Environment.NewLine + Environment.NewLine);  
  28.         sb.Append("Days Until Next Birthday: " +  
  29.         ab.DaysToBirthday.ToString() + Environment.NewLine);  
  30.         // display the age and birth day information  
  31.         MessageBox.Show("Birth Information" + Environment.NewLine +  Environment.NewLine + sb.ToString(), "Birthday Test");  
  32.     }
  33.     catch (Exception ex)
  34.     {  
  35.         MessageBox.Show(ex.Message, "Error");  
  36.     }  
  37. }

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.

  1. /// <summary>  
  2. /// On click handler used to obtain information  
  3. /// about the subject's age and pending birthday  
  4. /// </summary>  
  5. /// <param name="sender"></param>  
  6. /// <param name="e"></param>  
  7. private void button1_Click(object sender, EventArgs e)  
  8. {  
  9.     ShowYourAge();  
  10. }  

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.