8

I have looked at the following question: How to add days to current date in clojure.

However I am very new to Clojure and I am getting stuck on the following scenario I am getting the timestamp in string format. So I am parsing it using the following:

(.parse (java.text.SimpleDateFormat. "yyyy-MM-dd") date)

Which gives me a result that looks like this:

#inst "2015-02-13T00:20:00.000-00:00"

How do I add say 90 days to this and then convert it back to string format? I tried this based on the above link:

(java.util.Date. (+ (* 7 86400 1000) 
                    (.parse (java.text.SimpleDateFormat. "yyyy-MM-dd") date)))

Which gave me the following error:

ClassCastException java.util.Date cannot be cast to java.lang.Number  clojure.lang.Numbers.add
Stéphane Bruckert
  • 21,706
  • 14
  • 92
  • 130
newbie
  • 391
  • 1
  • 6
  • 20
  • It's better to use [Joda Time](http://www.joda.org/joda-time/) instead of the default Java date/time libraries. There is a Clojure wrapper available as well, [clj-time](https://github.com/clj-time/clj-time). See this [IBM Developer Works article](http://www.ibm.com/developerworks/java/library/j-jodatime/index.html#N100BA) for details on why Joda Time is the better option. – raju-bitter Feb 06 '15 at 10:16

4 Answers4

6

parse returns a java.util.Date, the error you are seeing is telling you that you can't cast a Date to a Number. You can use getTime to get the milliseconds of a Date:

(java.util.Date. (+ (* 7 86400 1000)
                 (.getTime (.parse (java.text.SimpleDateFormat. "yyyy-MM-dd") date))))

This potentially adds 7 days to the date. If you want to potentially add 90 days you need to replace the 7 with 90, like this: (* 90 86400 1000).

You can also use java.util.Calendar:

(let [cal (Calendar/getInstance)
      d (.parse (java.text.SimpleDateFormat. "yyyy-MM-dd") date)]
  (doto cal
    (.setTime d)
    (.add Calendar/DATE 90)
    (.getTime)))

Or better yet, clj-time:

(require '[clj-time.core :as t])
(require '[clj-time.format :as f])

(t/plus (f/parse (f/formatters :year-month-day) date)
        (t/days 90))
Scott
  • 17,127
  • 5
  • 53
  • 64
Rodrigo Taboada
  • 2,727
  • 4
  • 24
  • 27
  • Ohh sorry about the 7 and 90 days thing. That was a typo. – newbie Feb 06 '15 at 04:02
  • 4
    "This adds 7 days to the date" --- if only every of those is exactly `86400` seconds, which is not always the case – zerkms Feb 06 '15 at 04:25
  • 1
    Yes +1 for clj-time. I had to do something similar a while back and initially did it using native java methods. It worked fine, but had a lot of messy code. Re-wrote it when I found out about clj-time and now its much smaller and easier to understand. Dates and Times has always been a PITA in java – Tim X Feb 08 '15 at 00:26
4

I wouldn’t recommend using the legacy date and time API in new code if you can avoid it.

Java 8 brought a new API for dates with which you can express this problem elegantly:

(let [date-format java.time.format.DateTimeFormatter/ISO_LOCAL_DATE]
  (.. (java.time.LocalDate/parse "2015-02-13" date-format)
      (plusDays 90)
      (format date-format)))

Or even, taking all shortcuts:

(-> (java.time.LocalDate/parse "2015-02-13") (.plusDays 90) str)
glts
  • 21,808
  • 12
  • 73
  • 94
3

clj-time has from-now and ago:

(require '[clj-time.core :refer [days from-now]])

(-> 90 days from-now)

=> #object[org.joda.time.DateTime 0x4d8bcee3 "2017-01-11T16:03:40.067Z"]

(require '[clj-time.core :refer [hours ago]])

(-> 7 hours ago)

=> #object[org.joda.time.DateTime 0x3eef2142 "2016-10-13T09:19:01.246Z"]

Available PeriodType definitions: years, months, weeks, days, hours, minutes, seconds.


The resulting Joda DateTime objects can easily be manipulated, for instance to a unix epoch in milliseconds:

(require '[clj-time.core :refer [days from-now]])
(require '[clj-time.coerce :as coerce])

(coerce/to-long (-> 90 days from-now))

=> 1484150620067

Stéphane Bruckert
  • 21,706
  • 14
  • 92
  • 130
0

This solution returns a java.util.Date:

(defn add-days-to-instant [num-days ^java.util.Date d]
  (.getTime (let [cal (Calendar/getInstance)]
              (doto cal
                (.setTime d)
                (.add Calendar/DATE num-days)))))
Chris Murphy
  • 6,411
  • 1
  • 24
  • 42