.net TimeZoneInfo du fuseau horaire D'Olson

Comment puis-je convertir ce qui suit en un système.Le fuseau horaire ou d'un Système.TimeZoneInfo?

{
  "timeZone": "America/Los_Angeles", 
  "currentOffsetMs": -25200000
}

ce sont des données que je récupère d'un service web tiers.

je suppose que l'offset est la différence par rapport à UTC, et on m'a dit que le" America/Los_Angeles " est un fuseau horaire D'Olson. Java n'a aucun problème à analyser ceci dans un fuseau horaire Java, mais je dois analyser ceci dans un objet C# TimeZoneInfo.

61
demandé sur Judah Himango 2011-05-13 22:43:35

6 réponses

Ce Unicode.org la page a une "Olson fuseau horaire pour Win32 fuseau horaire" de la table. De là, j'ai créé une jolie petite fonction C # helper pour mapper la chaîne Olson time zone dans un .net TimeZoneInfo:

/// <summary>
/// Converts an Olson time zone ID to a Windows time zone ID.
/// </summary>
/// <param name="olsonTimeZoneId">An Olson time zone ID. See http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html. </param>
/// <returns>
/// The TimeZoneInfo corresponding to the Olson time zone ID, 
/// or null if you passed in an invalid Olson time zone ID.
/// </returns>
/// <remarks>
/// See http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html
/// </remarks>
public static TimeZoneInfo OlsonTimeZoneToTimeZoneInfo(string olsonTimeZoneId)
{
    var olsonWindowsTimes = new Dictionary<string, string>()
    {
        { "Africa/Bangui", "W. Central Africa Standard Time" },
        { "Africa/Cairo", "Egypt Standard Time" },
        { "Africa/Casablanca", "Morocco Standard Time" },
        { "Africa/Harare", "South Africa Standard Time" },
        { "Africa/Johannesburg", "South Africa Standard Time" },
        { "Africa/Lagos", "W. Central Africa Standard Time" },
        { "Africa/Monrovia", "Greenwich Standard Time" },
        { "Africa/Nairobi", "E. Africa Standard Time" },
        { "Africa/Windhoek", "Namibia Standard Time" },
        { "America/Anchorage", "Alaskan Standard Time" },
        { "America/Argentina/San_Juan", "Argentina Standard Time" },
        { "America/Asuncion", "Paraguay Standard Time" },
        { "America/Bahia", "Bahia Standard Time" },
        { "America/Bogota", "SA Pacific Standard Time" },
        { "America/Buenos_Aires", "Argentina Standard Time" },
        { "America/Caracas", "Venezuela Standard Time" },
        { "America/Cayenne", "SA Eastern Standard Time" },
        { "America/Chicago", "Central Standard Time" },
        { "America/Chihuahua", "Mountain Standard Time (Mexico)" },
        { "America/Cuiaba", "Central Brazilian Standard Time" },
        { "America/Denver", "Mountain Standard Time" },
        { "America/Fortaleza", "SA Eastern Standard Time" },
        { "America/Godthab", "Greenland Standard Time" },
        { "America/Guatemala", "Central America Standard Time" },
        { "America/Halifax", "Atlantic Standard Time" },
        { "America/Indianapolis", "US Eastern Standard Time" },
        { "America/Indiana/Indianapolis", "US Eastern Standard Time" },
        { "America/La_Paz", "SA Western Standard Time" },
        { "America/Los_Angeles", "Pacific Standard Time" },
        { "America/Mexico_City", "Mexico Standard Time" },
        { "America/Montevideo", "Montevideo Standard Time" },
        { "America/New_York", "Eastern Standard Time" },
        { "America/Noronha", "UTC-02" },
        { "America/Phoenix", "US Mountain Standard Time" },
        { "America/Regina", "Canada Central Standard Time" },
        { "America/Santa_Isabel", "Pacific Standard Time (Mexico)" },
        { "America/Santiago", "Pacific SA Standard Time" },
        { "America/Sao_Paulo", "E. South America Standard Time" },
        { "America/St_Johns", "Newfoundland Standard Time" },
        { "America/Tijuana", "Pacific Standard Time" },
        { "Antarctica/McMurdo", "New Zealand Standard Time" },
        { "Atlantic/South_Georgia", "UTC-02" },
        { "Asia/Almaty", "Central Asia Standard Time" },
        { "Asia/Amman", "Jordan Standard Time" },
        { "Asia/Baghdad", "Arabic Standard Time" },
        { "Asia/Baku", "Azerbaijan Standard Time" },
        { "Asia/Bangkok", "SE Asia Standard Time" },
        { "Asia/Beirut", "Middle East Standard Time" },
        { "Asia/Calcutta", "India Standard Time" },
        { "Asia/Colombo", "Sri Lanka Standard Time" },
        { "Asia/Damascus", "Syria Standard Time" },
        { "Asia/Dhaka", "Bangladesh Standard Time" },
        { "Asia/Dubai", "Arabian Standard Time" },
        { "Asia/Irkutsk", "North Asia East Standard Time" },
        { "Asia/Jerusalem", "Israel Standard Time" },
        { "Asia/Kabul", "Afghanistan Standard Time" },
        { "Asia/Kamchatka", "Kamchatka Standard Time" },
        { "Asia/Karachi", "Pakistan Standard Time" },
        { "Asia/Katmandu", "Nepal Standard Time" },
        { "Asia/Kolkata", "India Standard Time" },
        { "Asia/Krasnoyarsk", "North Asia Standard Time" },
        { "Asia/Kuala_Lumpur", "Singapore Standard Time" },
        { "Asia/Kuwait", "Arab Standard Time" },
        { "Asia/Magadan", "Magadan Standard Time" },
        { "Asia/Muscat", "Arabian Standard Time" },
        { "Asia/Novosibirsk", "N. Central Asia Standard Time" },
        { "Asia/Oral", "West Asia Standard Time" },
        { "Asia/Rangoon", "Myanmar Standard Time" },
        { "Asia/Riyadh", "Arab Standard Time" },
        { "Asia/Seoul", "Korea Standard Time" },
        { "Asia/Shanghai", "China Standard Time" },
        { "Asia/Singapore", "Singapore Standard Time" },
        { "Asia/Taipei", "Taipei Standard Time" },
        { "Asia/Tashkent", "West Asia Standard Time" },
        { "Asia/Tbilisi", "Georgian Standard Time" },
        { "Asia/Tehran", "Iran Standard Time" },
        { "Asia/Tokyo", "Tokyo Standard Time" },
        { "Asia/Ulaanbaatar", "Ulaanbaatar Standard Time" },
        { "Asia/Vladivostok", "Vladivostok Standard Time" },
        { "Asia/Yakutsk", "Yakutsk Standard Time" },
        { "Asia/Yekaterinburg", "Ekaterinburg Standard Time" },
        { "Asia/Yerevan", "Armenian Standard Time" },
        { "Atlantic/Azores", "Azores Standard Time" },
        { "Atlantic/Cape_Verde", "Cape Verde Standard Time" },
        { "Atlantic/Reykjavik", "Greenwich Standard Time" },
        { "Australia/Adelaide", "Cen. Australia Standard Time" },
        { "Australia/Brisbane", "E. Australia Standard Time" },
        { "Australia/Darwin", "AUS Central Standard Time" },
        { "Australia/Hobart", "Tasmania Standard Time" },
        { "Australia/Perth", "W. Australia Standard Time" },
        { "Australia/Sydney", "AUS Eastern Standard Time" },
        { "Etc/GMT", "UTC" },
        { "Etc/GMT+11", "UTC-11" },
        { "Etc/GMT+12", "Dateline Standard Time" },
        { "Etc/GMT+2", "UTC-02" },
        { "Etc/GMT-12", "UTC+12" },
        { "Europe/Amsterdam", "W. Europe Standard Time" },
        { "Europe/Athens", "GTB Standard Time" },
        { "Europe/Belgrade", "Central Europe Standard Time" },
        { "Europe/Berlin", "W. Europe Standard Time" },
        { "Europe/Brussels", "Romance Standard Time" },
        { "Europe/Budapest", "Central Europe Standard Time" },
        { "Europe/Dublin", "GMT Standard Time" },
        { "Europe/Helsinki", "FLE Standard Time" },
        { "Europe/Istanbul", "GTB Standard Time" },
        { "Europe/Kiev", "FLE Standard Time" },
        { "Europe/London", "GMT Standard Time" },
        { "Europe/Minsk", "E. Europe Standard Time" },
        { "Europe/Moscow", "Russian Standard Time" },
        { "Europe/Paris", "Romance Standard Time" },
        { "Europe/Sarajevo", "Central European Standard Time" },
        { "Europe/Warsaw", "Central European Standard Time" },
        { "Indian/Mauritius", "Mauritius Standard Time" },
        { "Pacific/Apia", "Samoa Standard Time" },
        { "Pacific/Auckland", "New Zealand Standard Time" },
        { "Pacific/Fiji", "Fiji Standard Time" },
        { "Pacific/Guadalcanal", "Central Pacific Standard Time" },
        { "Pacific/Guam", "West Pacific Standard Time" },
        { "Pacific/Honolulu", "Hawaiian Standard Time" },
        { "Pacific/Pago_Pago", "UTC-11" },
        { "Pacific/Port_Moresby", "West Pacific Standard Time" },
        { "Pacific/Tongatapu", "Tonga Standard Time" }
    };

    var windowsTimeZoneId = default(string);
    var windowsTimeZone = default(TimeZoneInfo);
    if (olsonWindowsTimes.TryGetValue(olsonTimeZoneId, out windowsTimeZoneId))
    {
        try { windowsTimeZone = TimeZoneInfo.FindSystemTimeZoneById(windowsTimeZoneId); }
        catch (TimeZoneNotFoundException) { }
        catch (InvalidTimeZoneException) { }
    }
    return windowsTimeZone;
}
93
répondu Judah Himango 2015-12-15 22:09:06

