March 2013

Volume 28 Number 03

The Working Programmer - Noda Time

By Ted Newarde | March 2013

Ted NewardEver spent much time thinking about time?

Very early in my career, I was working on a system that ended up deploying to several different call centers. Keeping track of “when” an event occurred was particularly important (it was a medical-­related system for a call center of nurses), and so, without thinking about it too much, we dutifully wrote the time of the event into a database row and left it at that. Except, as we discovered later, when the system was deployed to four different call centers, each in a different U.S. time zone, the time logs were all a little “off,” thanks to the fact that we hadn’t thought to include time-zone offsets.

Time in a software system is like that—it all seems pretty straightforward and simple, until it suddenly doesn’t anymore.

In keeping with the theme of my past two columns (all my columns can be found at bit.ly/ghMsco), once again the .NET community benefits from work done by the Java community; in this case, it’s a package called “Noda Time,” a Microsoft .NET Framework port of the Java “Joda Time” project, which itself was designed as a replacement for the Java “Date” class (a horribly broken piece of software dating back to the days of Java 1.0). Jon Skeet, the author of Noda Time, based it on the algorithms and concepts in Joda Time, but built it from the ground up as a .NET library.

Enough preamble: Do an “Install-Package NodaTime” (notice no space between “Noda” and “Time”), and let’s look at some code.

‘Me’ Time

The first thing to realize is that, with all due respect to Einstein’s theories, you don’t have to be approaching light speed to realize that time is relative. If it’s 7 p.m. (that’s 1900 to you European folks) here in Seattle, then it’s 7 p.m. for all of us in Seattle, but it’s 8 p.m. for my folks in Salt Lake City, 9 p.m. for my travel agent in Dallas and 10 p.m. for my drinking buddy in Boston. We all get that—that’s the magic of time zones. But my computer doesn’t really understand time zones, per se—it reports the time it’s been set to, which in this case is 7 p.m., despite the fact that it’s the exact same moment in time for all of us around the world. In other words, it’s not that time itself is relative, it’s that our representation of time is relative. In Noda Time, this representation is reflected as “global” time, meaning a moment on a universal timeline with which everyone agrees. What we consider to be “local” time—that is, that time with an associated time zone—Noda Time calls “zoned time,” as opposed to what Noda Time considers “local” time, which is without any time zone attached (more on this later).

So, for example, the Noda Time “Instant” refers to a point on the global timeline, with an origin point of midnight on Jan. 1, 1970, Coordinated Universal Time (UTC). (There’s nothing magical about that date, except that this is by convention the “start of the epoch” for Unix systems counting “ticks” since that date, and thus serves as good a reference origin point as any other.) So, doing this gives us the current Instant (assuming that the Noda Time namespace is referenced—“using NodaTime”—of course):

var now = SystemClock.Instance.Now;

To get a Seattle-relative time, we want a ZonedDateTime. This is essentially an Instant, but with the time zone information included, so that it identifies itself as being relative to “Seattle, on Jan. 9, 2013” (the date being important because we need to know whether we’re in daylight saving time [DST] or not). A ZonedDateTime is obtained through a constructor, passing in an Instant and a Date­Time zone. We have the Instant, but we need the DateTime zone for Seattle in DST. To obtain the DateTime zone, we need an IDateTime zoneProvider. (The reason for this indirection is subtle, but has to do with the fact that the .NET Framework uses a representation for time zones different from any other programming platform; the Internet Assigned Names Authority, or IANA, uses a format like “America/Los_Angeles.”) Noda Time offers two built-in providers, one being the IANA version and the other the standard .NET base class library (BCL) version, through static properties on the DateTime zoneProviders class:

var seattleTZ = dtzi["America/Vancouver"];
var dtzi = DateTime zoneProviders.Tzdb;

The time zone database (TZDB) version is the IANA version, and so obtaining the time zone that represents Seattle is a matter of selecting it (which, according to IANA, is “America/Los_Angeles,” or if you want something closer, “America/Vancouver”):

