Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert NodaTime DateTimeZone into TimeZoneInfo

Tags:

nodatime

I'm using NodaTime because of its nice support for zoneinfo data, however I have a case where I need to convert the DateTimeZone into TimeZoneInfo for use in Quartz.NET.

What's the recommended approach here? IANA has a mapping file between Windows time zones and zoneinfo time zones, can I create an extension method that utilises this information?

like image 924
Dean Ward Avatar asked Feb 19 '13 22:02

Dean Ward


1 Answers

Aha, I found it - TzdbDateTimeZoneSource has a MapTimeZoneId method that I can pop into TimeZoneInfo.FindSystemTimeZoneById.

Edit: MapTimeZoneId does the mapping from Windows time zone into zoneinfo... I ended up resorting to reflection to do the mapping in the opposite direction:

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;
    }
}
like image 78
Dean Ward Avatar answered Oct 09 '22 17:10

Dean Ward