Is there a way how to create JSR-310 formatter that is able to parse both following date/times with variable length of seconds fraction?
2015-05-07 13:20:22.276052
or
2015-05-07 13:20:22.276
Example code:
DateTimeFormatter formatter
= new java.time.format.DateTimeFormatterBuilder()
.append( java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") )
.appendOptional( java.time.format.DateTimeFormatter.ofPattern(".SSSSSS") )
.toFormatter();
formatter.parse("2015-05-07 13:20:22.276052", LocalDateTime::from);
This solves the problem:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd HH:mm:ss")
.appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
.toFormatter();
System.out.println(LocalDateTime.parse("2015-05-07 13:20:22.276052", formatter));
System.out.println(LocalDateTime.parse("2015-05-07 13:20:22.276", formatter));
System.out.println(LocalDateTime.parse("2015-05-07 13:20:22", formatter));
// output
2015-05-07T13:20:22.276052
2015-05-07T13:20:22.276
2015-05-07T13:20:22
The answer by JiriS is incorrect, as it uses appendValue
whereas the correct way is to use DateTimeFormatterBuilder.appendFraction
(which also handles the decimal point). The difference can be seen in the second system out, where appendValue
incorrectly parses "2015-05-07T13:20:22.000276".
When parsing, LocalDateTime.parse(str, formatter)
is a neater approach than using the formatter directly in most cases.
When using the builder, take advantage of appendPattern()
and optionalStart()
to keep things neat.
And this one works
DateTimeFormatter formatter
= new java.time.format.DateTimeFormatterBuilder()
.append( java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") )
.appendOptional(
new java.time.format.DateTimeFormatterBuilder()
.appendLiteral('.')
.appendValue( ChronoField.MICRO_OF_SECOND, 1, 6, SignStyle.NOT_NEGATIVE).toFormatter())
.toFormatter();
The accepted answer is written by the architect of modern date-time API and is the most elegant way to solve this problem. My answer shows an alternative way to solve this problem.
This solution leverages a feature of DateTimeFormatter
that allows specifying optional units using square brackets.
Demo:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
"yyyy-MM-dd HH:mm:ss[.[SSSSSSSSS][SSSSSSSS][SSSSSSS][SSSSSS][SSSSS][SSSS][SSS][SS][S]]",
Locale.ENGLISH);
// Test
Stream.of(
"2015-05-07 13:20:22.123456789",
"2015-05-07 13:20:22.276052",
"2015-05-07 13:20:22.276",
"2015-05-07 13:20:22"
).forEach(s -> System.out.println(LocalDateTime.parse(s, formatter)));
}
}
Output:
2015-05-07T13:20:22.123456789
2015-05-07T13:20:22.276052
2015-05-07T13:20:22.276
2015-05-07T13:20:22
Learn more about the modern date-time API from Trail: Date Time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With