Edit: IST is ambiguous
From your comment:
for example if the system timezone is in UTC and rss feed contains the
publishedDate as Sat, 28 Mar 2020 13:42:38 IST, the libary parses it to Sat Mar 28 11:42:38 GMT 2020
It took me a bit of investigation, but I have reproduced the behaviour. The problem is that IST is ambiguous: it may mean Irish Summer Time, Israel Standard Time, India Standard Time plus a few other possible time zone abbreviations. A similar ambiguity exists for very many time zone abbreviations, so we should not rely on them. Since you asked for a difference of 5 h 30, I take it that you intended India Standard Time. However, Java interprets IST as Israel Standard Time, which is at offset +02:00 from UTC/GMT. This explains your observed 2 hours difference. It does so even though Israel doesn’t use IST at this time of year, it uses Israel Daylight Time, IDT (at offset +03:00). However, when your default time zone is Asia/Kolkata (India Standard Time), Java does interpret IST to mean this. This explains why you got the expected and correct result in this case.
While fixing this problem in one’s own code would not be too hard, how to persuade your library to do as you want is a different matter. A couple of options come to mind:
The best solution is if you can persuade the publisher of your RSS feed not to use IST as time zone. According to the RSS 2.0 specification, the published date should be in RFC 822 format, and according to RFC 822, IST is not a valid time zone. So you have got arguments. From what I have seen, GMT
is very often used here and is in agreement with the specs.
I don’t know rometools, so there could be possibilities that I don’t know of and which you should investigate if you can. You may of course also file a bug report with the library developers.
You may try setting your default time zone to Asia/Kolkata at the time when rometools instantiates the formatter that it uses for parsing. Whether it does this on initialization, on the first call or on every call — make some experiments, or if you want to be sure, inspect the source code on GitHub. If you need to, you can always set the default time zone back to UTC afterward. It’s a very bad hack and not without the risk of occasional incorrect results.
If the published date from your RSS feed is always in IST in the sense India Standard Time, you may of course correct the wrong date that you get:
System.out.println("Incorrect date from rometools: " + javaUtilDateFromRometools);
ZonedDateTime correctedDateTime = javaUtilDateFromRometools.toInstant()
.atZone(ZoneOffset.ofHours(2)) // Israel Standard Time, but +02:00 all year, so not Asia/Jerusalem
.withZoneSameLocal(ZoneId.of("Asia/Kolkata"))
.withZoneSameInstant(ZoneOffset.UTC);
System.out.println("UTC time: " + correctedDateTime);
Example output assuming that rometools started out from parsing Sat, 28 Mar 2020 13:42:38 IST
:
Incorrect date from rometools: Sat Mar 28 11:42:38 UTC 2020
UTC time: 2020-03-28T08:12:38Z
Now you’ve got the difference of 5 h 30 min between the 13:42:38 in the RSS string and the 08:12:38 printed. Please note that if the published date in the RSS feeds comes in some other time zone, the Date
will probably be correct and our “correction” make it faulty. So it’s a fragile approach too.
Original answer
The first answer is: Do not rely on the default time zone of your JVM. Specify explicit time zone for your date and time operations.
There’s a tip that goes along: Use java.time, the modern Java date and time API. It is so much nicer to work with than the old classes Date
, TimeZone
and friends. These classes are not only old, they are generally poorly designed and they are long outdated. In addition, java.time generally makes it a lot more natural to provide an explicit time zone for your date and time operations. For example:
ZonedDateTime istTime = ZonedDateTime.of(
2020, 3, 27, 12, 34, 56, 123456000, ZoneId.of("Asia/Kolkata"));
System.out.println("IST time: " + istTime);
ZonedDateTime utcTIme = istTime.withZoneSameInstant(ZoneOffset.UTC);
System.out.println("UTC time: " + utcTIme);
Output is:
IST time: 2020-03-27T12:34:56.123456+05:30[Asia/Kolkata]
UTC time: 2020-03-27T07:04:56.123456Z
The difference is 5 hours 30 minutes, as you said it should. The code will give the same output regardless of the default time zone of your JVM.
Edit: If you’ve got a java.util.Date
and you want it printed in UTC no matter the time zone setting of your JVM:
OffsetDateTime utcTime = yourJavaUtilDate.toInstant().atOffset(ZoneOffset.UTC);
System.out.println("UTC time: " + utcTime);
UTC time: 2020-03-28T10:11:12.345Z
A different time zone for each thread? ThreadLocal
You can have a separate time zone for each thread. What you cannot have is a default time zone per thread. The default time zone of your JVM is exactly that: of your JVM. So if you change it, the change has effect for all threads in the JVM.
If you want, each thread can keep a time zone as a ThreadLocal
. It will be the resposibility of the thread to use the ThreadLocal
and not the JVM’s default time zone.
public class SetDifferentTimeZonesForThreads {
public static void main(String[] args) {
ZonedDateTime zdt = ZonedDateTime.of(
2020, 3, 27, 23, 30, 9, 0, ZoneId.of("Asia/Kolkata"));
Thread tUtc = new MyThread(zdt, "Etc/UTC");
Thread tIst = new MyThread(zdt, "Asia/Kolkata");
tUtc.start();
tIst.start();
}
}
class MyThread extends Thread {
private ZonedDateTime zdtToConvert;
private ThreadLocal<ZoneId> threadTimeZone;
public MyThread(ZonedDateTime zdt, String zoneIdString) {
zdtToConvert = zdt;
threadTimeZone = ThreadLocal.withInitial(() -> ZoneId.of(zoneIdString));
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
ZoneId zone = threadTimeZone.get();
System.out.format("In %-12s: %s%n", zone, zdtToConvert.withZoneSameInstant(zone));
}
}
}
Example output:
In Asia/Kolkata: 2020-03-27T23:30:09+05:30[Asia/Kolkata]
In Asia/Kolkata: 2020-03-27T23:30:09+05:30[Asia/Kolkata]
In Etc/UTC : 2020-03-27T18:00:09Z[Etc/UTC]
In Asia/Kolkata: 2020-03-27T23:30:09+05:30[Asia/Kolkata]
In Etc/UTC : 2020-03-27T18:00:09Z[Etc/UTC]
In Asia/Kolkata: 2020-03-27T23:30:09+05:30[Asia/Kolkata]
In Asia/Kolkata: 2020-03-27T23:30:09+05:30[Asia/Kolkata]
In Etc/UTC : 2020-03-27T18:00:09Z[Etc/UTC]
In Etc/UTC : 2020-03-27T18:00:09Z[Etc/UTC]
In Etc/UTC : 2020-03-27T18:00:09Z[Etc/UTC]
Links