Skip to content

Commit

Permalink
Merge branch 'master' into accept-no-Z
Browse files Browse the repository at this point in the history
  • Loading branch information
Richard Feldman authored Mar 29, 2019
2 parents 618f6ca + 0bedeb6 commit 83784c5
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 53 deletions.
132 changes: 79 additions & 53 deletions src/Iso8601.elm
Original file line number Diff line number Diff line change
Expand Up @@ -52,27 +52,24 @@ toTime str =
-}
paddedInt : Int -> Parser Int
paddedInt quantity =
Parser.chompWhile Char.isDigit
|> Parser.getChompedString
|> Parser.andThen
(\str ->
if String.length str == quantity then
-- StringtoInt works on zero-padded integers
case String.toInt str of
Just intVal ->
Parser.succeed intVal

Nothing ->
Parser.problem ("Invalid integer: \"" ++ str ++ "\"")

else
Parser.problem
("Expected "
++ String.fromInt quantity
++ " digits, but got "
++ String.fromInt (String.length str)
)
)
let
helper str =
if String.length str == quantity then
-- StringtoInt works on zero-padded integers
case String.toInt str of
Just intVal ->
Parser.succeed intVal
|> Parser.map Parser.Done

Nothing ->
Parser.problem ("Invalid integer: \"" ++ str ++ "\"")

else
Parser.chompIf Char.isDigit
|> Parser.getChompedString
|> Parser.map (\nextChar -> Parser.Loop <| String.append str nextChar)
in
Parser.loop "" helper


msPerYear : Int
Expand Down Expand Up @@ -308,11 +305,19 @@ iso8601 =
|. symbol "T"
|= paddedInt 2
-- HH
|. symbol ":"
|= paddedInt 2
|= oneOf
[ succeed identity
|. symbol ":"
|= paddedInt 2
, paddedInt 2
]
-- mm
|. symbol ":"
|= paddedInt 2
|= oneOf
[ succeed identity
|. symbol ":"
|= paddedInt 2
, paddedInt 2
]
-- ss
|= oneOf
[ succeed identity
Expand All @@ -321,30 +326,49 @@ iso8601 =
, succeed 0
]
-- SSS
|= oneOf
[ -- "Z" means UTC
map (\_ -> 0) (symbol "Z")

-- +05:00 means UTC+5 whereas -11:30 means UTC-11.5
, succeed utcOffsetMinutesFromParts
|= oneOf
[ map (\_ -> 1) (symbol "+")
, map (\_ -> -1) (symbol "-")
]
|= paddedInt 2
|. symbol ":"
|= paddedInt 2

-- No "Z" is valid
, succeed 0
|. end
]
|= utcOffsetInMinutes
|. end
, succeed (fromParts datePart 0 0 0 0 0)
|. end
]
)


utcOffsetInMinutes : Parser Int
utcOffsetInMinutes =
let
utcOffsetMinutesFromParts : Int -> Int -> Int -> Int
utcOffsetMinutesFromParts multiplier hours minutes =
-- multiplier is either 1 or -1 (for negative UTC offsets)
multiplier * (hours * 60) + minutes
in
Parser.succeed identity
|= oneOf
[ -- "Z" means UTC
map (\_ -> 0) (symbol "Z")

-- +05:00 means UTC+5 whereas -11:30 means UTC-11.5
, succeed utcOffsetMinutesFromParts
|= oneOf
[ map (\_ -> 1) (symbol "+")
, map (\_ -> -1) (symbol "-")
]
-- support 01, 0100 and 01:00
|= paddedInt 2
|= oneOf
[ succeed identity
|. symbol ":"
|= paddedInt 2
, paddedInt 2
, succeed 0
]

-- No "Z" is valid
, succeed 0
|. end
]


{-| Parse fractions of a second, and convert to milliseconds
-}
fractionsOfASecondInMs : Parser Int
Expand Down Expand Up @@ -381,21 +405,23 @@ monthYearDayInMs =
Parser.succeed (\year month day -> ( year, month, day ))
|= paddedInt 4
-- YYYY
|. symbol "-"
|= paddedInt 2
|= oneOf
[ succeed identity
|. symbol "-"
|= paddedInt 2
, paddedInt 2
]
-- MM
|. symbol "-"
|= paddedInt 2
|= oneOf
[ succeed identity
|. symbol "-"
|= paddedInt 2
, paddedInt 2
]
-- DD
|> Parser.andThen yearMonthDay


utcOffsetMinutesFromParts : Int -> Int -> Int -> Int
utcOffsetMinutesFromParts multiplier hours minutes =
-- multiplier is either 1 or -1 (for negative UTC offsets)
multiplier * ((hours * 60) + minutes)


{-| Inflate a Posix integer into a more memory-intensive ISO-8601 date string.
It's generally best to avoid doing this unless an external API requires it.
Expand Down
24 changes: 24 additions & 0 deletions tests/Example.elm
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,30 @@ knownValues =
\_ ->
Iso8601.toTime "2018-08-31T23:25:16.0123456789+02:00"
|> Expect.err
, test "toTime supports no delimeters" <|
\_ ->
Iso8601.toTime "20180831T232516Z"
|> Expect.equal (Ok (Time.millisToPosix 1535757916000))
, test "toTime supports nanoseconds precision when there are no delimeters" <|
\_ ->
Iso8601.toTime "20180831T232516.019345123+02:00"
|> Expect.equal (Ok (Time.millisToPosix 1535750716019))
, test "toTime fails with no delimeters and not enough numbers" <|
\_ ->
Iso8601.toTime "2080831T232516Z"
|> Expect.err
, test "toTime supports no delimiter in offset" <|
\_ ->
Iso8601.toTime "2012-11-12T00:00:00+0100"
|> Expect.equal (Ok (Time.millisToPosix 1352674800000))
, test "toTime supports offset with only hours" <|
\_ ->
Iso8601.toTime "2012-11-12T00:00:00+01"
|> Expect.equal (Ok (Time.millisToPosix 1352674800000))
, test "toTime fails on invalid offset" <|
\_ ->
Iso8601.toTime "2012-11-12T00:00:00+0130546"
|> Expect.err
]


Expand Down

0 comments on commit 83784c5

Please sign in to comment.