I am using Apache commons-csv
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 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 output. Instead, this method is merely a shortcut for using CSVPrinter
to generate the text of what would be written to your CSV if your CSV 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" ) ) ;
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.