Clojure parse timestamp to string - clojure

I am trying to convert a clojure timestamp to a specific format. I am using the clj-time library. https://github.com/clj-time/clj-time. Here is what I am doing:
(f/unparse :year-month-day (t/date-time 2010 10 3))
Which looks a lot like the documentation example, but I don't understand why I got a ClassCastException looking like that:
ClassCastException clojure.lang.Keyword cannot be cast to org.joda.time.format.DateTimeFormatter clj-time.format/unparse (format.clj:185)
Thanks for your help.

define a parser :
(def custom-formatter (fmt/formatter "yyyy-MM-dd"))
then use it:
(fmt/unparse custom-formatter (time/date-time 2010 10 3))

Related

How to print EDN output in JSON format using Cheshire custom encoder

I am newbie with Clojure and I am trying to print EDN output to valid JSON format using Cheshire custom encoder for classes defined in java.
My EDN file:
{:xyz #XyzBuilder "testString"}
Clojure code:
(defn getXyz [str]
(.getXyz (XyzBuilder.) str)
)
(defn custom-readers []
{'xyz/builder getXyz}
)
(add-encoder com.java.sample.Xyz
(fn [c jsonGenerator]
(.writeString jsonGenerator (str c))))
(edn/read-string
{:readers (custom-readers)}
(slurp filename)
)
This generates below output:
{"xyz":"Xyz(sampleString=testString)"}
I want to print it in proper JSON format as below. How can I achieve it?
{"xyz":{"sampleString":"testString"}}
Thanks in advance!
If your java object consists mostly of fields try to convert it to clojure map first and then use chechires's encode-map
(add-encoder com.java.sample.Xyz
(fn [c jsonGenerator]
(-> c
clojure.java/from-java ;; convert java object to clojure map
(select-keys [:sampleString]) ;; select only relevant fields
(encode-map jsonGenerator))))

Clojure convert currency string to float

I know that there's a lot of questions about converting string to float/number/decimal... but my case is quite different cause I need to convert the string number (representing a dollar value) but I must keep the cents in this conversion, here is my case.
I receive this values
"96,26"
"1.296,26"
And I expect to convert to this follow:
96.26
1296.26
If I try to use clojure.edn it escape cents
(edn/read-string "1.296,26")
=> 1.296
(edn/read-string "96,26")
=> 96
If I try to use another approach like bugdec I get NumberFormatException
I know that we can do some string replace but it looks like a big work around, like this:
(-> "1.296,87"
(clojure.string/replace #"\." "")
(clojure.string/replace #"," ".")
(edn/read-string))
what you can do, is to use java's formatting facilities:
(defn read-num [s]
(let [format (java.text.NumberFormat/getNumberInstance java.util.Locale/GERMANY)]
(.parse format s)))
user> (read-num "1.296,26")
;;=> 1296.26
user> (read-num "96,26")
;;=> 96.26
Just use straight Java interop:
(let [nf (java.text.NumberFormat/getInstance java.util.Locale/FRENCH)]
(.parse nf "12,6")) => 12.6
See the Oracle docs: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/text/NumberFormat.html
and this posting: https://www.baeldung.com/java-decimalformat
You can also get a BigDecimal to avoid any rounding errors. See https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/text/DecimalFormat.html#%3Cinit%3E(java.lang.String,java.text.DecimalFormatSymbols)
(let [nf (DecimalFormat. "" (DecimalFormatSymbols. Locale/ITALIAN))
>> (.setParseBigDecimal nf true)
result (.parse nf "123.45,9")]
result => <#java.math.BigDecimal 12345.9M>

Parse string to get date and time in a specific format in Clojure

I just started to play with wit/duckling. It is written in Clojure and I have no previous experience in Clojure. I need to parse a string like 2016-08-14T19:45:48.000+05:30 to a format like 1945hrs, Sunday, August 14th 2016. I searched on Internet and came across to lib clj-time. After struggling with it for a long time I came across this thread and thought that rfc822 is my cup of tea. So I used formatter rfc822 but it is giving me exception:
java.lang.IllegalArgumentException: Invalid format: "2016-08-16T00:00:00.000+05:30"
Here is my code:
(ns firstproj.core
(:gen-class)
(:require [duckling.core :as p])
(:require [clj-time.format :as f]))
(defn -main
"I don't do a whole lot."
[x]
(p/load! { :languages ["en"]})
(def var_ (p/parse :en$core x [:time]))
(def date_string "2016-08-14T19:45:48.000+05:30")
(f/parse (f/formatters :rfc822) date_string))
So can anybody tell me what I am doing wrong here. Or any other way in Clojure to get my desired date-time format. As I am completely naive in Clojure, I request you to answer in detail, it will help me to understand this in a better way. Thank You.
The clj-time library is a wrapper for Joda-Time. If you're using Java 8, you should prefer the built-in java.time library over Joda-Time, for reasons explained here. In Clojure, you can use the Clojure.Java-Time library, which wraps java.time. First, add it to your dependencies:
[clojure.java-time "0.2.1"]
Then you can use the offset-date-time and format functions in the java-time namespace:
(require '[java-time :as time])
(->> (time/offset-date-time "2016-08-14T19:45:48.000+05:30")
(time/format "HHmm'hrs', EEEE, MMMM d y"))
;;=> "1945hrs, Sunday, August 14 2016"
As #Piotrek pointed out in his answer, Joda-Time doesn't seem to support the "th" in your original question. Judging from the DateTimeFormatter docs, neither does java.time.
Without actually checking which predefined formatter matches your date format you might just call:
(f/parse "2016-08-14T19:45:48.000+05:30")
;; => #object[org.joda.time.DateTime 0x1bd11b14 "2016-08-14T14:15:48.000Z"]
It will try all predefined formatters and return parsed value from the first one that succeeds.
Then to print in your custom format:
(require '[clj-time.core :as t])
(def my-time-zone (t/time-zone-for-offset 5 30))
(def my-formatter
(f/formatter
"HHmm'hrs', EEEE, MMMM dd yyyy"
my-time-zone))
(f/unparse my-formatter some-date)
;; => "1945hrs, Sunday, August 14 2016"
Unfortunately to my knowledge JodaTime doesn't handle things like adding st, nd, rd, th to days.

clj-time always returns today's date.

I have a strange problem here. I am calling dates from a database and I am attempting to show the PostgreSQL dates, formatted as "2013-01-01", to display on my site as "January 1, 2013"
I have the following code:
(ns mr.layouts
(:require
[clj-time.format :as ctf]))
(def to-mdy (ctf/formatter "MMMM d, yyyy"))
(defn coerce-mdy [sd]
(ctf/unparse to-mdy (ctf/parse sd)))
The call to the database looks like:
(layouts/coerce-mdy startdate)
The above code does what I want if I test it from the REPL:
mr.handler=> (use 'mr.layouts)
nil
mr.handler=> (require '[clj-time.format :as ctf])
nil
mr.handler=> (coerce-mdy "2012-01-01")
"January 1, 2012"
mr.handler=> (coerce-mdy "2014-10-04")
"October 4, 2014"
mr.handler=>
But what I am getting on the webpage is "September 1, 2013" (today as of this writing) and no other dates. I don't have "2013-09-01" in the database.
I've returned the raw date-value from the data base from (coerse-mdy) and it returns the correct date, so the closest I've been able to isolate this issue is in either (to-mdy) or (coerce-mdy).
So far, I've tried moving the function to the local namespace and using localized let values.
When using clj-time with a database, I've found that I need to use the functions to-sql-date and from-sql-date in the coerce namespace (source here: https://github.com/clj-time/clj-time/blob/master/src/clj_time/coerce.clj)
This is because, as #noisesmith mentioned in his comment, most clojure sql libraries will give a date object (specifically, a java.sql.Date) for a date field in the db. This needs to be treated slightly differently from a string in order to get something that plays nice with clj-time.
Assuming your date is indeed a java.sql.Date, the following should do the trick...
(ns mr.layouts
(:require [clj-time.format :as ctf]
[clj-time.coerce :as coerce]))
(def to-mdy (ctf/formatter "MMMM d, yyyy"))
(defn coerce-mdy [sd]
(ctf/unparse to-mdy (coerce/from-sql-date sd)))

Why is my string formatting failing in Clojure?

In Java, I can do the following to format a floating point number for display:
String output = String.format("%2f" 5.0);
System.out.println(output);
In theory, I should be able to do the same thing with this Clojure:
(let [output (String/format "%2f" 5.0)]
(println output))
However, when I run the above Clojure snippet in the REPL, I get the following exception:
java.lang.Double cannot be cast to [Ljava.lang.Object;
[Thrown class java.lang.ClassCastException
What am I doing wrong?
Java's String.format takes an Object[] (or Object...), to use String.format in Clojure you need to wrap your arguments in an array:
(String/format "%2f" (into-array [5.0]))
Clojure provides a wrapper for format that's easier to use:
(format "%2f" 5.0)
Kyle