I have a floating point value representing seconds. I'd like to split it into two integers representing whole seconds and nanoseconds in order to pass it as the last two arguments to the java.time.ZonedDateTime.of() constructor.
This is my current approach, but I worry that I might be needlessly losing precision or recreating some sort of existing java-time functionality:
;;seconds >= 0 and < 60
(defn seconds-and-nanos
[seconds]
(cond
(integer? seconds) [seconds 0]
(float? seconds) [(int seconds) (int (* (mod seconds (int seconds)) 1000000000))]))
;;repl> (seconds-and-nanos 3.4)
;;[3 399999999]
Is there a better way? Thanks for any help.
Update, this appears to work better, but still curious if it could be improved:
;;seconds >= 0 and < 60
(defn seconds-and-nanos
[seconds]
(cond
(integer? seconds)
[seconds 0]
(float? seconds)
(let [whole (int seconds)
nano (Math/round (* (- seconds whole) 1000000000))]
(if (= nano 1000000000)
[whole (- nano 1)]
[whole nano]))))
;;repl> (seconds-and-nanos 3.4)
;;[3 400000000]
;;repl> (seconds-and-nanos 3.9999999999)
;;[3 999999999]
;;repl> (seconds-and-nanos 3.999999999)
;;[3 999999999]