2013-02-19 6 views
9

Ich verwende NodaTime wegen seiner schönen Unterstützung für zoneinfo Daten, jedoch habe ich einen Fall, in dem ich die DateTimeZone in TimeZoneInfo für den Einsatz in Quartz.NET konvertieren müssen.Konvertieren NodaTime DateTimeZone in Timezone

Was ist das hier empfohlene Vorgehensweise? IANA hat eine Zuordnungsdatei zwischen Windows-Zeitzonen und Zeitzonen zoneinfo, kann ich eine Erweiterungsmethode erstellen, die diese Informationen verwendet?

Danke, Dean

+0

Welche IANA Datei meinst du übrigens? Ich weiß, dass es eine CLDR gibt, aber wenn IANA dies in einem anderen Format bietet, wäre das interessant ... –

Antwort

12

ich vermeiden würde Reflexion, wenn möglich verwenden. Ich würde nicht gerne auf Ihren Ansatz mit zukünftigen Versionen arbeiten :)

Fühlen Sie sich frei, eine Feature-Anfrage für diese Funktionalität für zukünftige Versionen, aber für den Moment würde ich bauen Sie Ihre Reverse-Wörterbuch in einem stabileren übrigens:

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

natürlich wird diese nicht alle Zeitzonen in TZDB decken. Tatsächlich gibt es nicht einmal alle Informationen, die wir könnten basierend auf den CLDR Informationen geben wir verwenden ... CLDR gibt mehrere Zuordnungen für jede Windows ID, und wir speichern nur die erste im Moment. Wir haben versucht, wie man trainiert mehr davon zu, aber noch nicht geschaffen. willkommen Gedanken über die Noda Zeit Mailingliste :)

Beachten Sie auch, dass, nur weil es eine Zuordnung zwischen den BCL und TZDB Zonen bedeutet nicht, sie werden tatsächlich die gleichen Ergebnisse für alles geben - es ist nur die nächste Zuordnung zur Verfügung.

+0

Danke Jon , dieser Ansatz ist viel besser.Nehmen Sie an Ihren Kommentaren zu der Möglichkeit unterschiedlicher Daten zwischen TZDB und CLDR teil. Wir haben die Liste der Zeitzonen genommen, die unsere Endbenutzergeräte benötigen, und sie verfügen derzeit über eine Eins-zu-eins-Zuordnung zu gültigen Windows-Zeitzonen. Es ist möglich, dass wir uns einen anderen Weg überlegen müssen, aber das funktioniert jetzt. –

+0

@DeanWard: Wenn es irgendeine Hilfe ist, habe ich heute damit begonnen, [Problem 82] (https://code.google.com/p/noda-time/issues/detail?id=82) zu implementieren, um mehr Informationen über die Zuordnungen. Ich weiß nicht genau, ob es in die 1.1 Version kommen wird. –

+0

Ich behalte dieses hier im Auge, danke für eure Hilfe! –

4

Aha, fand ich es - TzdbDateTimeZoneSource eine MapTimeZoneId Methode, die ich in TimeZoneInfo.FindSystemTimeZoneById Pop kann.

Edit: MapTimeZoneId macht die Zuordnung von Windows-Zeitzone in ... zoneinfo Ich landete auf Reflexion zurückzugreifen die Zuordnung in der entgegengesetzten Richtung zu tun:

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

Das hilft, wenn du die Quelle nicht neu machen willst: NodaTime.TimeZones.TzdbDateTimeZoneSource.Default – jsgoupil

0

Dies funktioniert jedoch nicht in einer PCL, da die meiste Arbeit von .NET in den Methoden .GetSystemTimeZones() und .FindSystemTiemZoneById() ausgeführt wird, die in PCL nicht vorhanden sind.

Ich bin verblüfft, dass für alle Informationen, die Sie aus NodaTime bekommen können, etwas so einfach wie "EST" Abkürzung bekommen, wenn Sie bereits den Zonennamen "US/Eastern" scheint mich in meinen Spuren gestoppt haben .

1

Sie können TimeZoneConverter Bibliothek von Matt Johnson verwenden.

ZoneID von NodeTime TzdbZoneLocation verwendete IANA time zone, so dass Sie Timezone wie diese bekommen:

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

Vergessen Sie nicht wickeln Sie es mit try-catch mit irgendeiner Art von Rückfall nur für den Fall.

Überprüfen Sie auch original Matt Johnson solution für die Konvertierung zwischen IANA-Zeitzone und Windows-Zeitzone.