Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How would Time Ago function implementation look like in Clojure?

I mean function, when given time returns smallest time unit ago. E.g

  • "5 minutes ago"
  • "30 seconds ago"
  • "just now"
like image 725
ma2s Avatar asked Sep 10 '15 20:09

ma2s


3 Answers

One possible implementation might look like this:

Note, I've used clj-time/clj-time · GitHub library.

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

(defn time-ago [time]
  (let [units [{:name "second" :limit 60 :in-second 1}
               {:name "minute" :limit 3600 :in-second 60}
               {:name "hour" :limit 86400 :in-second 3600}
               {:name "day" :limit 604800 :in-second 86400}
               {:name "week" :limit 2629743 :in-second 604800}
               {:name "month" :limit 31556926 :in-second 2629743}
               {:name "year" :limit Long/MAX_VALUE :in-second 31556926}]
        diff (t/in-seconds (t/interval time (t/now)))]
    (if (< diff 5)
      "just now"
      (let [unit (first (drop-while #(or (>= diff (:limit %))
                                         (not (:limit %))) 
                                    units))]
        (-> (/ diff (:in-second unit))
            Math/floor
            int
            (#(str % " " (:name unit) (when (> % 1) "s") " ago")))))))

Example usage:

(time-ago (t/minus (t/now) (t/days 400)))
=> "1 year ago"

(time-ago (t/minus (t/now) (t/days 15)))
=> "2 weeks ago"

(time-ago (t/minus (t/now) (t/seconds 45))) 
=> "45 seconds ago"

(time-ago (t/minus (t/now) (t/seconds 1)))
=> "just now"
like image 68
ma2s Avatar answered Sep 19 '22 12:09

ma2s


If you are using Clojure on the JVM, consider using the PrettyTime library. Using that library for implementing "time ago" in Java was suggested here.

To use PrettyTime library from Clojure, first add the following to the :dependencies vector in project.clj:

[org.ocpsoft.prettytime/prettytime "3.2.7.Final"]

Then you can use Java interop directly. One quirk I found is that the cut-off between "moments ago" and other outputs is at 1 minute by default. I added a line to change that to one second. This library appears to support several languages, which is a plus. By default it prints "moments ago" instead of "just now". It would require some effort to deal with in case that is really important.

(import 'org.ocpsoft.prettytime.PrettyTime
       'org.ocpsoft.prettytime.units.JustNow
       'java.util.Date)

(defn time-ago [date]
  (let [pretty-time (PrettyTime.)]
    (.. pretty-time (getUnit JustNow) (setMaxQuantity 1000))
    (.format pretty-time date)))

(let [now (System/currentTimeMillis)]
  (doseq [offset [200, (* 30 1000), (* 5 60 1000)]]
     (println (time-ago (Date. (- now offset))))))

;; moments ago
;; 30 seconds ago
;; 5 minutes ago
like image 40
ez121sl Avatar answered Sep 17 '22 12:09

ez121sl


It only supports minutes, hours & days but if that's sufficient you may also want to look at goog.date.relative:

https://github.com/google/closure-library/blob/master/closure/goog/date/relative.js#L87

like image 33
Martin Klepsch Avatar answered Sep 21 '22 12:09

Martin Klepsch