Skip to content
Open
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
22 changes: 17 additions & 5 deletions src/main/java/org/apache/commons/cli/Converter.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
Expand Down Expand Up @@ -82,15 +83,26 @@ public interface Converter<T, E extends Exception> {
final SimpleDateFormat format = new SimpleDateFormat(pattern);
// reject out-of-range fields (for example "Feb 30") instead of silently rolling them over.
format.setLenient(false);
try {
return format.parse(s);
} catch (final java.text.ParseException e) {
// SimpleDateFormat.parse(String) stops at the first character it cannot use and ignores any
// trailing text, so "<valid date> garbage" would be accepted. Parse from an explicit position
// and reject the value unless the whole string is consumed.
final ParsePosition pos = new ParsePosition(0);
Date date = format.parse(s, pos);
if (date == null) {
// Date.toString() always emits English month/day names, so fall back to Locale.ENGLISH
// when the default locale rejects the documented format.
// when the default locale rejects the documented format. Only retry when the default
// locale matched nothing; a partial match is a trailing-text failure, handled below.
final SimpleDateFormat englishFormat = new SimpleDateFormat(pattern, Locale.ENGLISH);
englishFormat.setLenient(false);
return englishFormat.parse(s);
pos.setIndex(0);
pos.setErrorIndex(-1);
date = englishFormat.parse(s, pos);
}
if (date == null || pos.getIndex() != s.length()) {
final int errorIndex = pos.getErrorIndex() >= 0 ? pos.getErrorIndex() : pos.getIndex();
throw new java.text.ParseException(String.format("Unparseable date: \"%s\"", s), errorIndex);
}
return date;
};

/**
Expand Down
18 changes: 18 additions & 0 deletions src/test/java/org/apache/commons/cli/ConverterTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,24 @@ void testDate() throws Exception {
assertThrows(java.text.ParseException.class, () -> Converter.DATE.apply("Jun 06 17:48:57 EDT 2002"));
}

@Test
void testDateRejectsTrailingText() throws Exception {
final Date expected = new Date(1023400137000L);
final String formatted = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy").format(expected);
assertThrows(java.text.ParseException.class, () -> Converter.DATE.apply(formatted + " trailing"));
}

@Test
@DefaultLocale(language = "de", country = "DE")
void testDateRejectsTrailingTextLocaleDe() throws Exception {
// Trailing text must be rejected even when a non-English default locale parses the date, and
// the reported error position should point past the parsed date rather than at index 0.
final Date expected = new Date(1023400137000L);
final String formatted = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy").format(expected);
final java.text.ParseException e = assertThrows(java.text.ParseException.class, () -> Converter.DATE.apply(formatted + " trailing"));
assertEquals(formatted.length(), e.getErrorOffset());
}

@Test
@DefaultLocale(language = "de", country = "DE")
void testDateLocaleDe() throws Exception {
Expand Down
Loading