1

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;
}
Shaini Sinha
  • 527
  • 6
  • 10
  • 2
    Possible duplicate of [Timezone conversion](https://stackoverflow.com/questions/6567923/timezone-conversion) – John Jun 07 '18 at 19:35
  • Depends on which API you use. Is that `java.util.Date` you're talking about? Do you want to use the new java-8 API or is `SimpleDateFormatter` sufficient? – rustyx Jun 07 '18 at 19:40
  • 2
    @John Not a duplicate, since that duplicate only covers the time zone conversion, not how you do it using the two given values. – Andreas Jun 07 '18 at 20:40
  • @John As Andreas commented, this Question is *not* a duplicate of your linked Question. I imagine this is a duplicate, but I cannot find an original combining the parsing issue with the zone-adjustment issue. – Basil Bourque Jun 07 '18 at 21:47
  • Ok, this question is nuanced, I'd recently investigated it myself and didn't appreciate that distinction (why would anyone want new for newness's sake?). Worst is where researched questions given in a question are unhelpfully regurgitated as duplicate flags. – John Jun 08 '18 at 19:42

2 Answers2

4

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, e.g. ZoneOffset.of("+05:30"), or ZoneId, e.g. 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 e.g. 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
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • Is there any possibility to get the same result in java.util.Date as return type? Or any way to convert ZonedDateTime to java.util.Date? I tried to achieve the same but when I print the date using System.out.println(date); the Date returned is like TimeZone independent and always prints the date in local timezone. – Shaini Sinha Jun 09 '18 at 22:43
  • @ShainiSinha No, because `java.util.Date` is always UTC/GMT and doesn't store a time zone. With the old Date API, it is only the formatter that applies time zone. With the Java Time API, some of the classes can store time zone too. It's one of the things they fixed, and why they created the new API. So, to print a `java.util.Date` in a particular time zone, call [`DateFormat.setTimeZone(TimeZone zone)`](https://docs.oracle.com/javase/8/docs/api/java/text/DateFormat.html#setTimeZone-java.util.TimeZone-) before using the formatter, but the *input* time zone has been lost. Use the new classes!!! – Andreas Jun 09 '18 at 22:46
1

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.

QuentinC
  • 12,311
  • 4
  • 24
  • 37
  • 2
    No need for `DateTimeFormatter` for parsing that string. `Instant`, `OffsetDateTime`, and `ZonedDateTime` can all parse it natively. – Andreas Jun 07 '18 at 20:35
  • 1
    Just a detail, it is `Instant.atOffset` (`java.time` methods beginning with `with` return the same type again, for example `Instant.with()` returns an `Instant`). – Ole V.V. Jun 07 '18 at 21:54