.NET NodaTime How do I create a custom TimeZone?

I want to create a custom (non-existing) TimeZone which follows exactly the same rules as Europe/London however the only difference is that the offset should be -5 hours from UTC.

For testing purposes, this is what I was trying. How do I specify daylightsavings? Or is this implementation completely wrong?

   public class MyTimeZone : DateTimeZone
    {
        public MyTimeZone()
            : base("MyTimeZone", true, Offset.FromHours(-5), Offset.FromHours(-5))
        {

        }

        protected override bool EqualsImpl(DateTimeZone zone)
        {
            if (zone.Id == "MyTimeZone")
                return true;

            return false;
        }

        public override int GetHashCode()
        {
            return 0001;
        }

        public override NodaTime.TimeZones.ZoneInterval GetZoneInterval(Instant instant)
        {
            return new ZoneInterval("MyTimeZone", new Instant(DateTime.MinValue.Ticks), new Instant(DateTime.MaxValue.Ticks), Offset.FromHours(-5), Offset.FromHours(-5));
        }
    }
Jon Skeet
people
quotationmark

This certainly isn't a terribly common scenario, but it's definitely supported. (Unlike creating your own calendar, for example.)

You'd specify daylight saving via GetZoneInterval - that method is the key to the class. The important things to get right are:

  • Chained constructor call with min/max offset (your max will be UTC-4, not UTC-5)
  • GetZoneInterval
  • Equality/hash code, which you could always make identity equality for the moment.

So for example, you could have:

public class LondonOffsetZone : DateTimeZone
{
    private readonly DateTimeZone london;

    // This assumes London has a minimum of +0 and a maximum of +1.
    // To do it better, you'd resolve Europe/London and find *its*
    // min/max, and add -5 hours to each.
    public LondonOffsetZone()
        : base("LondonOffset", false, Offset.FromHours(-5), Offset.FromHours(-4))
    {
        london = DateTimeZoneProviders.Tzdb["Europe/London"];
    }

    public override int GetHashCode() => RuntimeHelpers.GetHashCode(this);

    // Base Equals method will have handled reference equality already.
    protected override bool EqualsImpl(DateTimeZone other) => false;

    public override ZoneInterval GetZoneInterval(Instant instant)
    {
        // Return the same zone interval, but offset by 5 hours.
        var londonInterval = london.GetZoneInterval(instant);
        return new ZoneInterval(
            londonInterval.Name,
            londonInterval.Start,
            londonInterval.End,
            londonInterval.WallOffset + Offset.FromHours(-5),
            londonInterval.Savings);
    }
}

That will fail - at least in Noda Time 2.0 - at the start and end of time, where the Start and End properties won't work, but it should be absolutely fine for any instant you're likely to actually encounter.

people

See more on this question at Stackoverflow