16

I'm trying to convert a timestamp (ex: "1493287973015") from a JSON to a Date type.

So far I created this custom decoder:

stringToDate : Decoder String -> Decoder Date
stringToDate decoder =
  customDecoder decoder Date.fromTime

But it doesn't work because it has return a Result, not a Date:

Function `customDecoder` is expecting the 2nd argument to be:

    Time.Time -> Result String a

But it is:

    Time.Time -> Date.Date

Is there a way to do a conversion?

Guilhem Soulas
  • 1,975
  • 2
  • 18
  • 30
  • ...and if it is a UNIX timestamp, remember to [multiple that value by 1000](https://stackoverflow.com/questions/4676195/why-do-i-need-to-multiply-unix-timestamps-by-1000-in-javascript)... – lifebalance Oct 09 '19 at 22:24

2 Answers2

20

Assuming your JSON is actually placing the numeric value inside quotes (meaning you are parsing the JSON value "1493287973015" and not 1493287973015), your decoder could look like this:

import Json.Decode exposing (..)
import Date
import String

stringToDate : Decoder Date.Date
stringToDate =
  string
    |> andThen (\val ->
        case String.toFloat val of
          Err err -> fail err
          Ok ms -> succeed <| Date.fromTime ms)

Notice that stringToDate doesn't get passed any parameters, as opposed to your example in which you were attempting to pass a Decoder String as a parameter. That's not quite how decoders work.

Instead, this can be done by building upon more primitive decoders, in this case, we start with the decoder string from Json.Decode.

The andThen portion then takes the string value given by the decoder, and tries to parse it to a float. If it is a valid Float, it is fed into Date.fromTime, otherwise, it's a failure.

The fail and succeed functions wrap up the normal values you're dealing with into Decoder Date.Date contexts so they can be returned.

Chad Gilbert
  • 36,115
  • 4
  • 89
  • 97
  • 1
    Thanks! I got it working. Decoding JSON with Elm is not exactly easy. – Guilhem Soulas May 11 '16 at 03:46
  • 3
    I wouldn't go far as to say it isn't _easy_. It's just unfamiliar if you've come from an imperative background. This kind of parsing is fairly common in functional languages; it's known as Parser Combinators. – Chad Gilbert May 11 '16 at 10:37
6

Two things, a JSON may actually have the milliseconds as an integer, not a string and things have changed since v 0.19 of Elm.

Given that your JSON looks something like.

{
    ...
    "someTime": 1552483995395,
    ...
}

Then this would decode to a Time.Posix:

import Json.Decode as Decode

decodeTime : Decode.Decoder Time.Posix
decodeTime =
    Decode.int
        |> Decode.andThen
            (\ms ->
                Decode.succeed <| Time.millisToPosix ms
            )
PerLundholm
  • 96
  • 1
  • 3
  • ...and if it is a UNIX timestamp, remember to [multiple that value by 1000](https://stackoverflow.com/questions/4676195/why-do-i-need-to-multiply-unix-timestamps-by-1000-in-javascript)... – lifebalance Oct 09 '19 at 22:25