Dealing with time in Elm

Note: This post was written for Elm 0.16. There is now an official documentation for dealing with time in the latest version.

Because Elm is based on functional reactive programming concepts, dealing with time is different to most other programming languages I have worked with. Although it might be unfamiliar at first I think the way Elm handles time is simpler. When I first stumbled upon the problem it took a while to get some time-based logic working. If you are new to Elm like I am, I thought a basic example might help you to understand it.

Goal

The simplest example I could think of is an app that does the following:

The whole example code is open source on GitHub. Coming from a JavaScript background I also like to render actual HTML elements and use the StartApp package for easy extension.

Inputs in StartApp

If you don’t know how the StartApp package works I recommend reading my tutorial on making HTTP requests in Elm first.

The Elm core library includes a time library. To get the current time there is Time.every, which returns a stream of timestamps. Streams can be added to Elm apps via inputs using StartApp:

inputs =
 [
   Signal.map UpdateTime
     <| Time.every Time.millisecond
 ]

This code creates a stream with Time.every Time.millisecond. Then I map over this stream and wrap every timestamp with an UpdateTime action, as inputs requires a list of action Signals.

Storing time in the model

Everytime update receives an UpdateTime action it stores the passed timestamp in the model. This can now be used in the view function to display the current time or for doing other logic with it whenever an action comes in.

UpdateTime time ->
  { model | time = time }

I also added another action UpdateTimestamp to store a specific timestamp, which is used to toggle the visibility of the button. It takes the current time from the model, adds 5000 milliseconds and stores this timestamp in the model as well:

UpdateTimestamp ->
  { model | timestamp = model.time + 5000 }

Hiding the button

The view function now receives everything it needs to compute the difference between model.time and model.timestamp which decides when to hide or show the button:

if model.time - model.timestamp > 0 then
  button [ onClick address UpdateTimestamp ] [ text "wait 5 seconds" ]
else
  node "noscript" [] []

I used <noscript> here to not display anything while the button is hidden. When the button is shown, clicks send the UpdateTimestamp action, which updates model.timestamp and therefore hides the button for the next 5 seconds.

Conclusion

Once there is an always up-to-date timestamp in the app’s model, it is easy to deal with time in Elm. I hope this example could get you started with adding time based logic to your Elm applications. As mentioned earlier the full example code is on GitHub.