0

I'm having a bit of trouble with JAva, but I'm following the instructions I find in this site (StackOverflow) to manage Dates in Java.

Basically, I'm parsing a string into a Date, simple stuff, however, I'm getting strange results.

Here's a simplified version of my code

package co.mil.fac.cetad.audit;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

@SpringBootApplication
public class AuditApplication {

    public static void main(String[] args) {

        SpringApplication.run(AuditApplication.class, args);
    }

    @Bean
    public CommandLineRunner run() throws Exception {

        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
        SimpleDateFormat changeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSXXX");
        return (args -> {

            TimeZone test = TimeZone.getDefault();
            String timestamp = "2020-04-11T14:52:34.8121672+00:00";
            Date timestampParsed = changeFormat.parse(timestamp);

        });
    }
}

The problem is that I'm getting the following result:

result of this parsing

  • Expected result: Sat Apr 11 14:52:34 UTC 2020
  • Observed result: Sat Apr 11 17:07:55 UTC 2020

for some strange reason it added 2 hours and 15 minutes to my dates.

Any ideas of what might be happening?

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • 3
    *FYI:* You should switch to [`java.time`](https://www.baeldung.com/java-8-date-time-intro), which will make everything much easier. – akuzminykh Jul 10 '20 at 15:46
  • 1
    I recommend you don’t use `TimeZone`, `SimpleDateFormat` and `Date`. All of those classes are poorly designed and long outdated, `SimpleDateFormat` in particular notoriously troublesome. Also there is no way that `SimpleDateFormat` can parse 7 decimals in the seconds. Instead use `OffsetDateTime` from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Jul 11 '20 at 03:12

1 Answers1

4

tl;dr

java.time.OffsetDateTime.parse( "2020-04-11T14:52:34.8121672+00:00" ) 

See this code run live at IdeOne.com.

Details

Never use java.util.Date. That flawed class was supplanted years ago by the modern java.time classes defined in JSR 310. Specifically replaced by java.time.Instant.

Avoid setting the JVM’s current default time zone. Doing so immediately affects all other code in all threads of all apps running in that JVM. Write your code such that you never depend on the default time zone. Always specify your desired/expected time zone.

No need to define this custom formatting pattern: "yyyy-MM-dd'T'HH:mm:ss.SSSSSSSXXX". That format is defined in the ISO 8601 standard, used by default in java.time when parsing/generating text.

By convention, the decimal fractions are written in groups of three digits. So suggest to the publisher of your data writing that textual value as 2020-04-11T14:52:34.812167200+00:00 rather than 2020-04-11T14:52:34.8121672+00:00. And congratulate the publisher on using both the hours and the minutes of the offset, as well as the colon. While technically optional in ISO 8601, including them maximizes compatibility with various date-time handling libraries in the real world.

Your format is asking for hundreds of nanoseconds. But the legacy date-time types resolve to mere milliseconds (thousandths of a second). So you were pressing a square peg into a round hole. Fortunately, java.time resolves to nanoseconds (billionths of a second). So we can handle parsing your input.

Parse your particular input as a OffsetDateTime.

OffsetDateTime odt = OffsetDateTime.parse( "2020-04-11T14:52:34.8121672+00:00" ) ;

Generate a string in standard ISO 8601 format.

String output = odt.toString() ;

2020-04-11T14:52:34.812167200Z

Convert to the terrible legacy java.util.Date only if you must. Find new conversion methods added to the old classes.

java.util.Date juDate = Date.from( odt.toInstant() ) ;

All of this has been addressed many many times on Stack Overflow. Please search more thoroughly before posting. And, search to learn more.

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