Qqwy
TypeCheck Core Team
As the talk about calendars, differences between calendars and the difficulties of converting dates and times from one calendar to the other got a little bit out of hand in the topic of the Jalaali calendar library, this discussion can continue here.
The problems with calendars
(a short summary of the discussion so far)
- Calendars are often irregular in an unpredictable way: Leap days, leap seconds, next month only starting if the moon is visible, etc.
- Different calendars use different measures (such as different times at which one day ends and the next one starts: midnight, noon, sunrise, sunset?)
- The OS clock in our computers ‘counts seconds’ but does not handle leap seconds, which complicate the conversion between OS (POSIX) time and datetimes in other calendar systems.
Now, of course: How would it be possible to overcome these problems as good as possible?
- We can look at already-existing calendar implemetations such as Joda Time.
- As @kip noted, Dershowitz and Rheingold described conversions between 23 calendars by using a fixed date representation. (He currently has an open pull request to add an integer calendar representation to the core)
- This representation might be enhanced by choosing a smaller denomination than integer ‘days’ to make the results truly unambiguous and allow conversions between calendars of different times.
- One such intermediate representation might be TAI (International Atomic Time), as it is one of the few calendars that is monotonically increasing and computationally simple.
- However, converting OS time to TAI again requires knowledge of leap seconds, which means that results will be unaccurate starting +6 months from now.
- Also, precision will diverge when we go too far in the past or future in any case, due to small irregularities or inaccuracies between calendars.
Calendars are hard (but interesting!). Let the discussion on how an accurate calendarium (for Elixir?) might be built continue!
Trending in Discussions
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
New
The obligatory hello world thread!
Who are you and where are you from? :stuck_out_tongue:
New
I want to open this thread for you all to discuss and help those who really like Ash but are still hesitant to use it in a real project. ...
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
We’re evaluating API mocking tools for OpenAPI-based projects and would love to hear what other teams are using.
We’re particularly inte...
New
I’m posting this in response to Jose’s recent tweet (Cr. link) :
People are sleeping on Elixir for a coding harness:
Hot-code swappi...
New
Hello,
I wrote Stop My Hand, a Scattergories-like web application using Phoenix/LiveView as my learning project for Elixir (after readin...
New
Other Trending Topics
Hobbes is a low-level distributed database for the Elixir programming language.
Hobbes provides a simple, safe, and scalable storage lay...
New
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
There are three potential reasons for members of this forum to have a look at https://vutuv.de
You are tired or annoyed of LinkedIn.
Yo...
New
Aludel - LLM Evaluation Workbench
Aludel is an embeddable Phoenix LiveView dashboard for evaluating and comparing LLM prompts across mult...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixir-ls
- #ai
- #elixirconf-us
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
kip
@Qqwy, thanks for starting this thread. And @alisinabh, apologies for hijacking your thread. From the earlier conversations and @qqwy’s summary above, i believe consensus so far is:
Calendarbehaviour is a good ideaDate,NaiveDateTimeandDateTimeThe candidates I have seen in discussion so far are:
Julian Date (JD)
This is well understood, especially in astronomy circles. In incorporates an integral number of days since an epoch (epoch depends on which version of JD is chosen, but the original epoch of Julian day number 0 is assigned to the day starting at noon on January 1, 4713 BC, proleptic Julian calendar (November 24, 4714 BC, in the proleptic Gregorian calendar). The fractional part represents the fraction of a day since noon.
Plus: well understood, incorporates date and time, conversions have good precision
Minus: float format means time conversions are approximate and therefore whilst quite precise, cannot be assumed to be accurate in the way formal time systems are accurate.
Rata Die
This is the mechanism used by Derschowitz and Rheingold. This is essentially the same mechanism as Julian Day but with epoch of 1 January 0001. In their book Calendrical Calculations, RD is sometimes used as an integer meaning number of days since epoch - and this is what I originally proposed in order to avoid the issues of time conversion. An alternative form uses the same approach as JD, using a fractional part of a float to denote fraction of a day since noon.
Plus: Mostly the same as JD. According to Wikipedia this is used by Go, Rexx and .Net. Another benefit is that D&R have described and tested the algorithms for 23 calendar types.
Minus: Same as JD, and also it seems to be less familiar than JD
Unix timestamp
Common timestamp format so well understood. As long as its 64 bits (as Elixir is) then precision is enough to cater for all practical date/time ranges
Plus: well understood epoch of January 1, 1970 Gregorian; many other library functions that can work directly on Unix timestamps. Precise in that only integer arithmetic is required whereas JD and Rata Die require float arithmetic.
Minus: Not monotonic due to leap second issues
TAI (Temps Atomique International)
Monotonic clock which underpins UT1 time and is part of the UTC time standard means the format is standardised (several formats are available from accuracy of seconds down to nanoseconds depending on needs).
Plus: Monotonic
Minus: Difficult to compute, requires calculation of drift from UTC and a leap second table. Must adjust each time a leap second is declared.
This is clearly not a definitive list, nor a complete explanation. Given that the primary discussion here is about calendar conversion, I would propose JD as the basis of conversion since that is familiar to calendarises, allows calculation of both arithmetic and astronomical calendar conversions and is computationally quite easy to calculate. Clearly I’m also ok with Rata Die (using the float form to represent time) since there is a solid body of work to be leveraged but that is still true using JD. I think despite the benefits, TAI is too complicated to calculate and to maintain.
josevalim
Could we use JD or RD but represent it as a tuple where the first element is the number of days and the second element is the number of microseconds elapsed in that day?
Qqwy
I think we could, as long as we define a very clear translation of day fraction ↔ microseconds. This might be as simple as saying ‘there are always
86_400_000_000microseconds in a JD (or RD)’. (86_400_000_000 == 24 * 60 * 60 * 1_000_000)This does mean that extra care needs to be taken when converting to/from UTC datetimes because of the afore-discussed leap second troubles:
On days at which UTC has a leap second, the conversion of an UTC microsecond is not
1:1to a JD/RD microsecond, but rather86401 : 86400(an UTC day with a leap second contains24 * 60 * 60 + 1seconds). Most timestamps with microsecond integer precision will have to be rounded when doing this conversion.As the gcd of
86400and86401is1, if we want to use an integer base in which no rounding would occur, we need to multiply it with the common base(86400 * 86401) == 7465046400first.So, if we want to have an exact (monotonically increasing) result, we’d need to store
microseconds * 7465046400in the second tuple field.This does sound like a bit of hard work, but the nice thing about using a
{day, in_day_amount}tuple is that the answers will always be exact and fast to convert to- and from UTC on any non-leap second days (Using for instance TAI as intermediate standard we would not be able to do this as in that case, every datetimestamp past a leap second needs to keep track of that leap second).I believe we’d be able to claim microsecond exactness for all times on days except the June 30ths and December 31ths that are more than 6 months in the future; during those days, this calculation might at most be
(amount_of_years_more_than_six_months_in_the_future * 2 * 86401) / 86400seconds off.(note: it theorerically is also possible that there are leap second deletions, in which case an UTC day might only have 86399 seconds. This has never happened during the past 45+ years that leap seconds are part of the internationally used calendar, but if we’d want to support it, we’d need
86399 * 86400 * 86401as base.)Qqwy
This kind of intra-day amount would also mean that conversions to- and from calendars that have a different (but well-defined) starting point for their days, as these would convert to static offsets in the intra-day amount.
josevalim
Thanks for the reply. I guess that raises the question of, even if we account for leap seconds in the datetime representation, the only way to calculate the difference between two dates is by having in hand all of the leap seconds that have occurred between the two dates. And if we are going to keep this information in memory, we will also need a way to update it.
Does all calendars have a fixed amount of hours in a day, except by the leap second case, or do some calendars have shorter and longer days?
Qqwy
Yes and no. As we count in days and ‘day fractions’ (my previous post was an explanation of how such a day fraction could be stored in an integer format that would be precise enough to handle leap second conversions), to calculate the difference between two dates (in days + day fractions) will not need to handle leap seconds.
In pseudocode:
When working with a POSIX time clock such as OS time, which ‘forgets’ that a leap second happened, conversions are accurate except during a leap second (during which different clock implementations (strict POSIX, NTP, et al.) will do different things such as repeating a second or ‘slowing down’ around it, neither of which can be recognized/handled at the level of our calendar implementation.) Lucky for us, Erlang already has done some work in this regard, having multiple different kinds of clocks (Erlang time documentation).
When converting to- or from an UTC datetime, we’ll need to consult the list of leap seconds for dates that are the 31st of December or the 30th of June, to check if that particular date is in there (but this thus is only necessary for those two days of the year!).
When converting to- or from TAI, you always need the list of leap seconds, as you’ll need to add/subtract all leap seconds that have happened before the timestamp under consideration.
Such a list therefore seems necessary. As to how handle updating the list: When working with POSIX times, the Network Time Protocol is often used (Erlang uses it) to keep the OS clock in sync and notify it about leap seconds. However, NTP only notifies you on the day itself that this is a day with a leap second. It therefore is unusable for working with dates in the future.
A simple solution would be to release new versions of the Calendar library each time a leap second is announced. I am not sure how easy it would be for systems that rely on hot-code reloading to update such an dependency while running.
In any case, it would seem fair to me to say that maintainers of applications that absolutely need the sub-second leap second precision should be considered responsible themselves to update their calendar library once every six months.
I believe the length of a day is earthwide the same; even if the length of daytime and nighttime differ depending on if you are on the poles or at the equator, the length of
(daytime + nighttime)is the same*, which means that all calendars that have been made through the ages at the different parts of the globe have this same ‘day’ unit.As for the subdivision of a day (in e.g. hours), this is something that calendars do differently.
(* unless we’d want to correct for relativistic time dilation differences, but that is definitely a precision and complexity we do not need for a general-purpose calendar library).
josevalim
But to calculate the difference between two dates in seconds, we would need to know which days had leap seconds, correct?
Qqwy
Yes. This would be the same as converting both times to TAI timestamps first, and subtracting these.
alisinabh
Hi everyone.
Sorry if i’m bugging you, i just have to understand this problem About the problem with leap seconds. If we use UNIX since we are only dealing with date and NOT time, assuming even if every year from now will have a leap second, in year 86336 we will have a day misplaced and that is why we want to use JD. To support +84K years ahead (again, assuming every year will have a leap second). Correct?
Eiji
It’s not always equal to a second. For more info see a leap second wikipedia article. How about create a simple API for Elixir to fetch a leap seconds?
We should know about add new second several months in advance, so update it is not a big problem
.