Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Time from one time zone to another using Java 8 Time

Tags:

java

timezone

I am trying to convert Date with GMT +5:30 to EST with java 8 ZonedDateTime.

String inputDate = "2015/04/30 13:00";
DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm", Locale.US);
LocalDateTime local = LocalDateTime.parse(inputDate, sourceFormatter);
// local : 2015-04-30T13:00
//Combining this local date-time with a time-zone to create a ZonedDateTime. 
ZonedDateTime zoned = local.atZone(TimeZone.getTimeZone("GMT+5:30").toZoneId());
// zoned : 2015-04-30T13:00+05:30[GMT+05:30]
ZonedDateTime zonedUS = zoned.withZoneSameInstant(TimeZone.getTimeZone("GMT-5:00").toZoneId());
// zonedUS : 2015-04-30T02:30-05:00[GMT-05:00]

I am expecting 3:30 AM EST but what I am getting is 2:30 AM EST as 1 PM IST= 3:30AM EST. What am I missing?

like image 380
Zeeshan Avatar asked Apr 30 '15 08:04

Zeeshan


2 Answers

It seems that whatever service you found was being over-helpful in interpreting what you meant and assumed North American Eastern Daylight Time (EDT) when you specified EST (Eastern Standard Time). Most, not all of the places using EST as standard time are using daylight saving time and hence were on EDT or offset UTC-04:00 on the date you use, April 30, 2015.

If it makes sense in your situation, you should always prefer to give time zone in the region/city format, as Asia/Kolkata and America/New_York. If you intended Eastern Time as in New York or Montréal, one may say that your “time zone” of GMT-5:00 was wrong and the cause of your unexpected result.

So your code becomes for example:

    String inputDate = "2015/04/30 13:00";
    DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm", Locale.US);
    LocalDateTime local = LocalDateTime.parse(inputDate, sourceFormatter);
    // local : 2015-04-30T13:00
    //Combining this local date-time with a time-zone to create a ZonedDateTime. 
    ZonedDateTime zoned = local.atZone(ZoneId.of("Asia/Kolkata"));
    // zoned : 2015-04-30T13:00+05:30[Asia/Kolkata]
    ZonedDateTime zonedUS = zoned.withZoneSameInstant(ZoneId.of("America/Montreal"));
    // zonedUS : 2015-04-30T03:30-04:00[America/Montreal]

I have made one other change: When using the modern classes from java.time, there is no point in also using the outdated TimeZone class, so I have taken that out. The code is slightly simpler, and more importantly, ZoneId.of(String) includes validation of your time zone string so you will discover any spelling error in the time zone name (like when I just happened to type a ( instead of the / in Asia/Kolkata — such happens all the time).

Most of the above has already been said in comments by Jon Skeet and others. I thought it deserved to go into an answer so it’s plain to see that the question has been answered.

like image 191
Ole V.V. Avatar answered Sep 18 '22 01:09

Ole V.V.


Though the question is old, felt like I could add more to the accepted answer.

A ZonedDateTime is different from an OffsetDateTime.

I would prefer to use ZonedDateTime when I'm getting a time for a specific location like "Asia/Kolkata", "Asia/Shanghai", "US/Pacific" (this time zone will change depending on the day of the year because of Daylight savings).

To illustrate with an example,

var pacific = ZonedDateTime.of(2020,11,01,1,59,0,0,ZoneId.of("US/Pacific"))
var afterAnHour = pacific.plusHours(1)

This will give me a time of

2020-November-01 01:59:00.000 AM -07:00[US/Pacific]

And if i add an hour to it, it will give me a time of

2020-November-01 01:59:00.000 AM -08:00[US/Pacific]

You can see that the hour component is same even after adding an hour to the time. This is because the daylight savings time has kicked in and the time zone is shifted from -07:00 to -08:00.

Now if i use an OffsetDateTime look what happens.

var offsetNow = OffsetDateTime.of(2020,11,01,1,59,0,0,ZoneOffset.of("-07:00"))
var offsetAfterAnHour = offsetNow.plusHours(1)

The offsetNow will be,

2020-November-01 01:59:00.000 -07:00

And adding an hour to it will be,

2020-November-01 02:59:00.000 -07:00

you can see that the hour component has become 2 after adding an hour.

The key point is a ZonedDateTime uses ZoneRules to calculate important properties like Daylight savings time so that it can adjust the time zone accordingly.

While the OffsetDateTime will not change the zone offset for anything.

like image 36
Thirumalai Parthasarathi Avatar answered Sep 20 '22 01:09

Thirumalai Parthasarathi