joda-time and Hibernate - Date gets not stored in UTC - java

I'm using DateTime in order to store timestamps on my server in UTC-Time:
// #Entity ..
#NotNull
#Column(name="DATE")
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime")
private DateTime date;
During the server boot up I'm doing this:
DateTimeZone.setDefault(DateTimeZone.UTC);
to make sure that new DateTime() will always be in UTC-Time and this is how I prepare a date to get stored:
DateTime utc = new DateTime();
utc = utc.dayOfMonth().roundFloorCopy();
DateTime thisMonday = utc.withDayOfWeek(DateTimeConstants.MONDAY);
DateTime thisTuesday = thisMonday.plusDays(1);
If I'm debugging this I see e.g.
2015-08-31 00:00:00 and 2015-09-01 00:00:00
but as I look into the database I see that
2015-08-31 02:00:00 and 2015-09-01 02:00:00
got stored there. It's +2h which is my local UTC offset (Berlin/Vienna).
Why is this happening and how can I make sure that my server stores all times in UTC?

You are using Jadira for converting JodaTime types to SQL date/time types. Use these JPA/Hibernate properties to tell Jadira what time zone should be applied when sending data to the DB
<properties>
<property name="jadira.usertype.javaZone" value="UTC" /> <!-- or "jvm" to use your default JVM TZ, explicit Europe/Berlin or +02:00 etc. -->
<property name="jadira.usertype.databaseZone" value="UTC" /> <!-- or "jvm" to use your default JVM TZ or +02:00 etc. But you'd better not use an explicit TZ with a DST change -->
</properties>
See Jadira User Guide for details.
Other thing is that maybe your DB is using your connection information to display you the timestamps in your time zone? That depends on which DB it is and which tool you use to connect. SQL Developer (for Oracle DB) is aware of your computer's TZ and sets the connection TZ to that.

Related

Oracle session timezone: Can Oracle DB session convert java.sql.Date to correct timezone?

We have an audit table( Columns/Types: ID/Number,.. Audited_Date/Date) which logs audit entries using prepared statements. Until now, for different contexts we set the database session timezone for the connection, after which we were using the CURRENT_DATE attribute for the audited_date column. THIS MEANT THAT THE DATE INSERTED INTO THE COLUMN IS IN THE TIMEZONE OF THE CONNECTION WHICH IS IMPORTANT.
Now, we have a new requirement to add different dates based on the supplied timestamps for the audit logs. Similar to the previous approach where the auditing engine didn't have to worry about the timezone, is there a way to set the date for the column, WITHOUT having to do something like this:
TimeZone timeZone = TimeZone.getTimeZone(timezone);
calendar.setTimeZone(timeZone);
preparedStatement.setDate(4, new java.sql.Date(userTimestampMillis), calendar);
I would really like NOT to do this because the timezone attribute is decided based on multiple attributes like system environments, and other parameters. The application uses ALTER SESSION SET TIME_ZONE="CONTEXT_TIMEZONE" in a global scope of the application where connections are fetched from.
Is there any way to let the DB session handle the timezone conversion?
These two approaches fail to convert the the timestamp to the DB session timezone. If i'm not wrong, they are using the JVM timezone.
FAIL1.
Timestamp timestamp = new Timestamp(userTimestampMillis);
preparedStatement.setTimestamp(4, timestamp);
FAIL2.
preparedStatement.setObject(4, new java.sql.Date(userTimestampMillis));
Any documentation is greatly appreciated.
DATEs are not time zone aware, so you probably want to work with something in the TIMESTAMP WITH TIME ZONE data type. You say you can correctly set the database session time zone, so you're mostly there. Say you're in Los Angeles and my database session is in Chicago:
alter session set time_zone = 'America/Chicago';
Session altered.
select current_timestamp from dual;
CURRENT_TIMESTAMP
---------------------------------------------
2018-07-27 20:30:28.672000000 AMERICA/CHICAGO
select cast( current_timestamp at time zone 'America/Los_Angeles' as date ) as d from dual;
D
-------------------
2018-07-27 18:30:28
So you basically need to use AT TIME ZONE to convert the TIMESTAMP WITH TIME ZONE into the correct time zone, then use CAST ( ... AS DATE ) to turn that into a DATE, which basically just trucates off the time zone information and doesn't do any conversion.

