【问题标题】:Clojure: creating a date-time object for the JDBCClojure:为 JDBC 创建一个日期时间对象
【发布时间】:2019-12-25 21:40:16
【问题描述】:

我用一列创建了我的 PostgreSQL 表:

  updated_at timestamp(0) with time zone 

我正在使用clojure.java-time,但我无法创建一个字符串(或者应该是一个对象?)来设置当前日期时间。我试过了:

 (time/format "yyyy-MM-dd HH:ss" (time/local-date-time))    

我尝试使用该字符串:

(db/update-answer! {:updated_at "2019-12-25 14:08", :id 102, :answer "Foo"} 

但 JDBC 告诉我“updated_at”字段没有有效类型。据我了解,JDBC 仍在使用旧的 java API 来处理日期和时区,而不是 JDK 8 中的新 API。所以,总而言之,我不知道如何创建对 Postgresql 时间有效的字符串或对象- 使用 clojure.java-time 标记列。

有人建议我扩展 JDBC 协议,我正在阅读它,但现在我只是在寻找一种方法来创建有效对象并完成此更新。

更新

在关注this page 之后,我可以为 Instant 提供格式:

(ns zentaur.hiccup.helpers-view
  (:require [clojure.tools.logging :as log]
        [java-time :as jt])
 (:import [java.time ZoneId]))

(defn format-date [date]
 (log/info (str ">>> DATE >>>>> " date "und type >>> " (type date)))
 (jt/format "yyyy-MM-dd HH:mm" (.atZone date  (ZoneId/systemDefault))))

【问题讨论】:

    标签: postgresql clojure


    【解决方案1】:

    (Java 语法,不是 Clojure)

    tl;博士

    使用对象,而不是字符串。在 Java 中使用 java.time 类,而不是旧的日期时间类。

    myPreparedStatement
    .setObject(
        … , 
        OffsetDateTime.now()
    )
    

    trigger 自动执行此操作会更好。

    总之,我不知道如何使用 clojure.java-time 创建一个对 Postgresql 时间戳列有效的对象。

    调用 OffsetDateTime.now() 以获取保存当前时刻的 java.time.OffsetDateTime 对象。

    使用类型为TIMESTAMP WITH TIME ZONE 而不是TIMESTAMPTIMESTAMP WITHOUT TIME ZONE 的缩写)的数据库列。

    时刻

    设置当前日期时间

    如果您想跟踪时刻、时间轴上的特定点,则您使用了错误的数据类型。

    您正在使用TIMESTAMP,它是TIMESTAMP WITHOUT TIME ZONE 的缩写。此类型缺少任何时区或与 UTC 偏移的概念。所以这种类型不能跟踪时刻。我建议您以后避免使用此类型名称的简短版本,以使您的 SQL 清晰。见Postgres doc

    您应该将您的列定义为TIMESTAMP WITH TIME ZONE。 Postgres 通过始终保存 UTC 中看到的时刻来处理这种类型。输入中提供的任何时区或偏移量都用于调整到 UTC。同样,检索时,您的值始终为 UTC,偏移量为零时分秒。

    谨防将某个时区动态应用于检索值的中间件和工具。这很重要,造成了价值存储在那个时区的错觉。该值实际上以 UTC 格式存储,在 Postgres 中始终以 UTC 格式存储。

    智能对象,而不是哑字符串

    但是我不能创建一个字符串(或者应该是一个对象?)来设置当前的日期时间。

    不要。

    您应该在 Java 和 Postgres 之间交换对象,而不仅仅是字符串。这样就避免了上面提到的时区注入问题。

    从 JDBC 4.2 开始,您可以与数据库交换现代 java.time 对象。永远不要使用诸如CalendarGregorianCalendarjava.util.Datejava.sql.Datejava.sql.Timestamp 等遗留类型。这些类是由不了解日期时间处理的人设计的,存在严重缺陷。在采用JSR 310 时,它们已被取代。

    将当前时刻捕获为OffsetDateTime。您的 JDBC 驱动程序可能支持 InstantZonedDateTime 但这些类型是可选的,如上图所示。相比之下,JDBC 需要支持OffsetDateTime

    OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
    myPreparedStatement.setObject( … , odt ) ;
    

    在上面的代码中明确使用ZoneOffset.UTC 并不是严格要求的。如果省略,您的 JVM 当前的默认偏移量将被隐式应用。如上所述,您的 JDBC 驱动程序和/或 Postgres 将根据 UTC 进行调整。为了调试/记录,我自己的偏好是指定 UTC,以便我可以看到该值,因为它最终将存储在数据库中。

    和检索。

    OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
    

    默认值

    如果您只是记录更新行的时刻,则无需在 SQL 中执行此操作。我建议您写一个trigger,以便在更新该表中的一行时调用。然后,无论更新行的机制如何,都可以保证写入值。编写 SQL 语句时无需担心。

    【讨论】:

    • Postgres 也接受 timestamptz 作为 timestamp with time zone 的简写
    猜你喜欢
    • 2017-04-04
    • 1970-01-01
    • 2018-07-25
    • 1970-01-01
    • 1970-01-01
    • 2014-07-24
    • 1970-01-01
    • 1970-01-01
    • 2016-03-12
    相关资源
    最近更新 更多