time & date util library for Clojure(Script)
- both for Clojure & ClojureScript
- Lightweight, use native inst (java.util.Date or js/Date), prevent date converting
- Extend Date in order to support `:first-day-of-week` & `:time-zone`
- Good performance
- Lightweight cronjob supports, co-working with core.async
(:require [time.core :as t])
;; current instant
(t/date)
;;=> #inst "2017-07-14T03:20:48.896-00:00"
(t/date (t/now-ms))
;;=> #inst "2017-07-14T03:23:43.276-00:00"
;; copy instant
(def d (t/date))
(t/date d)
;;=> #inst "2017-07-14T03:24:43.266-00:00"
;; copy and set time-zone
(t/date d :time-zone (t/time-zone "GMT+00:00"))
;;=> #inst "2017-07-14T03:24:43.266-00:00"
(t/date d :time-zone (t/time-zone "GMT+08:00"))
;;=> #inst "2017-07-14T03:24:43.266-00:00"
;; format use default time zone
(t/format (t/date) "yyyyMMdd HH:mm:ss")
;;=> "20170714 11:27:56"
(def zero-zone (t/time-zone "GMT+00:00"))
(def d (t/date (t/date) :time-zone zero-zone))
(t/format d "yyyyMMdd HH:mm:ss") ; format with zero zone
;;=> "20170714 07:45:50"
(-> d
(t/date :time-zone (t/time-zone "GMT+08:00"))
(t/format "yyyyMMdd HH:mm:ss"))
;;=> "20170714 15:45:50"
(def zero-zone (t/time-zone "GMT00:00"))
(t/parse "20170704" (t/formatter zero-zone "yyyyMMdd"))
;;=> #inst "2017-07-04T00:00:00.000-00:00"
;; use default zone
(t/parse "20170704" "yyyyMMdd")
;;=> #inst "2017-07-03T16:00:00.000-00:00"
;; more complicated
(t/parse "20170704T03:33:27.333" "yyyyMMdd'T'HH:mm:ss.SSS")
;;=> #inst "2017-07-03T19:33:27.333-00:00"
;; yyyy-MM-dd => yyyy-MM-01
(t/floor (t/date) [1 :month])
;;=> #inst "2017-06-30T16:00:00.000-00:00"
;; two month as period
(t/floor (t/date) [2 :month])
;;=> #inst "2017-05-31T16:00:00.000-00:00"
;; one week as period & sunday is first day (default)
(t/floor (t/date) [1 :week])
;;=> #inst "2017-07-08T16:00:00.000-00:00"
;; one week as period & monday is first day
(t/floor
(t/date (t/now-ms) :first-day-of-week :monday)
[1 :week])
;;=> #inst "2017-07-09T16:00:00.000-00:00"
;; sunday as first day of week
(def week-seq
(t/floor-seq :week (t/date)))
(take 2 week-seq)
;;=> (#inst "2017-07-08T16:00:00.000-00:00" #inst "2017-07-15T16:00:00.000-00:00")
;; `[1 :week]` = `:week`
(def week-seq
(t/floor-seq [1 :week] (t/date)))
;; use zero-zone, monday as first day, reverse traversal
;; last 15 week
(def week-seq2
(->> (t/date (t/now-ms)
:first-day-of-week :monday
:time-zone zero-zone)
(t/floor-seq [-1 :week])
(take 15)))
(take 2 week-seq2)
;;=> (#inst "2017-07-10T00:00:00.000-00:00" #inst "2017-07-03T00:00:00.000-00:00")
;; other periods: `:year`, `:month`, `:day`, `:hour`, `:minute`, `:second`
;; all periods support pair format exclude week, eg. `[1 :year]` = `:year`
(def quarter-seq
(t/floor-seq
[15 :minute]
(t/date (t/now-ms)
:time-zone zero-zone)))
(take 2 quarter-seq)
;;=> (#inst "2017-07-14T03:30:00.000-00:00" #inst "2017-07-14T03:45:00.000-00:00")
plus is a low level api, floor-seq implements vai `plus` & `floor`, here is an example of reverse traversal with `[-2 :week]` period:
(def double-week-seq
(iterate #(plus % [-2 :week]) (t/floor (t/date) :week)))
(take 2 double-week-seq)
;;=> (#inst "2017-07-08T16:00:00.000-00:00" #inst "2017-06-24T16:00:00.000-00:00")
(:require [time.chime :as chime]
[clojure.core.async :as a :refer [<! go-loop]])
(let [ch (->> (t/date)
(t/floor-seq :minute)
(chime/chime-ch))]
(go-loop []
;; println at every begining of minutes
(when-let [p (<! ch)]
(println p (t/date))
(recur))))
(with-chime [ch (->> (t/date)
(t/floor-seq :minute)
(chime/chime-ch))]
(println (t/date)))