The formatting strings are not standardized. Rather than wrangling with strings, this library defines a data structure for describing the format of date/time strings. A format is represented as a (JS or CLJS) list of keyword or string date fragments ( Examples:
- | (ns metabase.util.formatting.internal.date-builder
(:require
[clojure.string :as str])
#?(:clj (:import
java.time.format.DateTimeFormatter))) |
This is the complete set of keys the formats can contain, mapped to the platform-specific magic string expected by Moment.js or java.time.format.DateTimeFormatter. Many are the same, but not all. | (def format-strings
{:year #?(:cljs "YYYY" :clj "yyyy") ; 2022
:quarter "Q" ; 2 ("Q2" etc. is added by higher level formatting)
:month-full "MMMM" ; April
:month-short "MMM" ; Apr
:month-dd "MM" ; 04
:month-d "M" ; 4
:day-of-month-d #?(:cljs "D" :clj "d") ; 6
:day-of-month-dd #?(:cljs "DD" :clj "dd") ; 06
:day-of-week-full #?(:cljs "dddd" :clj "EEEE") ; Friday
:day-of-week-short #?(:cljs "ddd" :clj "EEE") ; Fri
:hour-24-dd "HH" ; 17, 05
:hour-24-d "H" ; 17, 5
:hour-12-dd "hh" ; 05
:hour-12-d "h" ; 5
:am-pm #?(:cljs "A" :clj "a") ; AM
:minute-d "m" ; 7, 39
:minute-dd "mm" ; 07, 39
:second-dd "ss" ; 08, 45
:millisecond-ddd "SSS" ; 001, 423
:day-of-year #?(:cljs "DDD" :clj "D") ; 235
:week-of-year #?(:cljs "wo" :clj "w")}) ; 34th in CLJS, 34 in CLJ. No ordinal numbers in Java. |
(defn- format-string-literal [lit]
#?(:cljs (str "[" lit "]")
:clj (str "'" (str/replace lit "'" "''") "'"))) | |
Given a data structure describing the date format, as given in [[format-strings]], return a function that takes a date object and formats it. | (defn ->formatter
[format-list]
(let [js->clj #?(:cljs js->clj :clj identity)
parts (for [fmt (js->clj format-list)]
(cond
(keyword? fmt) (get format-strings fmt)
(= fmt ":") (format-string-literal ":")
(str/starts-with? fmt ":") (-> fmt (subs 1) keyword format-strings)
(string? fmt) (format-string-literal fmt)
:else (throw (ex-info "Unknown element of date format"
{:bad-element fmt
:format format-list}))))
fmt-str (apply str parts)]
#?(:cljs #(.format % fmt-str)
:clj (let [formatter (DateTimeFormatter/ofPattern fmt-str)]
#(.format formatter %))))) |