2013-03-04 18 views
6

Điều tôi muốn thực hiện là chuyển đổi một DateTime (được phân tích cú pháp từ chuỗi được giả định là EST/EDT) sang UTC. Tôi đang sử dụng NodaTime vì tôi cần sử dụng múi giờ Olson.Sử dụng NodaTime để chuyển đổi giá trị ngày giờ không hợp lệ (bỏ qua) thành UTC

Chuyển đổi một DateTime không hợp lệ (bỏ qua) để sử dụng tính theo giờ UTC ZoneLocalMappingResolver NodaTime của không chuyển đổi phút và giây là một phần của đầu vào bởi vì tôi đã cấu hình CustomResolver để trả lại sự khởi đầu của khoảng thời gian sau khi khoảng cách. NodaTime dường như không tương đương với TimeZoneInfo.IsInvalidTime.

Làm cách nào để sử dụng NodaTime để chuyển đổi giá trị ngày giờ bị bỏ qua thành UTC và khớp với kết quả của phương thức GetUtc() trong lớp Utils bên dưới? (Phương pháp sử dụng Utils.GetUtc System.TimeZoneInfo không NodaTime)

Đây là trường hợp thử nghiệm:

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

Đây là những gì tôi nhận được:

Assert.AreEqual thất bại. Dự kiến: < 2013-03-10 07: 15: 45.000000>. Thực tế: < 2013-03-10 07: 00: 00.000000>.

Đây là lớp Utils (cũng trên 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(); 
    } 
} 

Trả lời

7

NodaTime dường như không có một tương đương với TimeZoneInfo.IsInvalidTime.

Vâng, thay vì chỉ hỏi một câu hỏi - và sau đó phải hỏi những câu hỏi tiếp theo - bạn sử dụng DateTimeZone.MapLocal. Điều đó cung cấp cho bạn mọi thứ bạn có thể biết về ánh xạ UTC cục bộ: cho dù nó rõ ràng, mơ hồ hoặc không hợp lệ.

Hoặc, sử dụng ResolveLocal nhưng với tùy chỉnh của riêng bạn SkippedTimeResolver đại biểu.

Ví dụ, việc thay đổi này làm cho việc mã của bạn cho tôi:

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

(Có nhiều cách tương đương khác để làm việc đó, tất nhiên.)

Cá nhân tôi muốn đề nghị cố gắng để tránh chuyển đổi đến và đi từ DateTime trừ khi bạn thực sự phải - Tôi sẽ làm càng nhiều càng tốt trong Thời gian Noda.

+0

Tôi đã cập nhật liên kết tham chiếu trong câu trả lời này để dẫn đến tài liệu API mới hơn của bạn được lưu trữ tại nodatime.org thay vì trang web cũ, thiếu, mã google. – clarkitect

Các vấn đề liên quan