user6465254
user6465254

Reputation:

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

Upvotes: 3

Views: 616

Answers (1)

Jon Skeet
Jon Skeet

Reputation: 1499660

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.

Upvotes: 3

Related Questions