4

Even with about 15 years in Java one always stumbles over the topic of handling dates and times...

Here's the situation: I get a timestamp from some external system as a String representation. The timestamp's semantic is that it represents an UTC date. This timestamp has to be put in an entity and then into a PostgreSQL database in a TIMESTAMP field. Additionally I need to put the same timestamp as local time (in my case CEST) into the entity and then into the database in a TIMESTAMP WITH TIME ZONE field.

What is the right way to ensure that no matter what the settings of the machine executing the code are, the timestamps get stored correctly in the entity (to make some validations with other UTC timestamps) and in the database (to use them in reports later on)?

Here's the code, which worked fine on my local machine:

SimpleDateFormat sdfUTC = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
sdfUTC.setTimeZone(TimeZone.getTimeZone("UTC"));
Date utcTimestamp = sdfUTC.parse(utcTimestampString);
// getMachinesTimezone is some internal util method giving the TimeZone object of the machines Location
Calendar localTimestamp = new GregorianCalendar(getMachinesTimezone());
localTimestamp.setTimeInMillis(utcTimestamp.getTime());

But when executing the same code on the server, it resulted in different times, so I assume that it's not the correct way to handle it. Any suggestions?

PS: I read about Joda Time when searching in this forum, but in the given project I'm not able to introduce new libraries since I only change an existing module, so I have to live with the standard JDK1.6

Alexander Rühl
  • 6,769
  • 9
  • 53
  • 96
  • Hi Geziesfer, if you don't get the answer you're looking for, consider adding a few examples of the actual results you were getting, both on your local computer as well as the server. This will give us some more context about the problem. +1 for a well-written, neat, and grammatically correct question! – jamesmortensen May 11 '12 at 05:14
  • It seems silly to store the same datum twice in a database – stew May 11 '12 at 05:20
  • @stew: Well, I'm not the one to judge about sillyness of the existing system, but the reason for that is, that the statement which later produces the report needs to have utc and local time directly as input parameters instead of calculating it on that point. – Alexander Rühl May 11 '12 at 05:23
  • seems like you should be one to judge, as you are the one implementing the sillyness. knowing the number of 'calculations' that are probably happening when generating a report, saving one integer add calculation is a fools errand. If you asked your boss. "Do you want me to do stupid things without questioning, just because I asked you to", would he really say "yes"? – stew May 11 '12 at 05:28
  • @stew: Why are you discussing about points where it's unnecessary to discuss? It seems to me, that you have never worked in a real-life project. It's not my boss who is involved here, it's the situation at the customer I have to deal with. And when you have to change a module and some other module needs these two timestamps, one may point out that this is not the best way to do it, but it's pretty much useless, since I'm not in the position to change the other module. So if you can provide not-silly information which might help me with the problem, I'll be very happy. – Alexander Rühl May 11 '12 at 05:36
  • @jmort253: Thanks for the nice remark. The timestamp in the string is for example "2012-05-10T15:00:07.000", after executing it locally, I find it correctly in the database. But on the server, I see "2012-05-10 19:00:07" in the UTC field and "2012-05-10 17:00:07+00" in the local field. Since my timezone is CEST, the local value should have been "2012-05-10 17:00:07+00" and the UTC field should have been the same as the input. – Alexander Rühl May 11 '12 at 05:50
  • 1
    "Even with about 15 years in Java one always stumbles over the topic of handling dates and times". Because dates, times, and timezones might as well have been invented to make programmers' lives hell, and Java's date/time APIs make it worse. Adopting JodaTime instead of the standard Java APIs can help in some cases but won't do you good when interacting with things like JDBC. – Craig Ringer May 11 '12 at 05:56

3 Answers3

6

If I understand correctly, You need to set the timezone on the same data/calendar object that you are printing. Like this:

private Locale locale = Locale.US;
private static final String[] tzStrings = {
    "America/New_York",
    "America/Chicago",
    "America/Denver",
    "America/Los_Angeles",
};

  Date now = new Date();
  for ( TimeZone z : zones) {
        DateFormat df = new SimpleDateFormat("K:mm a,z", locale);
        df.setTimeZone(z);
        String result = df.format(now);
        System.out.println(result); 
  }

if i set timezone to SimpleDateFormat it is working fine.

here is the sample code...

String date="05/19/2008 04:30 AM (EST)";
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm aaa (z)");
TimeZone.setDefault(TimeZone.getTimeZone("PST"));
long millis = sdf.parse(date).getTime();
sdf.setTimeZone(TimeZone.getDefault());
System.out.println(sdf.format(new Date(millis)));
Anil Kumar C
  • 1,604
  • 4
  • 22
  • 43
  • The point is, that I don't print it, but persist it. In the above answer I stated what I think is strange about that. – Alexander Rühl May 11 '12 at 11:51
  • I had a similar problem as the topic starter: I had a date as a string and wanted to parse it as a date in utc time zone. Using the SimpleDateFormat and setting its time zone as utc via `sdf.setTimeZone(TimeZone.getTimeZone("UTC"))` wasn't enough. The parser still used my local time. What did the trick was using `TimeZone.setDefault(TimeZone.getTimeZone("UTC"))`. So thanks for your answer. – Torsten Sep 07 '12 at 06:30
0

I think you have to set the target time zone in you Calendar object. I think something like:

Calendar localTimestamp = new GregorianCalendar(TimeZone.getTimeZone("GMT+10"));
localTimestamp.setTimeInMillis(utcTimestamp.getTime());

In other case Java takes the default system time zone for the Calendar instance.

sebastian
  • 2,427
  • 4
  • 32
  • 37
-1

You can do it by the below example code.

Date date = new Date();

DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
formatter.setTimeZone(TimeZone.getTimeZone("CET"));

Date date1 = dateformat.parse(formatter.format(date));

// Set the formatter to use a different timezone
formatter.setTimeZone(TimeZone.getTimeZone("IST"));

Date date2 = dateformat.parse(formatter.format(date)); 
// Prints the date in the IST timezone
//    System.out.println(formatter.format(date));
Bhavik Ambani
  • 6,557
  • 14
  • 55
  • 86
  • The problem is, that I don't come from a date as in your example, but from a String, e.g. "2012-01-01T12:00:00.000". Now, when I parse this on a DF in UTC and save it in the postgreSQL db via a JPA entity in a TIMESTAMP field, it results in a wrong timestamp: "2012-01-01 13:00:00". The machine executing that is in GMT. If I switch to local time (CET), it produces something different. And that's what I don't understand, since I have a given String and said it should formatted as UTC. – Alexander Rühl May 11 '12 at 11:50
  • @BhavikAmbani Have you tried it with parsing a string, like Geziefer mentioned? It didn't work for me either with your method. – Torsten Sep 07 '12 at 06:33
  • @BhavikAmbani Sorry, I was being sarcastic, and by the way, I'm not the original poster, so I can't accept your answer anyways. Did you ever try parsing a String instead of using a Date Object, like Geziefer said? (I apologize for repeating myself, but you don't seem to read the comments thoroughly or at least you don't answer them exhaustively enough.) If I do so with your solution, it doesn't work for me. When I use Anil Kumar C's answer, it works. The difference lies in using TimeZone.setDefault(String) before setting the TimeZone in the DateFormatter. – Torsten Sep 12 '12 at 07:12