Brett
Brett

Reputation: 799

Parse timestamp string in Java with variable number of nanoseconds

I have a CSV that contains timestamps in the following formats:

yyyy-MM-dd HH:mm:ssX

yyyy-MM-dd HH:mm:ss.SX

yyyy-MM-dd HH:mm:ss.SSX

yyyy-MM-dd HH:mm:ss.SSSX

yyyy-MM-dd HH:mm:ss.SSSSX

yyyy-MM-dd HH:mm:ss.SSSSSX

yyyy-MM-dd HH:mm:ss.SSSSSSX

How can I parse a string that could contain any one of the above formats?

The following code can parse the timestamp when 3-6 nanoseconds are present, but fails when the nano seconds aren't present or are less than 3:

String time = "2018-11-02 11:39:03.0438-04";
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSSX");            
Date date = sdf.parse(time);
System.out.println("Date and Time: " + date.getTime());

I currently have a method that iterates from 0-6 and generates a string with a number of "S" equal to the value of the iterated variable. The method attempts to parse the string within a try/catch until the string is successfully parsed. For example, the string 2018-11-02 11:39:03.0438-04 will attempt to be parsed five times before being successful.

The CSV is an export of a PostgreSQL table that has columns with type TIMESTAMP WITH TIME ZONE and appears to cut off trailing "0" nanosecond places.

I'm using Java 8 and am open to any external libraries (Joda?).

Upvotes: 1

Views: 2775

Answers (3)

MC Emperor
MC Emperor

Reputation: 22977

You'd better use Java Time API1, from the package java.time.

Date, SimpleDateFormatter and Calendar classes are flawed and obsolete.

The DateTimeFormatter class provides numerous options, so you can configure all you need. Note that by using the method appendFraction, the nanos are right-padded.

String[] dateStrs = {
    "2018-11-02 11:39:03.4-04",
    "2018-11-02 11:45:22.71-04",
    "2018-11-03 14:59:17.503-04"
};

DateTimeFormatter f = new DateTimeFormatterBuilder()
    .appendPattern("yyyy-MM-dd HH:mm:ss.")
    .appendFraction(ChronoField.NANO_OF_SECOND, 1, 9, false)
    .appendPattern("X")
    .toFormatter();

// Single item:
LocalDateTime date = LocalDateTime.parse("2018-11-02 11:39:03.7356562-04", f);

// Multiple items:
List<LocalDateTime> dates = Arrays.asList(dateStrs).stream()
    .map(t -> LocalDateTime.parse(t, f))
    .collect(Collectors.toList());

1 Java 8 new Date and Time API is heavily influenced by Joda Time. In fact the main author is Stephen Colebourne, the author of Joda Time.

Upvotes: 6

Amongalen
Amongalen

Reputation: 3131

I'm not sure but something like this seems to work for me:

String time = "2018-11-02 11:39:03.0438-04";
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSSX");            
Date date = sdf.parse(time);
System.out.println("Date and Time: " + date.getTime());

In general, you want to you the longest format possible, with 6x S in this case.

Upvotes: 0

Lajos Arpad
Lajos Arpad

Reputation: 76436

The first 19 characters are identical.

Also, you have different lengths in the different cases. You can use a switch to test the length of the String and handle the separate cases for the different possible values.

Upvotes: 0

Related Questions