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. 
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