First of all, avoid using the short abbreviations for timezones names (like CST
, PST
or CEST
) because they are ambiguous and not standard.
CST
, for example, is used by more than one timezone: it can be "Central Standard Time", "China Standard Time" or "Cuba Standard Time". And each one has different rules regarding Dayligh Saving Time, so using the abbreviation might not necessarily get the results you expect.
The TimeZone
class assumes some defaults for those short names (all arbitrary choices, as any default is) and also has the bizarre behaviour of returning GMT when the name is unknown.
To avoid those ambiguities, it's better to use IANA timezones names (always in the format Region/City
, like Asia/Kolkata
or America/New_York
).
You can get a list of available timezones (and choose the one that fits best your system) by calling TimeZone.getAvailableIDs()
.
Then you can use the inDaylightTime()
method, as already explained in the other answers.
Another alternative is to use a formatter, because it checks automatically if it's in Daylight Saving Time and prints the zone short name. I also use a java.util.Locale
to indicate that the names should be in English (I'm not sure if different languages affect the short zone names, it's a "just in case" approach):
// formatter with `z` (zone short name)
SimpleDateFormat sdf = new SimpleDateFormat("z", Locale.ENGLISH);
// set timezone in the formatter
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
// prints the zone name for the current date
System.out.println(sdf.format(new Date()));
The code above prints EDT
(because today, September 13th 2017, New York is in Daylight Saving Time and the abbreviation used is EDT).
In this case, you could create the formatter, and use your if
logic to set the correct timezone in it. Then, the formatter takes care of checking if the date is in Daylight Saving Time, returning the correct abbreviation.
Java new Date/Time API
The old classes (Date
, Calendar
and SimpleDateFormat
) have lots of problems and design issues, and they're being replaced by the new APIs.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time
and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp
), but the classes and methods names are the same.
First I create a DateTimeFormatter
with the z
pattern (that corresponds to zone short name) and English locale.
Then I use a ZonedDateTime
, which represents a date and time in a specific timezone, and the now()
method to get the current date/time. I also use ZoneId
to especify the timezone I want:
// create formatter for short zone name and English locale
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("z", Locale.ENGLISH);
// format current date in New York timezone
System.out.println(fmt.format(ZonedDateTime.now(ZoneId.of("America/New_York"))));
This also prints EDT
as well. You could apply the same if
logic above to define which timezone will be used in ZoneId.of()
. Just remind to not use the short names (CST
, etc), because the new API is not so lenient as the old one.
TimeZone
assumes lots of arbitrary defaults and returns "GMT" when the zone doesn't exist, but ZoneId
will throw an exception if you try to get an invalid zone (some abbreviations should work for retro-compatibility reasons, but the defaults are arbitrary as well, and you should avoid them).
Custom map of zone names
You can optionally create a custom map of timezone names, so you don't need to make lots of if
clauses to determine the corresponding zone. Something like this:
// create custom map of zone names
Map<String, String> customZones = new HashMap<>();
// map "E" to New York
customZones.put("E", "America/New_York");
// map "G" to GMT
customZones.put("G", "GMT");
...
// create timezone using the custom map ("E" will create "America/New_York" zone)
ZoneId zone = ZoneId.of("E", customZones);
// format current date in specified timezone
System.out.println(fmt.format(ZonedDateTime.now(zone)));