2

This sounds like a simple task.
Get UTC timestamp value from DB and pass it as UTC date via Web Service.

We have timestamp column DATE_COLUMN and store there time in UTC time zone.

With JPA we get this time with

@Column(name = "DATE_COLUMN")
private java.sql.Timestamp dateValue;

And as we have to pass this time via Web Service in UTC (Jax-ws 2.0) we have getDate and setDate methods.
We are interested in getDate.

public Calendar getDate()
{
   Calendar calendar = Calendar.getInstance(utcTimeZone);
   calendar.setTimeInMillis(dateValue.getTime());

   return calendar;
}

This doesn't work as you may think it should.
And this is because application's default time zone is not 'UTC'.

Here is an example for clarification.
Value in the DATE_COLUMN equals to "30.11.09 16:34:48,833045000", when I translate it to UTC I get "2009-11-30T14:34:48.833Z".
The difference is 2 hours. And this is because my default time zone is "Europe/Helsinki".

Same problem if you just want to map 'DATE_COLUMN' to Calendar

@Column(name = "DATE_COLUMN")
@Temporal(TemporalType.TIMESTAMP)
private Calendar dateValue;

public Calendar getDate()
{
   calendar.setTimeZone(utcTimeZone);
   return calendar;
}

I don't want to change application's time zone because it doesn't look like the solution.

By now we have only two options.

First. Calculate offset between application's time zone and UTC and add it manually after automatic subtraction in the calendar.setTimeZone.

public Calendar getDate()
{
   Calendar calendar = Calendar.getInstance(utcTimeZone);
   calendar.setTimeInMillis(dateValue.getTime());

   int offset = TimeZone.getDefault().getOffset(dateValue.getTime());

   calendar.add(Calendar.MILLISECOND, offset);

   return calendar;
}

Second. Pass dateValue as Long via Web Service. Which is not bad except that we lose real type of the field in wsdl.

My imaginary solution is

@Column(name = "DATE_COLUMN")
@Temporal(type = TemporalType.TIMESTAMP, timezone = 'UTC')
private Calendar dateValue;

But I tend to think that there is the real one somewhere. And I hope you can point it out.

Mykola Golubyev
  • 57,943
  • 15
  • 89
  • 102

4 Answers4

4

We decided to use following solution.
Use Date for retrieving date from database. It is because Date is timezoneless type.

@Column(name = "DATE_COLUMN")
@Temporal(TemporalType.TIMESTAMP)
private Date dateValue;

public Date getDate()
{
   return dateValue;
}

And to send it via WebService in UTC (jax-ws) we created UtcTimestampAdapter to change zone from application's default to UTC in the marshaling phase.

public class UtcTimestampAdapter extends XmlAdapter<XMLGregorianCalendar, Date>
{
   @Override
   public XMLGregorianCalendar marshal(Date date) throws Exception
   {
      GregorianCalendar calendar = new GregorianCalendar();
      calendar.setTime(date);

      DatatypeFactory dataTypeFactory = DatatypeFactory.newInstance();
      XMLGregorianCalendar xmlCalendar = 
         dataTypeFactory.newXMLGregorianCalendar(calendar);

      //Reset time zone to UTC
      xmlCalendar.setTimezone(0);

      return xmlCalendar;
   }

   @Override
   public Date unmarshal(XMLGregorianCalendar calendar) throws Exception
   {
      return calendar.toGregorianCalendar().getTime();
   }
}

Then to enable this rule to all Datas fields in the module we added package specific setting like so.

@XmlJavaTypeAdapter(value = UtcTimestampAdapter.class, type = Date.class)
@XmlSchemaType(name = "dateTime", type = XMLGregorianCalendar.class)
package com.companyname.modulename;

That's it. Now we have generic solution which encapsulate all logic in one place. And if we want to send timezoneless dates as UTC via web service in some other module we will just annotate certain package.

Mykola Golubyev
  • 57,943
  • 15
  • 89
  • 102
  • Mykola, your JPA solution won't work. See http://stackoverflow.com/questions/508019/jpa-hibernate-store-date-in-utc-time-zone. Why do you need JAX-WS to transmit only GMT dates? The client, knowing its own time zone, can (and should) translate a date from any remote time zone into its own local time zone. – Derek Mahar Nov 07 '10 at 12:49
  • The problem is something with C# client. We used old version. This solution works fine. – Mykola Golubyev Nov 08 '10 at 16:09
  • There are numerous problems when trying to store/interpret time information unless there is an absolute baseline. UTC is a good baseline and does not change due to day-light savings, will be consistent, can be translated to local time, etc. Simply consider storing transaction times in GMT+5 then changing to GMT+6 arbitrarily due to some daylight-savings clock-change rule. Now the client has to somehow know that transaction #1 was GMT+5 until a certain date then transaction #2 should be interpreted as GMT+6 when they are in a timezone not observing such changes. It's a disaster to not use UTC. – Darrell Teague Feb 22 '13 at 21:25
3

If you need the java process to run at the UTC timezone, the easiest way to do so is by adding the following JVM parameter:

-Duser.timezone=UTC
David Rabinowitz
  • 29,904
  • 14
  • 93
  • 125
  • But I don't need. And all things are going on Application Server. I don't want to change its timezone. – Mykola Golubyev Nov 30 '09 at 21:03
  • As far as I understand, you want your times in UTC. In this case, why not run the application (and the database) in UTC? I am doing it very successfully for the last 5 years. – David Rabinowitz Dec 01 '09 at 06:05
  • Because on the Application server there are a lot of applications. Not only mine. – Mykola Golubyev Dec 01 '09 at 10:11
  • And it really looks like hack and not a solution. – Mykola Golubyev Dec 01 '09 at 10:14
  • I agree that if you are hosting many applications it is not a solution. However why this is a hack? It is a system setting same as setting the time zone at the OS level. – David Rabinowitz Dec 01 '09 at 11:17
  • Hi @David and @Mykola, I'm exactly in the same decision that your comments are talking about. I want to store a 'Date' using a db timezone column. If I change the JPA mapping to Date or Calendar and my JVM timezone is NOT on UTC, I'll store the Date NOT on UTC. The unique way of storing a Data in DB on real UTC is changing my JVM to start on UTC, exactly as @David Rabinowitz mention on this post! – rafa.ferreira May 20 '11 at 15:13
3

TimeZone.setDefault(TimeZone.getTimeZone("UTC")); seems to be affecting the entire JVM.

This will cause other applications fail if they were expecting local time

freewill
  • 31
  • 2
0

Another solution is to set the default timezone for the application only in a @StartupBean:

import java.util.TimeZone;
import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;

@Startup
@Singleton
public class StartupBean {

    @PostConstruct
    public void initializeTheServer() {
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
    }
}

From then on, all interpretation of Date objects will be based on UTC. This includes XML marshalling.

Hank
  • 4,597
  • 5
  • 42
  • 84