Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom date format cannot be parsed. (Java)

I have to use a custom date format in Java. It contains microseconds although Java doesn't provide support for microseconds. Because of that I filled the time pattern with zeroes, which work fine when formatting, but I cannot parse date-strings with that pattern.

Is there a simple workaround or must I handle microseconds on my own (with String functions)?

@Test
public void testDateFormat() throws ParseException {
    DateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH.mm.ss.SSS000");
    String theDate = format.format(new Date());
    // this will fail:
    format.parse(theDate);
}

java.text.ParseException: Unparseable date: "2010-01-25-12.40.35.769000"

like image 660
Christian Strempfer Avatar asked Jan 25 '10 12:01

Christian Strempfer


3 Answers

tl;dr

LocalDateTime.parse( 
    "2010-01-25-12.40.35.769000" ,
    DateTimeFormatter.ofPattern( "uuuu-MM-dd-HH.mm.ss.SSSSSS" ) 
)

Using java.time

You are using troublesome old date-time classes that are now legacy, supplanted by the java.time classes.

These old classes were limited to tracking milliseconds, three digits of decimal fraction. The modern java.time classes resolve to nanoseconds, for nine digits of decimal fraction.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd-HH.mm.ss.SSSSSS" ) ;
LocalDateTime ldt = LocalDateTime.parse( "2010-01-25-12.40.35.769000" );

ldt.toString(): 2010-01-25T12:40:35.769

ISO 8601

Tip: Rather than invent your own format to textually represent a date-time value, stick to the standard ISO 8601 formats.

The java.time classes use the standard formats by default. You can see that format in the output above. The T separates the date portion from the time-of-day portion.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, and later
    • Built-in.
    • Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
    • See How to use ThreeTenABP….

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

like image 122
Basil Bourque Avatar answered Oct 02 '22 08:10

Basil Bourque


Your problem is that the pattern used in SimpleDateFormat unfortunately have different meanings depending on whether it is used as a parser or as a formatter. As a formatter, your pattern does what is expected, the output will end with the millisecond value formatted as three digits followed by three 0 characters, e.g:

2010-01-25-14.17.47.307000

Used as a parser, the "SSS" pattern will however match an arbitrary number of digits and parse the above example as 307000 ms. After having parsed the ms field, the parser will still look for a "000" substring and fail with an exception, since you've reached the end of the input string, without fulfilling the requirements of the pattern.

Since there is no pattern for a µs value in SimpleDateFormat, you will have to write your own wrapper to strip the input string for the last three 0 characters, before feeding it to SimpleDateFormat.

like image 40
jarnbjo Avatar answered Oct 02 '22 10:10

jarnbjo


In addition to jarnbjo's answer, if you need the microseconds, you might be able to use java.sql.Timestamp:

Date dateToMillis = format.parse(theDate.substring(0, 23));
DateFormat timestampFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Timestamp timestamp = Timestamp.valueOf(timestampFormat.format(dateToMillis) + theDate.substring(23,26));
like image 35
Stephen Denne Avatar answered Oct 02 '22 10:10

Stephen Denne