I used a new Date() object to fill a field in a MySQL DB, but the actual value stored in that field is in my local timezone.
How can I configure MySQL to store it in
I had the same problem, and it took me nearly a day to track down. I'm storing DateTime columns in MySQL. The RDS instance, running in Amazon's Cloud, is correctly set to have a UTC timestamp by default.
The Buggy Code is:
String startTime = "2013-02-01T04:00:00.000Z";
DateTime dt = ISODateTimeFormat.dateTimeParser().parseDateTime(startTime);
PreparedStatement stmt = connection.prepareStatement(insertStatementTemplate);
Timestamp ts = new Timestamp(dt.getMillis());
stmt.setTimestamp(1, ts, Calendar.getInstance(TimeZone.getTimeZone("UTC")));
In the code above, the ".setTimestamp" call would NOT take the date as a UTC date!
After hours of investigating, this turns out to be a known bug in the Java / MySQL Driver. The call to setTimestamp listerally just ignores the Calendar parameter.
To fix this add the "useLegacyDatetimeCode=false" to your database URI.
private final static String DatabaseName =
"jdbc:mysql://foo/?useLegacyDatetimeCode=false";
As soon as i did that, the date stored in the MySQL database was in proper UTC form, rather than in the timezone of my local workstation.
The short answer is:
when getting/setting dates or timestamps with JDBC, always use the Calendar parameter, set to UTC:
resultset.getTimestamp("my_date", Calendar.getInstance(TimeZone.getTimeZone("UTC")));
The long answer is this:
When dealing with dates and timezones in any database and with any client code, I usually recommend the following policy:
Configure your database to use UTC timezone, instead of using the server's local timezone (unless it is UTC of course).
How to do so depends on your database server. Instructions for MySQL can be found here: http://dev.mysql.com/doc/refman/5.0/en/time-zone-support.html. Basically you need to write this in my.cnf: default-time-zone=utc
This way you can host your database servers anywhere, change your hosting location easily, and more generally manipulate dates on your servers without any ambiguity.
Inside your application code, always use UTC dates, except when displaying dates to your users.
Timestamp myDate = resultSet.getTimestamp("my_date", Calendar.getInstance(TimeZone.getTimeZone("UTC")));
Synchronize your servers or only rely on the database server's time
If you have your Web server on one server (or more) and your database server on some other server, then I strongly recommend you synchronize their clocks with NTP.
OR, only rely on one server to tell you what time it is. Usually, the database server is the best one to ask for time. In other words, avoid code such as this:
preparedStatement = connection.prepareStatement("UPDATE my_table SET my_time = ? WHERE [...]");
java.util.Date now = new java.util.Date(); // local time! :-(
preparedStatement.setTimestamp(1, new Timestamp(now.getTime()));
int result = preparedStatement.execute();
preparedStatement = connection.prepareStatement("UPDATE my_table SET my_time = NOW() WHERE [...]");
int result = preparedStatement.execute();
Hope this helps! :-)
A java Date is timezone agnostic. It ALWAYS represents a date in GMD(UTC) in milliseconds from the Epoch.
The ONLY time that a timezone is relevant is when you are emitting a date as a string or parsing a data string into a date object.
Well, if we're talking about using PreparedStatement
s, there's a form of setDate where you can pass in a Calendar set to a particular time zone.
For instance, if you have a PreparedStatement named stmt, a Date named date, and assuming the date is the second parameter:
stmt.setDate(2, date, Calendar.getInstance(TimeZone.getTimeZone("GMT")));
The best part is, even if GMT is an invalid time zone name, it still returns the GMT time zone because of the default behavior of getTimeZone.
MiniQuark gave some good answers for databases in general, but there are some MySql specific quirks to consider...
Configure your database to use UTC timezone
That actually won't be enough to fix the problem. If you pass a java.util.Date to MySql as the OP was asking, the MySql driver will change the value to make it look like the same local time in the database's time zone.
Example: Your database if configured to UTC. Your application is EST. You pass a java.util.Date object for 5:00 (EST). The database will convert it to 5:00 UTC and store it. Awesome.
You'd have to adjust the time before you pass the data to "undo" this automatic adjustment. Something like...
long originalTime = originalDate.getTime();
Date newDate = new Date(originalTime - TimeZone.getDefault().getOffset(originalTime));
ps.setDate(1, newDate);
Reading the data back out requires a similar conversion..
long dbTime = rs.getTimestamp(1).getTime();
Date originalDate = new Date(dbTime + TimeZone.getDefault().getOffset(dbTime));
Here's another fun quirk...
In Java, when reading from the database, always use: Timestamp myDate = resultSet.getTimestamp("my_date", Calendar.getInstance(TimeZone.getTimeZone("UTC")));
MySql actually ignores that Calendar parameter. This returns the same value regardless of what calendar you pass it.