Nodatime BclDateTimeZone EqualsImpl throws NotImplementedException

182 views Asked by At

The EqualsImpl method in the Nodatime BclDateTimeZone class throws a NotImplementedException. It is documented to behave in this way - is there a reason for this?

If testing equality of two ZonedDateTimes that use a BclDateTimeZone this causes the exception to be thrown.

Is this a bug, it doesn't seem right?

2

There are 2 answers

4
Jon Skeet On BEST ANSWER

It is documented to behave in this way - is there a reason for this?

Yup - it's basically very hard to determine zone equality in a general way. Suppose we have two BclDateTimeZone instances which wrap two distinct TimeZoneInfo values... we could:

  • Say they're not equal arbitrarily, even if they are logically equivalent
  • Compare them by ID (impossible in the PCL which doesn't support IDs, and broken under Mono why TimeZoneInfo.Local has an ID of Local IIRC)
  • Compare them for equality through history, which is very costly

I agree that it's a pain, and I think I'm planning on removing value equality on ZonedDateTime entirely in Noda Time 2.0, and make ZonedDateTime use reference equality.

If you want to compare time zones, a better alternative is likely to be the use of ZonedEqualityComparer to specify how you want them to be compared.

But the inability to compare ZonedDateTime values for equality when using BCL values is definitely nasty. I've raised a bug for that; I'm preparing a 1.3.1 release, and I might see if I can fix it there, rather than you having to wait for 2.0.

0
Jason Allen On

After trying to write failing unit tests to prove this bug, I found it difficult to replicate.

Comparing ZonedDateTimes that have BclDateTimeZones on different offsets is not an issue. Comparing ZonedDateTimes with different LocalDateTimes is not an issue.

I could see from the source that the comparison of ZonedDateTime Zone only came into play if the LocalDateTime and Offset were equal.

My problem arose where I was using two different references of BclDateTimeZone on the same offset. I did this by using DateTimeZoneProviders.Bcl.GetSystemDefault() in one place and BclDateTimeZone.ForSystemDefault() in another. Needless to say, they are now calling into common code.

I have this failing test where I am comparing two ZonedDateTimes with different DateTimeZones on the same offset:

ZonedDateTime dtzOne = new ZonedDateTime(Instant.FromUtc(2014, 11, 11, 21, 00), DateTimeZoneProviders.Bcl.GetZoneOrNull("Greenwich Standard Time"));
ZonedDateTime dtzTwo = new ZonedDateTime(Instant.FromUtc(2014, 11, 11, 21, 00), DateTimeZoneProviders.Bcl.GetZoneOrNull("GMT Standard Time"));

Assert.That(dtzOne, Is.Not.EqualTo(dtzTwo));

This test throws an exception here:

System.NotImplementedException : The method or operation is not implemented.
   at NodaTime.TimeZones.BclDateTimeZone.EqualsImpl(DateTimeZone zone)
   at NodaTime.DateTimeZone.Equals(DateTimeZone obj)
   at NodaTime.ZonedDateTime.Equals(ZonedDateTime other)

I can easily work around this issue, but it is probably worth fixing.