mirror of
https://github.com/penpot/penpot.git
synced 2025-05-20 08:26:10 +02:00
231 lines
5.8 KiB
Clojure
231 lines
5.8 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
|
|
["./time_impl.js" :as impl]
|
|
[app.common.data.macros :as dm]
|
|
[app.common.time :as common-time]
|
|
[app.util.object :as obj]
|
|
[cuerdas.core :as str]))
|
|
|
|
(dm/export common-time/DateTime)
|
|
(dm/export common-time/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
|
|
(number? 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})))))
|
|
|
|
(dm/export common-time/now)
|
|
|
|
(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 "#app/instant \"%s\"" (format p :iso))))
|
|
|
|
Duration
|
|
(-pr-writer [p writer _]
|
|
(-write writer (str/fmt "#app/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))))
|
|
|
|
(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 impl/locales locale)}
|
|
(impl/format-distance-to-now v))))))
|
|
|
|
(defn format-date-locale
|
|
([v] (format-date-locale v nil))
|
|
([v {:keys [locale] :or {locale "en"}}]
|
|
(when v
|
|
(let [v (if (datetime? v) (format v :date) v)
|
|
locale (obj/get impl/locales locale)
|
|
f (.date (.-formatLong ^js locale) v)]
|
|
(->> #js {:locale locale}
|
|
(impl/format v f))))))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; Measurement Helpers
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(defn tpoint
|
|
"Create a measurement checkpoint for time measurement of potentially
|
|
asynchronous flow."
|
|
[]
|
|
(let [p1 (.now js/performance)]
|
|
#(duration (- (.now js/performance) p1))))
|
|
|
|
(defn tpoint-ms
|
|
"Create a measurement checkpoint for time measurement of potentially
|
|
asynchronous flow."
|
|
[]
|
|
(let [p1 (.now js/performance)]
|
|
#(- (.now js/performance) p1)))
|