Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ


Choose your language

InfoQ Homepage News Noda Time: An Advanced Date/Time Library for .NET

Noda Time: An Advanced Date/Time Library for .NET

This item in japanese

To put it bluntly, the date/time libraries in .NET are flawed. From the beginning there were no concepts of time zones or really any sort of universal time. As a result most libraries were designed to accept a DateTime class and left the developer to guess if the value should be in local or UTC time. For client server applications the problem was even worse, as local could mean client local or server local time.

In .NET 2.0 the DateTime.Kind property was introduced. This didn’t really solve any problems, but it did break existing applications in rather subtle ways. Even to this day most developers don’t take the time to correctly set the Kind property, or really pay any attention to it. As Jon Skeet explains,

The value of the property affects various different operations in different ways. For example, if you call ToUniversalTime() on an "unspecified" DateTime, it will assume that you really meant it as a local value before. On the other hand, if you call ToLocalTime() on an "unspecified" DateTime, it will assume that you really meant it as a UTC value before. That's one model of behaviour.

In .NET 3.5 we were finally introduced to the DateTimeOffset type. While this finally offered a universal means of including an offset from UTC, it also brought with it some new flaws. For example, a DateTime can be implicitly cast into a DateTimeOffset even if the Kind property is Unspecified. So chances are anytime you see such a conversion you are probably seeing a bug. But more importantly, a DateTimeOffset doesn’t actually represent time zone. Again, we turn it over to Jon Skeet to explain,

A local date and time isn't tied to any particular time zone. At this moment, is it before or after "10pm on August 20th 2011"? It depends where you are in the world. (I'm leaving aside any non-ISO calendar representations for the moment, by the way.) So a DateTimeOffset contains a time-zone-independent component (that "10pm on ..." part) but also an offset from UTC - which means it can be converted to an instant on what I think of as the time line. Ignoring relativity, everyone on the planet experiences a a particular instant simultaneously. If I click my fingers (infinitely quickly!) then any particular event in the universe happened before that instant, at that instant or after that instant. Whether you were in a particular time zone or not is irrelevant. In that respect instants are global compared to the local date and time which any particular individual may have observed at a particular instant.


DateTimeOffset also isn't a good type to use if you want to tie yourself to a specific time zone, because it has no idea of the time zone which gave the relevant offset in the first place. As of .NET 3.5 there's a pretty reasonable TimeZoneInfo class, but no type which talks about "a local time in a particular time zone". So with DateTimeOffset you know what that particular time is in some unspecified time zone, but you don't know what the local time will be a minute later, as the offset for that time zone could change (usually due to daylight saving time changes).

To address many, but far from all, of these problems Jon Skeet is working on a port of Joda Time called Noda Time. What follows are the key concepts in both libraries.

  • Instant: Represents an instant on the timeline measured from the Unix epoch. In .NET this uses ticks while the Java version uses milliseconds. There are 10,000 ticks in a millisecond. Aside from having a different epoch, this class is analogist to a DateTimeOffset with the offset being zero.
  • Partial: A partial represents part of a local date/time, but isn’t complete enough to represent a specific instant in time. For example, the MonthDay subclass can be used to represent annual events such as birthdays. The YearMonth subclass is useful for things like credit card expiration dates where defaulting to the first or last of the month may be inappropriate. For anyone who has had problems mixing date-only and date-time values, the LocalDate type will be appreciated.
  • Interval: This represents a specific time interval. Unlike TimeSpan, this retains the starting and ending instants. You would use this to express concepts such as “on January 1st, 2011 from 8 am to 12 pm”.
  • Duration: This is essentially the TimeSpan class. The resolution is in ticks for .NET and milliseconds for Java.
  • Period: “A period in Joda-Time represents a period of time defined in terms of fields, for example, 3 years 5 months 2 days and 7 hours. This differs from a duration in that it is inexact in terms of milliseconds. A period can only be resolved to an exact number of milliseconds by specifying the instant (including chronology and time zone) it is relative to.”
  • DateTimeZone and Chronology: A DateTimeZone contains most of the information needed to represent a timezone. It is rarely used alone, rather it is combined with a specific CalendarSystem object into a type called Chronology.
  • ZonedDateTime: This combines a local date/time with a specific time zone and calendar system. This makes it less error prone than just using a UTC offset.

Rate this Article