【问题标题】:clj-time.coerce java.sql.Date .toString decrements date?clj-time.coerce java.sql.Date .toString 递减日期?
【发布时间】:2019-03-02 12:50:10
【问题描述】:

test_ns.clj

(ns test-ns
  (:require [clj-time.jdbc :as tj]
            [clj-time.coerce :as tc]))

(.toString (tc/to-sql-date (tc/from-string "2018-09-28")))

=> "2018-09-27"

为什么 .toString 会减少日期?

  • 期望格式化的日期字符串将匹配其输入
  • tc/to-sql-date 转换为 java.sql.Date 类
  • .toString 方法似乎被 hugsql 默认 jbdc 适配器使用,这是用于 sql 事务的项目依赖项

project.clj:

(defproject my-project "0.1.0-SNAPSHOT"
  ...
  :min-lein-version "2.0.0"
  :dependencies [[org.clojure/clojure "1.10.0-beta1"]
                 [duct/core "0.7.0-alpha8"]
                 [duct/module.sql "0.5.0-alpha1"]
                 [duct/module.logging "0.4.0-alpha1"]
                 [duct/database.sql.hikaricp "0.3.3"]
                 [com.walmartlabs/lacinia "0.21.0"]
                 [com.rpl/specter "1.1.1"]
                 [net.mikera/core.matrix "0.62.0"]
                 [com.wsscode/pathom "2.2.4"]
                 [org.clojure/core.async "0.4.474"]
                 [org.postgresql/postgresql "42.2.5"]
                 [org.clojure/core.async "0.4.490"]
                 [com.layerware/hugsql "0.4.9"]
                 [cheshire "5.8.1"]
                 [camel-snake-kebab "0.4.0"]
                 [hickory "0.7.1"]
                 [incanter "1.9.3"]
                 [clj-http "3.9.1"]
                 [environ "1.1.0"]]
  :plugins [[lein-environ "1.1.0"]
            [duct/lein-duct "0.11.0-alpha6"]
            [lein-exec "0.3.7"]]
  :main ^:skip-aot portfolio-management.main
  :test-paths   ["test"]
  :source-paths ["src"]
  :target-path "target/%s"
  :resource-paths ["resources" "target/resources"]
  :prep-tasks ["javac" "compile" ["run" ":duct/compiler"]]
  :profiles
  {:dev          [:project/dev :profiles/dev]
   :repl         {:prep-tasks   ^:replace ["javac" "compile"]
                  :repl-options {:init-ns user}}
   :uberjar      {:aot :all}
   :profiles/dev {}
   :project/dev  {:source-paths   ["dev/src"]
                  :resource-paths ["dev/resources"]
                  :dependencies   [[integrant/repl "0.3.1"]
                                   [eftest "0.4.1"]
                                   [kerodon "0.9.0"]
                                   ]}})

编辑

~$ java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-8u191-b12-2ubuntu0.18.04.1-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)

【问题讨论】:

  • 我无法重现此内容。一个带有 project.clj 的空项目,代码返回“2018-09-28”。
  • 可以重现。我不得不删除clj-time.jdbc:require,因为它会导致错误,但代码仍然运行,结果是"2018-09-27"。您对clj-time.jdbc 的要求是否导致No such var: jdbc/IResultSetReadColumn 错误?
  • 有趣的是,(let [d (tc/to-sql-date (tc/from-string "2018-09-28"))] [(.getMonth d) (.getDate d)]) 返回[8 27]。似乎有些东西将月份和日期视为从 0 开始,而它们应该从 1 开始。
  • 我认为这是一个时区问题。其中一个日期构造函数考虑了本地时间,而另一个则没有。注意this。这将是一个问题,因为to-sql-time 是通过处理自纪元以来的毫秒数进行转换的。这也可能解释了为什么 Erwin 不能复制,因为这取决于当地时间。我认为这是一个库错误。

标签: clojure clojure-java-interop clj-time


【解决方案1】:

我很确定这是一个时区问题,正如 Carcigenicate 已经指出的那样。 from-string 解析 UTC 时区的字符串,java.sql.Date 使用默认的 JVM 时区。 如果您所在的时区位于 UTC(西部)“之后”的时区,则返回的结果是正确的,因为在这些时区中,日期 2018-09-28 00:00:00 实际上是 2017-09-27。

(java.util.TimeZone/setDefault(java.util.TimeZone/getTimeZone "GMT"))
(.toString (tc/to-sql-date (tc/from-string "2018-09-28")))
;; => "2018-09-28"

(java.util.TimeZone/setDefault(java.util.TimeZone/getTimeZone "GMT-1"))
(.toString (tc/to-sql-date (tc/from-string "2018-09-28")))
;; => "2018-09-27"

您不应使用 java.sql.Date 并期望它返回 UTC 时区中的日期,只要那不是您的默认时区。

【讨论】:

  • 谢谢!将默认时区设置为 GMT 解决了报告的行为。没想到日期对象会有这样的依赖,但这是有道理的。
  • 是的,这有点棘手,我们在生产中也被这个咬了。而且因为我们在 GMT+1 时区,但我们的一些客户在 GMT-X 运行,这非常棘手;尤其是在将数据保存到数据库时,转换是“静默”完成的。
猜你喜欢
  • 2018-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-12
  • 2013-07-31
  • 2012-08-09
  • 2018-08-02
相关资源
最近更新 更多