Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/main/java/org/apache/commons/validator/DateValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.text.DateFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Locale;

Expand Down Expand Up @@ -97,12 +98,11 @@ public boolean isValid(final String value, final String datePattern, final boole
}
final SimpleDateFormat formatter = new SimpleDateFormat(datePattern);
formatter.setLenient(false);
try {
formatter.parse(value);
} catch (final ParseException e) {
return false;
}
if (strict && datePattern.length() != value.length()) {
final ParsePosition pos = new ParsePosition(0);
// parse(String, ParsePosition) stops at the first unparsable character instead of failing, so a strict
// match must also confirm the whole value was consumed; otherwise trailing text such as the 'f' in
// "11/11/199f" is dropped and the truncated date validates.
if (formatter.parse(value, pos) == null || strict && (pos.getIndex() < value.length() || datePattern.length() != value.length())) {
return false;
}
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,22 +143,18 @@ public static Date formatDate(final String value, final Locale locale) {
* @return The converted Date value.
*/
public static Date formatDate(final String value, final String datePattern, final boolean strict) {
Date date = null;
if (value == null || datePattern == null || datePattern.isEmpty()) {
return null;
}
try {
final SimpleDateFormat formatter = new SimpleDateFormat(datePattern);
formatter.setLenient(false);
date = formatter.parse(value);
if (strict && datePattern.length() != value.length()) {
date = null;
}
} catch (final ParseException e) {
// Bad date so return null
if (LOG.isDebugEnabled()) {
LOG.debug("Date parse failed value=[" + value + "], " + "pattern=[" + datePattern + "], " + "strict=[" + strict + "] " + e);
}
final SimpleDateFormat formatter = new SimpleDateFormat(datePattern);
formatter.setLenient(false);
final ParsePosition pos = new ParsePosition(0);
Date date = formatter.parse(value, pos);
// parse(String, ParsePosition) stops at the first unparsable character instead of failing, so a strict
// match must also confirm the whole value was consumed; otherwise trailing text such as the 'f' in
// "11/11/199f" is dropped and the truncated date validates.
if (date != null && strict && (pos.getIndex() < value.length() || datePattern.length() != value.length())) {
date = null;
}
return date;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,21 @@ void testLongLocaleOverflow() {
assertNull(GenericTypeValidator.formatLong("123x", Locale.US));
}

/**
* Tests that strict {@link GenericTypeValidator#formatDate(String, String, boolean)} rejects a value with trailing characters instead of parsing only its
* leading portion.
*/
@Test
void testFormatDateStrict() {
assertNotNull(GenericTypeValidator.formatDate("11/11/1999", "MM/dd/yyyy", true));
// The trailing 'f' used to be dropped, leaving the year parsed as 199 and the value reported as valid.
assertNull(GenericTypeValidator.formatDate("11/11/199f", "MM/dd/yyyy", true));
// An abbreviated field is still rejected in strict mode.
assertNull(GenericTypeValidator.formatDate("2/12/1999", "MM/dd/yyyy", true));
// Non-strict parsing stays lenient about the pattern length.
assertNotNull(GenericTypeValidator.formatDate("2/12/1999", "MM/dd/yyyy", false));
}

/**
* Tests the byte validation.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ void testMaxLength() {
assertTrue(GenericValidator.maxLength("12345\n\r", 7, 2), "Max=7 End=2");
}

@Test
void testIsDate() {
assertTrue(GenericValidator.isDate("11/11/1999", "MM/dd/yyyy", true), "valid strict date");
// Strict validation used to accept a value with a trailing character by parsing only its leading portion.
assertFalse(GenericValidator.isDate("11/11/199f", "MM/dd/yyyy", true), "trailing character");
assertFalse(GenericValidator.isDate("2/12/1999", "MM/dd/yyyy", true), "abbreviated month");
}

@Test
void testMinLength() {

Expand Down
Loading