I used to support Java Date
or Joda Localdate
pattern in binding using Spring DateTimeFormat pattern
attribute like this
@DateTimeFormat(pattern = "dd.MM.yyyy")
private LocalDate creationDate;
But I need to support two date patterns, for example:
If the user entered 31/12/1999
or 31/12/99
, then both of them could be bound to the same value 31/12/1999
. Is it possible to define two patterns for the @DateTimeFormat
?
EDIT:
I tried to change the pattern to
@DateTimeFormat(pattern = "dd.MM.yy")
private LocalDate creationDate;
And I found that it could handle both cases (e.g. when the user enters 31/12/1999
or 31/12/99
) both are bound to 31/12/1999
. Any comments?
It appears to me that the spring annotation @DateTimeFormat bound to an attribute of type LocalDate
will cause Spring to choose a JodaTime-Formatter, not the standard formatter, otherwise Spring would not be able to successfully parse any input string to an object of type LocalDate
. This statement is done on the analysis of Spring source code (see implementation of method getParser(DateTimeFormat annotation, Class<?> fieldType)
).
If so then the question remains why your work-around and solution "dd.MM.yy" is able to parse two-digit-years as well as normal four-digit-years. The answer can be found in Joda sources and documentation.
Source extract of org.joda.time.format.DateTimeFormat (pattern analysis of JodaTime done in private method parsePatternTo(DateTimeFormatterBuilder builder, String pattern)
):
case 'y': // year (number)
case 'Y': // year of era (number)
if (tokenLen == 2) {
boolean lenientParse = true;
// Peek ahead to next token.
if (i + 1 < length) {
indexRef[0]++;
if (isNumericToken(parseToken(pattern, indexRef))) {
// If next token is a number, cannot support
// lenient parse, because it will consume digits that it should not.
lenientParse = false;
}
indexRef[0]--;
}
// Use pivots which are compatible with SimpleDateFormat.
switch (c) {
case 'x':
builder.appendTwoDigitWeekyear(new DateTime().getWeekyear() - 30, lenientParse);
break;
case 'y':
case 'Y':
default:
builder.appendTwoDigitYear(new DateTime().getYear() - 30, lenientParse);
break;
}
So we recognize that JodaTime translates the pattern expression "yy" to a call to builder-method appendTwoDigitYear()
with the argument lenientParse set to true
. Interesting also that the choosen pivot year deviates from usual Joda setting (+/-50 years), namely (-80/+20 years).
In the Javadoc of mentioned builder-method it is said:
"lenientParse - when true, if digit count is not two, it is treated as an absolute year"
That sufficiently explains why "dd.mm.yy" can as well parse two-digit-years as four-digit-years.
The current implementation of DateFormatter for Spring only allows the setting of one pattern.
As your edit found and as per the Java Documentation for SimpleDateFormat, using "yy" results in SimpleDateFormat interpreting the abbreviated year relative to some century. It does this by adjusting dates to be within 80 years before and 20 years after the time the SimpleDateFormat instance is created.
If you wanted to define a DateFormatter that accepts a list or a set of patterns and instead of calling return getDateFormat(locale).parse(text);
when its parse method is called , you would have to implement a CustomDateFormatter which implements the interface Formatter<T>
as mentioned at Spring 3 Field Formatting.
Instead of a single String for the pattern private variable, you would have a list of strings and your parse method would be similar to the example in this StackOverflow Question.
Implement AnnotationFormatterFactory
as mentioned at Spring 3 Field Formatting, and then you can specify your list of patterns as an Annotation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With