JDBC Prepared statement Timestamp issues [duplicate]

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
Date.getTime() is not in UTC
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?
Although it is not explicitly specified for setTimestamp(int parameterIndex, Timestamp x) drivers have to follow the rules established by the setTimestamp(int parameterIndex, Timestamp x, Calendar cal) javadoc:
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 SQL TIMESTAMP value, which the driver then sends to the database. With a Calendar object, the driver can calculate the timestamp taking into account a custom time zone. If no Calendar object is specified, the driver uses the default time zone, which is that of the virtual machine running the application.
When you call with setTimestamp(int parameterIndex, Timestamp x) the JDBC driver uses the time zone of the virtual machine to calculate the date and time of the timestamp in that time zone. This date and time is what is stored in the database, and if the database column does not store time zone information, then any information about the zone is lost (which means it is up to the application(s) using the database to use the same time zone consistently or come up with another scheme to discern timezone (ie store in a separate column).
For example: Your local time zone is GMT+2. You store "2012-12-25 10:00:00 UTC". The actual value stored in the database is "2012-12-25 12:00:00". You retrieve it again: you get it back again as "2012-12-25 10:00:00 UTC" (but only if you retrieve it using getTimestamp(..)), but when another application accesses the database in time zone GMT+0, it will retrieve the timestamp as "2012-12-25 12:00:00 UTC".
If you want to store it in a different timezone, then you need to use the setTimestamp(int parameterIndex, Timestamp x, Calendar cal) with a Calendar instance in the required timezone. Just make sure you also use the equivalent getter with the same time zone when retrieving values (if you use a TIMESTAMP without timezone information in your database).
So, assuming you want to store the actual GMT timezone, you need to use:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
stmt.setTimestamp(11, tsSchedStartTime, cal);
With JDBC 4.2 a compliant driver should support java.time.LocalDateTime (and java.time.LocalTime) for TIMESTAMP (and TIME) through get/set/updateObject. The java.time.Local* classes are without time zones, so no conversion needs to be applied (although that might open a new set of problems if your code did assume a specific time zone).
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.
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);
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.
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.
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
If your problem is to get a timestamp of the local zone, you can use this:
Timestamp.from(Instant.now()).toLocalDateTime()

Server time in local time

I have problems with formatting server time. Server is on central time I guess. I need to format following string 2016-08-22T10:29:22 in default zone (Central European Summer Time = GMT+2). I tried with Joda-Time library, I need to get 12:29:22, but I only managed to get same date with +02:00 the end, with code like this:
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss");
DateTime dateTime = formatter.withZone(DateTimeZone.getDefault()).parseDateTime(time);
Output of this code is: 2016-08-22T10:29:22.000+02:00, when I try to dateTime.getHourOfDay(); - I getting 10 again.
Where am I going wrong?
2016-08-22T10:29:22 in default zone (Central European Summer Time = GMT+2).
10:29 in GMT+2 is 10:29 in GMT+2 and 8:29 in GMT, and the 2016-08-22T10:29:22 simply lacks information of timezone. So either make server return timezone or manually add it (i.e. append Z) prior converting.

Getting date in UTC timezone when using Hibernate

