Date
is timezone agnostic in Java. It always takes UTC (by default and always). Therefore, Date
or Timestamp
itself is not the cause but when Date
/ Timestamp
is passed through a JDBC driver to a database, it interprets date / time according to the JVM time zone which defaults to the system time zone in turn (the native operating system zone).
Therefore, unless the MySQL JDBC driver was explicitly forced to use the UTC zone or JVM itself is set to use that zone, it would not store Date
/ Timestamp
into the target database using UTC even though MySQL itself were to be configured to use UTC using default_time_zone='+00:00'
in my.ini
or my.cnf
in the [mysqld]
section. Some databases like Oracle may support time stamp with time zone and it may be an exception which I am not familiar with (untested as I do not have that environment at present).
void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException
Sets the designated parameter to the given
java.sql.Timestamp
value, using the given Calendar object. The driver uses the Calendar object to construct an SQLTIMESTAMP
value, which the driver then sends to the database. With a Calendar object, the driver can calculate the timestamp taking into account a custom timezone. If noCalendar
object is specified, the driver uses the default timezone, which is that of the virtual machine running the application.
The same thing is also mentioned for other related getter and setter methods handling date-time in the java.sql.PreparedStatement
class.
This can further be clarified by checking the invocation of setTimestampInternal()
method of the MySQL JDBC driver implementation.
See the following two calls to the setTimestampInternal()
method from within the two overloaded versions of the setTimestamp()
method.
/** * Set a parameter to a java.sql.Timestamp value. The driver converts this * to a SQL TIMESTAMP value when it sends it to the database. * * @param parameterIndex the first parameter is 1... * @param x the parameter value * * @throws SQLException if a database access error occurs */ public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { setTimestampInternal(parameterIndex, x, this.connection.getDefaultTimeZone()); } /** * Set a parameter to a java.sql.Timestamp value. The driver converts this * to a SQL TIMESTAMP value when it sends it to the database. * * @param parameterIndex the first parameter is 1, the second is 2, ... * @param x the parameter value * @param cal the calendar specifying the timezone to use * * @throws SQLException if a database-access error occurs. */ public void setTimestamp(int parameterIndex, java.sql.Timestamp x,Calendar cal) throws SQLException { setTimestampInternal(parameterIndex, x, cal.getTimeZone()); }
So, when no Calendar
instance is specified with the PreparedStatement#setTimestamp()
method, the default timezone will be used (this.connection.getDefaultTimeZone()
) or the specified timezone with the supplied Calendar
instance will be used (cal.getTimeZone()
).
Therefore, just pass an instance of java.util.Calendar
or its subclass java.util.GregorianCalendar
to PreparedStatement#setTimestamp()
with an appropriate timezone of your interest (UTC which we are interested in).
Timestamp timestamp = new Timestamp(new java.util.Date().getTime());
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
preparedStatement.setTimestamp(1, timestamp, calendar);
The specified timezone will be used to generate a string representation of the Timestamp
being supplied before passing it to the underlying database.
If you happened to deal with an ORM framework like Hibernate, EclipseLink along with creating a connection pool in an application server / Servlet container using an appropriate datasource, then refer to this answer which this answer is based on and is directly copied from.