转换NodaTime DateTimeZone到的TimeZoneInfo(Convert Noda

2019-08-17 02:10发布

我使用NodaTime因为其时区信息数据很好的支持,但我有我需要的转换的情况下DateTimeZoneTimeZoneInfo在Quartz.NET使用。

这里有什么建议的方法? IANA拥有Windows时区和时区信息时区之间的映射文件,我可以创建可利用这些信息的扩展方法是什么?

谢谢,迪安

Answer 1:

我会尽可能避免使用反射。 我不喜欢赌上你的方法与未来版本的工作:)

随意立案此功能在将来的版本功能请求,但目前我会建立起自己的反向字典更稳定的方式:

// 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多个映射,我们只存储此刻的第一个。 我们一直在试图找出如何暴露更多的是,但还没有进行管理。 思考欢迎野田佳彦时间邮件列表上:)

另外请注意,仅仅因为有首创置业和TZDB区之间的映射并不意味着他们会实际上给的一切相同的结果 - 它只是提供的最接近的映射。



Answer 2:

啊哈,我发现它- TzdbDateTimeZoneSourceMapTimeZoneId ,我可以跳进方法TimeZoneInfo.FindSystemTimeZoneById

编辑: MapTimeZoneId确实从Windows时区到时区信息的映射......我最终诉诸反射做相反方向的映射:

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


Answer 3:

您可以使用TimeZoneConverter通过图书馆马特·约翰逊 。

通过NodeTime TzdbZoneLocation使用的是了zoneid IANA时区 ,这样你就可以像这样得到的TimeZoneInfo:

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

不要忘了,以防万一某种回退的使用try-catch来包装它。

另外,也要看看原来的马特·约翰逊的解决方案为IANA时区和Windows时区之间的转换。



Answer 4:

其中不存在PCL - 然而这一切都不在PCL,因为大部分的工作是由.NET在.GetSystemTImeZones()和.FindSystemTIemZoneById()方法来完成工作。

我目瞪口呆的是,所有的信息,你可以走出NodaTime的,越来越为“EST”的缩写,简单的东西,当你已经拥有“美/东”的区域名称似乎已经停止在我的轨道。



文章来源: Convert NodaTime DateTimeZone into TimeZoneInfo
标签: nodatime