简体   繁体   English

如何在Clojure中将日期作为字符串存储在数据库中?

[英]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/cheshirehttps://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 文档单元测试


Update更新

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.

相关问题 如何将JSON字符串日期转换为自定义格式日期? - How do I convert JSON string date to a custom format date? 如何从clojure中的字符串中获取每个json对象? - How to get each json object from a string in clojure? 如何使用 Swift 格式化 JSON 日期字符串? - How do I format JSON Date String with Swift? 如何验证字符串值的格式为“ \\ / Date(1239018869048)\\ /”? - How do I validate that a string value is in the format “\/Date(1239018869048)\/”? 如何将python数组转换为JSON字符串,以便可以将其存储在数据库中? - How can I convert a python array into a JSON string so that it can be stored in the database? 如何在.Net中获取javascript的Date.parse()? - How do I get javascript's Date.parse() in .Net? 如何从Google Firebase中存储的数据创建JSON字符串 - How do I create a JSON string from data stored in Google Firebase 如何在存储在localstorage中的json字符串中显示HTML页面中的json数据 - How do I display json data in HTML page from json string stored in localstorage 如何解析一个 Json 字符串,我将其作为响应将数据分离并存储在不同的变量中? - How to parse a Json String which I m getting as a response to get the data separated and stored in different variable? 如何从Webhook获取数据以存储在数据库中? - How do I get data from Webhook to store in a database?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM