crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.42k stars 1.62k forks source link

[RFC] Supporting floating time #5332

Closed straight-shoota closed 3 years ago

straight-shoota commented 6 years ago

In the context of my proposal for adding time zone support (#5324) the question arises how Crystal should handle time instances which are not tied to a specific time zone, known as floating time.

Conceptual Introduction

A short introduction to the concept from W3C's time zone guide:

Some observed time values are not related to a specific moment in incremental time. Instead, they need to be combined with local information to determine a range of acceptable incremental time values. We refer to these sorts of time values as "floating times" because they are not fixed to a specific incremental time value. Floating times are not attached and should never be attached to a particular time zone. Some examples of floating time events include a user’s birth date, a document's publication date, a list of official holidays, or the expiration date for an offer (if not tied explicitly to a time zone).

A floating time 08:30 can for example represent each point in time, where the local time shows 08:30, independent of local time's timezone. If I set an alarm at 08:30, I want that alarm to trigger when it is 8:30 wherever I am at that point and whatever time zone offset applies there.

Usage in computer systems

Such floating times are a ubiquitous, yet often unaware way of how people interact in temporal contexts. A computer system needs to handle them appropriately. This concept is present in many standard date and calendar formats, data serialization formats and databases. To my knowledge, most modern time libraries also have some support for floating time.

It's easy for a Crystal application to encounter a floating time reference. What should happen if there is no representation for this? Instantly converting a floating time to incremental and assuming it to be in the local time zone would defeat the purpose of using floating time alltogether (W3C guide: Floating times are not attached and should never be attached to a particular time zone.). Handling floating time wrongly is a serious issue in many pieces of software (example on Martin Fowler's blog and should be avoided by providing the right tools to work with.

Integration in Crystal

A huge portion of software applications need to work with incremental time. On the other hand, floating time is certainly not as frequently needed, it can be considered as being more specific to applications tailored towards calendaring purposes and interacting with human representations of time. So, there is not as much an important reason to have support for floating time available in the standard library. It could be implemented by a shard which can be used only by applications that need this feature.

However, it should not only be questioned how frequently needed this feature is to have it in the standard library, but also how it could be integrate from outside the standard library to work with the existing pieces. Obviously, while directly comparing floating time with incremental time is to be avoided, a representation of floating time would need to be tightly integrated with time spans, formatters and parsers, and of course to have conversion methods to and from incremental time. This calls for a tight integration, which - through Crystal's awesomeness - can probably be achieved from a third party shard. Yet it is not very desirable to need to potentially rely on monkey patching to implement and integrate such a fairly common feature.

Implementation

In my proposal #5324, floating time is currently indicated by the special location Location::UNSPECIFIED. This is suboptimal, because it can easily lead to comparing instances of floating time with incremental time which is strictly impossible.

For now, incremental time is converted to floating time, but this causes problems because it cannot be resolved straight forward.

A more logical solution would be to disallow any operation between floating and incremental time instances. This is for example the approach taken by python's datetime module: comparing such two times will raise an error.

This is certainly better. However it can still lead to surprises because every operation on two Time instances can theoretically fail.

A more cleanly solution would be to have a dedicated type for floating time. It should have roughly the same API as Time, but no location and integrate with other components such as Time::Span and Time::Format.

I would love to hear your thoughts about this.

ysbaddaden commented 6 years ago

Let's not bother with floating times in stdlib.

Let's work on a correct Time with offsets and zones and DST as is expected. Let's avoid confusion of having different types or an unspecified location (it should always be local).

I'm sorry if you feel disappointed, but an external shard, introducing a new type, specifically designed for floating time would be a far better solution. If it ends up being ubiquitous (I doubt it) we may consider, eventually, to integrate it. Maybe. Or not.

TLDR: no, please make a shard.

RX14 commented 6 years ago

I too think it should be a seperate type. This means we can tackle it later - either in a shard or in the stdlib.

BrianHawley commented 6 years ago

Being a separate type would also make it possible to have the operations between time and floating-time be more clearly defined, and checked at compile time. No need for a runtime error.

straight-shoota commented 3 years ago

Closing. Lack of interest suggest there is no common enough use case for a floating time type in stdlib.

crysbot commented 1 month ago

This issue has been mentioned on Crystal Forum. There might be relevant details there:

https://forum.crystal-lang.org/t/time-ergonomics/7159/5