12

DateTimeZonezoneinfo データの優れたサポートのために NodaTime を使用していますが、Quartz.NET で使用するために変換する必要がある場合がありTimeZoneInfoます。

ここで推奨されるアプローチは何ですか? IANA には、Windows タイム ゾーンと zoneinfo タイム ゾーン間のマッピング ファイルがあります。この情報を利用する拡張メソッドを作成できますか?

4

5 に答える 5

13

可能であれば、リフレクションの使用は避けます。将来のバージョンで動作するあなたのアプローチに賭けたくありません:)

将来のバージョンのためにこの機能の機能リクエストを提出してください。

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

もちろん、これで TZDB のすべてのタイム ゾーンがカバーされるわけではありません。実際、私たちが使用する CLDR 情報に基づいて提供できるすべての情報を提供することさえできません... CLDR は各 Windows ID に対して複数のマッピングを提供し、現時点では最初の 1 つだけを保存します私たちはそれをもっと公開する方法を考え出そうとしていますが、まだうまくいきません. Noda Timeメーリングリストでの考えを歓迎します:)

また、BCL ゾーンと TZDB ゾーンの間にマッピングがあるからといって、実際にすべてに対して同じ結果が得られるわけではありません。これは、利用可能な最も近いマッピングにすぎません。

于 2013-02-23T08:32:40.423 に答える
5

あはは、見つけました - に飛び込めるTzdbDateTimeZoneSourceメソッドMapTimeZoneIdがありTimeZoneInfo.FindSystemTimeZoneByIdます。

編集: MapTimeZoneIdWindows タイム ゾーンから zoneinfo へのマッピングを行います...逆方向のマッピングを行うためにリフレクションに頼ることになりました:

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;
    }
}
于 2013-02-19T22:21:55.527 に答える
2

ただし、ほとんどの作業は PCL には存在しない .GetSystemTImeZones() および .FindSystemTIemZoneById() メソッドで .NET によって行われるため、これは PCL では機能しません。

NodaTime から得られるすべての情報に対して、既に「US/Eastern」のゾーン名を持っているときに「EST」のような単純な略語を取得することで、私の足が止まったように思われることに驚いています。

于 2016-06-21T16:55:14.720 に答える