[英]how do I get a date stored in a database as a string in Clojure?
When getting values back out of a Postgres database with clojure.java.jdbc, I'm ending up with当使用 clojure.java.jdbc 从 Postgres 数据库中取回值时,我最终得到
{:id 1, :name "example", :created_at #object[java.time.LocalDateTime 0x15e0aadc "2019-02-08T12:52:11.438633"]}
when I want当我想要
{:id 1, :name "example", :created_at :created_at "2019-02-08T12:52:11.438633"]}
I want the date to be returned as JSON and consumable by JavaScript.我希望将日期作为 JSON 返回并由 JavaScript 使用。 The second example may not be the ideal format for that and so I'm open to others, but a Java object is not going to work.
第二个示例可能不是理想的格式,因此我对其他人持开放态度,但 Java 对象将不起作用。
I tried a couple of approaches, but the compiler produced a number of 'unmatched parenthesis' errors as a result of the date #object.我尝试了几种方法,但是由于日期#object,编译器产生了许多“不匹配的括号”错误。
Thoughts on how to do this?关于如何做到这一点的想法? Do I do something with the original SQL query, do I do something with my returned data, or something else?
我是对原始 SQL 查询做些什么,我是对返回的数据做些什么,还是其他什么?
I'd imagine that cheshire.core/encode would give you nice JSON from that map.我想 cheshire.core/encode 会从那个地图给你很好的 JSON。
Read more about cheshire at https://github.com/dakrone/cheshire在https://github.com/dakrone/cheshire阅读更多关于柴郡的信息
I tried recreating your result with the H2 db, but it is giving me a Clojure #inst
result instead of an object reference.我尝试使用 H2 db 重新创建您的结果,但它给了我一个 Clojure
#inst
结果而不是对象引用。
OK, here is the problem.好的,问题来了。 As your printout says, you have a
java.time.LocalDateTime
(a Clojure #inst
is a java.util.Date
object).正如您的打印输出所说,您有一个
java.time.LocalDateTime
(Clojure #inst
是一个java.util.Date
对象)。
If you want a string version, all you need to do is call the member function toString
on it:如果你想要一个字符串版本,你需要做的就是在它上面调用成员函数
toString
:
(let [ldt (LocalDateTime/parse "2019-02-01T00:00:00" )]
(.toString ldt) => <#java.lang.String "2019-02-01T00:00">
However, you have no Time Zone information attached.但是,您没有附加时区信息。 So, you probably want a ZonedDateTime.
所以,你可能想要一个 ZonedDateTime。 WE WILL ASSUME UTC TIME ZONE BELOW (please verify for your DB server config):
我们将在下面假设 UTC 时区(请验证您的数据库服务器配置):
(let [jud (Date.)
ldt (LocalDateTime/parse "2019-02-01T00:00:00")
zdt (.atZone ldt (ZoneId/of "UTC")) ; *** big assumption here! ***
inst (.toInstant zdt)
inst-str (.toString inst) ]
; a Clojure #inst is just a java.util.Date object
jud => #inst "2019-02-09T19:38:30.088-00:00"
; a ZonedDateTime can print in 2 ways
zdt => #object[java.time.ZonedDateTime 0x780af31 "2019-02-01T00:00Z[UTC]"]
(.toString zdt) => "2019-02-01T00:00Z[UTC]"
; a java.time.Instant also prints in 2 ways:
instant => #object[java.time.Instant 0x48301adb "2019-02-01T00:00:00Z"]
instant-str => "2019-02-01T00:00:00Z"
Note that the ZDT has a suffix like [UTC]
tacked onto the end, so you may wish to convert it to an Instant and then use the .toString
method to get a simpler string representation of it (ISO-8601).请注意,ZDT 在末尾添加了类似
[UTC]
的后缀,因此您可能希望将其转换为 Instant,然后使用.toString
方法来获得更简单的字符串表示形式 (ISO-8601)。
If you don't mind using an external library to make this easier, the tupelo.java-time
lib has a helper function that is very handy:如果您不介意使用外部库来
tupelo.java-time
此操作, tupelo.java-time
库有一个非常方便的辅助函数:
(ns xyz
(require [tupelo.java-time :as tjt] ... ))
(tjt/string-date-time-iso zdt) => "2019-02-01T00:00:00Z"
There are many other helper functions available.还有许多其他的辅助函数可用。 Please see the API Docs and the unit tests for examples .
有关示例,请参阅API 文档和单元测试。
I finally got my Postgres install fixed up (had to reset the password to make Hikari work).我终于修复了我的 Postgres 安装(必须重置密码才能使 Hikari 工作)。 Here is my test code:
这是我的测试代码:
(ns tst.demo.jdbc-pool
(:use demo.core tupelo.core tupelo.test)
(:require
[clojure.java.jdbc :as jdbc]
[hikari-cp.core :as pool]
[tupelo.java-time :as tjt] ) )
(def datasource-options-pg
{:adapter "postgresql"
:database-name "alan"
:server-name "localhost"
:port-number 5433
:username "alan"
:password "secret" } )
(def ^:dynamic db-conn nil)
(defn with-connection-pool
"Creates and uses a connection for test function"
[tst-fn]
(let [datasource (pool/make-datasource datasource-options-pg)]
(binding [db-conn {:datasource datasource}]
(tst-fn)
(pool/close-datasource datasource)))) ; close the connection - also closes/destroys the in-memory database
(use-fixtures
:once with-connection-pool) ; use the same db connection pool for all tests
The above is all just config stuff.以上只是配置的东西。 Here is the unit test that verifies the behavior:
这是验证行为的单元测试:
(dotest
(jdbc/db-do-commands db-conn ["drop table if exists langs"])
(jdbc/db-do-commands db-conn
[(jdbc/create-table-ddl :langs [[:id :serial]
[:lang "varchar not null"]
[:creation :timestamptz]])])
(jdbc/insert-multi! db-conn :langs
[{:lang "Clojure" :creation (tjt/iso-str->timestamp "2008-01-01T12:34:56Z")}
{:lang "Java" :creation (tjt/iso-str->timestamp "1995-06-01T07:08:09Z")}])
(let [result (jdbc/query db-conn ["select * from langs"])]
(is= (vec result)
[{:id 1, :lang "Clojure",
:creation #inst "2008-01-01T12:34:56.000000000-00:00"}
{:id 2, :lang "Java",
:creation #inst "1995-06-01T07:08:09.000000000-00:00"}])))
So you can see I am still getting a java.util.Date
result, which Clojure prints with the #inst
formatting.所以你可以看到我仍然得到一个
java.util.Date
结果,Clojure 用#inst
格式打印。 I'm not sure how you are getting JDBC to output the LocalDateTime
format.我不确定您是如何让 JDBC 输出
LocalDateTime
格式的。
Extend the java.time.Instant in your db.core.clj file.扩展 db.core.clj 文件中的 java.time.Instant。 See https://rundis.github.io/blog/2015/clojure_dates.html for examples on extending types and protocols.
有关扩展类型和协议的示例,请参阅https://rundis.github.io/blog/2015/clojure_dates.html 。
(extend-type java.time.Instant
jdbc/ISQLParameter
(set-parameter [v ^PreparedStatement stmt ^long idx]
(.setTimestamp stmt idx (Timestamp. (.toEpochMilli v)))))
(extend-protocol cheshire.generate/JSONable
java.time.Instant
(to-json [dt gen]
(cheshire.generate/write-string gen (str dt))))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.