Details
-
Improvement
-
Resolution: Unresolved
-
Major
-
None
-
2.2
-
None
-
Unknown
-
Description
Steps to reproduce
- Create an XWiki class with a date property having format "MM/yyyy"
- In the BatchImport configuration, specify the default date format as "dd/MM/yyyy"
- Import data containing dates with format "dd/MM/yyyy", for example a row containing the string value "01/03/2019"
Expected behaviour
The data gets imported with dates resulting from a parsing using the default format, since the data format is not the one declared in the class. For example "01/03/2019" should be interpreted as March 1 00:00:00 2019.
Actual behaviour
The data gets imported with wrong dates. For example "01/03/2019" is interpreted as Mon Jan 01 00:00:00 CET 3.
Notes towards a fix
Java example of the issue
String dateAsString = "01/03/2019"; String format = "MM/yyyy"; SimpleDateFormat formatter = new SimpleDateFormat(format); format.setLenient(false); // does actually not change the output Date date = formatter.parse(dateAsString); System.out.println(date);
Produces the output below, while a ParseException would be more expected:
Mon Jan 01 00:00:00 CET 3
Possible solutions
Check that the parsed date, once re-formatted as a string, is equal to the original string
if (!dateAsString.equals(formatter.format(date))) { throw new ParseException("Invalid date format", 0); }
Reference: https://rolfje.wordpress.com/2010/03/06/simple-strict-date-parsing/
Use DateTimeFormatter
DateTimeFormatter provides a more strict parsing by default, and advanced strictness configuration levels. With the code below, an attempt to parse "01/03/2019" will throw an exception, as expected. The wiki or user timezone should to be used instead of the system default.
DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendPattern(format) .parseDefaulting(ChronoField.YEAR_OF_ERA, ZonedDateTime.now().getYear()) .parseDefaulting(ChronoField.DAY_OF_MONTH, 1) .parseDefaulting(ChronoField.DAY_OF_MONTH, 1) .parseDefaulting(ChronoField.HOUR_OF_DAY, 0) .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0) .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0) .toFormatter(); LocalDate dateTime = LocalDate.parse(dateAsString, formatter); System.out.println(localDate); date = Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());