Any idea what causes this…
It’s a well known problem with three and four letter time zone abbreviations. A third interpretation of IST is Irish Standard Time (Europe/Dublin). I don’t know exactly what causes one JVM to prefer one interpretation over another. In at least one case I have seen it prefer its default time zone setting over other interpretations. So if your development machine has an Asia/Kolkata time zone setting and your production machine hasn’t, this would probably be the explanation. However, I would not rely on this as a sure fact, and also I would want to write code robust enough to run on computers and JVMs with different time zone settings.
…and how to resolve it.
Ideal solution: Avoid getting a date-time string with a three or four letter time zone abbreviation in it. Prefer a zone offset from UTC and/or a time zone name in the form continent/city. I acknowledge that this is not always possible.
Given your input string, since SimpleDateFormat
and TimeZone
are outdated and the modern Java date and time API is much more programmer friendly, and you have also tagged your question with the ZonedDateTime
class, a part of the modern API, let’s take the modern solution first:
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.appendPattern("EEE MMM dd HH:mm:ss ")
.appendZoneText(TextStyle.SHORT, Collections.singleton(ZoneId.of("Asia/Kolkata")))
.appendPattern(" uuuu")
.toFormatter(Locale.ROOT);
ZonedDateTime dateTime = ZonedDateTime.parse(input, dtf);
System.out.println(dateTime.getZone());
It prints:
Asia/Kolkata
The second argument I pass to appendZoneText()
is a set of preferred time zones. In the documentation it says “The matched preferred zone id will be used if the textural zone name being parsed is not unique.” This is what we are after here.
On my computer I was also able to solve the issue within your code using the outdated classes. I inserted the following line before parsing.
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
However, the documentation of the old classes is vaguer, so I would be less assured that this solution always works.
As an aside and no matter if you use the old or the modern classes, I recommend you always give explicit locale to your parsing. “Mon” and “Jun” are in English, so parsing will not work on a computer with a non-English locale setting unless you specify a locale. Let me guess, your date string isn’t in English because it comes from an English-speaking locale, but just because English is the universal language in computing. If so, I consider Locale.ROOT
appropriate. I am already using it in my code. To use it in yours, add it as argument to the constructor:
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ROOT);
Locale.ENGLISH
works to, as do other English-speaking locales.