Java 8
Instant inst = LocalDateTime.of(2016, Month.MARCH, 12, 20, 45)
.atZone(ZoneId.of("America/Chicago"))
.toInstant();
System.out.println(inst);
This prints
2016-03-13T02:45:00Z
Today you should not (normally) have a need for a Timestamp
object. The java.sql.Timestamp
class is long outdated. Once we used it for transferring timestamp values with nanosecond precision to and from SQL databases. Today we use the Instant
class for this instead. Instant
is one of the classes of java.time
, the modern Java date and time API (sometimes we use LocalDateTime
from the same API, it depends on your exact requirements and the datatype of your database column).
Neither a Timestamp
nor an Instant
have a time zone in them. Unlike Timestamp
the Instant
always prints in UTC (denoted by the Z
at the end of the above output). As you can see, the above snippet has correctly converted your time of 20:45 CST to 02:45 the next day UTC.
If you do need a timestamp, typically for a legacy API that you cannot change or don’t want to change just now, conversion is easy:
Timestamp ts = Timestamp.from(inst);
System.out.println(ts);
2016-03-12 20:45:00.0
Timestamp.toString
uses the JVM’s time zone setting for generating the string, so you recognize the time we started out from. So the Timestamp
contains the correct point in time. There is no need to convert it in any way. If it gets inserted incorrectly into your database, the problem is with your JDBC driver, your database or somewhere else, and you should prefer to correct it there if you can.
Java 6 and 7
Code very similar to the above will work in Java 7 if you add ThreeTen Backport to your project. This is the backport of the java.time
classes to Java 6 and 7, and I include a link at the bottom (it’s ThreeTen for JSR-310, where the modern API was first described).
Instant inst = LocalDateTime.of(2016, Month.MARCH, 12, 20, 45)
.atZone(ZoneId.of("America/Chicago"))
.toInstant();
Timestamp ts = DateTimeUtils.toSqlTimestamp(inst);
You notice that the only difference from Java 8 is the way we convert the Instant
to a Timestamp
. The result is the same, of course.
I you don’t want a dependency on ThreeTen Backport, there are of course still ways to obtain a Timestamp
. I wouldn’t use the deprecated constructor, as you do in your code, even though it works as long as no one tampers with your JVM’s time zone setting. If you know you want a Timestamp
equal to 02:45 UTC, one option is
Timestamp ts = Timestamp.valueOf("2016-03-12 20:45:00");
It still depends on your JVM’s time zone setting, though.
What went wrong in your code?
As mentioned a Timestamp
hasn’t got a time zone in it, so converting a Timestamp
to UTC does not make sense.
What happens in your code:
- The deprecated
Timestamp
constructor uses your JVM’s time zone setting (America/Chicago, I presume) for constructing a Timestamp
corresponding 12 March 2016 at 8.45 PM in your time zone (the same point in time as 13 March 2:45 AM UTC).
- Your
SimpleDateFormat
correctly formats this into 2016-03-13 02:45:00
(UTC).
Timestamp.valueOf()
too uses America/Chicago time zone. However, on the night between 12 and 13 March summer time (daylight saving time) begins in this time zone. At 2 AM the clock is moved forward to 3. So there is no 2:45 this night. Timestamp
picks 3:45 instead.
Links