简体   繁体   中英

Can I force Java to ignore timezones?

Short version: Can I force Java to be timezone-ignorant?

Longer version: I have an older, Java 6-based, three-tier system with a Java GUI frontend (running on user PC's), a Java/OSGi middleware server and a Oracle 11g database backend. The two servers are located in the same rack within a cluster. The main entity (an inspection) stored in the database has a Date column which stores the date and time for the instant when the inspection occurred. The date and time are entered as strings in the GUI, and are stored in the DB as follows:

(theInspection.getInspectionDate() returns a java.util.Date object)

inspectionDate = new java.sql.Timestamp(theInspection.getInspectionDate().getTime());
...
statementHandler.openPreparedStatement(C_INSERT_INTO_INSPECTIONS);
...
statementHandler.setTimestamp(4, inspectionDate);

The inspections date and time are then read back to the middleware server to identify and locate raw data files which have the date and time in their filenames. Reading from DB is done as follows:

resultSet.getDate("inspection_date");
if (resultSet.wasNull()) {
    inspection.setInspectionDate(null);
    } else {
        date = new java.util.Date(resultSet.getDate("inspection_date").getTime() 
                    + resultSet.getTime("inspection_date").getTime() + (3600 * 1000L) );
        inspection.setInspectionDate(date);
    }

Now, this ran fine for years in CET/CEST (UTC+1) timezone, but moving it to MSK (UTC+3) broke it. The time gets shifted +2 hours when its stored to DB, and shifted again +2 hours when it is read back. I have established that it is Java that does this, Oracle is timezone-ignorant in this setup.

I am considering changing this so that the middleware server converts to UTC when storing, and back to the local timezone when reading. I know that java.util.Date is deprecated and that there are other ways of representing time and date. However, I am concerned what would happen if the GUI client and the servers are in different timezones, or if servers or data are moved across timezones.

Finally, it would perhaps make most sense to force Java to be timezone-ignorant. Is that at all possible?

Thanks!

You get hit by the fact that Date is using an implied timezone.
A Date is defined as milliseconds since "1970-01-01T00:00:00" UTC. So, the number of ms (for the internal value) will be different if a date(+time) String is being converted to a Date instance with different timezones being applied.

Not specifying an explicit timezone with the String-to-Date conversion and the conversion to a DB value does not imply the values are not subject to being related with a timezone.

As soon as this implied timezone is being changed "silently" without the code knowing, such change is observable as a time "warp".

Such "silent" timezone changes will eg happen at the following occasions (incomplete list!):

  • Sending a Date object instance accross the "wire", from one timezone to a different one
  • parsing a date at a timezone that is not the implied one associated with the value
  • (wrong) assumptions of code on the implicit timezone of a date/time value and trying to apply a false "correction" thereof. (Eg when a timzone-less DB value is getting attributed an implied timezone from the DB that the reading application code tries to adjust to a (different) local timezone as assumed by the application.)

For overcomming that kind of trouble, there are basically two strategies:

  1. Strictly enforcing a unique timezone accross the whole application. (given the implicit semantics of Date using UTC will be a good choice.)
    IN that case, you would immediately convert any value being entered from "outside" to your common application timezone (from known or implied local timezone). And also only convert (internal) date/time values to local timezone for being displayed (as late as possible). Any value "inside" your application (and stored with the DB) will be in application timezone.
    This is invariant against changing timezone of servers and DB and only requires proper detection date I/O locations. You also need to take care of date/time values relating to other external entities (like the filenames you mention). Those values would best be generated according to application timezone in the first place.

  2. You give up trying to get by without notion of timezone and change to using explicit timezones with any date/time value.

The first approach has the benefit of providing consistent values accross different timezones (eg with generated file names using date/time value - that then needs to be used as UTC value).

The second one is easily providing consistent ordering of events from different timezones.

Doing the timezone conversion when storing/reading values from the from DB has the potential risk of misinterpretations on the client that might live in a completely different timezone or change timezone between storing and retrieving such value (as you already suspected).


And to explicit address the question from the subject:

No, as long as you are using java Date class you will always refer to an implicit timezone on conversion from/to String while the internal value is based on UTC .

JDBC provides methods to set timezone during reading or writing date.

For timestamp following are the methods.

ResultSet getTimeStamp
PreparedStatement setTimeStamp

Use these methods with the Calendar instance as constructed below.

Calendar gmtCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

While writing your code will become

statementHandler.setTimestamp(4, inspectionDate, gmtCalendar);

While reading it will be

date = new java.util.Date(resultSet.getDate("inspection_date", gmtCalendar).getTime() 
                    + resultSet.getTime("inspection_date", gmtCalendar).getTime());

And that's all should be needed to resolve the issue as you're using the getTime() (number of milliseconds) the time that you read is GMT/UTC . As timestamp (number of milliseconds) is by default in GMT/UTC .

Only thing left is to instruct JDBC to consider that timezone.

See this SO entry for more details on the topic https://stackoverflow.com/a/37103310/5343269

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM