DEV Community

Cover image for Don't use clj-time, use clojure.java-time instead
David Liman
David Liman

Posted on

Don't use clj-time, use clojure.java-time instead

clj-time

A date and time library for Clojure, wrapping the Joda Time library. DEPRECATED

A big warning sign on a project's README should have deterred anyone from using the library but my goldfish memory can't remember why

I have used clj-time in my previous project before. I did not recall anything bad about it. Time, just like a logger, in Java has a long history. For the most part, when you have to deal with time, you google around, find which method to call, and move on.

Until this one fine afternoon, I saw lots of new error logs. The stacktrace looks like this:

#error {
 :cause "The datetime zone id 'America/Ciudad_Juarez' is not recognised"
 :via
 [{:type java.lang.IllegalArgumentException
   :message "The datetime zone id 'America/Ciudad_Juarez' is not recognised"
   :at [org.joda.time.DateTimeZone forID "DateTimeZone.java" 234]}]
 :trace
 [[org.joda.time.DateTimeZone forID "DateTimeZone.java" 234]
  [clj_time.core$time_zone_for_id invokeStatic "core.clj" 411]
  [clj_time.core$time_zone_for_id invoke "core.clj" 406]
  [app.domain.hotel$time_zone invokeStatic "hotel.clj" 129]
   ...
  [clojure.core$reduce1 invokeStatic "core.clj" 944]
  [clojure.core$set invokeStatic "core.clj" 4101]
  [org.eclipse.jetty.util.thread.QueuedThreadPool$Runner run "QueuedThreadPool.java" 1034]
  [java.lang.Thread run nil -1]]}

Enter fullscreen mode Exit fullscreen mode

It turns out a partner system sends an update with timezone record like 'America/Ciudad_Juarez'

Wait, what is wrong with that time zone? Let's fire up a REPL and check that:

(require '[clj-time.core :as time])

(time/time-zone-for-id "America/Ciudad_Juarez')
Execution error (IllegalArgumentException) at org.joda.time.DateTimeZone/forID (DateTimeZone.java:234).
The datetime zone id 'America/Ciudad_Juarez' is not recognised
Enter fullscreen mode Exit fullscreen mode

Uh oh, wait that can't be right. How about:

(time/time-zone-for-id "America/Chicago")
;; => #<org.joda.time.tz.CachedDateTimeZone@23749549 America/Chicago>
Enter fullscreen mode Exit fullscreen mode

That one is fine. Quick Google-ing tells me Ciudad Juarez was only recently added to a list of timezones back in 2022

Okay, how do we upgrade our Clojure / Java system with that latest timezone? Does Java reads the timezone database somewhere? That leads me to Oracle TZUpdater app

Fair enough. Let's update our Dockerfile:

FROM debian:bullseye-slim as final
RUN apt-get update && apt-get install -y curl wget unzip

ENV JAVA_HOME=/usr/local/openjdk-17

RUN wget --header "Cookie: oraclelicense=accept-securebackup-cookie" https://download.oracle.com/otn-pub/java/tzupdater/2.3.2/tzupdater-2.3.2.zip && \
    unzip tzupdater-2.3.2.zip && \
    $JAVA_HOME/bin/java -jar tzupdater-2.3.2/tzupdater.jar -f -l https://www.iana.org/time-zones/repository/tzdata-latest.tar.gz

ENTRYPOINT ["java", "-jar", "app-standalone.jar"]
Enter fullscreen mode Exit fullscreen mode

Not a big deal. That should be it, right? Not too soon! Turns out clj-time is a wrapper of Joda Time and the project's README says:

If you are using Java 8 or later, please use the built-in Java Time instead of Joda Time -- or look at clojure.java-time if you want a Clojure wrapper for that, or cljc.java-time for a thin Clojure(Script) wrapper, or juxt/tick for another cross-platform option. See Converting from Joda Time to java.time for more details about the similarities and differences between the two libraries.

Okay so clj-time is deprecated, latest version is 0.15.2. Let's try dm3/clojure.java-time. Sure enough:

(jt/local-date (jt/instant) "America/Ciudad_Juarez")
;; => #<java.time.LocalDate@5bfc8967 2024-01-09>
Enter fullscreen mode Exit fullscreen mode

It picks up the new timezone. Now why wouldn't Joda pick up the latest timezone? To be fair, Joda time does. Here is the release report. It bundles new Global Tz which is derived from IANA Time Zone database

But clj-time wouldn't. It is marked as deprecated. Now my only option is to wholesale adopt java-time, change hundreds of lines of code, or fork clj-time and upgrade to the latest Joda time. Note to myself, pick the newer library for new project guys.

Top comments (0)