-
Notifications
You must be signed in to change notification settings - Fork 248
feat: Add evaluation layer to CalDateTime
#805
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
If a `CalDateTime` is instantiated from a lenient timezone conversion, this leniently determined value must not be converted again. Reasoning: Lenient conversions resolve non-existing or ambiguous times caused by DST transitions. Resolves #737
Codecov ReportAttention: Patch coverage is
❌ Your project status has failed because the head coverage (67%) is below the target coverage (80%). You can increase the head coverage or adjust the target coverage. @@ Coverage Diff @@
## main #805 +/- ##
===================================
Coverage 67% 67%
===================================
Files 106 107 +1
Lines 4430 4448 +18
Branches 1065 1069 +4
===================================
+ Hits 2954 2976 +22
+ Misses 1039 1038 -1
+ Partials 437 434 -3
🚀 New features to boost your workflow:
|
|
@axunonb Not sure we should track the precise instant in CalDateTime. I.e. |
* Introduced `CalDateTimeExtensions` for extension methods on `CalDateTime` * Moved `CalDateTime` arithmetic and conversion methods to `CalDateTimeExtensions` * Adjusted related classes with new references Note: * `CalDateTimeExtensions.ToTimeZone` links the input `CalDateTime` with its `ZonedDateTime` representation, using a cache with weak references to `CalDateTime`. * This way, once a `CalDateTime` is resolved to a `ZonedDateTime`, the `ZonedDateTime` will be used for further conversions. Why cache `ZonedDateTime`? * If a `CalDateTime` is instantiated from a lenient timezone conversion, this leniently determined value must not be converted again. * Lenient conversions resolve non-existing or ambiguous times caused by DST transitions. Open: * When and how to clear the cache? * Introduce `CalDateTimeZoned`, inhertiting from `CalDateTime` with``ZonedDateTime` as a property?
CalDateTime
CalDateTimeCalDateTime
If your time allows, I'd be interested in your opinion on this kind of "evaluation layer" which comes as extension methods for TBD:
Needs to be covered separately. |
4fcfbfd to
5472460
Compare
This is the link for `CalDateTime` objects to is `ZonedDateTime` representation after the first call of `CalDateTimeExtensions.ToTimeZone`. All subsequent conversions use the cached `ZonedDateTime`. Costs for this link are very low.
5472460 to
e127d27
Compare
|
|
@axunonb I love all the evaluation/arithmetics code being moved out of CalDateTime into extension methods, very nice! I'm not convinced by the caching code though for several reasons. The outcome is very hard to reason upon. Consider the following test case: [Test]
public void CalDateTime_AmbiguousTime_ResolvedCorrectly2()
{
var dt1 = new CalDateTime(2024, 10, 27, 1, 30, 0, "UTC").ToTimeZone("CET");
var dt2 = new CalDateTime(2024, 10, 27, 2, 30, 0, "CET");
// This is a fundamental assumption
Assert.That(dt1 == dt2, Is.EqualTo(dt1.AsUtc() == dt2.AsUtc()));
}It's not quite obvious that this will fail. Or this one: [Test]
public void CalDateTime_AmbiguousTime_ResolvedCorrectly()
{
TimeZoneResolvers.TimeZoneResolver = _ => NodaTime.DateTimeZoneProviders.Tzdb.GetZoneOrNull("UTC");
var dt1 = new CalDateTime(2024, 10, 27, 1, 30, 0, "CET");
var dt2 = new CalDateTime(2024, 10, 27, 1, 30, 0, "CET");
var _ = dt1.AsUtc();
TimeZoneResolvers.TimeZoneResolver = TimeZoneResolvers.Default;
Assert.That(dt1, Is.EqualTo(dt2));
Assert.That(dt1.AsUtc(), Is.EqualTo(dt2.AsUtc()));
}Its not obvious that the first assertion will succeed but the second will fail (clearly this is not a typical case, it rather shows the problems arising from By attaching the converted value via a cache does still attach it so the problems as outlined in my previous comment still exist but with the external cache its even harder to understand what's happening. Regarding the serialization round-trip, the following test will still fail: [Test]
public void CalDateTime_AmbiguousTime_ResolvedCorrectly3()
{
var dt1 = new CalDateTime(2024, 10, 27, 1, 30, 0, "UTC").ToTimeZone("CET");
var serializer = new DateTimeSerializer();
var stream = new System.IO.MemoryStream();
serializer.Serialize(dt1, stream, System.Text.Encoding.UTF8);
stream.Position = 0;
var restored = ((CalDateTime)serializer.Deserialize(stream, System.Text.Encoding.UTF8)).ToTimeZone("CET");
Assert.That(dt1.AsUtc(), Is.EqualTo(restored.AsUtc()));
}The evaluation layer as I was thinking about it would be a completely independent set of classes. They might be allowed to reference the model layer but not the other way round. The model layer would just represent the ICAL model as it is but without any evaluation/arithmetic operations on it, including adding, converting, ... Only after conversion to the evaluation layer all the magic would be available. The date-time classes there would probably operate on something like ZonedDateTime, including the concrete instant they represent. Then the ambiguity would be gone. However, in the meantime it would be quite straight-forward to return something else than Period from GetOccurrences() et al. I.e. we could easily introduce a new type that doesn't contain an end time but only a TimeSpan representing the exact duration, instead. Then there wouldn't be any ambiguity either. |
|
Closed in favor of #809 |



Add evaluation layer to
CalDateTime(WIP!)CalDateTimeExtensionsfor extension methods onCalDateTimeCalDateTimearithmetic and conversion methods toCalDateTimeExtensionsNote:
CalDateTimeExtensions.ToTimeZonelinks the inputCalDateTimewith itsZonedDateTimerepresentation, using a cache with weak references toCalDateTime. The cache is implemented withConditionalWeakTable<CalDateTime, ZonedDateTime>.CalDateTimeis resolved to aZonedDateTime, theZonedDateTimewill be used for further conversions.Why cache
ZonedDateTime?CalDateTimeis instantiated from a lenient timezone conversion, this leniently determined value must not be converted again.Resolves #737
Resolves #677