Voici une fonction de cartographie inverse (tzdb - > windows) utilisant NodaTime :

using NodaTime;
using NodaTime.TimeZones;

...

public TimeZoneInfo GetTimeZoneInfoForTzdbId(string tzdbId)
{
  var mappings = TzdbDateTimeZoneSource.Default.WindowsMapping.MapZones;
  var map = mappings.FirstOrDefault(x =>
      x.TzdbIds.Any(z => z.Equals(tzdbId, StringComparison.OrdinalIgnoreCase)));
  return map == null ? null : TimeZoneInfo.FindSystemTimeZoneById(map.WindowsId);
}

notez qu'il est possible qu'il y ait plus d'un mapping (dans ce cas, ceci utilise seulement le premier trouvé), ou pas de mapping du tout (où cela renvoie null).

dans les fuseaux horaires les plus utilisés, cela devrait fonctionner assez bien. Mais la meilleure solution serait de sauter l'utilisation de TimeZoneInfo du tout, et juste utiliser NodaTime tout au long de l'application, directement avec la zone TZDB que vous avez.

voir aussi: comment traduire entre Windows et IANA time zones?

25
répondu Matt Johnson 2017-05-23 12:34:14

vous pourriez vouloir regarder dans le de Jon Skeet" Noda-Time et abandonner TimeZoneInfo tout à fait. Noda-Time utilise Olson timezones donc votre cartographie serait un jeu d'enfant. Il y a d'autres raisons pour lesquelles vous pourriez vouloir utiliser :

