[java] Is java.sql.Timestamp timezone specific?

I have to store UTC dateTime in DB.
I have converted the dateTime given in specific timezone to UTC. for that I followed the below code.
My input dateTime is "20121225 10:00:00 Z" timezone is "Asia/Calcutta"
My Server/DB(oracle) is running in the same timezone(IST) "Asia/Calcutta"

Get the Date object in this specific Timezone

        String date = "20121225 10:00:00 Z";
        String timeZoneId = "Asia/Calcutta";
        TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);

        DateFormat dateFormatLocal = new SimpleDateFormat("yyyyMMdd HH:mm:ss z");
                    //This date object is given time and given timezone
        java.util.Date parsedDate = dateFormatLocal.parse(date + " "  
                         + timeZone.getDisplayName(false, TimeZone.SHORT));

        if (timeZone.inDaylightTime(parsedDate)) {
            // We need to re-parse because we don't know if the date
            // is DST until it is parsed...
            parsedDate = dateFormatLocal.parse(date + " "
                    + timeZone.getDisplayName(true, TimeZone.SHORT));
        }

       //assigning to the java.sql.TimeStamp instace variable
        obj.setTsSchedStartTime(new java.sql.Timestamp(parsedDate.getTime()));

Store into DB

        if (tsSchedStartTime != null) {
            stmt.setTimestamp(11, tsSchedStartTime);
        } else {
            stmt.setNull(11, java.sql.Types.DATE);
        }

OUTPUT

DB (oracle) has stored the same given dateTime: "20121225 10:00:00 not in UTC.

I have confirmed from the below sql.

     select to_char(sched_start_time, 'yyyy/mm/dd hh24:mi:ss') from myTable

My DB server also running on the same timezone "Asia/Calcutta"

It gives me the below appearances

  1. Date.getTime() is not in UTC
  2. Or Timestamp is has timezone impact while storing into DB What am I doing wrong here?

One more question:

Will timeStamp.toString() print in local timezone like java.util.date does? Not UTC?

This question is related to java oracle date datetime jdbc

The answer is


You can use the below method to store the timestamp in database specific to your desired zone/zone Id.

ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Calcutta")) ;
Timestamp timestamp = Timestamp.valueOf(zdt.toLocalDateTime());

A common mistake people do is use LocaleDateTime to get the timestamp of that instant which discards any information specif to your zone even if you try to convert it later. It does not understand the Zone.

Please note Timestamp is of the class java.sql.Timestamp.


The answer is that java.sql.Timestamp is a mess and should be avoided. Use java.time.LocalDateTime instead.

So why is it a mess? From the java.sql.Timestamp JavaDoc, a java.sql.Timestamp is a "thin wrapper around java.util.Date that allows the JDBC API to identify this as an SQL TIMESTAMP value". From the java.util.Date JavaDoc, "the Date class is intended to reflect coordinated universal time (UTC)". From the ISO SQL spec a TIMESTAMP WITHOUT TIME ZONE "is a data type that is datetime without time zone". TIMESTAMP is a short name for TIMESTAMP WITHOUT TIME ZONE. So a java.sql.Timestamp "reflects" UTC while SQL TIMESTAMP is "without time zone".

Because java.sql.Timestamp reflects UTC its methods apply conversions. This causes no end of confusion. From the SQL perspective it makes no sense to convert a SQL TIMESTAMP value to some other time zone as a TIMESTAMP has no time zone to convert from. What does it mean to convert 42 to Fahrenheit? It means nothing because 42 does not have temperature units. It's just a bare number. Similarly you can't convert a TIMESTAMP of 2020-07-22T10:38:00 to Americas/Los Angeles because 2020-07-22T10:30:00 is not in any time zone. It's not in UTC or GMT or anything else. It's a bare date time.

java.time.LocalDateTime is also a bare date time. It does not have a time zone, exactly like SQL TIMESTAMP. None of its methods apply any kind of time zone conversion which makes its behavior much easier to predict and understand. So don't use java.sql.Timestamp. Use java.time.LocalDateTime.

LocalDateTime ldt = rs.getObject(col, LocalDateTime.class);
ps.setObject(param, ldt, JDBCType.TIMESTAMP);

It is specific from your driver. You need to supply a parameter in your Java program to tell it the time zone you want to use.

java -Duser.timezone="America/New_York" GetCurrentDateTimeZone

Further this:

to_char(new_time(sched_start_time, 'CURRENT_TIMEZONE', 'NEW_TIMEZONE'), 'MM/DD/YY HH:MI AM')

May also be of value in handling the conversion properly. Taken from here