var seattleNow = new ZonedDateTime(now, seattleTZ);

And if we print this out, we get a representation of “Local: 1/9/2013 7:54:16 PM Offset: -08 Zone: America/Vancouver.” Notice that “Offset” portion in the representation? It’s important, because remember that based on what day of the year it is (and what country you’re in, and what calendar you’re operating under, and ...), the offset from UTC will change. For those of us in Seattle, DST means gaining or losing an hour off the local clock, so it’s important to note what the offset from UTC is. In fact, Noda Time keeps track of that separately, because when parsing a date such as “2012-06-26T20:41:00+01:00,” for example, we know that it was one hour ahead of UTC, but we don’t know if that was because of DST in that particular time zone or not.

Still think time is easy?

‘Us’ Time

Now let’s assume that I want to know how long until an important date in my life—such as my 25th wedding anniversary, which will be on Jan. 16, 2018. (Keeping track of such things is somewhat important, as I think any spouse would tell you, and I need to know how long I have before I have to buy a really expensive gift.) This is where Noda Time is really going to shine, because it’s going to keep track of all the niggling little details for you.

First, I need to construct a LocalDateTime (or, if I didn’t care about the time, a LocalDate; or, if I didn’t care about the date, a LocalTime). A LocalDateTime (or LocalDate or LocalTime) is a relative position on the timeline that doesn’t know exactly what it’s relative to—in other words, it’s a point in time without knowing its time zone.

(Despite not knowing the time zone, this is still a useful bit of information. Think of it like this: If you and I are working together in the same office, and we want to meet later today, I’ll say, “Let’s meet at 4 p.m.” Because we’re both in the same time zone, no additional information is necessary to qualify this time unambiguously to each other.)

So, because I know the point in time that I care about already, it’s easy to construct:

var twentyFifth = new LocalDate(2018, 1, 16);

And because I’m just asking about the difference of two dates without concern for the time zones, I only need the LocalDate part of the LocalDateTime part of the ZonedDateTime from my earlier calculation:

var today = seattleNow.LocalDateTime.Date;

But what we’re asking here is for a new kind of time unit: a “period” between two times. (In the BCL, this is a Duration.) Noda Time uses a different construct to represent this—a Period—and like all properly represented units of measure, it requires a unit to go with it. For example, the answer “47” is useless without an accompanying unit, such as “47 days,” “47 hours” or “47 years.” Period provides a handy method, Between, to calculate the number of some particular time unit between two LocalDates:

var period = Period.Between(today, twentyFifth, PeriodUnits.Days);
testContextInstance.WriteLine("Only {0} more days to shop!", period.Days);

This tells me exactly how many days, but we don’t usually count days at that large an amount (1,833, at the time I wrote this article) like that. We prefer time to be in more manageable chunks, such as “years, months, days,” which we can again ask Noda Time to manage. We can ask it to give us a Period that contains a years/months/days breakdown, by OR-ing the PeriodUnits flags together:

Period.Between(today, twentyFifth,
  PeriodUnits.Years | PeriodUnits.Months | PeriodUnits.Days)

Or, because this is a pretty common request, we can ask it to give us a Period that contains a years/months/days breakdown by using the pre-constructed flag of the same name:

Period.Between(today, twentyFifth, PeriodUnits.YearMonthDay)

(Apparently, I still have a little time yet, which is good, because I have no idea what to get her.)

Testing Time

Frequent readers of this column will know that I like to write exploration tests when investigating a new library, and this column is no exception. However, it’s impossible to write tests based on time, particularly because time has this annoying habit of continuing on. Each millisecond that passes throws off whatever the expected result is, and that makes it hard, if not impossible, to write tests that will produce predictable results that we can assert and report violations.

