Neikon
Neikon

Reputation: 169

Clojure java-time: getting instant with millis

I'm trying to convert a local-date into an instant with millis using java-time, but instant returns a timestamp without millis.

(def UTC (java-time/zone-id "UTC")

(defn local-date-to-instant [local-date] 
  (-> local-date
      (.atStartOfDay UTC)
      java-time/instant))

(local-date-to-instant (java-time/local-date))
=> #object[java.time.Instant 0xdb3a8c7 "2021-05-13T00:00:00Z"]

but

(java-time/instant)
=> #object[java.time.Instant 0x1d1c27c8 "2021-05-13T13:12:31.782Z"]

The service downstream expects a string in this format: yyyy-MM-ddTHH:mm:ss.SSSZ.

Upvotes: 0

Views: 2365

Answers (3)

Steffan Westcott
Steffan Westcott

Reputation: 2201

Create a DateTimeFormatter that prints an ISO instant with milliseconds (3 fractional digits) even if they are zeroes:

(ns steffan.overflow
  (:require [java-time :as jt])
  (:import (java.time.format DateTimeFormatterBuilder)))

(def iso-instant-ms-formatter
  (-> (DateTimeFormatterBuilder.) (.appendInstant 3) .toFormatter))

Example of use:

(def today-inst (jt/truncate-to (jt/instant) :days))

(str today-inst)                                ; => "2021-05-13T00:00:00Z"
(jt/format iso-instant-ms-formatter today-inst) ; => "2021-05-13T00:00:00.000Z"

Upvotes: 2

Alan Thompson
Alan Thompson

Reputation: 29958

You need to use a DateTimeFormatter. Then you can write code like:

LocalDate date = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
String text = date.format(formatter);

In particular, look at these format pattern codes:

S   fraction-of-second  fraction    978
A   milli-of-day        number      1234
n   nano-of-second      number      987654321

I think the S code is the best one for your purposes. You'll have to experiment a bit as the docs don't have all the details.

Here is one example:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require
    [schema.core :as s]
    [tupelo.java-time :as tjt]
  )
  (:import
    [java.time Instant LocalDate LocalDateTime ZonedDateTime]
    [java.time.format DateTimeFormatter]
  ))

(dotest
  (let [top-of-hour (tjt/trunc-to-hour (ZonedDateTime/now))
        fmt         (DateTimeFormatter/ofPattern "yyyy-MM-dd HH:mm:ss.SSS")
       ]
    (spyx top-of-hour)
    (spyx (.format top-of-hour fmt))
  ))

with result

-----------------------------------
   Clojure 1.10.3    Java 15.0.2
-----------------------------------

Testing tst.demo.core
top-of-hour => #object[java.time.ZonedDateTime 0x9b64076 "2021-05-13T07:00-07:00[America/Los_Angeles]"]
(.format top-of-hour fmt) => "2021-05-13 07:00:00.000"

The above is based from this template project and the library tupelo.java-time.

Upvotes: 1

xificurC
xificurC

Reputation: 1178

LocalDate doesn't have a time component. .atStartOfDay puts zeroes in all time fields. A LocalDateTime can be converted to an Instant through .toInstant.

Upvotes: 0

Related Questions