How to get the current Time and TimeZone from Locale?

Locale and time zone are orthogonal issues

Locale

A Locale represents the pair of:

  • A human language, such as French, English, or Chinese.
  • A set of cultural norms, for deciding issues such as formatting questions like capitalization, abbreviation, order of elements such as day-month-year in a date, and using COMMA versus FULL STOP as a decimal separator.

Locale is not geographical. While a Locale may use a country or region as a way of representing the cultural norms, that does not literally mean the user is in a particular geographic area. For example, an engineer from Québec at a conference in Tokyo Japan will be using a locale of Locale.CANADA_FRENCH but her time zone may be Asia/Tokyo for the duration of her trip.

ZoneId

A time zone, ZoneId, represents a history of the past, present, and future changes to the offset-from-UTC used by the people of a particular region. An offset is merely a number of hours-minutes-seconds ahead or behind the prime meridian used by UTC. Politicians around the world have shown a penchant for frequently redefining their time zones and changing the offset to be used by their jurisdiction(s). Indeed, those regions that adopted the silliness of Daylight Saving Time (DST) change their offset twice a year, about ever six months.

➥ So, no, you cannot get a current time nor a time zone from just a given locale.


when I create a calendar with a locale, the TimeZone just reverts to the local one

You are using terrible date-time classes that are now legacy, supplanted by the modern java.time classes defined by JSR 310.

To get the current moment in UTC (an offset of zero hours-minutes-seconds), use Instant. An Instant is always in UTC by definition.

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

If you want the current moment in a particular time zone, specify the ZoneId to get a ZonedDateTime object.

ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;  // Capture the current moment as seen in the wall-clock time used by the people of a particular region.

As for knowing the time zone to apply, as I said above you must either:

  • Use the default (ZoneId.systemDefault), or…
  • Confirm with the user.

You can get a list of known time zones by calling ZoneId.getAvailableZoneIds.

Calendar c = new GregorianCalendar( locale ) ;

You may confused by this constructor of GregorianCalendar taking a Locale, and understandably so.

This constructor is one of the many poor and incorrect design decisions found in the legacy date-time classes. To be blunt, these legacy classes are quite terrible, designed by people who did not understand the complexities and subtleties of date-time handling. Sun, Oracle, and the JCP community decided to supplant them with java.time for good reason.

Locale intersects with time zone when it comes to generating text representing the value of a date-time object for display to the user. A Locale specifies the human language to use in translating name of month, name of day of week, and so on. And Locale specifies the cultural norms for deciding issues such as abbreviating the month or day-of-week (Is the name capitalized? Is a FULL STOP appended?), ordering day, month, and year, and other such aspects.


The short answer: you can't.

The long answer: There is no such thing as "proper time zone for a locale". That's just because there are a few countries that have more than one time zone (for example United States). Time zone is a different concept.

Anyway, you are looking to solve your problem. I am guessing that you are writing a web application and you see that the time zone is reverting to the server default. That's a typical situation. Both Locale.getDefault() and TimeZone.getDefault() will return server-related information. The JVM has no way of knowing the "proper" time zone. So what can you do about it?

  1. You can add time zone information to user profile (if you have one), or create a time zone combo box (so that the user can switch at runtime). Then you can assign an appropriate object to DateFormat instance and it will convert time zone automatically.
  2. You can read the current time zone offset from the client via JavaScript Date Object's getTimezoneOffset() function and somehow (AJAX) send it to the server. The problem with this method is that there are several time zones with that offset, and the selected time zone might be inappropriate for other dates. Of course you can guess the time zone by polling the data around time change date, but this is probably not what you want to do.
  3. You can send the unformatted time to the client (for example written as ISO 8601 date-time format or as a Unix time of the epoch in relation to UTC) and have Globalize or Dojo format date and time for you.

Out of these three possible choices, I always opt for number 1. By putting time zone information to user profile, you know for sure what his/her preferred time zone is, regardless of their current web browser, etc. Please keep in mind that some users might want to use your application while visiting other countries...