Search code examples
timejava-8java-timelocaltime

Parse (ss.nnn) second and nanosecond in Java 8


I am trying to parse second and nanosecond, i.e., 10.337000, where 10 is second and 337000 is nanoseconds in Java 8. I am not able to figure out how should I parse these values into LocalTime.

I have tried DateTimeFormatter.ofPattern("ss:nnnnnn"), but it didn't work.


Solution

  • There are a couple of options.

    If your time string denotes an amount of time

    For a duration, an amount of time (in days, hours, minutes, seconds and/or fraction of second) the Duration class in java.time is the right one to use:

        String timeString = "10.337000";
        Duration amountOfTime = Duration.parse("PT" + timeString + "S");
        System.out.println("Duration: " + amountOfTime);
        System.out.println("Seconds: " + amountOfTime.getSeconds());
        System.out.println("Nanos: " + amountOfTime.getNano());
    

    This prints

    Duration: PT10.337S
    Seconds: 10
    Nanos: 337000000
    

    We got 337000000 nanoseconds. I assume this is correct since there are 1,000,000,000 nanoseconds in a second (a millionth of a second is called a microsecond).

    The Duration class has limited parsing and formatting capabilities. It parses ISO 8601 format, which goes like PT10.337000S, so I just put the correct letters in front of and at the end of your string, and it worked. You see the Duration.toString() also prints the same format back (omitting superfluous 0 decimals).

    If your time string denotes a time of day

    You asked for a LocalTime. A LocalTime is for hour of day, so if you intended 10.337 seconds past midnight, this is the correct class to use. One easy option is to prepend a string to match ISO 8601 format for a time without an offset from UTC, similarly to what I did for the duration:

        LocalTime time = LocalTime.parse("00:00:" + timeString);
    

    This gives a LocalTime of

    00:00:10.337
    

    Again, toString() just gives as many groups of three decimals as necessary to render the full precision.

    You mentioned using a DateTimeFormatter, and you may want to stick to this idea. This will allow you to build your formatter once in one place and use it in other places in your code without having to worry about prepending a string. We need to tell the formatter to set the minutes and hours to 0, and in order to do that, we need to go through a DateTimeFormatterBuilder:

        DateTimeFormatter timeParser = new DateTimeFormatterBuilder()
                .appendPattern("s.SSSSSS")
                .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                .toFormatter();
        LocalTime time = LocalTime.parse(timeString, timeParser);
    

    This gives exactly the same result as before, a LocalTime of 00:00:10.337.

    The formatter in this snippet requires exactly 6 decimals on the seconds (since there are 6 capital S after the decimal point). If your number of decimals may vary, you need to look into the DateTimeFormatterBuilder.appendFraction method.