0

I am making a change to some code which runs on a unix box. It sets the time for a field in a database based on the current date and time for London.

The methods I am using are as follows;

private static Date getCurrentTime() {
    SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd-kk:mm:ss.SSS");
    format.setTimeZone(TimeZone.getTimeZone("Europe/London"));

    Calendar cal = Calendar.getInstance();
    Date currentDate = cal.getTime();

    try {
        return format.parse(format.format(currentDate));
    } catch (ParseException e) {
        log.error("Error occured while parsing date-->" + e.getMessage());
    }
    return new Date();
}

private String getStringFromDate(Date date){
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd-kk:mm:ss.SSS");
    return sdf.format(date);
}

When the message is processed by the java app on the production unix box (which is set to north america time as thats where it is hosted) then when it is inserted into the database it is an hour behind (not being set to BST).

If I run the same code in Eclipse on my desktop, I get the correct time in the database.

I am unsure what might be causing this issue and was hoping someone might be able to help.

Thanks

edit*** at second glance, even the log files on the unix box are an hour behind so on that basis i assume its unix that is causing the issue opposed to my code.

Biscuit128
  • 5,218
  • 22
  • 89
  • 149

2 Answers2

2

A Date instance is always in UTC (or, it should be unless you've done something wrong). you should store your dates in the db in UTC and convert them to whatever timezone you desire when presenting them to the user. anything else is just asking for trouble.

your code which formats and then parses the Date instance in the same TimeZone is just meaningless.

jtahlborn
  • 52,909
  • 5
  • 76
  • 118
  • "you should store your dates in the db in UTC" <-- hardly so, if you do so, you lose the timezone information; what is more, prior to 1970, Jan 1 midnight GMT you are doomed – fge Jul 20 '13 at 19:07
  • @fge - if you need the _original_ timezone, then, yes, you must store that as well. how does that contradict what i said. storing dates in UTC doesn't affect whether or not you need to store the timezone as well. what you are saying only applies if you store your dates in the db in text. i was assuming a date/time column. – jtahlborn Jul 20 '13 at 20:33
  • OK, fair enough. I have misinterpreted your answer, sorry – fge Jul 20 '13 at 21:02
0

tl;dr

A Date (and Instant) are always in UTC by definition. So no need to futz with time zone.

Instant.now()  // Capture current moment in UTC.

Or, if you must use the troublesome legacy class Date:

java.util.Date.from( Instant.now() )  // Avoid the legacy classes whenever possible. When required, you can convert back-and-forth via new methods added to the old classes as seen here.

Always specify time zone

Never rely on the current default time zone of either your host OS or your JVM. That default value is out of your control and can change at any moment during runtime.

Instead:

  • Always use the java.time classes rather than the troublesome old legacy classes seen in your code.
  • Always specify your desired/expected time zone as an optional argument to the various java.time methods rather than rely implicitly on the JVM’s current default.

java.time

You appear to be trying to get the current moment as a java.util.Date object. That legacy class represents a value in UTC, so the time zone is irrelevant.

Instant

The modern replacement for that class is java.time.Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Capturing the current moment is simple: Instant.now.

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

If you must have Date to inter-operate with old code not yet updated to java.time, convert by calling new methods added to the old classes.

java.util.Date javaUtilDate = java.util.Date.from( instant ) ;

Either way, be very aware that both a Date and an Instant represent a point on the timeline in UTC, always UTC.

UTC versus London Time

Also, be aware that UTC is not London time, a common misconception given that UTC/GMT is tracked from a point at the Royal Observatory, Greenwich. Actually, London has a history of anomalies in its offset-from-UTC, including the adoption of Daylight Saving Time (DST).

To get London time, assign a ZoneId to get a ZonedDateTime.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;  // Same moment, same point on the timeline, but viewed with a different wall-clock time used by the people of a particular region (time zone).

Generally, best practice is to keep your servers in UTC, and to do as much of your business logic, storage, and exchange of date-time values in UTC. Use a zoned value such as London time only when required either by business logic or presentation to user.

Notice in the code seen above that the current default time zone of any computer or JVM is irrelevant. A change in that default has no effect on your code.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154