Time zones are frequently redefined by politicians. New zones appear. Old ones get renamed (ex: Asia/Kolkata
). Some are determined to not actually be distinct, and end up pointing to another (ex: America/Montreal
). And that is just the names – the offsets within each zone are also often modified by politicians for anomalies such as Daylight Saving Time (DST), or deciding to get off DST altogether or deciding to stay on DST all-year-round or deciding to change the offset by 15 minutes to make some political statement such as distinguishing yourself from your neighboring countries. So there is no simple permanent list.
Java comes with a copy of the tzdata time zone database. If any zones you care about experience a change, you need to update this tzdata in your Java installations. Oracle provides a tool for this chore in their implementation; I do not know about others. Similarly you should also update the tzdata in your host computer’s OS as well as other utilities such as your database like Postgres.
As for references to a ZoneId
object in Java, you may define some as constants. The java.time classes are thread-safe. So you may keep a single instance around as a constant.
public class TimeUtils {
static public ZoneId ZONEID_EUROPE_PARIS = ZoneId.of( "Europe/Paris" ) ;
static public ZoneId ZONEID_ASIA_KOLKATA = ZoneId.of( "Asia/Kolkata" ) ;
}
You have a LocalDateTime
representing potential moments, not a specific point on the timeline. A LocalDateTime
has no time zone or offset information. So a LocalDateTime
of noon June 1 this year could mean many different moments, with the first noon happening in Kiribati where the time zone has an offset fourteen hours ahead of UTC. Noon in Bangladesh comes later, and noon in Paris France still hours later. So a LocalDateTime
has no real meaning until you apply a time zone for context.
LocalDateTime noon1June2017Anywhere = LocalDateTime.of( 2017 , Month.JUNE , 1 , 12 , 0);
Use those constants where you need a ZoneId
.
ZonedDateTime noon1June2017EuropeParis = noon1June2017Anywhere.atZone( TimeUtils.ZONEID_EUROPE_PARIS ) ;
ZonedDateTime noon1June2017AsiaKolkata = noon1June2017Anywhere.atZone( TimeUtils.ZONEID_ASIA_KOLKATA ) ;
Note that noon1June2017EuropeParis
and noon1June2017AsiaKolkata
are two different moments, different points on the timeline. Noon happens much earlier in India than it does in France.
Let's see those two values in UTC as Instant
objects. These two Instant
objects are not equal, as the Kolkata one is several hours earlier than the Paris one.
Instant instantNoon1June2017EuropeParis = noon1June2017EuropeParis.toInstant() ; // Extract the same moment but in UTC zone.
Instant instantNoon1June2017AsiaKolkata = noon1June2017AsiaKolkata.toInstant() ; // Extract the same moment but in UTC zone.
Externalize
If the intent of your Question is to externalize the decision of what zone to apply, so that you may change that choice without recompiling your source code again, simply store a string of the zone name such as Europe/Paris
as a string in some external resource.
Pass your string to ZoneId.of
.
ZoneId z = ZoneId.of( someStringOfZoneName ) ;
Possible storage mechanisms commonly used by folks:
- Store the text in a file.
- Store the text in a database row to retrieved by your app.
- Store the text as an entry in a JNDI facility (LDAP server, a configuration file in your Servlet container, etc.) (see Tutorial)
- Query from a Web Service. (See Tutorial)
- Ask the user for their preference and store in a variable such as a member of a class, or in a Servlet environment store string as an attribute on the context object or on the session object. You can provide the user with a choice list of all zones by calling
ZoneId.getAvailableZoneIds
.
You can ask for the JVM’s current default zone: ZoneId.systemDefault
. But beware, this can be changed at anytime by any code in any app in that JVM.