For this reason, anything that provides time (such as, you know, a clock) implements the IClock interface, including the SystemClock I used earlier to obtain the Instant for “right now” (the Now static property). If we, for example, create an implementation that implements the IClock interface and provides a constant value back for the Now property (the only member required by the IClock interface, in fact), because the rest of the Noda Time library basi­cally uses Instants to recognize that moment in time, we have essentially created an entirely testable environment, which allows the entire thing to be tested, asserted and verified. Thus, I can change my earlier code slightly and create a set of exploration tests, as shown in Figure 1.

Figure 1 Creating Exploration Tests

[TestClass]
public class UnitTest1
{
  // SystemClock.Instance.Now was at 13578106905161124 when I
  // ran it, so let's mock up a clock that returns that moment
  // in time as "Now"
  public class MockClock : IClock
  {
    public Instant Now
    {
      get { return new Instant(13578106905161124); }
    }
  }
  [TestMethod]
  public void TestMethod1()
  {
    IClock clock = new MockClock(); // was SystemClock.Instance;
    var now = clock.Now;
    Assert.AreEqual(13578106905161124, now.Ticks);
    var dtzi = DateTime zoneProviders.Tzdb;
    var seattleTZ = dtzi["America/Vancouver"];
    Assert.AreEqual("America/Vancouver", seattleTZ.Id);
    var seattleNow = new ZonedDateTime(now, seattleTZ);
    Assert.AreEqual(1, seattleNow.Hour);
    Assert.AreEqual(38, seattleNow.Minute);
    var today = seattleNow.LocalDateTime.Date;
    var twentyFifth = new LocalDate(2018, 1, 16);
    var period = Period.Between(today, twentyFifth, PeriodUnits.Days);
    Assert.AreEqual(1832, period.Days);
  }
}

By going through all of your time-related code and using Noda Time instead of the built-in .NET time types, code becomes much more testable simply by replacing the IClock used to obtain the Instant for “right now” to something controllable and known.

But Wait ...

There’s a lot more to Noda Time than just what I’ve shown here. For example, it’s relatively easy to add time units (days, months and so on) to a given time by using the “Plus” and “Minus” methods (for which there are also operator overloads, if those make more sense to use), as well as a FakeClock class designed specifically for testing time-related code, including the ability to programmatically “advance” time in some discrete fashion, making it easier to test elapsed-time-sensitive code (such as Windows Workflow instances, for example, that are supposed to act after a period of time has elapsed without activity).

At a deeper, more conceptual level, Noda Time also demonstrates how a type system in a programming language can help differentiate between subtly different kinds of values within the problem domain: By separating out the different kinds of time (instants, local time, local dates, local dates and times, and zoned dates and times, for example) into discrete and interrelated types, it helps the programmer be clear and explicit about exactly what this code is supposed to be doing or working with. It can be particularly important, for example, to differentiate a “birth date” from a “birth day” in some code: One reflects the moment in the universe’s timeline when a person was born, the other is a recurring date on which we celebrate that moment in the universe’s timeline. (Practically speaking, one has a year attached to it, the other doesn’t.)

Skeet has made it clear that he doesn’t consider the library “finished” in any way, and he has plans to enhance and extend it further. Fortunately, Noda Time is available for use today, and developers owe it to themselves to NuGet Noda Time, have a look, and start figuring out how and where to use it in the problem domain. After all, time is precious.

Happy coding!


Ted Neward is a principal with Neward & Associates LLC. He has written more than 100 articles and authored and coauthored a dozen books, including “Professional F# 2.0” (Wrox, 2010). He is an F# MVP and noted Java expert, and speaks at both Java and .NET conferences around the world. He consults and mentors regularly—reach him at ted@tedneward.com if you’re interested in having him come work with your team. He blogs at blogs.tedneward.com and can be followed on Twitter at twitter.com/tedneward.

Thanks to the following technical expert for reviewing this article:  Jon Skeet
Jon Skeet is a senior software engineer at Google, working in London. By day he codes in Java, but his passion is C#. You can reach Jon on Twitter (@jonskeet) or simply post a question on Stack Overflow.