我有一个浮点值表示秒。我想将它分割成两个整数,表示整秒和纳秒,以便将它作为最后两个参数传递给java.time.ZonedDateTime.of()构造函数。
这是我目前的方法,但我担心我可能会不必要地失去精度,或者重新创建某种现有的java时功能:
;;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]有更好的办法吗?谢谢你的帮助。
Update,这似乎工作得更好,但仍然好奇它是否可以改进:
;;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]更新2
根据已被接受的答案和评论,以及我自己对代码进行重新定位的一些经验,我合并为:
(defn seconds-and-nanos
[seconds]
(let [whole (long (Math/floor seconds))
fraction (- seconds whole)
nano (* fraction 1000000000)
nano (cond
(float? nano) (Math/round nano)
(instance? clojure.lang.BigInt nano) (long nano)
:else nano)]
(if (= nano 1000000000)
[whole (- nano 1)]
[whole nano])))seconds不再被限制在60或更少。if (= nano 1000000000)块与上下文高度相关,可以根据需要删除或重写;对于我的用例,我认为这是一种非常罕见的边缘情况(仅在某种程度上处理超出了nano精度的seconds时才出现,这已经令人怀疑),因此我决定走一条更加方便的路径,始终向下舍入,以避免添加整个第二个单元,并且可能会级联到每一个其他单元(分钟、小时等)。
谢谢你的帮助。
发布于 2022-09-25 10:22:20
我将使用如下内容,从我最喜欢的模板项目开始
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test)
(:require
[schema.core :as s])
(:import
[java.time Instant]))
(def SECOND->NANOS 1.0e9)
(s/defn epoch-sec->Instant :- Instant
"Accepts a floating point value of epoch second and converts to a java.time.Instant"
[epoch-seconds :- s/Num]
(assert (<= 0 epoch-seconds)) ; throw for negative times for simplicity
(let [esec-dbl (double epoch-seconds)
esec-whole (Math/floor esec-dbl)
esec-fraction (- esec-dbl esec-whole)
esec-nanos (Math/round (* esec-fraction SECOND->NANOS))
result (Instant/ofEpochSecond (long esec-whole) (long esec-nanos))]
result))单元测试
(verify
(throws? (epoch-sec->Instant -1))
(is= "1970-01-01T00:00:00Z" (str (epoch-sec->Instant 0.0)))
(is= "1970-01-01T00:00:00.100Z" (str (epoch-sec->Instant 0.1)))
(is= "1970-01-01T00:00:00.999990Z" (str (epoch-sec->Instant 0.99999)))
(is= "1970-01-01T00:00:00.999999900Z" (str (epoch-sec->Instant 0.9999999))))然后,可以使用静态方法从Instant值构建ZDT。
static ZonedDateTime ofInstant(Instant instant, ZoneId zone)您可以为java.time 已经写在这里了找到大量的转换和方便函数。
https://stackoverflow.com/questions/73830954
复制相似问题