tags:

views:

304

answers:

4

I'm having a problem sending java.util.Date objects over RMI, to and from machines in different timezones.

For example, a client in Germany will send a date object to a server in the UK.

  1. User enters a date string e.g. 20090220.
  2. Client app in Germany converts it to date using SimpleDateFormat("yyyyMMdd") to give: Fri Feb 20 00:00:00 CET 2009
  3. Server in UK receives Date over RMI as: Thu Feb 19 23:00:00 GMT 2009
  4. Server stores Date into a UK Oracle Database DATE column

What is the best way to get around this issue of incorrect dates? I could send the date string across and have the Server convert it to a Date, but I want to reduce the amount of work that the Server has to do.

Here is a stand-alone test program showing date serialisation:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class SerializationTest {

    public static void main(String[] args) throws Exception {

        final String yyyyMMdd = "20090220";
        final Date date = new SimpleDateFormat("yyyyMMdd").parse(yyyyMMdd);

        if (args.length != 1) {
            System.out.println("Usage SerializationTest S|D");
        }

        boolean serialise = false;
        if (args[0].equals("S")) {
            serialise = true;
        }
        else if (args[0].equals("D")) {
            serialise = false;
        }

        String filename = "date.ser";
        if (serialise) {
            // write the object to file
            FileOutputStream fos = new FileOutputStream(filename);
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            ObjectOutputStream outputStream = new ObjectOutputStream(bos);
            outputStream.writeObject(date);
            outputStream.flush();
            outputStream.close();

            System.out.println("Serialised: " + date);
        }
        else {
            FileInputStream fis = new FileInputStream(filename);
            BufferedInputStream bis = new BufferedInputStream(fis);
            ObjectInputStream inputStream = new ObjectInputStream(bis);
            Date outDate = (Date) inputStream.readObject();
            inputStream.close();

            // print the object
            System.out.println(outDate);
        }
    }
}
+2  A: 

I fail to see what your problem is here, those dates look correct to me- they're just being formatted to the locale in use. If you want the date entered by the user to be in GMT, specify the locale on the SimpleDateFormat constructor

MrWiggles
The problem is that my server is storing the wrong date in my database. Instead of getting 20/02/2009, I am getting 19/02/2009. (My database column is a java.sql.Types.DATE)
dogbane
What I said still stands then. The dates in your DB should be stored in a single timezone (preferably GMT)- just convert your dates to that timezone before storing them
MrWiggles
A: 

The Dates are actually the same. The println() is calling the toString() on date which is using the locale to format it in the local timezone.

Clint
A: 

Look at getTime() and setTime(). They should do what you're looking for. Instead of sending it over the wire as a location-specific string, send it as the number of milliseconds since epoch using getTime() on the client, then build a new Date on the client and use setTime() with the long value on the server.

Chris Doggett
I'm not sending it as a "location-specific string" but as a java.util.Date object.I have tried sending the number of milliseconds, but when I create a Date object on the server and call setTime it still gives me Thu Feb 19, instead of Fri Feb 20.
dogbane
Sending that same long back to the client should display Fri Feb 20 when formatted in their locale, despite the server value.If you need to modify it via an admin UI on the server side, you'll have to work with Timezone math, and I haven't written Java in years, so I can't help you there.
Chris Doggett
You don't have to work with timezone math, just set the correct locale and it will format it correctly
MrWiggles
A: 

Take a look at the java.util.Calendar specifically the getTime() method.

That way you will be sending the time in milliseconds rather than a String the is interpretable in different ways.

TofuBeer