Search code examples
javasimpledateformatmillisecondsdatetime-parsing

Java SimpleDateformatter with 10 decimals after the seconds, cannot convert to Date


I'm trying to convert date string with 10 milliseconds (2018-11-02 6:05:59.1541162159 PM) to date but not able get the exact date.

Code to convert:

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

public class DateFormatCheck {
    private static TimeZone tz = TimeZone.getTimeZone("Asia/Colombo");
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS aa");

    public static void main(String[] a){
        try {
            Calendar cal = Calendar.getInstance(tz);
            sdf.setCalendar(cal);
            cal.setTime(sdf.parse("2018-11-02 6:05:59.1541162159 PM"));
            Date date = cal.getTime();
            System.out.println(date);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

Output:

Tue Nov 20 02:12:01 IST 2018

Solution

  • There are multiple problems at the moment. I'd strongly recommend using java.time for as much work as possible, although even that doesn't make this easy.

    As you say, your value has 10 digits for "fraction of a second" - which means it goes down to 10th-of-a-nanosecond precision. That's highly unusual to start with, in my experience - and I don't think Java can handle that, even with java.time.

    I suspect you'll need to massage the data first, down to 9 digits of precision. At that point, it's fairly straightforward to parse the value to a ZonedDateTime:

    // Note this only has 9 digits of precision, not the original 10
    String text = "2018-11-02 6:05:59.154116215 PM";
    ZoneId zone = ZoneId.of("Asia/Colombo");
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
        "yyyy-MM-dd h:mm:ss.SSSSSSSSS a", Locale.US)
        .withZone(zone);
    ZonedDateTime parsed = ZonedDateTime.parse(text, formatter);
    System.out.println(parsed);
    

    Note how I've provided SSSSSSSSS as the fraction-of-a-second part, to handle all 9 digits. Also note the use of h instead of HH - HH would mean "24-hour hour of day, with 0 padding" - neither part of which is true for your original value, which uses "6" for 6pm. It's very rare that you would want to combine H or HH with a.

    That code gives you a ZonedDateTime, which you could convert into a Date like this:

    Date date = Date.from(parsed.toInstant());
    

    I'd recommend you don't do that unless you really, really need to for interop reasons though; the Date API is nasty in various ways.