Formatting for dates, times, and ranges. | (ns metabase.util.formatting.date (:require [metabase.util.formatting.constants :as constants] [metabase.util.formatting.internal.date-builder :as builder] [metabase.util.formatting.internal.date-formatters :as formatters] [metabase.util.formatting.internal.date-options :as options] [metabase.util.time :as u.time])) |
The range separator is a Unicode en-dash, not an ASCII hyphen. | (def range-separator " \u2013 ") |
-------------------------------------------- Parameter Formatting --------------------------------------------- | (def ^:private parameter-formatters
{:month (builder/->formatter [:year "-" :month-dd])
:quarter (builder/->formatter ["Q" :quarter "-" :year])
:day formatters/big-endian-day}) |
Returns a formatting date string for a datetime used as a parameter to a Card. | (defn ^:export format-for-parameter
[value options]
(let [options (options/prepare-options options)
t (u.time/coerce-to-timestamp value options)]
(if (not (u.time/valid? t))
;; Fall back to a basic string rendering if we couldn't parse it.
(str value)
(if-let [fmt (parameter-formatters (:unit options))]
;; A few units have special formats.
(fmt t)
;; Otherwise, render as a day or day range.
(let [[start end] (u.time/to-range t options)]
(if (u.time/same-day? start end)
(formatters/big-endian-day start)
(str (formatters/big-endian-day start) "~" (formatters/big-endian-day end)))))))) |
------------------------------------------------ Format Range ------------------------------------------------- | (defn- format-range-with-unit-inner [[start end] options]
(cond
;; Uncondensed, or in different years: January 1, 2018 - January 23, 2019
(or (not (constants/condense-ranges? options))
(not (u.time/same-year? start end)))
(let [fmt (formatters/month-day-year options)]
(str (fmt start) range-separator (fmt end)))
;; Condensed, but different months: January 1 - February 2, 2018
(not (u.time/same-month? start end))
(str ((formatters/month-day options) start)
range-separator
((formatters/month-day-year options) end))
;; Condensed, and same month: January 1 - 14, 2018
:else (str ((formatters/month-day options) start)
range-separator
((builder/->formatter [:day-of-month-d ", " :year]) end)))) |
Returns a string with this datetime formatted as a range, rounded to the given | (defn ^:export format-range-with-unit
[value options]
(let [options (options/prepare-options options)
t (u.time/coerce-to-timestamp value options)]
(if (u.time/valid? t)
(format-range-with-unit-inner (u.time/to-range t options) options)
;; Best-effort fallback if we failed to parse - .toString the input.
(str value)))) |
Returns a string with this datetime formatted as a single value, rounded to the given ---------------------------------------------- Format Single Date ----------------------------------------------- | (defn ^:export format-datetime-with-unit
[value options]
(let [{:keys [is-exclude no-range type unit]
:as options} (options/prepare-options options)
t (u.time/coerce-to-timestamp value options)]
(cond
is-exclude (case unit
:hour-of-day (formatters/hour-only t)
:day-of-week (formatters/weekday t)
(throw (ex-info "is-exclude option is only compatible with hour-of-day and day-of-week units"
{:options options})))
;; Weeks in tooltips and cells get formatted specially.
(and (= unit :week) (#{"tooltip" "cell"} type) (not no-range))
(format-range-with-unit value options)
:else ((formatters/options->formatter options) t)))) |
Coerce date and format as big-endian-day string. | (defn ^:export date->iso-string [d] (formatters/big-endian-day (u.time/coerce-to-timestamp d))) |
Coerce datetime and format as iso string. | (defn ^:export datetime->iso-string [dt] (formatters/->iso (u.time/coerce-to-timestamp dt))) |