-
-
Save francoisdevlin/93c7e40cc95a486cfc0f to your computer and use it in GitHub Desktop.
Clojure Date
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns demo.clojure-date | |
(:import [java.util Calendar GregorianCalendar TimeZone]) | |
) | |
;1 - String to parse zulu time. Port from joda. | |
;2 - Reader Syntax | |
;3 - Timezone type. It's a sorted map. | |
(def millisecond 1) | |
(def seconds (* 1000 millisecond)) | |
(def minute (* 60 seconds)) | |
(def hour (* 60 minute)) | |
(def day (* 24 hour)) | |
(def year (* 365 day)) | |
(def leap-year (* 366 day)) | |
(def leap-year-zero 1968) | |
(def epoch-year-zero 1970) | |
(def time-regex | |
#"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}(Z|(\+|-)\d{2}:\d{2})") | |
(def normal-month-offset | |
(sorted-map | |
1 0, | |
2 31, | |
3 59, | |
4 90, | |
5 120, | |
6 151, | |
7 181, | |
8 212, | |
9 243, | |
10 273, | |
11 304, | |
12 334)) | |
(def leap-month-offset | |
(sorted-map | |
1 0, | |
2 31, | |
3 60, | |
4 91, | |
5 121, | |
6 152, | |
7 182, | |
8 213, | |
9 244, | |
10 274, | |
11 305, | |
12 335)) | |
(defn leap-year-count | |
"This is a convenience fn to figure out how many leap years have passed." | |
[y] | |
(int (/ (- y leap-year-zero) 4))) | |
(defn get-month-offset-map | |
[y] | |
(cond | |
(zero? (mod y 400)) leap-month-offset | |
(zero? (mod y 100)) normal-month-offset | |
(zero? (mod y 4)) leap-month-offset | |
true normal-month-offset)) | |
(defn zulu | |
([y mo d h mi s ms] (zulu y mo d h mi s ms 0)) | |
([y mo d h mi s ms offset] | |
(+ | |
(* (- y epoch-year-zero) year) | |
(* (leap-year-count y) day) | |
(* ((cond | |
(zero? (mod y 400)) leap-month-offset | |
(zero? (mod y 100)) normal-month-offset | |
(zero? (mod y 4)) leap-month-offset | |
true normal-month-offset) mo) day) | |
(* (dec d) day) | |
(* h hour) | |
(* mi minute) | |
(* s seconds) | |
(* ms millisecond) | |
offset))) | |
(defn parse-zulu [input-s] | |
(let [[y mo d h mi s ms tzh tzm] (map #(Integer/parseInt %) | |
(.split input-s "[-:TZ\\.\\+]")) | |
offset (if (and tzh tzm) | |
(({\+ -,\- +} (.charAt input-s 23));Semantics are backwards... | |
(+ | |
(* tzh hour) | |
(* tzm minute))) 0)] | |
(zulu y mo d h mi s ms offset))) | |
(defn long->map | |
[epoch] | |
(let [remaining epoch | |
delta-years (int (/ epoch year)) | |
years (+ delta-years 1970) | |
remaining (- epoch (* delta-years year)) | |
leap-days (leap-year-count years) | |
years (if (< remaining (* leap-days day)) | |
(dec years) | |
years) | |
remaining (- remaining (* leap-days day)) | |
remaining (if (neg? remaining) | |
(+ year remaining) | |
remaining) | |
month-offset (get-month-offset-map years) | |
months (first | |
(last | |
(take-while (fn [[k v]] (< (* v day) remaining)) | |
month-offset))) | |
months (if months months 1) | |
remaining (- remaining (* (month-offset months) day)) | |
day-of-month (int (/ remaining day)) | |
remaining (- remaining (* day day-of-month)) | |
] | |
{:year years | |
:month months | |
:day day-of-month | |
:ms remaining})) | |
(defn long->map | |
[t] | |
(let [base-cal (doto | |
(GregorianCalendar. (TimeZone/getTimeZone "UTC")) | |
(.setTimeInMillis t))] | |
{:year (.get base-cal Calendar/YEAR) | |
:month (inc (.get base-cal Calendar/MONTH)) | |
:day (.get base-cal Calendar/DAY_OF_MONTH) | |
:hour (.get base-cal Calendar/HOUR_OF_DAY) | |
:minute (.get base-cal Calendar/MINUTE) | |
:second (.get base-cal Calendar/SECOND) | |
:millis (.get base-cal Calendar/MILLISECOND) | |
;:offset (.getRawOffset base-cal) | |
})) | |
(defprotocol Dateable | |
(clj-date* [t])) | |
(deftype CljDate | |
[epoch tz-offset] | |
Object | |
(toString [this] | |
(str epoch)) | |
;clojure.lang.IMeta | |
;(meta [_] _meta) | |
java.lang.Comparable | |
(compareTo [this o] | |
(compare (.epoch this) (.epoch o))) | |
Dateable | |
(clj-date* [this] this) | |
) | |
(extend java.lang.String | |
Dateable | |
{:clj-date* #(CljDate. (parse-zulu %) 0)}) | |
(extend clojure.lang.IPersistentMap | |
Dateable | |
{:clj-date* (fn [{y :year | |
mo :month | |
d :day | |
h :hour | |
mi :minute | |
s :second | |
ms :millis | |
os :offset}] | |
(CljDate. (zulu y mo d h mi s ms os) os))}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment