Home > Software design >  Parsing a Date / Time format with Apache Commons CSV `CSVFormat` class
Parsing a Date / Time format with Apache Commons CSV `CSVFormat` class

Time:12-22

I am using Apache Commons CSV library.

I am trying to parse a date / time format to CSVFormat which leads to, if there is any time / date columns it will be formatted according to the format provided to CSVFormat.

When I remove date / time format it's working perfect, but it's NOT working when adding date / time format.

example of date / time formats I would like to add:

  • YYYY-MM-DD
  • DD-MM-YYYY HH:mm:SS
  • YYYY-MM-DD HH:mm:SS

Also here is the code I am trying to add the date / time format to;

public ByteArrayInputStream dataToCSV(List<?> dataList, char delimiter){
        final CSVFormat format = CSVFormat.DEFAULT.withDelimiter(delimiter);
//        final String format = CSVFormat.DEFAULT.withDelimiter(delimiter).format("MM-YYYY-DD HH:mm:SS");
        try (ByteArrayOutputStream out = new ByteArrayOutputStream();
             CSVPrinter csvPrinter = new CSVPrinter(new PrintWriter(out), format);) {
            if (dataList.size() > 0){
                // headers will be written just one time
                csvPrinter.printRecord(this.getHeaders(dataList.get(0)));
                for (Object objectClass : dataList) {
                    List<String> data = getRecordData(objectClass);
                    csvPrinter.printRecord(data);
                }
            }
            csvPrinter.flush();
            return new ByteArrayInputStream(out.toByteArray());
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

The line I commented is the one that not working. The first above one is the one that works properly.

Data is coming from a PostgreSQL DB, also I am using hibernate and commons-csv dependency

<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-csv</artifactId>
            <version>1.8</version>
</dependency>

example of timestamp field in DB

2022-11-23 11:12:13.123456

example of the same field formatted I got in CSV

2022-11-23 11:12:13.123456

example of needed format

11-23-2022 11:12:13.123456

Any help is appreciated,

Thanks in advance!

CodePudding user response:

CSVFormat#format does not do what you think

Your call to CSVFormat#format in the commented line:

final String format = CSVFormat.DEFAULT.withDelimiter(delimiter).format("MM-YYYY-DD HH:mm:SS");

… is incorrect. And shows that you misunderstand how Apache Commons CSV works.

Unfortunately, the Javadoc for that command is nearly useless:

Formats the specified values.

So let's look at the source code:

1427    /**
1428     * Formats the specified values.
1429     *
1430     * @param values the values to format
1431     * @return the formatted values
1432     */
1433    public String format(final Object... values) {
1434        final StringWriter out = new StringWriter();
1435        try (CSVPrinter csvPrinter = new CSVPrinter(out, this)) {
1436            csvPrinter.printRecord(values);
1437            final String res = out.toString();
1438            final int len = recordSeparator != null ? res.length() - recordSeparator.length() : res.length();
1439            return res.substring(0, len);
1440        } catch (final IOException e) {
1441            // should not happen because a StringWriter does not do IO.
1442            throw new IllegalStateException(e);
1443        }
1444    }

We can see that you are supposed to pass values, not a date-time formatting pattern.

We can also see that this method does not write to your CSV file. Instead, this method is merely a shortcut for using CSVPrinter to generate the text of what would be written to your CSV file if your CSV file were the actual target of output. With this format method, the text generated is merely returned to the calling code.

You need to understand that Commons CSV does not do binding. The library merely parses pieces of CSV as plain text, not objects. So specifying a date-time formatting pattern with Commons CSV makes no sense; that's not a feature.

You must write your own Java code to produce the strings you want to send out to a CSV file through Commons CSV.

So you need to do the parsing from text to date-time object yourself. If you have a string such as 2022-11-23 00:00:00.0000, you should be parsing as a LocalDateTime object. To do so, you could define your own formatting pattern with DateTimeFormatter class. But instead I would do a bit of string manipulation to alter the input by replacing the SPACE in the middle with a T:

LocalDateTime myLocalDateTime = LocalDateTime.parse( "2022-11-23 00:00:00.0000".replace( " " , "T" ) ) ;

To learn more about using Apache Commons CSV, search Stack Overflow. Many posts have already been made, including some authored by me.

ISO 8601

Big Tip: Always use ISO 8601 standard formats for data exchange of date-time values. Quite easy to do with java.time classes as they use the ISO 8601 formats by default when parsing/generating text.

String output = myLocalDateTime.toString() ;

… and:

LocalDateTime myLocalDateTime = LocalDateTime.parse( "2022-11-23T00:00:00.0000" ) ;

See that code run at Ideone.com.

Another tip: If you are trying to represent a moment, a specific point on the timeline, always include an offset-from-UTC or a time zone. The LocalDateTime class cannot represent a moment as it lacks the context of an offset or zone.

  • Related