How to get a zone name from the Time package?

When working with the Time package I’m able to use justinmimbs/timezone-data to load timezones. My question is given a Zone from the Time package how do I get the name of the zone?

For example:

import Time
import Time.TimeZones

zone = Time.TimeZones.america_new_york ()

How do get “America/New_York” from that zone? I’m looking for a function with the signature Zone -> String but can’t seem to find one. Or perhaps it just isn’t possible yet?

The Zone from elm/time doesn’t store a zone name. But it shouldn’t really need to. In your example you already know the zone name. :smile:

The TimeZone.getZone task returns the local zone name with the zone data, so you can store the name too if you’d like.

Is there a case where a Zone -> String function would be essential? I can’t think of a way to get a Zone without having access to its name.

Well, in this example I know the name. And I should always know the name. It just a question of storing both the name of the zone itself and the zone data. For example, some JSON is fetched from the server with the zone name. I then pass the Zone around and don’t track the name of it, perhaps updating the value in a view, but then I’m stuck with just the zone data so when I pass the data back to the server I’ve lost track of the name.

In my case I can just use a tuple to track and proxy the functions of the Time library:

type alias TimeZone =
    ( String, Zone )

toDay : TimeZone -> Posix -> Int
toDay ( _, z ) =
    Time.toDay z

There isn’t a Zone -> String function, but there is a similar Task called simply getZoneName:
https://package.elm-lang.org/packages/elm/time/latest/Time#getZoneName

You could store time information in a record on your model, something like:

type alias TimeInfo =
      { zone : Time.Zone
      , zoneName : Time.ZoneName
      }

type alias Model =
    { timeInfo : TimeInfo
    , ...
    }

Then you just need to perform two tasks in your init:

init ...
     let
         initZone =
              { zone = Time.utc
              , zoneName = Time.Offset 0
              }
         timeZoneCommand =
            Task.perform GetTimeZone Time.here

        zoneNameCommand =
            Task.perform GetZoneName Time.getZoneName
    in
    ....

Where

type Msg
type Msg
    = GetTimeZone Time.Zone
    | GetZoneName Time.ZoneName
    ....

and the update does the obvious thing of setting the relevant parts of the timeInfo on the Model.
Then you just need a function to format the ZoneName:

formatZoneName : Time.ZoneName -> String
formatZoneName zoneName =
    case zoneName of
        Time.Name n ->
            n

        Time.Offset 0 ->
            "UTC"

        Time.Offset o ->
            let
                sign =
                    case o > 0 of
                        True ->
                            "+"

                        False ->
                            "-"

                numMinutes =
                    abs o

                hours =
                    String.fromInt (numMinutes // 60)

                minutes =
                    modBy 60 numMinutes

                minSuffix =
                    case minutes == 0 of
                        True ->
                            ""

                        False ->
                            ":" ++ String.fromInt minutes
            in
            "UTC " ++ sign ++ hours ++ minSuffix

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