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:
- get client time at request beginning
- fetch server time with HTTP request
- 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