2
final Timestamp rawDateTime = Timestamp.valueOf("2031-04-25 18:30:00");
final ZoneId zoneId = ZoneId.of("Asia/Calcutta");
final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(
    Instant.ofEpochMilli(rawDateTime.getTime()), zoneId); 
// here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]

final ZonedDateTime zonedDateTime1 = 
ZonedDateTime.of(rawDateTime.toLocalDateTime(), zoneId);
// here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]

But I want to get the converted date time as 2031-04-26 00:00:00+5:30 as my timestamp value is in the UTC Timezone.

Please help.

Tansheet Izhad
  • 103
  • 2
  • 3
  • 10
  • Your code does not compile. You are missing a semi colon on the first line and "Asia/Calcutta" is not a `ZoneId`, it's a `String`. Please ensure that your code actually does what you claim it does before posting to Stack Overflow. – Michael Jan 09 '19 at 10:52
  • Since you are using java.time, the modern Java date and time API, you should avoid the `Timestamp` class, it belongs with the old and outdated classes that have now been replaced. Use `Instant` instead (or in special cases `LocalDateTime`). – Ole V.V. Jan 09 '19 at 10:53
  • 1
    Possible duplicate of [Java: How do you convert a UTC timestamp to local time?](https://stackoverflow.com/questions/12487125/java-how-do-you-convert-a-utc-timestamp-to-local-time) and many other questions. Please search and find. – Ole V.V. Jan 09 '19 at 10:57

3 Answers3

10

First, you should not use Timestamp. You can use DateTimeFormatter to parse into a LocalDateTime.

You then zone that LocalDateTime to UTC before converting to the Calcutta zone with ZonedDateTime.withZoneSameInstant.

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .append(DateTimeFormatter.ISO_LOCAL_DATE)
    .appendLiteral(' ')
    .append(DateTimeFormatter.ISO_LOCAL_TIME)
    .toFormatter();

LocalDateTime localDateTime = LocalDateTime.parse("2031-04-25 18:30:00", formatter);
ZoneId calcuttaZone = ZoneId.of("Asia/Calcutta");
ZonedDateTime calcuttaZonedDateTime = localDateTime.atZone(ZoneOffset.UTC)
    .withZoneSameInstant(calcuttaZone);
Michael
  • 41,989
  • 11
  • 82
  • 128
  • DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[XXX]").format(calcuttaZonedDateTime ) should give the formatted date - ie, 2031-04-26 00:00:00+5:30 in this case. – JineshEP Jan 11 '19 at 12:24
3

Using DateTimeFormatter to format ZonedDateTime:

    final Timestamp rawDateTime = Timestamp.valueOf("2031-04-25 18:30:00");
    final ZoneId zoneId = ZoneId.of("Asia/Calcutta");
    final ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(
            Instant.ofEpochMilli(rawDateTime.getTime()), zoneId);
    // here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[XXX]");
    System.out.println(formatter.format(zonedDateTime));

    final ZonedDateTime zonedDateTime1 =
            ZonedDateTime.of(rawDateTime.toLocalDateTime(), zoneId);
    // here we are getting output as 2031-04-25T18:30+05:30[Asia/Calcutta]
    System.out.println(formatter.format(zonedDateTime1));

The output:

2031-04-25 23:00:00+05:30
2031-04-25 18:30:00+05:30

Edited: according to the comment from @Ole V.V. - The local date time has to be converted to the zonedatetime , before applying the format :

 final Timestamp rawDateTime = Timestamp.valueOf("2031-04-25 18:30:00");
        LocalDateTime ldt = rawDateTime.toLocalDateTime();
        final ZoneId zoneId = ZoneId.of("Asia/Calcutta");
        ZonedDateTime zdt = ldt.atZone(ZoneId.of("UTC"))
                .withZoneSameInstant(zoneId);


        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[XXX]");
        System.out.println(formatter.format(zdt));

This will give the output:

2031-04-26 00:00:00+5:30
JineshEP
  • 738
  • 4
  • 7
  • 1
    Right, the localdate time needs to be converted to zone date time at the requested zone. Have edited, thanks. It should give the required result. – JineshEP Jan 09 '19 at 14:51
2

Instead of ZonedDateTime with named zones having (supra-)national standards like day-time-savings, use OffsetDateTime.

OffsetDateTime utc = OffsetDateTime.parse("2031-04-25T18:30:00Z");
OffsetDateTime asia = utc.withOffsetSameInstant(ZoneOffset.ofHoursMinutes(5, 30));

The default parsing is for the ISO format.

  • Z means zero, UTC, +0:00.
  • The resulting default formatting is 2031-04-26T00:00+05:30.

After comment of Ole V.V.

The above is especially error prone if summer time is involved, like in Central European Time with varying offsets +1:00 and +2:00.

Instant raw = Instant.parse("2031-04-25T18:30:00Z");
ZonedDateTime zoned = raw.atZone(ZoneId.of("Asia/Calcutta"));
OffsetDateTime offset = OffsetDateTime.from(zoned);
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • 1
    Not really recommended. While `Asia/Calcutta` tells something about why the offset of +05:30 is desired, `ZoneOffset.ofHoursMinutes(5, 30)` doesn’t. And the latter will break if Parliament of India some day decides to move to a whole number of hours from UTC or introduce summer time (DST) (the risk may not be great in this particular case, but generally using the zone ID is the better practice; other zones do change offset more often that you would expect). – Ole V.V. Jan 09 '19 at 12:41
  • @OleV.V. I agree, but an offset was required, and _not_ Asia/Calcutta. For that reason I mentioned the difference, i.e. "national standard" and DST. But OffsetDateTime indeed drops valuable information. The OP wanted an UTC date represented as Indian offset. For a CET with summer time, I would have gone via a ZoneId. – Joop Eggen Jan 09 '19 at 13:50
  • Instant wont parse the string of form '2031-04-25 18:30:00' , a DateTimeFormatter or LocalDate.parse will be required to create an Instant, at first. – JineshEP Jan 11 '19 at 12:23
  • @user1653941 yes. ISO prescribes a `T` instead of a space in front of the _time_ part. For a default parsing. – Joop Eggen Jan 11 '19 at 12:35