Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java8 LocalDateTime and NANO_OF_SECOND strange formatting

I try this code:

import java.time.*; 
...
   LocalDateTime now = LocalDateTime.now();
   DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
                                    "dd-MMM-yyyy  HH:mm:ss.n");
   System.out.format("Now = %s %n", now.format(formatter));

in order to get an output with subsecond information Now = 12-Apr-2018 14:47:38.039578300

Unfortunately, in the first 100 ms of every second, the leading zero of the subsecond information is omitted and I get a very misleading output Now = 12-Apr-2018 14:47:38.39578300 , which can be easily misinterpreted as about 38.4 sec, or 396 ms after the full second, instead of the real 38.04 sec.

The only workarond I found, is a format of ss.nnnnnnnnn with exactly 9 n, to get my desired output.

Edit:

There is something nicer, which I missed in this area when posting this question.

I'm not really interested in Nanoseconds, but a fractional part of seconds (about ms resolution), is what I'm really looking for.

Then, this one is much more suitable

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSS");

The capital S indicates the number of subsecond digits, including leading zeros of course.

like image 609
datafiddler Avatar asked Apr 12 '18 13:04

datafiddler


1 Answers

If you want just ms resolution, you can use S instead of n:

DateTimeFormatter formatter = DateTimeFormatter
    .ofPattern("dd-MMM-yyyy  HH:mm:ss.SSS", Locale.US);

This will print just the first 3 fractional digits (which is ms resolution):

12-Apr-2018 14:47:38.039

Note that I used a java.util.Locale to define the language to be used for the month name. That's becase the JVM might not always be set to English, and the results can't be what you expect. Ex: my JVM is set to Portuguese and the month name is "abr". Setting a specific locale eliminates this problem.


To print all the 9 digits, using either nnnnnnnnn or SSSSSSSSS will work.


We can see why it behaves like this when we check the javadoc. S and n have different presentations:

Symbol  Meaning                     Presentation      Examples
------  -------                     ------------      -------
S       fraction-of-second          fraction          978
n       nano-of-second              number            987654321

S is a fraction, while n is a number. The docs tell you the difference:

Number: If the count of letters is one, then the value is output using the minimum number of digits and without padding.

Fraction: Outputs the nano-of-second field as a fraction-of-second. The nano-of-second value has nine digits, thus the count of pattern letters is from 1 to 9. If it is less than 9, then the nano-of-second value is truncated, with only the most significant digits being output.

So, just 1 n will print the value without padding (without the 0 in the beginning), leading to the wrong output you've got, while SSS will give you the correct output.

like image 160
jonpebs Avatar answered Sep 28 '22 16:09

jonpebs