TIL: Clojure #inst Reader Literal Shortcuts
I’m a big fan of the Today I Learned microblog that Hashrocket runs. The TIL format of simply sharing what is new and useful to the author encourages Hashrocket’s engineers to share practical knowledge when they might not otherwise find the time if they needed to write a wordy introduction or conduct a topical deep dive. Beyond that, it also gives license for the author to share something that is new to him or her–and likely many others–without any implicit suggestion of blazing new technological trails. I’d like to embrace that format to some degree on this blog, sharing some quick TIL posts alongside longer pieces that dig deeper.
At a recent Austin Clojure Meetup I picked up a tiny
tip that has saved me quite a bit of typing when testing code
involving dates. Because the java.util.Date
class is not a lot of
fun to work with from Clojure (you know what I mean if you’ve ever
used it), I almost always end up pulling clj-time into my
date/time-related tests when they require anything more complicated
than the current datetime (Date.
).
But because I often need to ultimately work with java.util.Date
s
(e.g. with Datomic), I then end up having to coerce. So I end up with
a bunch of junk like this in my date-related tests:
(deftest old-records-excluded
(let [old-date (time.coerce/to-date (time/date-time 2018 1))
new-date (time.coerce/to-date (time/date-time 2018 2))]
;; ... test involving dates ...
))
It works, and I choose it because the dates are easier to understand at a glance than the (nearly1) equivalent…
(deftest old-records-excluded
(let [old-date (Date. 118 0 1)
new-date (Date. 118 1 1)]
;; ... test involving dates ...
))
But what I recently learned is that the familiar #inst
literal
reader (which you may think of as the format Clojure shows dates in at
the REPL) actually supports eliding the later portions of the date
string, meaning we can succinctly write common date literals. In
other words, all of the following are valid and equivalent:
(= #inst "2018"
#inst "2018-01"
#inst "2018-01-01"
#inst "2018-01-01T00:00:00.000-00:00")
;; => true
This reduces our test to the much more compact…
(deftest old-records-excluded
(let [old-date #inst "2018-01"
new-date #inst "2018-02"]
;; ... test involving dates ...
))
…and involves no require
s. Much better!
-
There are actually some timezone related differences, but for the purposes of such tests they tend to be irrelevant since they’re consistently offset. ↩︎