Java 8 uses IANA timezones names (always in the format Region/City
, like America/Sao_Paulo
or Europe/Berlin
).
Avoid using the short abbreviations (like CEST
or PST
) because they are ambiguous and not standard.
Actually, those names don't work with ZoneId
mainly because of this ambiguity (CST, for example, can be "Central Standard Time", "Cuba Standard Time" or "China Standard Time"). Actually, some of them might work due to retro-compatibility reasons, but it's not guaranteed to work with all of them.
I'm assuming that CEST is the Central European Summer Time. There are lots of different countries (and timezones) that are currently in CEST, so the API can't decide which timezone to choose if you just pass "CEST" to it.
That's because a timezone contains all the different offsets a region had during its history. There may be lots of countries using CEST today, but their history differs in the past (some might had DST in different years, or used a different offset and then changed, etc), and that's why they have one timezone for each.
To use such short names (like CEST
), though, you can define some defaults for each one (which will be an arbitrary choice) and put these choices in a map:
// map of custom zone names
Map<String, String> map = new HashMap<>();
// setting my arbitrary choices for each name
map.put("CEST", "Europe/Berlin"); // Berlin during DST period
map.put("CET", "Europe/Berlin"); // Berlin during non-DST period
// ... and so on
Then you can use this map to create the ZoneId
:
// use the custom map to create the ZoneId
ZoneId zoneFrom = ZoneId.of(tzFrom, map);
...
// use the custom map to create the ZoneId
ZonedDateTime rezDate = dateAndTimeINeed.withZoneSameInstant(ZoneId.of(tzTo, map));
I've chosen Europe/Berlin
, but of course you can change it to whatever timezone you need. You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds()
.
Using the map above:
System.out.println(changeTZ("CEST", "UTC", "2017-08-10 14:23:58"));
This code outputs:
2017-08-10 12:23:58
Note that 14:23 in CEST
(which I chose to be Europe/Berlin
) is 12:23 in UTC, which is correct because in August Berlin is in DST (offset is +02:00
).
ZoneId
and ZonedDateTime
classes handle DST effects automatically. You can check this by choosing a date in January (when DST is not in effect in Berlin):
// January is not DST, so use CET
System.out.println(changeTZ("CET", "UTC", "2017-01-10 14:23:58"));
The output is:
2017-01-10 13:23:58
In January Berlin is not in DST, so the offset is +01:00
, then 14:23 in Berlin becomes 13:23 in UTC.
Of course the ideal is to always use the full names (like Europe/Berlin
), but the custom map is an alternative if you don't have control over the inputs.
Java 8 also has a built-in predefined map, but as any other predefined stuff, the choices are arbitrary and not necessarily the ones you need.