Qu'est-ce qui ne va pas avec DateTime de toute façon?

donc question de la mine dont le résultat était D'utiliser le temps de Noda

11
répondu Stephen Kennedy 2017-05-23 12:09:39

un petit extrait que j'ai trouvé pour obtenir une liste des mappages olson vers les fuseaux horaires de windows à partir du xml à http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml

private static void LoadMappingsO()
{
    var file = new FileInfo("windowsZones.xml");
    if (!file.Exists)
    {
        return;
    }

    var map = new Dictionary<string, string>();
    using (var reader = file.OpenText())
    {
        var readerSettings = new XmlReaderSettings { XmlResolver = null, ProhibitDtd = false };

        using (var xmlReader = XmlReader.Create(reader, readerSettings))
        {
            var document = new XPathDocument(xmlReader);
            var navigator = document.CreateNavigator();

            var nodes = navigator.Select("/supplementalData/windowsZones/mapTimezones/mapZone");

            while (nodes.MoveNext())
            {
                var node = nodes.Current;
                if (node == null) continue;

                var olsonNames = node.GetAttribute("type", "").Split(' ');
                var windowsName = node.GetAttribute("other", "");
                foreach (var olsonName in olsonNames)
                {
                    if (!map.ContainsKey(olsonName))
                    {
                        map.Add(olsonName, windowsName);
                    }
                }
            }
        }
    }

    using (TextWriter tw = new StreamWriter("dict.txt", false))
    {
        foreach (var key in map.Keys)
        {
            tw.WriteLine(string.Format("{{\"{0}\", \"{1}\"}},", key, map[key]));
        }
    }
}

