Skip to content
Snippets Groups Projects
  • Braden Shepherdson's avatar
    335d161f
    [metabase-lib] Port date and time parsing and formatting to CLJC (#27551) · 335d161f
    Braden Shepherdson authored
    This adds a cross-platform date/time formatting library in CLJC, with
    (nearly) identical output in both JVM and JS environments.
    
    The only known difference is week numbers.
    
    CLJS (through Moment.js) has ordinal numbers, and renders the week
    number as "34th". Neither the JVM nor Clojure has a handy library for
    this (I'm sure it's out there somewhere, but it seems like a silly
    dep to add) so it renders week numbers as simply "34".
    
    Both platforms have date formatters that use pattern strings (eg.
    `"YYYY-MM-dd"`) to turn date/time objects into strings. There's a strong
    resemblance in how these work and what letters stand for what parts of
    the date and time, but they are far from identical.
    
    Rather than try to hackily convert one set of strings to another with
    regexes or other manipulations, this PR defines a set of names for
    fragments of dates (eg. `:year`, `:day-of-week-full`, `:hour-24-dd`)
    and includes functions to transform a list of these keys into a
    platform-specific format function.
    
    This is portable and transparent, and can be written in Clojure or
    JS code:
    
    ```clj
    [:year "-" :month-dd "-" :day-of-month-dd]   ; 2022-04-08
    [:month-full " " :day-of-month-d ", " :year] ; April 8, 2022
    [:hour-12-dd ":" :minute-dd " " :am-pm]      ; 7:52 AM
    ```
    
    ```js
    [":year", "-", ":month-dd", "-", ":day-of-month-dd"]   ; 2022-04-08
    [":month-full", " ", ":day-of-month-d", ", ", ":year"] ; April 8, 2022
    [":hour-12-dd", ":", ":minute-dd", " ", ":am-pm"]      ; 7:52 AM
    ```
    
    Note that the original code allowed an unrecognized `:date-style` string
    to be used directly as the formatting string. With the move to
    formatting data structures that no longer works. Instead there is a
    fixed map of format strings to the above data structures, that contains
    all the currently used `:date-style` inputs.
    
    If some caller needs a new format someday, we can either: (a) add the
    style to the map; or (b) pass the data structure form directly to the
    `:date-format` option, which if provided is used as the format.
    
    It's tempting to go to all the call sites and replace these `:date-style`
    strings with the new format structures. However, the strings are still
    embedded in the `:visualization_settings` in user appDBs, so we still
    need to recognize them.
    
    Most of the existing functions in the TS library have the same API.
    
    The set of allowed `:date-style` and `:time-style` values is turned into
    a type using `keyof`, so that we get precise type-checking of these
    values rather than simply `string`.
    
    One function has been dropped from the API: `getDateFormatFromStyle`.
    There was no practical way to implement it using the new format data
    structures. The only caller was the date format column settings, and it
    has been rewritten to use the formatted string for its sample date as
    its key instead.
    [metabase-lib] Port date and time parsing and formatting to CLJC (#27551)
    Braden Shepherdson authored
    This adds a cross-platform date/time formatting library in CLJC, with
    (nearly) identical output in both JVM and JS environments.
    
    The only known difference is week numbers.
    
    CLJS (through Moment.js) has ordinal numbers, and renders the week
    number as "34th". Neither the JVM nor Clojure has a handy library for
    this (I'm sure it's out there somewhere, but it seems like a silly
    dep to add) so it renders week numbers as simply "34".
    
    Both platforms have date formatters that use pattern strings (eg.
    `"YYYY-MM-dd"`) to turn date/time objects into strings. There's a strong
    resemblance in how these work and what letters stand for what parts of
    the date and time, but they are far from identical.
    
    Rather than try to hackily convert one set of strings to another with
    regexes or other manipulations, this PR defines a set of names for
    fragments of dates (eg. `:year`, `:day-of-week-full`, `:hour-24-dd`)
    and includes functions to transform a list of these keys into a
    platform-specific format function.
    
    This is portable and transparent, and can be written in Clojure or
    JS code:
    
    ```clj
    [:year "-" :month-dd "-" :day-of-month-dd]   ; 2022-04-08
    [:month-full " " :day-of-month-d ", " :year] ; April 8, 2022
    [:hour-12-dd ":" :minute-dd " " :am-pm]      ; 7:52 AM
    ```
    
    ```js
    [":year", "-", ":month-dd", "-", ":day-of-month-dd"]   ; 2022-04-08
    [":month-full", " ", ":day-of-month-d", ", ", ":year"] ; April 8, 2022
    [":hour-12-dd", ":", ":minute-dd", " ", ":am-pm"]      ; 7:52 AM
    ```
    
    Note that the original code allowed an unrecognized `:date-style` string
    to be used directly as the formatting string. With the move to
    formatting data structures that no longer works. Instead there is a
    fixed map of format strings to the above data structures, that contains
    all the currently used `:date-style` inputs.
    
    If some caller needs a new format someday, we can either: (a) add the
    style to the map; or (b) pass the data structure form directly to the
    `:date-format` option, which if provided is used as the format.
    
    It's tempting to go to all the call sites and replace these `:date-style`
    strings with the new format structures. However, the strings are still
    embedded in the `:visualization_settings` in user appDBs, so we still
    need to recognize them.
    
    Most of the existing functions in the TS library have the same API.
    
    The set of allowed `:date-style` and `:time-style` values is turned into
    a type using `keyof`, so that we get precise type-checking of these
    values rather than simply `string`.
    
    One function has been dropped from the API: `getDateFormatFromStyle`.
    There was no practical way to implement it using the new format data
    structures. The only caller was the date format column settings, and it
    has been rewritten to use the formatted string for its sample date as
    its key instead.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.