how to get the current date as YYYYMMDD in clojure? - clojure

I am using the following code:
(require '[clj-time.core :as time]
'[clj-time.coerce :as tc]
'[clj-time.format :as f])
(f/unparse (f/formatter "yyyyMMdd") time/now)
But it throws the following error.
caused by: java.lang.ClassCastException: clj_time.core$now cannot be cast to org.joda.time.ReadableInstant

unparse function takes 2 arguments. First is the format,which should be an instance of org.joda.time.format.DateTimeFormatter, which you create correctly by calling
(f/formatter "yyyyMMdd")
the second argument is date time, which should be an instance of org.joda.time.DateTime and here you are doing small mistake. Instead of passing DateTime you are passing clojure function time/now, what you should do is to call the function like this
(f/unparse (f/formatter "yyyyMMdd") (time/now))

Related

How to convert instant time to date in clojure

I have an instant time in clojure as "2016-08-03T18:45:00.000-00:00". I want to convert it to only date ("2016-08-03"). How do I do this.
My actual date is in the format "2016-08-03T18:45:00Z". I converted it to instant using (c/to-date (f/parse "2016-08-03T18:45:00Z")).How to get only date?
Thank you
clj-time is now deprecated, new projects should use java-time:
(:require [java-time :as jt]))
(defn format-date
"Format a Java instant"
[date]
(let [formatter (jt/format "dd-MM-yyyy HH:mm")
instant-with-zone (.atZone date (jt/zone-id))]
(jt/format formatter instant-with-zone)))
Note that (jt/zone-id) returns the current server zone, so you must use (jt/zone-id "America/Mexico_City") if you want a static zoned date.
If you want to get just the date part of the date and time string:
(require '[clojure.string :as str])
(def date-str "2016-08-03T18:45:00.000-00:00")
(first (str/split date-str #"T"))
;; => "2016-08-03"

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.

Clojure - call one method from another, both methods are in the same protocol/record

A protocol has two methods:
(defprotocol ITimeInterop
(parse-int [this str])
(stringify-time [this host-time]))
Here I am calling parse-int from stringify-time:
(defrecord CljTime []
ITimeInterop
(parse-int [_ str]
(Integer. (re-find #"[0-9]*" str)))
(stringify-time [the-obj host-time]
(let [specific-format (SimpleDateFormat. "MM dd yyyy HH:mm:ss")
as-str (.format specific-format host-time)
[month day-of-month year time-str] (str/split as-str #" ")
month-as-idx (dec (parse-int the-obj month))]
{})))
The error message I am getting is 'java.lang.RuntimeException: Unable to resolve symbol: parse-int in this context'.
How should I be calling parse-int from stringify-time?
Perhaps using a dot in front of parse-int would help?
Answer Unfortunately I did not show namespaces in the question. Using a dot seemed to work but a better resolution was to :require the protocol's namespace :as i then call using: (i/parse-int the-obj month).
There should be no problem calling parse-int in stringify-time as long as you provide with the this as the first argument, which is exactly what you have done. But in your presented code, I expect the error message to be "unable to resolve month".
I'd suggest you double check your question first.

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)))

Calling Function In Separate Clojure Namespace

How do I call a function in one Clojure namespace, bene-csv.core from another namespace, bene-cmp.core? I've tried various flavors of :require and :use with no success.
Here is the function in bene-csv:
(defn ret-csv-data
"Returns a lazy sequence generated by parse-csv.
Uses open-csv-file which will return a nil, if
there is an exception in opening fnam.
parse-csv called on non-nil file, and that
data is returned."
[fnam]
(let [ csv-file (open-csv-file fnam)
csv-data (if-not (nil? csv-file)
(parse-csv csv-file)
nil)]
csv-data))
Here is the header of bene-cmp.core:
(ns bene-cmp.core
.
.
.
(:gen-class)
(:use [clojure.tools.cli])
(:require [clojure.string :as cstr])
(:use bene-csv.core)
(:use clojure-csv.core)
.
.
.
The calling function -- currently a stub -- in (bene-cmp.core)
defn fetch-csv-data
"This function merely loads the two csv file arguments."
[benetrak-csv-file gic-billing-file]
(let [benetrak-csv-data ret-csv-data]))
If I modify the header of bene-cmp.clj
(:require [bene-csv.core :as bcsv])
and change the call to ret-csv-data
(defn fetch-csv-data
"This function merely loads the two csv file arguments."
[benetrak-csv-file gic-billing-file]
(let [benetrak-csv-data bcsv/ret-csv-data]))
I get this error
Caused by: java.lang.RuntimeException: No such var: bcsv/ret-csv-data
So, how do I call fetch-csv-data?
Thank You.
You need to invoke the function, not just reference the var.
If you have this in your ns:
(:require [bene-csv.core :as bcsv])
Then you need to put parentheses around the namespace/alias qualified var to invoke it:
(let [benetrak-csv-data (bcsv/ret-csv-data arg)]
; stuff
)