mise à jour (utilisant Linq Xml):

private static void LoadMappings()
{
    var map = new Dictionary<string, string>();
    var xdoc = XDocument.Load("windowsZones.xml");

    var zones = xdoc.XPathSelectElements("/supplementalData/windowsZones/mapTimezones/mapZone");
    foreach (var zone in zones)
    {
        var olsonNames = zone.Attribute("type")?.Value.Split(' ');
        if (olsonNames == null)
            continue;

        var windowsName = zone.Attribute("other")?.Value;
        if (string.IsNullOrWhiteSpace(windowsName))
            continue;

        foreach (var olsonName in olsonNames)
        {
            map[olsonName] = windowsName;
        }
    }

    using (TextWriter tw = new StreamWriter("dict.txt", false))
    {
        foreach (var key in map.Keys)
        {
            tw.WriteLine($"{{\"{key}\", \"{map[key]}\"}},");
        }
    }
}
11
répondu H77 2017-12-04 15:16:09

mise à jour: j'ai supprimé l'URL du script. Veuillez trouver le fichier manuellement. Ce script n'était pas destiné à fonctionner sans arrêt en mettant une charge inutile sur unicode.org. Voir les commentaires ci-dessous.

ce script Powershell peut être utilisé pour générer une instruction de cas en utilisant le fichier XML courant de unicode.org. Il génère des correspondances entre les noms D'IANA et ceux de TimeZoneInfoId.

    # Download the xml file.
    $xml = [Xml] /// Load the XML content here

    # Parse the fields we want from the XML.
    $mappings1 = $xml.supplementalData.windowsZones.mapTimezones.mapZone | select Type,Other 

    # Extrapolate extra rows for entries that contain more than one IANA name seperated by spaces.
    # Example: |<mapZone other="Alaskan Standard Time" territory="US" type="America/Anchorage America/Juneau America/Nome America/Sitka America/Yakutat"/>
    $mappings2 = $mappings1 | %{
        $mapping = $_
        $_.Type.Split(" ") | %{
            New-Object PSObject -Property @{type = $_; other = $mapping.other}
        }  
    }

    # Remove dup's
    $mappings3 = $mappings2 | sort type -Unique

    # Generate the case statements.
    $mappings3 | %{ [String]::Format("case @""{0}"": return @""{1}"";", $_.Type, $_.Other)}
3
répondu Jared Kells 2014-07-03 05:50:31

après avoir converti les currentOffsetMs en heures et minutes restantes, vous pouvez énumérer les objets TimeZoneInfo définis:

foreach (TimeZoneInfo nextZone in TimeZoneInfo.GetSystemTimeZones())
{
    int nextHours = nextZone.BaseUtcOffset.Hours + 24;     // To prevent negative numbers
    int nextMinutes = nextZone.BaseUtcOffset.Minutes;
    if (tzHours == nextHours && tzMinutes == nextMinutes)
    {
        myTimeZoneInfo = nextZone;
        break;
    }
}
2
répondu Ed Bayiates 2011-05-13 18:51:42