Format strings for dates.
Use a format string to format a date. See the README for a list of accepted formatters.
Use a localization record and a format string to format a date. See the README for a list of accepted formatters.
Formats a UTC date acording to
ISO-8601. This is commonly used to
send dates to a server. For example: 2016-01-06T09:22:00Z
.
module Date.Format exposing (format, formatISO8601, localFormat)
{-| Format strings for dates.
@docs format, localFormat, formatISO8601
-}
import Date
import Date.Local exposing (Local, international)
import List exposing (head, tail)
import Maybe exposing (andThen, withDefault)
import Regex
import String exposing (padLeft, right, toUpper)
re : Regex.Regex
re =
Regex.regex "%(_|-|0)?(%|Y|y|m|B|b|d|e|a|A|H|k|I|l|L|p|P|M|S)"
type Padding
= NoPadding
| Space
| Zero
| ZeroThreeDigits
{-| Use a format string to format a date. See the
[README](https://github.com/mgold/elm-date-format/blob/master/README.md) for a
list of accepted formatters.
-}
format : String -> Date.Date -> String
format s d =
localFormat international s d
{-| Use a localization record and a format string to format a date. See the
[README](https://github.com/mgold/elm-date-format/blob/master/README.md) for a
list of accepted formatters.
-}
localFormat : Local -> String -> Date.Date -> String
localFormat loc s d =
Regex.replace Regex.All re (formatToken loc d) s
{-| Formats a UTC date acording to
[ISO-8601](https://en.wikipedia.org/wiki/ISO_8601). This is commonly used to
send dates to a server. For example: `2016-01-06T09:22:00Z`.
-}
formatISO8601 : Date.Date -> String
formatISO8601 =
format "%Y-%m-%dT%H:%M:%SZ"
formatToken : Local -> Date.Date -> Regex.Match -> String
formatToken loc d m =
let
( padding, symbol ) =
case m.submatches of
[ Just "-", Just x ] ->
( Just NoPadding, x )
[ Just "_", Just x ] ->
( Just Space, x )
[ Just "0", Just x ] ->
( Just Zero, x )
[ Nothing, Just x ] ->
( Nothing, x )
_ ->
( Nothing, " " )
in
case symbol of
"%" ->
"%"
"Y" ->
d |> Date.year |> toString
"y" ->
d |> Date.year |> toString |> right 2
"m" ->
d |> Date.month |> monthToInt |> padWith (withDefault Zero padding)
"B" ->
d |> Date.month |> monthToWord loc.date.months
"b" ->
d |> Date.month |> monthToWord loc.date.monthsAbbrev
"d" ->
d |> Date.day |> padWith (withDefault Zero padding)
"e" ->
d |> Date.day |> padWith (withDefault Space padding)
"a" ->
d |> Date.dayOfWeek |> dayOfWeekToWord loc.date.wdaysAbbrev
"A" ->
d |> Date.dayOfWeek |> dayOfWeekToWord loc.date.wdays
"H" ->
d |> Date.hour |> padWith (withDefault Zero padding)
"k" ->
d |> Date.hour |> padWith (withDefault Space padding)
"I" ->
d |> Date.hour |> mod12 |> zero2twelve |> padWith (withDefault Zero padding)
"l" ->
d |> Date.hour |> mod12 |> zero2twelve |> padWith (withDefault Space padding)
"p" ->
if Date.hour d < 12 then
toUpper loc.time.am
else
toUpper loc.time.pm
"P" ->
if Date.hour d < 12 then
loc.time.am
else
loc.time.pm
"M" ->
d |> Date.minute |> padWith (withDefault Zero padding)
"S" ->
d |> Date.second |> padWith (withDefault Zero padding)
"L" ->
d |> Date.millisecond |> padWith (withDefault ZeroThreeDigits padding)
_ ->
""
monthToInt m =
case m of
Date.Jan ->
1
Date.Feb ->
2
Date.Mar ->
3
Date.Apr ->
4
Date.May ->
5
Date.Jun ->
6
Date.Jul ->
7
Date.Aug ->
8
Date.Sep ->
9
Date.Oct ->
10
Date.Nov ->
11
Date.Dec ->
12
monthToWord loc m =
case m of
Date.Jan ->
loc.jan
Date.Feb ->
loc.feb
Date.Mar ->
loc.mar
Date.Apr ->
loc.apr
Date.May ->
loc.may
Date.Jun ->
loc.jun
Date.Jul ->
loc.jul
Date.Aug ->
loc.aug
Date.Sep ->
loc.sep
Date.Oct ->
loc.oct
Date.Nov ->
loc.nov
Date.Dec ->
loc.dec
dayOfWeekToWord loc dow =
case dow of
Date.Mon ->
loc.mon
Date.Tue ->
loc.tue
Date.Wed ->
loc.wed
Date.Thu ->
loc.thu
Date.Fri ->
loc.fri
Date.Sat ->
loc.sat
Date.Sun ->
loc.sun
mod12 h =
h % 12
zero2twelve n =
if n == 0 then
12
else
n
padWith : Padding -> a -> String
padWith padding =
let
padder =
case padding of
NoPadding ->
identity
Zero ->
padLeft 2 '0'
ZeroThreeDigits ->
padLeft 3 '0'
Space ->
padLeft 2 ' '
in
padder << toString