mirror of
https://github.com/penpot/penpot.git
synced 2025-02-19 05:15:44 -05:00
234 lines
6.1 KiB
Clojure
234 lines
6.1 KiB
Clojure
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
;;
|
|
;; Copyright (c) KALEIDOS INC
|
|
|
|
(ns app.util.time
|
|
(:require
|
|
["date-fns/formatDistanceToNowStrict" :default dateFnsFormatDistanceToNowStrict]
|
|
["date-fns/locale/ar-SA" :default dateFnsLocalesAr]
|
|
["date-fns/locale/ca" :default dateFnsLocalesCa]
|
|
["date-fns/locale/de" :default dateFnsLocalesDe]
|
|
["date-fns/locale/el" :default dateFnsLocalesEl]
|
|
["date-fns/locale/en-US" :default dateFnsLocalesEnUs]
|
|
["date-fns/locale/es" :default dateFnsLocalesEs]
|
|
["date-fns/locale/fa-IR" :default dateFnsLocalesFa]
|
|
["date-fns/locale/fr" :default dateFnsLocalesFr]
|
|
["date-fns/locale/he" :default dateFnsLocalesHe]
|
|
["date-fns/locale/pt-BR" :default dateFnsLocalesPtBr]
|
|
["date-fns/locale/ro" :default dateFnsLocalesRo]
|
|
["date-fns/locale/ru" :default dateFnsLocalesRu]
|
|
["date-fns/locale/tr" :default dateFnsLocalesTr]
|
|
["date-fns/locale/zh-CN" :default dateFnsLocalesZhCn]
|
|
["luxon" :as lxn]
|
|
[app.util.object :as obj]
|
|
[cuerdas.core :as str]))
|
|
|
|
(def DateTime lxn/DateTime)
|
|
(def Duration lxn/Duration)
|
|
|
|
(defprotocol ITimeMath
|
|
(plus [_ o])
|
|
(minus [_ o]))
|
|
|
|
(defprotocol ITimeFormat
|
|
(format [_ fmt]))
|
|
|
|
(defn duration?
|
|
[o]
|
|
(instance? Duration o))
|
|
|
|
(defn datetime?
|
|
[o]
|
|
(instance? DateTime o))
|
|
|
|
(defn duration
|
|
[o]
|
|
(cond
|
|
(integer? o) (.fromMillis Duration o)
|
|
(duration? o) o
|
|
(string? o) (.fromISO Duration o)
|
|
(map? o) (.fromObject Duration (clj->js o))
|
|
:else (throw (js/Error. "unexpected arguments"))))
|
|
|
|
(defn datetime
|
|
([s] (datetime s nil))
|
|
([s {:keys [zone force-zone] :or {zone "local" force-zone false}}]
|
|
(cond
|
|
(integer? s)
|
|
(.fromMillis ^js DateTime s #js {:zone zone :setZone force-zone})
|
|
|
|
(map? s)
|
|
(.fromObject ^js DateTime (-> (clj->js s)
|
|
(obj/set! "zone" zone)
|
|
(obj/set! "setZone" force-zone)))
|
|
|
|
:else
|
|
(throw (js/Error. "invalid arguments")))))
|
|
|
|
(defn epoch->datetime
|
|
([seconds] (epoch->datetime seconds nil))
|
|
([seconds {:keys [zone force-zone] :or {zone "local" force-zone false}}]
|
|
(.fromSeconds ^js DateTime seconds #js {:zone zone :setZone force-zone})))
|
|
|
|
(defn iso->datetime
|
|
"A faster option for transit date parsing."
|
|
[s]
|
|
(.fromISO ^js DateTime s #js {:zone "local"}))
|
|
|
|
(defn parse-datetime
|
|
([s] (parse-datetime s :iso nil))
|
|
([s fmt] (parse-datetime s fmt nil))
|
|
([s fmt {:keys [zone force-zone] :or {zone "local" force-zone false}}]
|
|
(if (string? fmt)
|
|
(.fromFormat ^js DateTime s fmt #js {:zone zone :setZone force-zone})
|
|
(case fmt
|
|
:iso (.fromISO ^js DateTime s #js {:zone zone :setZone force-zone})
|
|
:rfc2822 (.fromRFC2822 ^js DateTime s #js {:zone zone :setZone force-zone})
|
|
:http (.fromHTTP ^js DateTime s #js {:zone zone :setZone force-zone})))))
|
|
|
|
(defn now
|
|
[]
|
|
(.local ^js DateTime))
|
|
|
|
(defn utc-now
|
|
[]
|
|
(.utc ^js DateTime))
|
|
|
|
(defn ->utc
|
|
[dt]
|
|
(.toUTC ^js dt))
|
|
|
|
(defn diff
|
|
[dt1 dt2]
|
|
(.diff ^js dt1 dt2))
|
|
|
|
(extend-protocol IEquiv
|
|
DateTime
|
|
(-equiv [it other]
|
|
(if other
|
|
(.equals it other)
|
|
false))
|
|
|
|
Duration
|
|
(-equiv [it other]
|
|
(if other
|
|
(.equals it other)
|
|
false)))
|
|
|
|
(extend-protocol Inst
|
|
DateTime
|
|
(inst-ms* [inst] (.toMillis ^js inst))
|
|
|
|
Duration
|
|
(inst-ms* [inst] (.toMillis ^js inst)))
|
|
|
|
(extend-protocol IComparable
|
|
DateTime
|
|
(-compare [it other]
|
|
(if ^boolean (.equals it other)
|
|
0
|
|
(if (< (inst-ms it) (inst-ms other)) -1 1)))
|
|
|
|
Duration
|
|
(-compare [it other]
|
|
(if ^boolean (.equals it other)
|
|
0
|
|
(if (< (inst-ms it) (inst-ms other)) -1 1))))
|
|
|
|
(extend-protocol ITimeMath
|
|
DateTime
|
|
(plus [it o]
|
|
(if (map? o)
|
|
(.plus ^js it (clj->js o))
|
|
(.plus ^js it o)))
|
|
|
|
(minus [it o]
|
|
(if (map? o)
|
|
(.minus ^js it (clj->js o))
|
|
(.minus ^js it o)))
|
|
|
|
Duration
|
|
(plus [it o]
|
|
(if (map? o)
|
|
(.plus ^js it (clj->js o))
|
|
(.plus ^js it o)))
|
|
|
|
(minus [it o]
|
|
(if (map? o)
|
|
(.minus ^js it (clj->js o))
|
|
(.minus ^js it o))))
|
|
|
|
(extend-protocol IPrintWithWriter
|
|
DateTime
|
|
(-pr-writer [p writer _]
|
|
(-write writer (str/fmt "#stks/datetime \"%s\"" (format p :iso))))
|
|
|
|
Duration
|
|
(-pr-writer [p writer _]
|
|
(-write writer (str/fmt "#stks/duration \"%s\"" (format p :iso)))))
|
|
|
|
(defn- resolve-format
|
|
[v]
|
|
(case v
|
|
:time-24-simple (.-TIME_24_SIMPLE ^js DateTime)
|
|
:datetime-short (.-DATETIME_SHORT ^js DateTime)
|
|
:datetime-med (.-DATETIME_MED ^js DateTime)
|
|
:datetime-full (.-DATETIME_FULL ^js DateTime)
|
|
:date-full (.-DATE_FULL ^js DateTime)
|
|
:date-med-with-weekday (.-DATE_MED_WITH_WEEKDAY ^js DateTime)
|
|
v))
|
|
|
|
(defn- format-datetime
|
|
[dt fmt]
|
|
(case fmt
|
|
:iso (.toISO ^js dt)
|
|
:rfc2822 (.toRFC2822 ^js dt)
|
|
:http (.toHTTP ^js dt)
|
|
:json (.toJSON ^js dt)
|
|
:date (.toJSDate ^js dt)
|
|
:epoch (js/Math.floor (.toSeconds ^js dt))
|
|
:millis (.toMillis ^js dt)
|
|
(let [f (resolve-format fmt)]
|
|
(if (string? f)
|
|
(.toFormat ^js dt f)
|
|
(.toLocaleString ^js dt f)))))
|
|
|
|
(extend-protocol ITimeFormat
|
|
DateTime
|
|
(format [it fmt]
|
|
(format-datetime it fmt))
|
|
|
|
Duration
|
|
(format [it fmt]
|
|
(case fmt
|
|
:iso (.toISO it)
|
|
:json (.toJSON it)
|
|
(.toFormat ^js it fmt))))
|
|
|
|
(def ^:private locales
|
|
#js {:en dateFnsLocalesEnUs
|
|
:ar dateFnsLocalesAr
|
|
:he dateFnsLocalesHe
|
|
:fr dateFnsLocalesFr
|
|
:tr dateFnsLocalesTr
|
|
:es dateFnsLocalesEs
|
|
:ca dateFnsLocalesCa
|
|
:el dateFnsLocalesEl
|
|
:ru dateFnsLocalesRu
|
|
:ro dateFnsLocalesRo
|
|
:de dateFnsLocalesDe
|
|
:fa dateFnsLocalesFa
|
|
:pt_br dateFnsLocalesPtBr
|
|
:zh_cn dateFnsLocalesZhCn})
|
|
|
|
(defn timeago
|
|
([v] (timeago v nil))
|
|
([v {:keys [locale] :or {locale "en"}}]
|
|
(when v
|
|
(let [v (if (datetime? v) (format v :date) v)]
|
|
(->> #js {:includeSeconds true
|
|
:addSuffix true
|
|
:locale (obj/get locales locale)}
|
|
(dateFnsFormatDistanceToNowStrict v))))))
|