Clojure

Instant literals do not round trip correctly

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Declined
  • Affects Version/s: Release 1.4
  • Fix Version/s: None
  • Component/s: None
  • Patch:
    Code and Test
  • Approval:
    Screened

Description

When using java.util.Date for instant literals (which is the default) instants do not round-trip properly during daylight savings. Here is an example:

(read-string "#inst \"2010-11-12T13:14:15.666-06:00\"")
#inst "2010-11-13T06:14:15.666+10:00"

I'm currently in Melbourne, which is normally GMT+10. However, on November 12th daylight savings is in effect, so the proper GMT offset is +11. The date above is actually using the correct local time (6:14:15) but with the wrong offset. The problem is more obvious when you attempt to round-trip the instant that was read.

user> #inst "2010-11-13T06:14:15.666+10:00"
#inst "2010-11-13T07:14:15.666+10:00"

Notice that we read 6:14am but the output was 7:14 with the same offset. Upon digging deeper the real culprit seems to be the use of String.format (through clojure.core/format) when outputting java.util.Date. Notice the following inside caldate->rfc3339

(format "#inst \"%1$tFT%1$tT.%1$tL%1$tz\"" d))

Let's compare the timezone offset in the underlying date with what is printed by %1$tz

user> (def d #inst "2010-11-13T06:14:15.666+10:00")
#'clojure.instant/d                                                                                                                                                                                         
user> (.getHours d)
7                                                                                                                                                                                                           
user> (.getTimezoneOffset d)
-660

For reference, the definition of getTimezoneOffset is

-(Calendar.get(Calendar.ZONE_OFFSET) + Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)

So far it looks good. 6am in GMT+10 becomes 7am in GMT+11. Let's see how String.format handles it though.

                                                                                               
clojure.instant> (format "%1$tz" d)
"+1000"                                                                                                                                                                                                     
clojure.instant> (format "%1$tT" d)
"07:14:15"

String.format prints the correct hour, but with the wrong offset. The recommended way for formatting dates is to use a DateFormatter.

The String.format approach appears to work properly for Calendar, but not for Date. Therefore the attached patch keeps the current
implementation for java.util.Calendar but uses SimpleDateFormat to handle java.util.Date correctly. This fixes the roundtrip problem.

Activity

Cosmin Stejerean made changes -
Field Original Value New Value
Attachment CLJ-926-fixed-printing-instants.patch [ 10892 ]
Cosmin Stejerean made changes -
Patch Code [ 10001 ]
Cosmin Stejerean made changes -
Attachment CLJ-926-thread-local-date-format.patch [ 10894 ]
Cosmin Stejerean made changes -
Attachment CLJ-926-fixed-printing-instants.patch [ 10892 ]
Cosmin Stejerean made changes -
Attachment CLJ-926-thread-local-date-format.patch [ 10894 ]
Cosmin Stejerean made changes -
Cosmin Stejerean made changes -
Patch Code [ 10001 ] Code and Test [ 10002 ]
Fogus made changes -
Waiting On stuart.sierra
Approval Screened [ 10004 ]
Labels instant reader tagged-literals
Stuart Sierra made changes -
Approval Screened [ 10004 ] Vetted [ 10003 ]
Stuart Sierra made changes -
Approval Vetted [ 10003 ] Test [ 10013 ]
Stuart Sierra made changes -
Approval Test [ 10013 ] Screened [ 10004 ]
Stuart Sierra made changes -
Resolution Declined [ 2 ]
Status Open [ 1 ] Closed [ 6 ]

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: