Converting DateTimes by Offsets with NodaTime

There must be a simple way to convert one DateTime to another DateTime using only a GMT/UTC Offset integer… right?

What do I mean by DateTime?

There are constraints on converting between and within these Times. For example, Offset != Time Zone so you must be aware of ambiguities resulting from Daylight Savings Time transitions.

Time is difficult, especially when you start thinking about it. Big mistakes can be made when you don’t think about it.

BCL or No?

There are ways to manipulate Time with the BCL’s DateTime and DateTimeOffset classes. However, with its DateTimeKind property, DateTime violates the Single Responsibility Principle. It can have different behaviors based on this property (Matt Johnson)

Let’s rephrase the original problem so I can to introduce you to a library that I guarantee will help you work with Time more clearly.

Is there a simple way to:

There is a simple way, and NodaTime lets us be clear about what we’re trying to do.

NodaTime

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. - NodaTime.org

NodaTime forces you to make decisions about your use case for Time. This is a good thing. Beyond a slight learning curve, it makes Time easier.

In our case, we have a Global Instant - a moment that the world is observing. Let’s say this Instant at UTC (Offset = 0) is 2016-01-21T20:06:00Z

Instant instant = Instant.FromUtc(2016, 1, 21, 20, 6); 
// 2016-01-21T20:06:00Z

What Time would this be at UTC-05?

Since we don’t know what Time Zone we are in, we can use Noda’s OffsetDateTime class. “It preserves the offset information you genuinely have, but without giving the impression of knowing the “real” time zone” (NodaTime User Guide)

Offset offset = Offset.FromHours(-5);
OffsetDateTime sourceOffsetDateTime = instant.WithOffset(offset); 
// 2016-01-21T15:06:00-05

It’s that simple… for this use case.

If we were given a Local DateTime, we could use Noda’s LocalDateTime class. If we were concerned about Daylight Savings Time and other Time Zone rules, we could use Noda’s ZonedDateTime class.

NodaTime gives you clear separation of concerns with its Instant, LocalDateTime, OffsetDateTime, and ZonedDateTime classes.

Summary

We asked if there was a simple way to manipulate DateTime by UTC Offset.

While there are ways to do this with the BCL’s DateTime classes, NodaTime forces you to be aware of the different representations of Time and their constraints.

Noda provided us with Instant and OffsetDateTime to help us stay honest about what we could do with UTC Offset. It turned out to be a simple calculation once we clarified our use case.

Some sample code where I was testing a few different calculations with both NodaTime and the BCL can be found here.

As always, stay tuned by sign up for my newsletter. I look forward to hearing from you! Have a great day!


Sources:

Tweet
comments powered by Disqus