2013-02-19 12 views
9

Zoneinfo verileri için verdiği güzel destek nedeniyle NodaTime kullanıyorum, ancak Quartz.NET'te kullanılmak üzere DateTimeZone'u TimeZoneInfo'a dönüştürmem gereken bir durum var.NodaTime DateTimeZone'ı TimeZoneInfo'ya dönüştürün

Burada önerilen yaklaşım nedir? IANA, Windows saat dilimleri ve zoneinfo saat dilimleri arasında bir eşleme dosyası var, bu bilgileri kullanan bir uzantı yöntemi oluşturabilir miyim?

sayesinde Dekan

+0

Bu arada hangi IANA dosyasını kastediyorsunuz? Bir CLDR var biliyorum, ama IANA farklı bir biçimde bunu sağlar, bu ilginç olurdu ... –

cevap

12

Ben mümkünse yansıma kullanarak önleyeceğini: MapTimeZoneId zoneinfo içine, Windows saat diliminden eşleme yapar ... Ben ters yönde eşleme yapmak için yansıma başvurmadan sona erdi. Yaklaşan gelecekteki sürümlerle çalışma konusunda bahse girerim :)

Gelecek sürümler için bu özellik için bir özellik isteği göndermekten çekinmeyin, ancak şu an için ters sözlüğünüzü daha kararlı bir şekilde hazırlayacağım. yolu: elbette

// Note: this version lets you work with any IDateTimeZoneSource, although as the only 
// other built-in source is BclDateTimeZoneSource, that may be less useful :) 
private static IDictionary<string, string> LoadTimeZoneMap(IDateTimeZoneSource source) 
{ 
    var nodaToWindowsMap = new Dictionary<string, string>(); 
    foreach (var bclZone in TimeZoneInfo.GetSystemTimeZones()) 
    { 
     var nodaId = source.MapTimeZoneId(bclZone); 
     if (nodaId != null) 
     { 
      nodaToWindowsMap[nodaId] = bclZone.Id; 
     } 
    } 
    return nodaToWindowsMap; 
} 

, bu TZDB tüm zaman dilimlerini kapsamaz olacaktır. Aslında, kullandığımız CLDR bilgilerine dayanarak verebildiğimiz tüm bilgileri bile vermeyecek ... CLDR, her bir Windows ID için birden fazla eşleşme verir ve biz sadece birincisini saklarız. Daha fazlasını nasıl ortaya çıkaracağımıza, ama henüz başlamamıza çalıştık. Düşünceler, Noda Time posta listesine hoş geldiniz :)

Ayrıca, BCL ve TZDB bölgeleri arasında bir haritalama olması, aslında her şey için aynı sonuçları vereceği anlamına gelmediğinden, yalnızca mevcut en yakın eşleme olduğunu unutmayın.

+0

Teşekkürler Jon Bu yaklaşım çok daha iyi.TZDB ve CLDR arasında farklı veri olasılığına dair yorumlarınızı gözden geçirin. Son kullanıcı cihazlarımız tarafından ihtiyaç duyulan zaman dilimlerinin listesini aldık ve şu anda geçerli Windows saat dilimlerine bire bir eşleme yaptık. Farklı bir yaklaşımı düşünmemiz gereken çizgiyi aşmak mümkün ama bu şimdilik işe yarıyor. –

+0

@DeanWard: Herhangi bir yardım varsa, bu konuda daha fazla bilgi sağlamak için bugün [issue 82] (https://code.google.com/p/noda-time/issues/detail?id=82) kullanmaya başladım. eşleştirmeleri. Yine de 1.1 sürümüne girip girmeyeceğinden emin değilim. –

+0

Bu konuda bir gözüm var, yardımlarınız için teşekkürler! –

4

Aha, buldum - TzdbDateTimeZoneSource Ben TimeZoneInfo.FindSystemTimeZoneById içine patlatabilir bir MapTimeZoneId yöntemi vardır.

Düzenleme:

using System; 
using System.Collections.Generic; 
using System.Reflection; 

using NodaTime; 
using NodaTime.TimeZones; 

/// <summary> 
/// Extension methods for <see cref="DateTimeZone" />. 
/// </summary> 
internal static class DateTimeZoneExtensions 
{ 
    private static readonly Lazy<IDictionary<string, string>> map = new Lazy<IDictionary<string, string>>(LoadTimeZoneMap, true); 

    public static TimeZoneInfo ToTimeZoneInfo(this DateTimeZone timeZone) 
    { 
     string id; 
     if (!map.Value.TryGetValue(timeZone.Id, out id)) 
     { 
      throw new TimeZoneNotFoundException(string.Format("Could not locate time zone with identifier {0}", timeZone.Id)); 
     } 

     TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(id); 
     if (timeZoneInfo == null) 
     { 
      throw new TimeZoneNotFoundException(string.Format("Could not locate time zone with identifier {0}", timeZone.Id)); 
     } 

     return timeZoneInfo; 
    } 

    private static IDictionary<string, string> LoadTimeZoneMap() 
    { 
     TzdbDateTimeZoneSource source = new TzdbDateTimeZoneSource("NodaTime.TimeZones.Tzdb"); 
     FieldInfo field = source.GetType().GetField("windowsIdMap", BindingFlags.Instance | BindingFlags.NonPublic); 
     IDictionary<string, string> map = (IDictionary<string, string>)field.GetValue(source); 

     // reverse the mappings 
     Dictionary<string, string> reverseMap = new Dictionary<string, string>(); 
     foreach (KeyValuePair<string, string> kvp in map) 
     { 
      reverseMap.Add(kvp.Value, kvp.Key); 
     } 

     return reverseMap; 
    } 
} 
+1

Eğer kaynak yeni istemiyorsanız, bu yardımcı olacaktır: NodaTime.TimeZones.TzdbDateTimeZoneSource.Default – jsgoupil

0

Ancak bunların hiçbiri bir PCL'de çalışmaz, çünkü çalışmaların çoğunun .NET tarafından .GetSystemTImeZones() ve .FindSystemTIemZoneById() yöntemlerinde - PCL'de bulunmadığı için yapılmasıdır.

NodaTime'den çıkabileceğin tüm bilgiler için, "ABD/Doğu" bölge adının olduğu zaman "EST" kısaltması kadar basit bir şey almamın benim izlerimde beni durdurduğuna şaşıyorum. .

1

Matt Johnson numaralı telefondan TimeZoneConverter kitaplığını kullanabilirsiniz.

string windowsTimeZoneName = TZConvert.IanaToWindows(tzdbZoneLocation.ZoneId); 
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(windowsTimeZoneName); 

ihtimale çare çeşit try-catch ile tamamlamayı unutmayın: Eğer böyle TimeZoneInfo alabilirsiniz NodeTime TzdbZoneLocation kullandığı

BölgeKimliği, IANA time zone olduğunu.

Ayrıca, IANA saat dilimi ile Windows saat dilimi arasında dönüştürme için original Matt Johnson solution'a bakın.