【问题标题】:How to convert clojure's #inst literals to equivalent java.time types?如何将 clojure 的 #inst 文字转换为等效的 java.time 类型?
【发布时间】:2020-12-22 12:49:14
【问题描述】:

我使用next.jdbc 库将记录保存到 PostgreSQL 表中。正如您在下面看到的,这些值是一个 LocalDate 实例和一个 Instant 实例。 SQL 列的类型分别为 DATE 和 TIMESTAMPTZ。

需要 next.jdbc.date-time 命名空间从 Java -> SQL 映射,如文档中所述。

{:id 7, :trade_date #object[java.time.LocalDate 0x6b751cb1 2020-12-22], :created_at #object[java.time.Instant 0x3add5e17 2020-12-22T11:41:07.557790Z]}

当我读回记录时(SQL -> Clojure),表示如下

{:id 7, :trade_date #inst "2020-12-21T18:30:00.000-00:00", :created_at #inst "2020-12-22T11:41:07.557790000-00:00"}

所以它们被读回为#inst 文字? 我希望它们作为 java.time 类型返回。另请注意,LocalDate 似乎已转换为 UTC 时间戳。这是我到目前为止挖出的东西..

; inst -> Instant
=> (.toInstant #inst "2020-12-22T11:41:07.557790000-00:00")
#object[java.time.Instant 0x312cc79e "2020-12-22T11:41:07.557Z"]

; inst -> LocalDate
=> (-> #inst "2020-12-21T18:30:00.000-00:00"
            #_=> .toInstant
            #_=> (ZonedDateTime/ofInstant (ZoneId/of "UTC"))
            #_=> (.withZoneSameInstant (ZoneId/systemDefault))
            #_=> (.toLocalDate))
#object[java.time.LocalDate 0x44048462 "2020-12-22"]

看起来并不简单/Clojure 方式。有没有更好的办法?

参考资料: 摘自Alan ThompsonBasil Bourque的答案

【问题讨论】:

    标签: clojure java-time clojure-next.jdbc


    【解决方案1】:

    1 小时后。好吧,那没用。

    原来 next.jdbc 使用 java.sql.* 类型重建记录,发生在 REPL 中打印为 #inst 文字。

    调用(.toInstant sql-date-instance) 会出现异常(这是设计的)。然而,有了这些信息,很容易达到最终结果。通过这个映射器运行返回的地图向量。

    (defn mapSqlToTimeTypes [map-with-sql-types]
      (reduce (fn [return-map [k, v]]
                
                (cond
                  (instance? java.sql.Timestamp v) (assoc return-map k (.toInstant v))
                  (instance? java.sql.Date v) (assoc return-map k (.toLocalDate v))
                  :else (assoc return-map k v)))
              {} 
              map-with-sql-types))
    

    【讨论】:

      【解决方案2】:

      所以#inst 只是一个标记文字,默认情况下它的底层类型是java.util.Date。

      (def my-inst #inst "2018-03-28T10:48:00.000")
      (= java.util.Date (class my-inst))
      ;=> true
      

      但是您或任何库都可以更改#inst 的默认阅读器,因为 data-readers 是一个动态变量。所以在任何时候,根据你使用的库,#inst 可能会产生不同的底层类型。

      我自己还没有使用过nex.jdbc,但我认为你需要的是调用read-as-instantread-as-local函数.见here 还可以查看 clj-time Clojure 库。还要检查 java.time 周围的 clojure.java-time 包装器

      【讨论】:

      • 这些选项每个都完成了一半的工作——我的表有一个 UTC 时间戳和一个本地日期。因此,我将通过这些方法调用获得 Instant 或 LocalDate。你能给我一些链接以更好地理解#inst 文字吗?我读过几本 Clojure 书,但不记得有过这个内容。
      • 您不应使用 clj-time 库,因为它已被弃用! 而应使用 java.time 互操作。这里还有辅助函数:cljdoc.org/d/tupelo/tupelo/20.12.16/api/tupelo.java-time
      • @AlanThompson,哦,谢谢。我还是老同学。 Gishu,在这里阅读 clojure 阅读器的页面clojure.org/reference/reader
      【解决方案3】:

      作为对@Gishu 答案的一个小简化,使用postwalk 进行这种类型的数据转换通常非常方便。 Here is a simple function 将所有关键字转换为纯字符串,例如:

      (defn walk-keywords->strings
        "Recursively walks form, converting all keywords to strings. "
        [form]
        (walk/postwalk (fn [item]
                         (if (keyword? item)
                           (t/kw->str item)
                           item))
          form))
      

      这在处理网络请求和响应时特别有用,这些请求和响应通常是深度嵌套的地图和向量。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-11-13
        • 2013-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-12
        • 2021-01-12
        • 1970-01-01
        相关资源
        最近更新 更多