I think the correct answer should be java.sql.Timestamp is NOT timezone specific. Timestamp is a composite of java.util.Date and a separate nanoseconds value. There is no timezone information in this class. Thus just as Date this class simply holds the number of milliseconds since January 1, 1970, 00:00:00 GMT + nanos.

In PreparedStatement.setTimestamp(int parameterIndex, Timestamp x, Calendar cal) Calendar is used by the driver to change the default timezone. But Timestamp still holds milliseconds in GMT.

API is unclear about how exactly JDBC driver is supposed to use Calendar. Providers seem to feel free about how to interpret it, e.g. last time I worked with MySQL 5.5 Calendar the driver simply ignored Calendar in both PreparedStatement.setTimestamp and ResultSet.getTimestamp.


For Mysql, we have a limitation. In the driver Mysql doc, we have :

The following are some known issues and limitations for MySQL Connector/J: When Connector/J retrieves timestamps for a daylight saving time (DST) switch day using the getTimeStamp() method on the result set, some of the returned values might be wrong. The errors can be avoided by using the following connection options when connecting to a database:

useTimezone=true
useLegacyDatetimeCode=false
serverTimezone=UTC

So, when we do not use this parameters and we call setTimestamp or getTimestamp with calendar or without calendar, we have the timestamp in the jvm timezone.

Example :

The jvm timezone is GMT+2. In the database, we have a timestamp : 1461100256 = 19/04/16 21:10:56,000000000 GMT

Properties props = new Properties();
props.setProperty("user", "root");
props.setProperty("password", "");
props.setProperty("useTimezone", "true");
props.setProperty("useLegacyDatetimeCode", "false");
props.setProperty("serverTimezone", "UTC");
Connection con = DriverManager.getConnection(conString, props);
......
Calendar nowGMT = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Calendar nowGMTPlus4 = Calendar.getInstance(TimeZone.getTimeZone("GMT+4"));
......
rs.getTimestamp("timestampColumn");//Oracle driver convert date to jvm timezone and Mysql convert date to GMT (specified in the parameter)
rs.getTimestamp("timestampColumn", nowGMT);//convert date to GMT 
rs.getTimestamp("timestampColumn", nowGMTPlus4);//convert date to GMT+4 timezone

The first method returns : 1461100256000 = 19/04/2016 - 21:10:56 GMT

The second method returns : 1461100256000 = 19/04/2016 - 21:10:56 GMT

The third method returns : 1461085856000 = 19/04/2016 - 17:10:56 GMT

Instead of Oracle, when we use the same calls, we have :

The first method returns : 1461093056000 = 19/04/2016 - 19:10:56 GMT

The second method returns : 1461100256000 = 19/04/2016 - 21:10:56 GMT

The third method returns : 1461085856000 = 19/04/2016 - 17:10:56 GMT

NB : It is not necessary to specify the parameters for Oracle.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to oracle

concat yesterdays date with a specific time ORA-28001: The password has expired how to modify the size of a column How to create a blank/empty column with SELECT query in oracle? Find the number of employees in each department - SQL Oracle Query to display all tablespaces in a database and datafiles When or Why to use a "SET DEFINE OFF" in Oracle Database How to insert date values into table error: ORA-65096: invalid common user or role name in oracle In Oracle SQL: How do you insert the current date + time into a table?

Examples related to date

How do I format {{$timestamp}} as MM/DD/YYYY in Postman? iOS Swift - Get the Current Local Time and Date Timestamp Typescript Date Type? how to convert current date to YYYY-MM-DD format with angular 2 SQL Server date format yyyymmdd Date to milliseconds and back to date in Swift Check if date is a valid one change the date format in laravel view page Moment js get first and last day of current month How can I convert a date into an integer?

Examples related to datetime

Comparing two joda DateTime instances How to format DateTime in Flutter , How to get current time in flutter? How do I convert 2018-04-10T04:00:00.000Z string to DateTime? How to get current local date and time in Kotlin Converting unix time into date-time via excel Convert python datetime to timestamp in milliseconds SQL Server date format yyyymmdd Laravel Carbon subtract days from current date Check if date is a valid one Why is ZoneOffset.UTC != ZoneId.of("UTC")?

Examples related to jdbc

Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver' Hibernate Error executing DDL via JDBC Statement Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] MySQL JDBC Driver 5.1.33 - Time Zone Issue Spring-Boot: How do I set JDBC pool properties like maximum number of connections? Where can I download mysql jdbc jar from? Print the data in ResultSet along with column names How to set up datasource with Spring for HikariCP? java.lang.ClassNotFoundException: sun.jdbc.odbc.JdbcOdbcDriver Exception occurring. Why? java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/dbname