Better way to do: (get time, fetch JSON, get time)?

I made a small Elm program which checks if your clock has correct time by fetching time from server and comparing it to your time.

Getting client-server time offset is done with three tasks run one after another:

  1. get client time at request beginning
  2. fetch server time with HTTP request
  3. get client time at request end

I’d like to know if there is better way (most likely there is) to create this queryServerTime function shown below. I also included some relevant helper functions below, full code is here, and I also have live example.

queryServerTime : Cmd Msg
queryServerTime =
    Time.now
        |> Task.andThen
            (\clientStartTime ->
                Http.get "https://www.markuslaire.com/ajax/TimeNowUTC.php" serverTimeDecoder
                    |> Http.toTask
                    |> Task.andThen
                        (\serverTime ->
                            Time.now
                                |> Task.andThen
                                    (\clientEndTime ->
                                        createTimeQuery clientStartTime serverTime clientEndTime
                                            |> Task.succeed
                                    )
                        )
            )
        |> Task.attempt GotServerTime

type alias TimeQuery =
    { offset : Int
    , roundTripDelay : Int
    }

serverTimeDecoder : Json.Decode.Decoder Int
serverTimeDecoder =
    Json.Decode.field "time_ms" Json.Decode.int


createTimeQuery : Time.Posix -> Int -> Time.Posix -> TimeQuery
createTimeQuery clientStartTime serverTime clientEndTime =
    { offset = serverTime - timeAverageToMillis clientStartTime clientEndTime
    , roundTripDelay = timeDeltaToMillis clientEndTime clientStartTime
    }

{-| using integer division here gives wrong result, apparently because of Int overflow
<https://github.com/elm/compiler/issues/1832>
-}
timeAverageToMillis : Time.Posix -> Time.Posix -> Int
timeAverageToMillis timeA timeB =
    floor (toFloat (Time.posixToMillis timeA + Time.posixToMillis timeB) / 2)


timeDeltaToMillis : Time.Posix -> Time.Posix -> Int
timeDeltaToMillis timeA timeB =
    Time.posixToMillis timeA - Time.posixToMillis timeB

Thanks, I was certain I was missing something easier here. And at Task.map2 it’s documented that those maps perform tasks in the given order, which is needed here.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.