简体   繁体   中英

How to convert ISO 8601 formatted DateTime to another time zone in Java?

My current date:
Date utc: 2018-06-06T16:30:00Z (ISO 8601 in UTC)
OR
Date iso: 2018-06-06T11:30:00-05:00 (ISO 8601)
OR
Date epoch: 1528302600000 (Epoch/Unix Timestamp)

I wish to convert the above DateTime to some another time zone areas (like GMT+5:30). And I'm not sure which time format I'll receive from above three. So can I've a generic method which can convert above to some another time zone returning java.util.Date in Java 8?

I did Something like this, But it didn't worked out

public Date convertDateToLocalTZ(Date iso8601, ZoneId toZoneId) {
    Date dateTime = null;
    if (iso8601 != null && toZoneId != null) {
        Instant instant = iso8601.toInstant();
        LocalDateTime localDateTime = instant.atZone(toZoneId).toLocalDateTime();
        dateTime = Date.from(localDateTime.atZone(toZoneId).toInstant());
        return dateTime;
    }
    return dateTime;
}

Since question is tagged java-8 use java.time API.


UPDATE : For version 4 of question where 2018-06-06T11:30:00-05:00 was added.

To parse 1528302600000 , you parse it into a long , then use Instant.ofEpochMilli() .

To parse a format like 2018-06-06T11:30:00-05:00 , you can using OffsetDateTime or ZonedDateTime . Both can also parse 2018-06-06T16:30:00Z .

To change the time zone specifically to a particular offset like GMT+5:30 , use ZoneOffset , eg ZoneOffset.of("+05:30") , or ZoneId , eg ZoneId.of("GMT+05:30") .
Note 1: GMT+5:30 is not valid.
Note 2: To change to the time zone of a region, honoring Daylight Savings Time, use eg ZoneId.of("Asia/Kolkata") .

To parse all 3 input formats, and even support the extended format like 2018-06-06T11:30-05:00[America/Chicago] , use ZonedDateTime , with special handling for the epoch number.

public static ZonedDateTime parseToZone(String text, ZoneId zone) {
    if (text.indexOf('-') == -1)
        return Instant.ofEpochMilli(Long.parseLong(text)).atZone(zone);
    return ZonedDateTime.parse(text).withZoneSameInstant(zone);
}

The caller can then decide if only the offset, not the full time zone, should be used, by converting it to OffsetDateTime using toOffsetDateTime() .

Test

ZoneId india = ZoneId.of("Asia/Kolkata");

System.out.println(parseToZone("2018-06-06T16:30:00Z", india));
System.out.println(parseToZone("2018-06-06T11:30:00-05:00", india));
System.out.println(parseToZone("1528302600000", india));

System.out.println(parseToZone("1528302600000", india).toOffsetDateTime());

Output

2018-06-06T22:00+05:30[Asia/Kolkata]
2018-06-06T22:00+05:30[Asia/Kolkata]
2018-06-06T22:00+05:30[Asia/Kolkata]
2018-06-06T22:00+05:30

Original Answer

Use the parse() method with 2018-06-06T16:30:00Z .
Use the ofEpochMilli() method with 1528302600000 .
Then use atZone() to convert to your desired time zone.

Demo

Instant instant1 = Instant.parse("2018-06-06T16:30:00Z");
Instant instant2 = Instant.ofEpochMilli(1528302600000L);

ZoneId india = ZoneId.of("Asia/Kolkata");
ZonedDateTime date1 = instant1.atZone(india);
ZonedDateTime date2 = instant2.atZone(india);

System.out.println(instant1);
System.out.println(instant2);
System.out.println(date1);
System.out.println(date2);

Output

2018-06-06T16:30:00Z
2018-06-06T16:30:00Z
2018-06-06T22:00+05:30[Asia/Kolkata]
2018-06-06T22:00+05:30[Asia/Kolkata]

To print the result in human format, use a DateTimeFormatter .

DateTimeFormatter indiaFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG)
                                                    .withLocale(Locale.forLanguageTag("en-IN"));
DateTimeFormatter hindiFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG)
                                                    .withLocale(Locale.forLanguageTag("hi-IN"));
System.out.println(date1.format(indiaFormatter));
System.out.println(date1.format(hindiFormatter));

Output

6 June 2018 at 10:00:00 PM IST
6 जून 2018 को 10:00:00 अपराह्न IST

In Java 8+, you should use the new java.time API.

Your initial UTC time must be modelized as an Instant. Use DateTimeFormatter to parse from a string like 2018-06-07T22:21:00Z if needed, or get the current Instant with Instant.now .

Then you can use Instant.atZone or Instant.withOffset to convert to a ZonedDateTime resp. OffsetDateTime with the desired time shift. ZonedDateTime helps you get the date/time at a given region/country, while OffsetDateTime makes a purely numerical time shift independent from location and daylight saving time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM