Date: 27 November 2018
Version: 3.0.2
1 Introduction
hara.time is a unified framework for representating time on the JVM.
1.1 Installation
Add to project.clj
dependencies:
[hara/time "3.0.2"]
All functions are in the hara.time
namespace.
(use (quote hara.time))
2 General
calendar ^
creates a calendar to be used by the base date classes
(-> ^Calendar (calendar (Date. 0) (TimeZone/getTimeZone "GMT"))
(.getTime))
=> #inst "1970-01-01T00:00:00.000-00:00"
default-type ^
accesses the default type for datetime
(default-type) ;; getter
=> clojure.lang.PersistentArrayMap
(default-type Long) ;; setter
=> java.lang.Long
duration? ^
checks if an object implements the duration protocol
(t/duration? 0) => true
(t/duration? {:weeks 1})
=> true
epoch ^
returns the beginning of unix epoch
(t/epoch {:type Date})
=> #inst "1970-01-01T00:00:00.000-00:00"
instant? ^
checks if an object implements the instant protocol
(t/instant? 0) => true
(t/instant? (Date.)) => true
now ^
returns the current datetime
(t/now)
;; => #(instance? (t/default-type) %)
(t/now {:type Date})
=> #(instance? Date %)
(t/now {:type Calendar})
=> #(instance? Calendar %)
representation? ^
checks if an object implements the representation protocol
(t/representation? 0) => false
(t/representation? (common/calendar (Date. 0) (TimeZone/getTimeZone "GMT")))
=> true
time-meta ^
retrieves the meta-data for the time object
(t/time-meta TimeZone)
=> {:base :zone}
3 Timezone
default-timezone ^
accesses the default timezone as a string
(default-timezone) ;; getter
=> "Asia/Ho_Chi_Minh"
(default-timezone "GMT") ;; setter
=> "GMT"
get-timezone ^
returns the contained timezone if exists
(t/get-timezone 0) => nil
(t/get-timezone (common/calendar (Date. 0)
(TimeZone/getTimeZone "EST")))
=> "EST"
has-timezone? ^
checks if the instance contains a timezone
(t/has-timezone? 0) => false
(t/has-timezone? (common/calendar (Date. 0)
(TimeZone/getDefault)))
=> true
local-timezone ^
returns the current timezone as a string
(local-timezone)
=> "Asia/Ho_Chi_Minh"
with-timezone ^
returns the same instance in a different timezone
(t/with-timezone 0 "EST") => 0
4 Access
day ^
accesses the day representated by the instant
(t/day 0 {:timezone "GMT"}) => 1
(t/day (Date. 0) {:timezone "EST"}) => 31
day-of-week ^
accesses the day of week representated by the instant
(t/day-of-week 0 {:timezone "GMT"}) => 4
(t/day-of-week (Date. 0) {:timezone "EST"}) => 3
hour ^
accesses the hour representated by the instant
(t/hour 0 {:timezone "GMT"}) => 0
(t/hour (Date. 0) {:timezone "Asia/Kolkata"}) => 5
millisecond ^
accesses the millisecond representated by the instant
(t/millisecond 1010 {:timezone "GMT"}) => 10
minute ^
accesses the minute representated by the instant
(t/minute 0 {:timezone "GMT"}) => 0
(t/minute (Date. 0) {:timezone "Asia/Kolkata"}) => 30
month ^
accesses the month representated by the instant
(t/month 0 {:timezone "GMT"}) => 1
second ^
accesses the second representated by the instant
(t/second 1000 {:timezone "GMT"}) => 1
year ^
accesses the year representated by the instant
(t/year 0 {:timezone "GMT"}) => 1970
(t/year (Date. 0) {:timezone "EST"}) => 1969
5 Convert
coerce ^
adjust fields of a particular time
(t/coerce 0 {:type Date})
=> #inst "1970-01-01T00:00:00.000-00:00"
(t/coerce {:type clojure.lang.PersistentHashMap,
:timezone "PST", :long 915148800000,
:year 1999, :month 1, :day 1, :hour 0, :minute 0 :second 0, :millisecond 0}
{:type Date})
=> #inst "1999-01-01T08:00:00.000-00:00"
format ^
converts a date into a string
(f/format (Date. 0) "HH MM dd Z" {:timezone "GMT" :cached true})
=> "00 01 01 +0000"
(f/format (common/calendar (Date. 0)
(TimeZone/getTimeZone "GMT"))
"HH MM dd Z"
{})
=> "00 01 01 +0000"
(f/format (Timestamp. 0)
"HH MM dd Z"
{:timezone "PST"})
=> "16 12 31 -0800"
(f/format (Date. 0) "HH MM dd Z")
=> string?
from-long ^
creates an instant from a long
(-> (t/from-long 0 {:timezone "Asia/Kolkata"
:type Calendar})
(t/to-map))
=> {:type java.util.GregorianCalendar,
:timezone "Asia/Kolkata", :long 0
:year 1970, :month 1, :day 1,
:hour 5, :minute 30 :second 0, :millisecond 0}
from-map ^
creates an map from an instant
(t/from-map {:type java.util.GregorianCalendar,
:timezone "Asia/Kolkata", :long 0
:year 1970, :month 1, :day 1,
:hour 5, :minute 30 :second 0, :millisecond 0}
{:timezone "Asia/Kolkata"
:type Date})
=> #inst "1970-01-01T00:00:00.000-00:00"
parse ^
converts a string into a date
(f/parse "00 00 01 01 01 1989 +0000"
"ss mm HH dd MM yyyy Z"
{:type Date :timezone "GMT"})
=> #inst "1989-01-01T01:00:00.000-00:00"
(-> (f/parse "00 00 01 01 01 1989 -0800"
"ss mm HH dd MM yyyy Z"
{:type Calendar})
(map/to-map {:timezone "GMT"}
common/+default-keys+))
=> {:type java.util.GregorianCalendar,
:timezone "GMT",
:long 599648400000,
:year 1989,
:month 1, :day 1,
:hour 9, :minute 0,
:second 0, :millisecond 0}
(-> (f/parse "00 00 01 01 01 1989 +0000"
"ss mm HH dd MM yyyy Z"
{:type Timestamp})
(map/to-map {:timezone "Asia/Kolkata"}
common/+default-keys+))
=> {:type java.sql.Timestamp,
:timezone "Asia/Kolkata",
:long 599619600000,
:year 1989,
:month 1, :day 1,
:hour 6, :minute 30,
:second 0, :millisecond 0}
to-long ^
gets the long representation for the instant
(t/to-long #inst "1970-01-01T00:00:10.000-00:00")
=> 10000
to-map ^
creates an map from an instant
(-> (t/from-long 0 {:timezone "Asia/Kolkata"
:type Date})
(t/to-map {:timezone "GMT"} [:year :month :day]))
=> {:type java.util.Date, :timezone "GMT", :long 0,
:year 1970, :month 1, :day 1}
to-vector ^
converts an instant to an array representation
(to-vector 0 {:timezone "GMT"} :all)
=> [1970 1 1 0 0 0 0]
(to-vector (Date. 0) {:timezone "GMT"} :day)
=> [1970 1 1]
(to-vector (common/calendar (Date. 0)
(TimeZone/getTimeZone "EST"))
{}
[:month :day :year])
=> [12 31 1969]
(to-vector (common/calendar (Date. 0)
(TimeZone/getTimeZone "EST"))
{:timezone "GMT"}
[:month :day :year])
=> [1 1 1970]
6 Operation
adjust ^
adjust fields of a particular time
(t/adjust (Date. 0) {:year 2000 :second 10} {:timezone "GMT"})
=> #inst "2000-01-01T00:00:10.000-00:00"
after ^
compare dates, returns true if t1 is after t2, etc
(t/after 2
(Date. 1)
(common/calendar
(Date. 0)
(TimeZone/getTimeZone "GMT")))
=> true
before ^
compare dates, returns true if t1 is before t2, etc
(t/before 0
(Date. 1)
(common/calendar
(Date. 2)
(TimeZone/getTimeZone "GMT")))
=> true
earliest ^
returns the earliest date out of a range of inputs
(t/earliest (Date. 0) (Date. 1000) (Date. 20000))
=> #inst "1970-01-01T00:00:00.000-00:00"
equal ^
compares dates, retruns true if all inputs are the same
(t/equal 1
(Date. 1)
(common/calendar
(Date. 1)
(TimeZone/getTimeZone "GMT")))
=> true
latest ^
returns the latest date out of a range of inputs
(t/latest (Date. 0) (Date. 1000) (Date. 20000))
=> #inst "1970-01-01T00:00:20.000-00:00"
minus ^
substracts a duration from the time
(t/minus (Date. 0) {:years 1})
=> #inst "1969-01-01T00:00:00.000-00:00"
(-> (t/from-map {:type java.time.ZonedDateTime
:timezone "GMT",
:year 1970, :month 1, :day 1,
:hour 0, :minute 0, :second 0, :millisecond 0})
(t/minus {:years 10 :months 1 :weeks 4 :days 2})
(t/to-map {:timezone "GMT"}))
=> {:type java.time.ZonedDateTime, :timezone "GMT",
:long -320803200000
:year 1959, :month 11, :day 2,
:hour 0, :minute 0, :second 0, :millisecond 0}
plus ^
adds a duration to the time
(t/plus (Date. 0) {:weeks 2})
=> #inst "1970-01-15T00:00:00.000-00:00"
(t/plus (Date. 0) 1000)
=> #inst "1970-01-01T00:00:01.000-00:00"
(t/plus (java.util.Date. 0)
{:years 10 :months 1 :weeks 4 :days 2})
=> #inst "1980-03-02T00:00:00.000-00:00"
to-length ^
converts a object implementing IDuration to a long
(t/to-length {:days 1})
=> 86400000
truncate ^
truncates the time to a particular field
(t/truncate #inst "1989-12-28T12:34:00.000-00:00"
:hour {:timezone "GMT"})
=> #inst "1989-12-28T12:00:00.000-00:00"
(t/truncate #inst "1989-12-28T12:34:00.000-00:00"
:year {:timezone "GMT"})
=> #inst "1989-01-01T00:00:00.000-00:00"
7 Walkthrough
We can start off with the easiest call:
(t/now)
;;=> {:day 4, :hour 14, :timezone "Asia/Kolkata",
;; :long 1457081866919, :second 46, :month 3,
;; :type java.util.Date, :year 2016, :millisecond 919, :minute 27}
Note that now
returns a clojure map representing the current time. This is the default type, but we can also specify that we want a java.util.Date
object
(t/now {:type java.util.Date})
;;=> #inst "2016-03-04T08:57:46.919-00:00"
If on Java version 1.8, the use of :type
can set the returned object to be of type java.time.Instant
.
(t/now {:type java.time.Instant})
;;=> #<Instant 2016-03-04T08:58:11.678Z>
The default timezone can also be accessed and modified through default-timezone
(t/default-timezone)
;;=> "Asia/Kolkata"
The default type can be accessed and modified through default-type
:
(t/default-type)
;;=> clojure.lang.PersistentArrayMap
7.1 Supported Types
Currently hara.time
supports the following time representations
java.lang.Long
java.util.Date
java.util.Calendar
java.sql.Timestamp
java.time.Instant
java.time.Clock
org.joda.time.DateTime
(when required)
Changing the default-type
to Calendar will immediately affect the now
function to return a java.util.Calendar
object
(t/default-type java.util.Calendar)
(t/now)
;;=> #inst "2016-03-04T14:28:39.481+05:30"
(type (t/now))
;;=> java.util.GregorianCalendar
And again, a change of type will result in another representation
(t/default-type java.time.ZonedDateTime)
(t/now)
;;=> #<ZonedDateTime 2016-03-04T15:41:17.901+05:30[Asia/Kolkata]>
(type (t/now))
;;=> java.time.ZonedDateTime
7.2 Date as Data
hara.time
has two basic concepts of time:
- time as an absolute value (long)
- time as a representation in a given context (map)
These concepts can also be set as the default type, for example, we now set Long
as the default type:
(t/default-type Long)
(t/now)
;;=> 1457086323250
As well as a map as the default type:
(t/default-type clojure.lang.PersistentArrayMap)
(t/now)
;;=> {:day 4, :hour 14, :timezone "Asia/Kolkata",
;; :second 0, :day-of-week 6, :month 3,
;; :year 2016, :millisecond 611, :minute 33}
A specific timezone can be passed in and this is the same for all supported time objects:
(t/now {:timezone "GMT"})
;;=> {:day 4, :hour 9, :timezone "GMT",
;; :second 13, :day-of-week 6, :month 3,
;; :year 2016, :millisecond 585, :minute 4}
7.3 Extensiblity
Because the API is based on protocols, it is very easy to extend. For an example of how other date libraries can be added to the framework, please see hara.time.joda for how joda-time was added.