DateTimeZone
zoneinfo データの優れたサポートのために NodaTime を使用していますが、Quartz.NET で使用するために変換する必要がある場合がありTimeZoneInfo
ます。
ここで推奨されるアプローチは何ですか? IANA には、Windows タイム ゾーンと zoneinfo タイム ゾーン間のマッピング ファイルがあります。この情報を利用する拡張メソッドを作成できますか?
DateTimeZone
zoneinfo データの優れたサポートのために NodaTime を使用していますが、Quartz.NET で使用するために変換する必要がある場合がありTimeZoneInfo
ます。
ここで推奨されるアプローチは何ですか? IANA には、Windows タイム ゾーンと zoneinfo タイム ゾーン間のマッピング ファイルがあります。この情報を利用する拡張メソッドを作成できますか?
可能であれば、リフレクションの使用は避けます。将来のバージョンで動作するあなたのアプローチに賭けたくありません:)
将来のバージョンのためにこの機能の機能リクエストを提出してください。
// 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 ゾーンの間にマッピングがあるからといって、実際にすべてに対して同じ結果が得られるわけではありません。これは、利用可能な最も近いマッピングにすぎません。
あはは、見つけました - に飛び込めるTzdbDateTimeZoneSource
メソッドMapTimeZoneId
がありTimeZoneInfo.FindSystemTimeZoneById
ます。
編集: MapTimeZoneId
Windows タイム ゾーンから 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;
}
}
ただし、ほとんどの作業は PCL には存在しない .GetSystemTImeZones() および .FindSystemTIemZoneById() メソッドで .NET によって行われるため、これは PCL では機能しません。
NodaTime から得られるすべての情報に対して、既に「US/Eastern」のゾーン名を持っているときに「EST」のような単純な略語を取得することで、私の足が止まったように思われることに驚いています。