Incorrect #inst parsing with respect to Julian / Gregorian calendar transition

Description

This manifests itself In the Node REPL, where #inst "1582-10-01" parses into an inst that has the date as 11:

ClojureScript (Node):

Clojure:

Analysis:

In Clojure, when the default java.util.Date is employed, #inst value strings are interpreted using Java's GregorianCalendar, essentially a hybrid Julian / Gregorian system.

In ClojureScript, the underlying JavaScript Date type uses the proleptic Gregorian system.

This effectively means that for dates prior to the Julian to Gregorian transition, the string representations are interpreted differently.

For example, in Java / Clojure (Date. -14830992000000) is #inst "1500", while in JavaScript / ClojureScript (js/Date. -14831769600000) is #inst "1500". In other words, these two different time instants share a string representation that is common between the two calendaring systems. And conversely, a given string, when interpreted in each system (for dates prior to the Julian to Gregorian discontinuity), can represent two different instants in time.

The underlying problem here is that when an #inst embedded in code is read by the JVM ClojureScript compiler, it results in a java.util.Date instance and the resulting epoch time is directly conveyed to a JavaScript Date instance, thus causing a mismatch. In other words, for example, #inst "1500", when in code, is interpreted using the calendar in use in Clojure (if the code is being compiled via JVM ClojureScript). Compare this, for example if you read an #inst literal embedded in a string at runtime---in that case you will get the correct result.

Environment

None

Activity

Show:
Alex Miller
January 14, 2021, 8:54 PM

#inst in edn/clojure is about a representation for Gregorian calendar instants and does not prescribe a behavior for pre-Gregorian calendar dates. That is, it is considered undefined how pre-Gregorian insts are interpreted by a particular language.

Certainly, I think that all users would expect #inst to read/print roundtrip in a particular host.

Mike Fikes
January 4, 2021, 4:50 PM

Added a site page ticket to document the differences between the default inst calendar systems in use in Clojure and ClojureScript: https://github.com/clojure/clojurescript-site/issues/367

Mike Fikes
December 29, 2020, 6:35 PM

CLJS-3291-3.patch resolves the issue by relying on java.time.Instance for #inst interpretation which employs a proleptic Gregorian calendar, just like JavaScript, thus making #inst values read in ClojureScript code match those read at runtime.

It does this in a way that allows macro authors to opt into the same machinery for #inst values embedded in macros, if desired: They could use the cljs.instant facility and bind *data-readers*.

Mike Fikes
December 26, 2020, 11:22 PM

The above assertion is incorrect. Also, #inst "1500" yields a date in 1499. Assigning back to me...

Fixed
Your pinned fields
Click on the next to a field label to start pinning.

Assignee

Mike Fikes

Reporter

Mike Fikes

Approval

Accepted

Patch

Code and Test