Weird timezone issues with Timestamp.valueOf(String s)

dwfranken at dwfranken at
Fri Feb 9 15:08:45 UTC 2018

Not that I encourage using date/time classes from the packages of either
java.util or java.sql, but sometimes it happens under the hood.


We found a weird issue with timestamps.

In our (PostgreSQL) database we have a column of SQL type TIMESTAMP - no


When JPA fills our entity field with a java.sql.Timestamp value, it is given
an inherent timezone of the system it's running on; in our case it was CET
(UTC +1).

Now this timezone isn't immediately obvious, because if you print it to
system out, it seems to have the correct time. However when you convert it
with .toInstant() the timezone rears its ugly head.


I digged deeper and found Timestamp.valueOf(String s), it does a lot of
magic, but in the end it calls its own deprecated constructor new
Timestamp(int year, int month, int date,  int hour, int minute, int second,
int nano).

That constructor calls the deprecated constructor of java.util.Date(int
year, int month, int date,  int hour, int minute, int second) and that is
the one doing something with the current timezone on the system.

The method Timestamp.valueOf(String s) itself however, is not deprecated and
I find this odd.

More odd is that Timestamp.valueOf(LocalDateTime dateTime) has a
@SuppresWarnings("deprecation") annotation.


Thus I found that Timestamp.valueOf("2017-10-04 00:00:00") on a system
running in CET timezone yields a different result than one running in UTC

Here is some example code where I put the output of the println's in



    Timestamp fromStringCet = Timestamp.valueOf("2017-10-04 00:00:00");

    System.out.println(fromStringCet); // 2017-10-04 00:00:00.0

    System.out.println(fromStringCet.toInstant()); // 2017-10-03T22:00:00Z



    Timestamp fromStringUtc = Timestamp.valueOf("2017-10-04 00:00:00");

    System.out.println(fromStringUtc); // 2017-10-04 00:00:00.0

    System.out.println(fromStringUtc.toInstant()); // 2017-10-04T00:00:00Z


    System.out.println(fromStringCet.equals(fromStringUtc)); // false


    LocalDateTime localDateTime = LocalDateTime.of(2017, 10, 4, 0, 0, 0);



    Timestamp fromLocalDateTimeCet = Timestamp.valueOf(localDateTime);

    System.out.println(fromLocalDateTimeCet.toInstant()); //



    Timestamp fromLocalDateTimeUtc = Timestamp.valueOf(localDateTime);

    System.out.println(fromLocalDateTimeUtc.toInstant()); // 2017-10-04


// false


So what to do?


Some options are:

*	Make Timestamp.valueOf(String s) deprecated?
*	Always use UTC when doing the implicit conversion




Dave Franken


More information about the jdk-dev mailing list