optic92
optic92

Reputation: 23

Get Person Local time by timezone in elm

I am quite new in elm and I am trying to create an admin panel that shows the technical support list and their available time according to their local time and their working hours. Supporter List:

init flags =
    ( { supportUserList =
            [ { supportName = "Maynard Kaminski"
              , numberOfClient = 12
              , zone = "Europe/Moscow"
              , startTime = "9 am"
              , endTime = "1 pm"
              }
            , { supportName = "Belle Willett"
                , numberOfClient = 8
              , zone = "Canada/Eastern"
              , startTime = "2 pm"
              , endTime = "6 pm"
              }
            , { supportName = "Gaylene Hickson"
              , numberOfClient = 7
              , zone = "Africa/Nairobi"
              , startTime = "6 pm"
              , endTime = "10 pm"
              }
            , { supportName = "Cinthia Talbert"
              , numberOfClient = 4
              , zone = "Asia/Tokyo"
              , startTime = "2 pm"
              , endTime = "6 pm"
              }
            , { supportName = "Sydney Crenshaw"
              , numberOfClient = 7
              , zone = "Pacific/Honolulu"
              , startTime = "6 am"
              , endTime = "10 am"
              }
            ]
      }
    , Cmd.none
    )
viewSupporter : Supporter -> Html msg
viewSupporter supporter =
    li []
        [ text supporter.supportName
        , text " "
        , text " ("
        , text (String.fromInt (supporter.numberOfClient))
        , text ")"
        , text " "
        , text supporter.startTime
        , text " - "
        , text supporter.endTime
        , text " ("
        , text "local time ?"
        , text ")"
        ]

Expected Result enter image description here

Current Result enter image description here

I was trying to check https://guide.elm-lang.org/effects/time.html and How do I get the current time in Elm?

But still could not find a solution. Here is my current code is in Eillie. Spent almost 9 hours and could not find a solution. How could I get a person's local time by their time zone value. Thanks

Upvotes: 2

Views: 221

Answers (1)

Robert K. Bell
Robert K. Bell

Reputation: 10194

You'll want to convert those zone strings into actual Time.Zones, which can be done with justinmimbs' TimeZone library.

Then, you'll need to get the current time with something like Time.every, and convert it to local parts with Time.Extra.posixToParts.

Some example code:

module Main exposing (main)

import Browser
import Dict
import Html exposing (Html, li, text, ul)
import Time exposing (Month(..))
import Time.Extra
import TimeZone


type Msg
    = Tick Time.Posix


type alias Model =
    { now : Time.Posix }


type alias RawSupporter =
    { supportName : String
    , numberOfClient : Int
    , zone : String
    , startTime : String
    , endTime : String
    }


type alias Supporter =
    { supportName : String
    , numberOfClient : Int
    , zone : Maybe Time.Zone
    , rawZone : String
    , startTime : String
    , endTime : String
    }


rawSupporters : List RawSupporter
rawSupporters =
    [ { supportName = "Maynard Kaminski"
      , numberOfClient = 12
      , zone = "Europe/Moscow"
      , startTime = "9 am"
      , endTime = "1 pm"
      }
    , { supportName = "Belle Willett"
      , numberOfClient = 8
      , zone = "Canada/Eastern"
      , startTime = "2 pm"
      , endTime = "6 pm"
      }
    , { supportName = "Gaylene Hickson"
      , numberOfClient = 7
      , zone = "Africa/Nairobi"
      , startTime = "6 pm"
      , endTime = "10 pm"
      }
    , { supportName = "Cinthia Talbert"
      , numberOfClient = 4
      , zone = "Asia/Tokyo"
      , startTime = "2 pm"
      , endTime = "6 pm"
      }
    , { supportName = "Sydney Crenshaw"
      , numberOfClient = 7
      , zone = "Pacific/Honolulu"
      , startTime = "6 am"
      , endTime = "10 am"
      }
    ]


supporters : List Supporter
supporters =
    rawSupporters
        |> List.map
            (\raw ->
                { supportName = raw.supportName
                , numberOfClient = raw.numberOfClient
                , zone =
                    TimeZone.zones
                        |> Dict.get raw.zone
                        |> Maybe.map (\evaluate -> evaluate ())
                , rawZone = raw.zone
                , startTime = raw.startTime
                , endTime = raw.endTime
                }
            )


viewSupporter : Time.Posix -> Supporter -> Html msg
viewSupporter now supporter =
    let
        parts =
            supporter.zone
                |> Maybe.map
                    (\zone ->
                        Time.Extra.posixToParts zone now
                    )

        localTimeDisplay =
            case parts of
                Just { year, month, day, hour, minute, second, millisecond } ->
                    ([ [ year, monthNum month, day ]
                        |> List.map String.fromInt
                        |> String.join "-"
                     , [ hour, minute, second ]
                        |> List.map String.fromInt
                        |> String.join ":"
                     ]
                        |> String.join " "
                    )
                        ++ " (local time)"

                Nothing ->
                    "<Not a valid timezone: '" ++ supporter.rawZone ++ "'>"
    in
    [ supporter.supportName
    , " ("
    , String.fromInt supporter.numberOfClient
    , ") "
    , supporter.startTime
    , " - "
    , supporter.endTime
    , " "
    , localTimeDisplay
    ]
        |> List.map text
        |> li []


monthNum : Month -> Int
monthNum m =
    case m of
        Jan ->
            1

        Feb ->
            2

        Mar ->
            3

        Apr ->
            4

        May ->
            5

        Jun ->
            6

        Jul ->
            7

        Aug ->
            8

        Sep ->
            9

        Oct ->
            10

        Nov ->
            11

        Dec ->
            12


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Tick newTime ->
            ( { model | now = newTime }, Cmd.none )


view : Model -> Html Msg
view model =
    supporters
        |> List.map (viewSupporter model.now)
        |> ul []


main : Program () Model Msg
main =
    Browser.element
        { init = \() -> ( { now = Time.millisToPosix 0 }, Cmd.none )
        , view = view
        , update = update
        , subscriptions = \_ -> Time.every 1000 Tick
        }

Here's the same code running on ellie-app.com.

Upvotes: 1

Related Questions