I was looking at a coding exercise recently that consisted of source code that needed refactoring. Embedded in part of the code was a check to see if someone was 21 or over. I thought this was a great chance to use the Noda Time library created by Jon Skeet to create nicely understandable code. Noda Time is described in the following terms:
“Noda Time is an alternative date and time API for .NET. It helps you to think about your data more clearly, and express operations on that data more precisely.” [1]
So, here’s a quick piece of playful code using Noda Time to check a person’s age in years. Firstly, let’s create a service interface.
using System;
namespace AgeService
{
public interface IAgeService
{
bool IsOfAgeAtDate(DateTime dateOfTest, DateTime dateOfBirth, int expectedAgeInYears);
}
}
Now let’s implement the interface.
using System;
using NodaTime;
namespace AgeService
{
public class AgeService : IAgeService
{
public bool IsOfAgeAtDate(DateTime dateOfTest, DateTime dateOfBirth, int expectedAgeInYears)
{
var localDateOfTest = new LocalDate(dateOfTest.Year, dateOfTest.Month, dateOfTest.Day);
var localDateOfBirth = new LocalDate(dateOfBirth.Year, dateOfBirth.Month, dateOfBirth.Day);
Period age = Period.Between(localDateOfBirth, localDateOfTest, PeriodUnits.Years);
return age.Years >= expectedAgeInYears;
}
}
}
A LocalDate is the date portion of a Noda Time LocalDateTime that has no concept of the time of day; it's just a date. A Period described as follows:
“A Period is a number of years, months, weeks, days, hours and so on, which can be added to (or subtracted from) a LocalDateTime, LocalDate or LocalTime. The amount of elapsed time represented by a Period isn't fixed: a period of "one month" is effectively longer when added to January 1st than when added to February 1st, because February is always shorter than January.” [2]
Finally here are a couple of simple tests to demonstrate it works.
using System;
using NUnit.Framework;
namespace AgeServiceTests
{
[TestFixture]
public class AgeServiceTests
{
[Test]
public void IsOfAgeAtDate_WhenOfCorrectAge_ReturnsTrue()
{
// Arrange
var ageService = new AgeService.AgeService();
var dateOfTest = new DateTime(2014, 10, 23);
var dateOfBirth = new DateTime(1993, 10, 23);
// Act
var result = ageService.IsOfAgeAtDate(dateOfTest, dateOfBirth, 21);
// Assert
Assert.That(result, Is.True);
}
[Test]
public void IsOfAgeAtDate_WhenUnderAge_ReturnsFalse()
{
// Arrange
var ageService = new AgeService.AgeService();
var dateOfTest = new DateTime(2014, 10, 23);
var dateOfBirth = new DateTime(1993, 10, 24);
// Act
var result = ageService.IsOfAgeAtDate(dateOfTest, dateOfBirth, 21);
// Assert
Assert.That(result, Is.False);
}
}
}
There’s lots more to Noda Time than that but it’s a start! Happy coding.