Difference in date calculation Java SimpleDateFormat

400 Views Asked by At

I have a requirement to parse the date into milliseconds. Here is how I am doing it.

 private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");

      public void setTime(String date) {
      try {
            sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
            this.time = sdf.parse(date).getTime();
        } catch (ParseException e) {
                e.printStackTrace();
        }

Here is the problem in my server.

For example, for the given input date "2015-06-20T01:57:13Z", I get output value as 1592618233000 ms, however, the expected value should be 1434765433000.

Analyzing the issue I found that difference of 157852800000 ms which when converted gives to "Thu Jan 01 1975 05:30:00 GMT+0530 (IST)" Date.

I see that 157852800000 ms is getting added to few of the dates in my server. There is no code issue here. I am using the code as shown above. When I run the same in my local machine it is working absolutely fine. Also, this scenario in my server do not occur all the times.

Please advise on this.

4

There are 4 best solutions below

1
On

Maybe it is concurrency issue. SimpleDateFormat is not threadsafe. So create it every time it is used or synchronize access to it and check if that resolves your problem.

1
On

It might or might not be causing your problem here, but in general you shouldn't make SimpleDateFormat a static field. This is because this class is stateful and therefore not thread safe; when multiple threads access the same instance, unexpected results might ensue.

1
On

SimpleDateFormat is not thread safe. It might be a possibility that multiple threads are accessing the same simpledateformat instance. Generally it is not advised to make it static. Every instance should have each its own simpledateformat instance.

0
On

Apparently something is going wrong on your end.

Here is my version of your code. Using Java 8 Update 45.

try {
    String input = "2015-06-20T01:57:13Z";
    SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss'Z'" );

    sdf.setTimeZone( TimeZone.getTimeZone( "GMT" ) );
    java.util.Date date = sdf.parse( input );
    long millisSinceEpoch = date.getTime();

    System.out.println( "millis: " + millisSinceEpoch );

} catch ( ParseException ex ) {
    // Handle exception
}

When run.

millis: 1434765433000

I get your expected results.

Perhaps the problem is related to your incorrect use of a SimpleDateFormat instance as static, as other pointed out in comments and Answers.

By the way, the java.util.Date/.Calendar classes are notoriously troublesome. They are now supplanted by either:

Both of these frameworks support your input string’s ISO 8601 format by default.

And both of these frameworks assign a time zone to their respective date-time objects.

Joda-Time

Here is code in Joda-Time 2.8.1. Search StackOverflow for many more examples and discussions.

String input = "2015-06-20T01:57:13Z";
DateTimeZone zone = DateTimeZone.forID( "Asia/Kolkata" );
DateTime dateTimeKolkata = new DateTime( input , zone );
DateTime dateTimeUtc = dateTimeKolkata.withZone( DateTimeZone.UTC );
long millisSinceEpoch = dateTimeKolkata.getMillis();

Dump to console.

System.out.println( "dateTimeKolkata: " + dateTimeKolkata );
System.out.println( "dateTimeUtc: " + dateTimeUtc );
System.out.println( "millisSinceEpoch: " + millisSinceEpoch );

When run.

dateTimeKolkata: 2015-06-20T07:27:13.000+05:30
dateTimeUtc: 2015-06-20T01:57:13.000Z
millisSinceEpoch: 1434765433000

java.time

Code for java.time will be similar in concept to the Joda-Time code seen above, except that java.time use Factory methods rather than "new" constructors.

See this Question, Parse ISO timestamp using Java 8 java.time api (standard edition only) for code examples.

Avoid Count-Since-Epoch

I suggest avoiding working directly with a count-from-epoch (milliseconds in your case) whenever possible. Use a decent date-time framework and stick with its intelligent objects. Do you handle text as raw byte arrays instead of String instances? Same logic applies to date-time values.