I'm using Spring Boot and Hibernate 5 along with MySQL in my project.
How can I get a DateTime from the database in UTC instead of my JVM's timezone?
Is there any configuration to add to the application.properties like jadira.usertype.javaZone for Jadira or some other trick?
Since Hibernate 5.2, you can now use the hibernate.jdbc.time_zone configuration property.
Basically, you can now force the UTC time zone for all TIMESTAMP and TIME columns using the following configuration property:
<property name="hibernate.jdbc.time_zone" value="UTC"/>
To set UTC for all the date fields add following fields to MySQL connection string:
useTimezone=true
serverTimezone=UTC
useLegacyDatetimeCode=false
Example connection string:
jdbc:mysql://hostname/databaseName?useTimezone=true&serverTimezone=UTC&useLegacyDatetimeCode=false
AND
Use jadira user type to set UTC for a particular field
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentDateTime",
parameters = { #Parameter(name = "databaseZone", value = "UTC")})
private DateTime dateTime;
You can set the default timezone of your JVM to UTC when you start your app like
TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC"));
This will make sure the date is always in UTC when it moves around in your application, saved to db, retrieved from db etc.. and can be converted to any desired timezone when required.
You can get the date from the database and convert it to UTC
Date localTime = getDateFromDB();
String format = "yyyy/MM/dd HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date gmtTime = new Date(sdf.format(localTime));
Thank you all for your help, i tried Arul Kumaran and Sanj solutions but it's not working well. So i've chosen to store dates as varchar and use a converter to get it as a ZonedDateTime

Retrieving UTC DATETIME field from MySQL in Java when server timezone is not UTC

I'm trying to write code to interoperate with a third-party-developed database using Java and MySQL. This database has a field that stores a time stamp in a DATETIME field as a UTC date. The timezone for the server on which both the database and client run is set to a non-UTC zone (Europe/London), so by default the timestamp is read back incorrectly as if it were a local time. I'm trying to write code to read it back as UTC.
I have read several similar questions here, but none of them have an answer that works for me:
MySQL - how to store time with correct timezone? (from Java)
How to store a java.util.Date into a MySQL timestamp field in the UTC/GMT timezone?
Date in UTC in mysql
How do I set the time zone of MySQL?
Unfortunately, I cannot change any server settings, so I have tried using the connection's "time_zone" variable to set the database server to use UTC and the optional Calendar parameter to ResultSet.getTimestamp to retrieve the date, but this has no effect on the result. Here is my code:
private static final Calendar UTCCALENDAR = Calendar.getInstance (TimeZone.getTimeZone (ZoneOffset.UTC));
public Date getDate ()
{
try (Connection c = dataSource.getConnection ();
PreparedStatement s = c
.prepareStatement ("select datefield from dbmail_datefield where physmessage_id=?"))
{
fixTimeZone (c);
s.setLong (1, getPhysId ());
try (ResultSet rs = s.executeQuery ())
{
if (!rs.next ()) return null;
return new Date (rs.getTimestamp(1,UTCCALENDAR).getTime ()); // do not use SQL timestamp object, as it fucks up comparisons!
}
}
catch (SQLException e)
{
throw new MailAccessException ("Error accessing dbmail database", e);
}
}
private void fixTimeZone (Connection c)
{
try (Statement s = c.createStatement ())
{
s.executeUpdate ("set time_zone='+00:00'");
}
catch (SQLException e)
{
throw new MailAccessException ("Unable to set SQL connection time zone to UTC", e);
}
}
The database field I'm trying to read has a value stored in it as follows:
mysql> select * from dbmail_datefield where physmessage_id=494539;
+----------------+--------+---------------------+
| physmessage_id | id | datefield |
+----------------+--------+---------------------+
| 494539 | 494520 | 2015-04-16 10:30:30 |
+----------------+--------+---------------------+
But unfortunately, the result comes out as BST not UTC:
java.lang.AssertionError: expected:<Thu Apr 16 11:30:30 BST 2015> but was:<Thu Apr 16 10:30:30 BST 2015>
Your client getDate() code looks correct as far as it goes. I think you also need to get the MySQL Connector/J JDBC driver to treat the dates stored in the table as UTC dates, to avoid a spurious time zone conversion. This means setting the effective server time zone, in addition to the client session time zone and Calendar used for JDBC getTimestamp calls as you're doing.
Take a look at the values you got in your failed assertion, and which direction the error is in:
expected:<Thu Apr 16 11:30:30 BST 2015> but was:<Thu Apr 16 10:30:30 BST 2015>
What you got back was 10:30 BST, which is 9:30 GMT. This is consistent with the database treating that 10:30 in the table as a BST value and spuriously converting it to GMT for you, before you parse it as a GMT date. That's the opposite direction of a GMT value being spuriously converted to BST.
This may be a JDBC-specific issue, because JDBC requires that time times be converted to the local zone. (Where the MySQL C API doesn't, probably because C's classic time types are not zone-aware the way Java's are.) And it needs to know what zone it's converting from, as well. The MySQL TIMESTAMP type is always stored as UTC. But that's not stated for the DATETIME type. I think that implies that MySQL is going to interpret DATETIME column values as being in the server's time zone. Which you mentioned as being set to BST, and that's consistent with the direction of the shift shown in your assertion error message.
The time_zone session variable you set is telling the MySQL server what your client machine's time zone is, but it doesn't affect what the server thinks its own time zone is. That can be overridden with the serverTimezone JDBC connection property. On your connection, set the serverTimezone to UTC, and make sure useLegacyDatetimeCode is off. (And look through the other zone-related properties if that doesn't work.) See if that gets your dates to come through as UTC with the same calendar field values as in the database.
Be aware that this is going to change the interpretation of other DATETIME values in your database: they're all going to look like UTC dates now (in the context of your JDBC connection). Whether that's correct is going to depend on how they were populated initially. While your client code will have the behavior you want, I don't know if this system as a whole can be made to behave fully consistently without setting the server's time zone to UTC at the server level. Basically, if it doesn't have its zone set to UTC, it's not fully configured for the behavior you want, and you're kludging around it.
Maybe you can use JodaTime as follows;
private static final Calendar UTCCALENDAR = Calendar.getInstance (TimeZone.getTimeZone (ZoneOffset .UTC));
public Date getDate ()
{
try (Connection c = dataSource.getConnection ();
PreparedStatement s = c
.prepareStatement ("select datefield from dbmail_datefield where physmessage_id=?"))
{
s.setLong (1, getPhysId ());
try (ResultSet rs = s.executeQuery ())
{
if (!rs.next ()) return null;
DateTime dt = new LocalDateTime(rs.getTimestamp(1,UTCCALENDAR).getTime ()).toDateTime(DateTimeZone.forID("Europe/London"));
return dt.toDate(); }
}
catch (SQLException e)
{
throw new MailAccessException ("Error accessing dbmail database", e);
}
}
EDIT:
java.util.Date is not TimeZone agnostic. The method toDateTime takes care of TimeZone and DST so you don't care about it
The following code:
public static void main(String[] args) {
// 29/March/2015 1:05 UTC
DateTime now = new DateTime(2015, 3,29,1,5,DateTimeZone.UTC);
// Pre DST 29/March/2015 0:30 UTC
DateTime preDst = new DateTime(2015, 3,29,0,30,DateTimeZone.UTC);
System.out.println("1:05 UTC:"+now);
System.out.println("0:30 UTC:"+preDst);
DateTimeZone europeDTZ = DateTimeZone.forID("Europe/London");
DateTime europeLondon = now.toDateTime(europeDTZ);
System.out.println("1:05 UTC as Europe/London:"+europeLondon);
DateTime europeLondonPreDst = preDst.toDateTime(europeDTZ);
System.out.println("0:30 UTC as Europe/London:"+europeLondonPreDst);
}
Will print:
1:05 UTC:2015-03-29T01:05:00.000Z
0:30 UTC:2015-03-29T00:30:00.000Z
1:05 UTC as Europe/London:2015-03-29T02:05:00.000+01:00
0:30 UTC as Europe/London:2015-03-29T00:30:00.000Z
If you can see JodaTime takes care of DST.
Your best bet, in my view, is to tell MySQL to use GMT and handle all local time issues in your application code, not your database. The values in the database would always be GMT, full stop, which is unambiguous. As you say, with daylight savings time (summer time) adjustments, you can end up with the same value in your database for what is, to us humans, two different times.
This also makes the database portable. If you move to North America and start using MySQL set to (say) Central time, all of a sudden the values in your database seem to have moved several hours. I had that issue with a database I inherited which was using the server's local time, when I moved it from the east coast of the U.S. to the west coast, not having thought to check whether MySQL was slaved to the machine's zone...
long t = 1351382400000; // the timestamp in UTC
String insert = "INSERT INTO my_table (timestamp) VALUES (?)";
PreparedStatement stmt = db.prepareStatement(insert);
java.sql.Timestamp date = new Timestamp(t);
stmt.setTimestamp(1, date);
stmt.executeUpdate();
.....
TimeZone timezone = TimeZone.getTimeZone("MyTimeZoneId");
Calendar cal = java.util.Calendar.getInstance(timezone);
String select = "SELECT timestamp FROM my_table";
// some code omitted....
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
java.sql.Timestamp ts = rs.getTimestamp(1);
cal.setTimeInMillis(ts.getTime());
System.out.println("date in db: " + cal.getTime());
}
If you want to use timezone you can read column as UTC.
ZonedDateTime zdt = ZonedDateTime.of(rs.getTimestamp(1).toLocalDateTime(), ZoneOffset.UTC);
Next you can change to whatever timezone you want using:
zdt = zdt.withZoneSameInstant(ZoneId.of(
TARGET_ZONE));
If you want only to read Date and do not care about zones at all use only:
LocalDateTime ldt = rs.getTimestamp(1).toLocalDateTime()
You will obtain LocalDateTime without timezone.
If you have to return java.util.Date use:
Date.from(ldt.atZone(ZoneOffset.UTC).toInstant());
Don't think about converting or adapting time zone. Don't think about the TZ the mysql uses to store your timestamps or anythink like that. Those things are already handled.
There are three things that you must handle: INPUT, OUTPUT and bugs.
INPUT
When a user enters a date (in a form) without an explicit time zone you have to know what TZ did he intend to use. You can use a SimpleDateFormat object with time zone set to solve this. You don't have to convert the input date, you have to 'interpret' it correctly. Once you have a correctly interpreted Date or timestamp you are done with input.
Input is not only user input, includes configuration files too.
OUTPUT
The same here. Forget about what TZ have your Date objects and timestamps have none, they are just milliseconds since epoch. You have to format your dates to the TZ the user expects so he understand them.
Bugs
You may have bugs in your code related to TZ, but libraries may have them too!!
I noticed mysql java driver failed to communicate the client timezone to the server.
This command s.executeUpdate ("set time_zone='+xx:yy'"); is the workaround but you are using it wrong. You have to tell the server with it the TZ the client is using, before both inserting and querying. The variable is stored in the session. Maybe you may automatize it on your connection pool config.
This is needed so the server know what TZ the client need to use to read or write. This is not dependent on server TZ. It does not mean "store this date in UTC", it does mean "this date I am giving to you is UTC" and "Send me result sets in UTC". No matter you are using Date class with it's internal TZ, the driver screws it up, you would need to set that session variable.
By default it assumes client TZ is the same as server TZ so you shouldn't need to worry about it as you said they are the same.

Categories