What I want to accomplish is to convert a DateTime (parsed from a string assumed to be in EST/EDT) to UTC. I am using NodaTime because I need to use Olson timezones.
Converting an invalid (skipped) DateTime to UTC using NodaTime's ZoneLocalMappingResolver is not converting minute and seconds part of the input because I have configured the CustomResolver to return the start of interval after the gap. NodaTime does not seem to have an equivalent of TimeZoneInfo.IsInvalidTime.
How do I use NodaTime to convert skipped datetime values to UTC and match the result of GetUtc() method in the Utils class below? (Utils.GetUtc method uses System.TimeZoneInfo not NodaTime)
This is the test case :
[TestMethod]
public void Test_Invalid_Date()
{
var ts = new DateTime(2013, 3, 10, 2, 15, 45);
// Convert to UTC using System.TimeZoneInfo
var utc = Utils.GetUtc(ts).ToString(Utils.Format);
// Convert to UTC using NodaTime (Tzdb/Olson dataabase)
var utcNodaTime = Utils.GetUtcTz(ts).ToString(Utils.Format);
Assert.AreEqual(utc, utcNodaTime);
}
This is what I am getting :
Assert.AreEqual failed. Expected:<2013-03-10 07:15:45.000000>. Actual:<2013-03-10 07:00:00.000000>.
Here is the Utils class (also on github):
using System;
using NodaTime;
using NodaTime.TimeZones;
/// <summary>
/// Functions to Convert To and From UTC
/// </summary>
public class Utils
{
/// <summary>
/// The date format for display/compare
/// </summary>
public const string Format = "yyyy-MM-dd HH:mm:ss.ffffff";
/// <summary>
/// The eastern U.S. time zone
/// </summary>
private static readonly NodaTime.DateTimeZone BclEast = NodaTime.DateTimeZoneProviders.Bcl.GetZoneOrNull("Eastern Standard Time");
private static readonly TimeZoneInfo EasternTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
private static readonly NodaTime.DateTimeZone TzEast = NodaTime.DateTimeZoneProviders.Tzdb.GetZoneOrNull("America/New_York");
private static readonly ZoneLocalMappingResolver CustomResolver = Resolvers.CreateMappingResolver(Resolvers.ReturnLater, Resolvers.ReturnStartOfIntervalAfter);
public static DateTime GetUtc(DateTime ts)
{
return TimeZoneInfo.ConvertTimeToUtc(EasternTimeZone.IsInvalidTime(ts) ? ts.AddHours(1.0) : ts, EasternTimeZone);
}
public static DateTime GetUtcTz(DateTime ts)
{
var local = LocalDateTime.FromDateTime(ts);
var zdt = TzEast.ResolveLocal(local, CustomResolver);
return zdt.ToDateTimeUtc();
}
public static DateTime GetUtcBcl(DateTime ts)
{
var local = LocalDateTime.FromDateTime(ts);
var zdt = BclEast.ResolveLocal(local, CustomResolver);
return zdt.ToDateTimeUtc();
}
}