【问题标题】:clojure.java.jdbc: How to read postgres dates as localdate when in a non-utc timezone?clojure.java.jdbc:如何在非 UTC 时区将 postgres 日期读取为本地日期?
【发布时间】:2021-03-26 00:58:00
【问题描述】:

当我阅读 postgres 日期类型时,我希望它们被强制转换为 joda time LocalDates(或新的 java.time localdates)。 这是因为 postgres 日期没有时区信息,所以我不希望我的 java 或 clojure 对象以某种方式添加它。

这是我为此设置的 IResultSetReadColumn 协议扩展:

(extend-protocol clojure.java.jdbc/IResultSetReadColumn
  java.sql.Date
  (result-set-read-column [v _rsmeta _idx]
    (tc/to-local-date v)))

但是,当我尝试使用它时,我得到了错误的结果:

(DateTimeZone/getDefault)
=> #object[org.joda.time.tz.CachedDateTimeZone 0x60470ff "Europe/Stockholm"]

(jdbc/query db/db ["SHOW TIMEZONE"])
=> ({:timezone "Europe/Stockholm"})

(jdbc/query db/db ["SELECT '2020-01-01'::date"])
=> ({:date #object[org.joda.time.LocalDate 0x75081795 "2019-12-31"]}) ; ARGH!! It changed date!

我怀疑这是由于日期被转换为 java.sql.date 造成的,其中包含时区信息。有没有办法直接阅读 postgres 日期以避免这种情况?我找到了documentation on the postgres JDBC driver that seems promising,但我不知道如何在 clojure.java.jdbc 中实现它。

基本上: 如果我的默认时区不是 UTC,有什么方法可以让我的 postgres 日期从数据库中取出而不弄乱它们?

【问题讨论】:

标签: postgresql date jdbc clojure timezone


【解决方案1】:

我现在知道该怎么做了:

(defn sql-date->LocalDate [v]
      ; Convert a java.sql.Date into a LocalDate.
      ; LocalDates does NOT have any timezone info - bit un-intuitive perhaps.
      ; Neither does the postgres date type.
      ;
      ; Unfortunately, java.sql.Date has a time component, 
      ; which would causes lots of issues if we were to pass it along as is.
      ; How it works is:
      ; 1. The postgres JDBC driver reads the postgres date as a java.sql.Date,
      ;    by setting the jav.sql.Date timestamp to 00.00
      ;    the date of the postgres date in the 
      ;    JVM default timezone (DateTimeZone/getDefault).
      ;
      ; 2. .toLocalDate converts the java.sql.Date to a java.time.LocalDate 
      ;     in the JVM default timezone (DateTimeZone/getDefault).
      ;
      ; 3. Then we convert the java.time.LocalDate to a joda-time LocalDate, 
      ;    as that is what clj-time uses.
      ;
      ; So because we convert both date -> timestamp -> date in the same
      ; timezone, it all evens out.
      ;
      (let [java-time-localdate (.toLocalDate v)]
        (time/local-date (.getYear java-time-localdate)
                         (.getValue (.getMonth java-time-localdate))
                         (.getDayOfMonth java-time-localdate))))

最重要的是不要使用 clj-time.coerce 的to-localtime 函数。我不确定它的作用,但无论如何它会在涉及时区时搞砸一天。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-25
    • 2021-03-26
    • 2012-10-07
    • 1970-01-01
    相关资源
    最近更新 更多