2013-03-04 30 views
6

我想要完成的是将DateTime(从假定的字符串解析为EST/EDT中)转换为UTC。我使用的是NodaTime,因为我需要使用Olson时区。使用NodaTime将无效(跳过)的日期时间值转换为UTC

使用NodaTime的ZoneLocalMappingResolver将无效的(跳过的)DateTime转换为UTC ZoneLocalMappingResolver不会转换输入的分秒部分,因为我已配置CustomResolver以在间隔后返回间隔的开始。 NodaTime似乎没有相应的TimeZoneInfo.IsInvalidTime

如何使用NodaTime将跳过的日期时间值转换为UTC并与下面的Utils类中的GetUtc()方法的结果相匹配? (Utils.GetUtc方法使用System.TimeZoneInfo不NodaTime)

这是测试用例:

[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); 
} 

这就是我得到:

Assert.AreEqual失败。预计:< 2013-03-10 07:15:45.000000>。实际:< 2013-03-10 07:00:00.000000>。

这里是utils的类(也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(); 
    } 
} 

回答

7

NodaTime似乎并不具有TimeZoneInfo.IsInvalidTime的等效。

那么,而不是只是问一个问题 - 然后不得不问后续问题 - 您使用DateTimeZone.MapLocal。这给你提供了关于本地UTC映射的所有知识:无论是明确的,模糊的还是无效的。

或者,使用ResolveLocal,但使用您自己的自定义SkippedTimeResolver委托。

例如,使这一变化使你的代码工作对我来说:

private static readonly ZoneLocalMappingResolver CustomResolver = 
    Resolvers.CreateMappingResolver(Resolvers.ReturnLater, AddGap); 

// SkippedTimeResolver which adds the length of the gap to the 
// local date and time. 
private static ZonedDateTime AddGap(LocalDateTime localDateTime, 
            DateTimeZone zone, 
            ZoneInterval intervalBefore, 
            ZoneInterval intervalAfter)   
{ 
    long afterMillis = intervalAfter.WallOffset.Milliseconds; 
    long beforeMillis = intervalBefore.WallOffset.Milliseconds; 
    Period gap = Period.FromMilliseconds(afterMillis - beforeMillis); 
    return zone.AtStrictly(localDateTime + gap); 
} 

(这样做有它,当然其他等效方法。)

我个人建议尽量避免转换到DateTime或从DateTime转换,除非你真的必须 - 我会尽可能在野田时间做。

+0

我已更新此答案中的参考链接,以导致您在nodatime.org上托管的新API文档而不是旧的缺失的Google代码网站。 – clarkitect 2016-03-08 15:36:46

相关问题