How to parse time zone string "Pacific Time (US & Canada)" on JVM?

3.1k views Asked by At

I'm writing an integration with Yammer and it returns a time zone string that looks like this:

Pacific Time (US & Canada)

How does one parse this into a TimeZone or DateTimeZone on the JVM? I've tried TimeZone.getTimeZone and DateTimeZone.forID but to no avail.

3

There are 3 answers

2
Matt Johnson-Pint On BEST ANSWER

It would appear that Yammer returns a timezone field as part of the user object in its REST API. An example can be seen as part of the authorization docs in the response body in the section labeled "C. App Authentication", and looks like:

{
  "user":
  {
    "timezone": "Hawaii",
    "interests": null,
    "type": "user",

...

This is also returned from any of the GET /users/... APIs. From experimenting, I can see that the value returned by the API corresponds to the keys of the drop-down list that appears in the user account settings screen (found at https://yammer.com/<your domain>/account/display_options) :

screenshot

When you view the source of this web page, you can see the drop-down list with all of the keys and values:

<select id="meta_user_timezone" name="meta_user[timezone]"><option value="Hawaii">(GMT-10:00) Hawaii</option>
<option value="Alaska">(GMT-09:00) Alaska</option>
<option value="Pacific Time (US &amp; Canada)" selected="selected">(GMT-08:00) Pacific Time (US &amp; Canada)</option>
<option value="Arizona">(GMT-07:00) Arizona</option>
<option value="Mountain Time (US &amp; Canada)">(GMT-07:00) Mountain Time (US &amp; Canada)</option>
<option value="Central Time (US &amp; Canada)">(GMT-06:00) Central Time (US &amp; Canada)</option>
<option value="Eastern Time (US &amp; Canada)">(GMT-05:00) Eastern Time (US &amp; Canada)</option>
<option value="Indiana (East)">(GMT-05:00) Indiana (East)</option><option value="" disabled="disabled">-------------</option>
<option value="American Samoa">(GMT-11:00) American Samoa</option>
<option value="International Date Line West">(GMT-11:00) International Date Line West</option>
<option value="Midway Island">(GMT-11:00) Midway Island</option>
<option value="Tijuana">(GMT-08:00) Tijuana</option>
<option value="Chihuahua">(GMT-07:00) Chihuahua</option>
<option value="Mazatlan">(GMT-07:00) Mazatlan</option>
<option value="Central America">(GMT-06:00) Central America</option>
<option value="Guadalajara">(GMT-06:00) Guadalajara</option>
<option value="Mexico City">(GMT-06:00) Mexico City</option>
<option value="Monterrey">(GMT-06:00) Monterrey</option>
<option value="Saskatchewan">(GMT-06:00) Saskatchewan</option>
<option value="Bogota">(GMT-05:00) Bogota</option>
<option value="Lima">(GMT-05:00) Lima</option>
<option value="Quito">(GMT-05:00) Quito</option>
<option value="Caracas">(GMT-04:30) Caracas</option>
<option value="Atlantic Time (Canada)">(GMT-04:00) Atlantic Time (Canada)</option>
<option value="Georgetown">(GMT-04:00) Georgetown</option>
<option value="La Paz">(GMT-04:00) La Paz</option>
<option value="Newfoundland">(GMT-03:30) Newfoundland</option>
<option value="Brasilia">(GMT-03:00) Brasilia</option>
<option value="Buenos Aires">(GMT-03:00) Buenos Aires</option>
<option value="Greenland">(GMT-03:00) Greenland</option>
<option value="Santiago">(GMT-03:00) Santiago</option>
<option value="Mid-Atlantic">(GMT-02:00) Mid-Atlantic</option>
<option value="Azores">(GMT-01:00) Azores</option>
<option value="Cape Verde Is.">(GMT-01:00) Cape Verde Is.</option>
<option value="Casablanca">(GMT+00:00) Casablanca</option>
<option value="Dublin">(GMT+00:00) Dublin</option>
<option value="Edinburgh">(GMT+00:00) Edinburgh</option>
<option value="Lisbon">(GMT+00:00) Lisbon</option>
<option value="London">(GMT+00:00) London</option>
<option value="Monrovia">(GMT+00:00) Monrovia</option>
<option value="UTC">(GMT+00:00) UTC</option>
<option value="Amsterdam">(GMT+01:00) Amsterdam</option>
<option value="Belgrade">(GMT+01:00) Belgrade</option>
<option value="Berlin">(GMT+01:00) Berlin</option>
<option value="Bern">(GMT+01:00) Bern</option>
<option value="Bratislava">(GMT+01:00) Bratislava</option>
<option value="Brussels">(GMT+01:00) Brussels</option>
<option value="Budapest">(GMT+01:00) Budapest</option>
<option value="Copenhagen">(GMT+01:00) Copenhagen</option>
<option value="Ljubljana">(GMT+01:00) Ljubljana</option>
<option value="Madrid">(GMT+01:00) Madrid</option>
<option value="Paris">(GMT+01:00) Paris</option>
<option value="Prague">(GMT+01:00) Prague</option>
<option value="Rome">(GMT+01:00) Rome</option>
<option value="Sarajevo">(GMT+01:00) Sarajevo</option>
<option value="Skopje">(GMT+01:00) Skopje</option>
<option value="Stockholm">(GMT+01:00) Stockholm</option>
<option value="Vienna">(GMT+01:00) Vienna</option>
<option value="Warsaw">(GMT+01:00) Warsaw</option>
<option value="West Central Africa">(GMT+01:00) West Central Africa</option>
<option value="Zagreb">(GMT+01:00) Zagreb</option>
<option value="Athens">(GMT+02:00) Athens</option>
<option value="Bucharest">(GMT+02:00) Bucharest</option>
<option value="Cairo">(GMT+02:00) Cairo</option>
<option value="Harare">(GMT+02:00) Harare</option>
<option value="Helsinki">(GMT+02:00) Helsinki</option>
<option value="Istanbul">(GMT+02:00) Istanbul</option>
<option value="Jerusalem">(GMT+02:00) Jerusalem</option>
<option value="Kyiv">(GMT+02:00) Kyiv</option>
<option value="Pretoria">(GMT+02:00) Pretoria</option>
<option value="Riga">(GMT+02:00) Riga</option>
<option value="Sofia">(GMT+02:00) Sofia</option>
<option value="Tallinn">(GMT+02:00) Tallinn</option>
<option value="Vilnius">(GMT+02:00) Vilnius</option>
<option value="Baghdad">(GMT+03:00) Baghdad</option>
<option value="Kuwait">(GMT+03:00) Kuwait</option>
<option value="Minsk">(GMT+03:00) Minsk</option>
<option value="Moscow">(GMT+03:00) Moscow</option>
<option value="Nairobi">(GMT+03:00) Nairobi</option>
<option value="Riyadh">(GMT+03:00) Riyadh</option>
<option value="St. Petersburg">(GMT+03:00) St. Petersburg</option>
<option value="Volgograd">(GMT+03:00) Volgograd</option>
<option value="Tehran">(GMT+03:30) Tehran</option>
<option value="Abu Dhabi">(GMT+04:00) Abu Dhabi</option>
<option value="Baku">(GMT+04:00) Baku</option>
<option value="Muscat">(GMT+04:00) Muscat</option>
<option value="Tbilisi">(GMT+04:00) Tbilisi</option>
<option value="Yerevan">(GMT+04:00) Yerevan</option>
<option value="Kabul">(GMT+04:30) Kabul</option>
<option value="Ekaterinburg">(GMT+05:00) Ekaterinburg</option>
<option value="Islamabad">(GMT+05:00) Islamabad</option>
<option value="Karachi">(GMT+05:00) Karachi</option>
<option value="Tashkent">(GMT+05:00) Tashkent</option>
<option value="Chennai">(GMT+05:30) Chennai</option>
<option value="Kolkata">(GMT+05:30) Kolkata</option>
<option value="Mumbai">(GMT+05:30) Mumbai</option>
<option value="New Delhi">(GMT+05:30) New Delhi</option>
<option value="Sri Jayawardenepura">(GMT+05:30) Sri Jayawardenepura</option>
<option value="Kathmandu">(GMT+05:45) Kathmandu</option>
<option value="Almaty">(GMT+06:00) Almaty</option>
<option value="Astana">(GMT+06:00) Astana</option>
<option value="Dhaka">(GMT+06:00) Dhaka</option>
<option value="Novosibirsk">(GMT+06:00) Novosibirsk</option>
<option value="Urumqi">(GMT+06:00) Urumqi</option>
<option value="Rangoon">(GMT+06:30) Rangoon</option>
<option value="Bangkok">(GMT+07:00) Bangkok</option>
<option value="Hanoi">(GMT+07:00) Hanoi</option>
<option value="Jakarta">(GMT+07:00) Jakarta</option>
<option value="Krasnoyarsk">(GMT+07:00) Krasnoyarsk</option>
<option value="Beijing">(GMT+08:00) Beijing</option>
<option value="Chongqing">(GMT+08:00) Chongqing</option>
<option value="Hong Kong">(GMT+08:00) Hong Kong</option>
<option value="Irkutsk">(GMT+08:00) Irkutsk</option>
<option value="Kuala Lumpur">(GMT+08:00) Kuala Lumpur</option>
<option value="Perth">(GMT+08:00) Perth</option>
<option value="Singapore">(GMT+08:00) Singapore</option>
<option value="Taipei">(GMT+08:00) Taipei</option>
<option value="Ulaan Bataar">(GMT+08:00) Ulaan Bataar</option>
<option value="Osaka">(GMT+09:00) Osaka</option>
<option value="Sapporo">(GMT+09:00) Sapporo</option>
<option value="Seoul">(GMT+09:00) Seoul</option>
<option value="Tokyo">(GMT+09:00) Tokyo</option>
<option value="Yakutsk">(GMT+09:00) Yakutsk</option>
<option value="Adelaide">(GMT+09:30) Adelaide</option>
<option value="Darwin">(GMT+09:30) Darwin</option>
<option value="Brisbane">(GMT+10:00) Brisbane</option>
<option value="Canberra">(GMT+10:00) Canberra</option>
<option value="Guam">(GMT+10:00) Guam</option>
<option value="Hobart">(GMT+10:00) Hobart</option>
<option value="Magadan">(GMT+10:00) Magadan</option>
<option value="Melbourne">(GMT+10:00) Melbourne</option>
<option value="Port Moresby">(GMT+10:00) Port Moresby</option>
<option value="Solomon Is.">(GMT+10:00) Solomon Is.</option>
<option value="Sydney">(GMT+10:00) Sydney</option>
<option value="Vladivostok">(GMT+10:00) Vladivostok</option>
<option value="New Caledonia">(GMT+11:00) New Caledonia</option>
<option value="Auckland">(GMT+12:00) Auckland</option>
<option value="Fiji">(GMT+12:00) Fiji</option>
<option value="Kamchatka">(GMT+12:00) Kamchatka</option>
<option value="Marshall Is.">(GMT+12:00) Marshall Is.</option>
<option value="Wellington">(GMT+12:00) Wellington</option>
<option value="Nuku&#x27;alofa">(GMT+13:00) Nuku&#x27;alofa</option>
<option value="Samoa">(GMT+13:00) Samoa</option>
<option value="Tokelau Is.">(GMT+13:00) Tokelau Is.</option></select>

The question was about how to translate these? Well, I don't have any hard proof, but it would appear that these time zone keys are all partial bits of Windows time zone display names. They're not distinct identifiers in Windows, or any Microsoft technology. I am puzzled why Yammer would choose these as time zone ids. But the way you would go about it is as follows:

  • Look at the CLDR Windows Zone mapping file. You'll see entries such as:

    <!--  (UTC-08:00) Pacific Time (US & Canada)  -->
    <mapZone other="Pacific Standard Time" territory="001" type="America/Los_Angeles"/>
    <mapZone other="Pacific Standard Time" territory="CA" type="America/Vancouver America/Dawson America/Whitehorse"/>
    <mapZone other="Pacific Standard Time" territory="MX" type="America/Tijuana"/>
    <mapZone other="Pacific Standard Time" territory="US" type="America/Los_Angeles"/>
    <mapZone other="Pacific Standard Time" territory="ZZ" type="PST8PDT"/>
    <!--  (UTC-07:00) Arizona  -->
    <mapZone other="US Mountain Standard Time" territory="001" type="America/Phoenix"/>
    <mapZone other="US Mountain Standard Time" territory="CA" type="America/Dawson_Creek America/Creston"/>
    <mapZone other="US Mountain Standard Time" territory="MX" type="America/Hermosillo"/>
    <mapZone other="US Mountain Standard Time" territory="US" type="America/Phoenix"/>
    <mapZone other="US Mountain Standard Time" territory="ZZ" type="Etc/GMT+7"/>
    <!--  (UTC-07:00) Chihuahua, La Paz, Mazatlan  -->
    <mapZone other="Mountain Standard Time (Mexico)" territory="001" type="America/Chihuahua"/>
    <mapZone other="Mountain Standard Time (Mexico)" territory="MX" type="America/Chihuahua America/Mazatlan"/>
    
  • Search for the Yammer time zone key in the comment lines, as a partial substring match. For example, if the Yammer time zone is "La Paz", it would match to the entry with the comment <!-- (UTC-07:00) Chihuahua, La Paz, Mazatlan -->

  • Take the IANA time zone ID from the very next line following the comment. It will be the one with marked with territory="001". You want the type field. For the previous example, this would be "America/Chihuahua".

  • You can use that ID in Java with any of the standard Java 7 or Java 8 APIs (or with Joda Time).

One last point. I checked (via the users API) the timezone setting of many people in my own Yammer network that I know to be in other time zones, and only a few had ever changed their time zone from the "Pacific Time (US & Canada)" default setting. Therefore, I would be suspicious to trust these values to be accurate. As far as I can tell, there's nothing that would force a Yammer user to change this setting from the default, and they have to go out of their way to do it.

1
AudioBubble On

You may be better off using a timezone offset, if Yammer provides one to you. As far as I can tell, that timezone string given to you by Yammer is incorrect (or at least, is Microsoft-specific). If you execute this Java code:

System.out.println(Arrays.toString(TimeZone.getAvailableIDs()));

you'll find that the string Pacific Time (US & Canada) doesn't appear in it, because it is (I think) a Microsoft-style timezone name, and for reasons known only to themselves, Microsoft decided to name them differently.

1
AudioBubble On

This looks familiar to Ruby on Rails time APIs which use "friendly" timezone names instead of the standard "America/Los_Angeles". Which, as suggested in another answer, might actually be Windows names.

This led me to this discussion about TimeZones in Java, and from there to a Github repo that provides these Windows names for Java programs.

Looks like you are going to have to wrap your date-time stuff in a translation layer that you borrow or write yourself.