10
public static void main(String[] args) {

    LocalDateTime ldt = LocalDateTime.now();

    ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault());

    Instant instant = Instant.from(zdt);

    Timestamp timestamp = Timestamp.from(instant);

    System.out.println(ldt + "\n");

    System.out.println(zdt + "\n");

    System.out.println(instant + "\n");

    System.out.println(timestamp + "\n");
}

And it prints:

2017-05-07T18:13:26.969

2017-05-07T18:13:26.969-04:00[America/New_York]

2017-05-07T22:13:26.969Z

2017-05-07 18:13:26.969

How can I make an SQL Timestamp save with the same time as the Instant? I need to be able to get the Timestamp from anywhere and convert it to whatever time it happens to be in that part of the world. The problem is that it keeps saving as the same time as whatever my system clock happens to be set at.

Skywarp
  • 989
  • 3
  • 15
  • 32
  • This did the job for me when using an oracle `DATE` column that doesn't store the timezone. `Timestamp.valueOf(ZonedDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneOffset.UTC).toLocalDateTime())` – AlikElzin-kilaka Jan 15 '20 at 14:45

2 Answers2

18

You are best to get a Timestamp from a LocalDateTime, rather than from an Instant.

The first step is to take your ZonedDateTime and convert it to GMT:

ZonedDateTime gmt = zdt.withZoneSameInstant(ZoneId.of("GMT"));

Then you can convert it to a Timestamp via a LocalDateTime:

Timestamp timestamp = Timestamp.valueOf(gmt.toLocalDateTime());
Joe C
  • 15,324
  • 8
  • 38
  • 50
  • This helped. The `Instant` was totally deceiving because it would print the current UTC time, but when converted to a `Timestamp`, displayed my local time. So when it saved to the remote db, it would be whatever time it is where I'm at. I get that a `Timestamp` has no time zone and that an `Instant` is an offset from an epoch, but it's totally useless if the `Timestamp` records the current time as the local time instead of the current UTC time. It was a difficult question to pose because everyone just automatically assumed that I thought it was supposed to display a time zone. – Skywarp May 07 '17 at 22:42
  • This seemed to help me get around the Timestamp local time conversion problem as well. I don't know if this is overdoing the conversion, but the following chain converts a stored long that was in UTC and converts it to a Timestamp by way of LDT instead of from an Instant: `Timestamp.valueOf( LocalDateTime.ofEpochSecond(longEpochVal, 0, ZoneOffset.UTC))` – Robert Casey Nov 07 '17 at 17:15
  • It might be worth noting here that Timestamp itself is kind of timezone agnostic..? for Example if you print out the fastTime of Timestamp you get milliseconds in UTC, but if you use .toString it is the toString method that converts it to UTC+X... Instant.toString() returns the time in UTC timezone. On the other hand, Timezone.toString() returns the time in the local machine timezone. See here: https://www.baeldung.com/java-time-instant-to-java-sql-timestamp – niid Mar 18 '20 at 10:26
  • `LocaleDateTime` discards any info specific to the zone. It will always return the value of local zone. `zdt` will have the local value and not the GMT. So adding any zone offset for conversion will not make any changes. I tried doing this. – Ayush Kumar Jul 24 '20 at 14:44
  • @Skywarp I agree, it's pretty dumb that Timestamp is to be interpreted zone specific, but holds no zone information. As thus it should always return UTC. – Splitframe Mar 28 '22 at 14:39
-1

You might need to use the specific overload of setTimestamp that takes a Calendar object if you want to represent a "TIMESTAMP WITH TIME ZONE" value.

David A
  • 344
  • 1
  • 4