At work, I recently needed to do locale-aware formatting of a date-time value, where I did not know the locale ahead of time. Because of details of the project, I needed to do this synchronously, so I was looking for an Elm library that would format date-times for any locale (the sort of thing that a JS developer would use Luxon or the Intl
API for). A cursory web search indicates that I am far from the first person to have this desire, and yet a fully Elm end-to-end solution for this problem does not exist yet. Without rehashing anything from the past, I would like to propose an API for such a library.
(My work problem is currently solved via the workaround of having JS pass in the formatted strings along with the date-time values, since all of my date-time values are being passed in a port from a JS API)
Goal and scope
The goal is to reach a pure Elm API for locale-aware date and date-time formatting that feels like Elm, while being familiar enough to JS developers to make the learning curve of Elm easier rather than harder. This API will cover a subset of the behavior from Intl.DateTimeFormat.
Prior Work
This research greatly aided by https://korban.net/elm/catalog/packages/data/time
Published
-
justinmimbs/date - my go-to library for a
Date
type. Includesformat
andformatWithLanguage
functions that takes a subset of Unicode Technical Standard #35 tokens as a format string. Languages are records, and thus can be provided from outside of this library. - danhandrea/elm-date-format - Uses format strings. Languages are an opaque type.
- ryannhg/date-format - Uses well-typed tokens as the format template. Languages are records.
- miniBill/date-format-languages - Additional languages for the above packages that use record languages.
-
CoderDennis/elm-time-format - Uses format strings based on Ruby’s format strings. Uses a
Config
which is roughly analogous to aLanguage
from the other packages. - samhstn/time-format - Uses custom format strings. No languages.
- thaterikperson/elm-strftime - Uses format strings from strftime.org. No languages.
All of these libraries require the library user to know the format instead of being able to derive the format based on the user’s locale.
- wolfadex/locale-negotiation - provides functions for negotiating which BCP47 locale identifiers to use from a list of requested and supported locale identifiers.
- yumlonne/elm-japanese-calendar - This shows that working with non-Gregorian calendars is important to some people.
Unpublished
-
Module for formatting Time in different timezones and languages - Request Feedback - Elm - A wrapper around a custom element that uses
Intl.DateTimeFormat.format
. - New Date/Time Library: Interested? - Request Feedback - Elm - New primitives for working with Dates, Times, and Moments. Does not seem to include formatting
Gaps
- Deriving a format for a given locale. E.g. given that the user is in “en-US”, and we want to format a date-time value in a
Short
way (in the Gregorian calendar), the UTS #35 format string is”M/d/yy, h:mm a”
, according to Unicode CLDR 39. - Parsing/canonicalization of Locales.
wolfadex/locale-negotiation
provides locale negotiation based on BCP47 strings, but handles values like “de_DE” or “de-DE-EURO” (nonstandard but real-world examples) in a way that I find unintuitive. Most of the time, the language and region are all that we need from a locale identifier, but this may not always be the case.
The first gap is the thing I actually want to solve. However, I believe that a Locale
type can encapsulate a lot of complexities and make the API simpler.
Proposal
module Locale exposing (..)
type Locale = Opaque
toBCP47 : Locale -> String
{-| fromString "en-US" == Just en_US
-}
fromString : String -> Maybe Locale
-- A few default locales:
en : Locale
en_US : Locale
en_GB : Locale
es : Locale
module Format.Length exposing (Length(..))
type Length = Full | Long | Medium | Short
module Format.DateTime exposing (..)
type FormatType = DateOnly Length
| TimeOnly Length
| DateAndTime { date : Length, time : Length }
format : FormatType -> Locale -> Zone -> Posix -> String
module Format.Date exposing (..)
import Date exposing (Date) -- from justinmimbs/date
format : Length -> Locale -> Date -> String
As a library user, this would allow me to get some locale strings either from navigator.language
, navigator.languages
, or some other source (probably passed in with my program flags), convert them into a Locale
type that I store in my model (manually choosing a default locale), and then use that Locale
to do all of my date and date-time formatting, which is what I believe most people who want to “use Intl
” actually want to do.
Summary
The above API only covers the small part of the browser’s Intl.DateTimeFormat
API that I consider to be the most important, and not already covered by previous high quality libraries. I believe that this API is fairly idiomatic Elm, while being familiar enough to JS developers to not make the learning curve more difficult.
Please provide any feedback about:
- Ways to make this API more idiomatically Elm
- Ways to make this API more friendly to newcomers
- Other parts of the
Intl.DateTimeFormat
API that you have seen use cases for in Elm. - Non-Gregorian Calendar support. Is it needed as part of a library like this?