我很惊讶地发现,在DateFormat.parse()
使用DateFormat.SHORT
时,一年中嵌入的某些字符(例如$或&)会“成功”解析。例如,"08/01/20&&"
将解析为"Sat Aug 01 00:00:00 EDT 2020"
。
我更加惊讶的是我找不到任何点击这个问题。
练习是解析和验证日期。我们可以扫描我们正在解析特殊字符的字符串,但这看起来很无聊。
有人有任何建议吗?
public static void main(String[] args) {
String s = "08/01/20&&";
Date value = null;
try {
value = getDateFormat().parse(s);
} catch (ParseException pe) {
System.out.println("' must be a valid date in the form 'mm/dd/yyyy'");
}
System.out.println("Value:" + value);
}
public static DateFormat getDateFormat() {
DateFormat formatDate = null;
if (formatDate == null) {
formatDate = DateFormat.getDateInstance(DateFormat.SHORT);
//or at least in English locale
//formatDate = DateFormat.getDateInstance(DateFormat.SHORT,Locale.ENGLISH);
formatDate.setLenient(false);
}
return formatDate;
}
答案 0 :(得分:4)
DateFormat
返回的DateFormat.getDateInstance
为SimpleDateFormat
。
formatDate instanceof SimpleDateFormat => true
根据Locale.US
中的M/d/yy
方法,模式(toPattern()
)为SimpleDateFormat
。
parse
方法似乎不会考虑超出日期模式的尾随文本。 s
的以下值将生成Sat Aug 01 00:00:00 PDT 2020
,而不会抛出异常。对于格式字符20
,2020
被解释为yy
,并且后面的文字似乎被忽略。
"08/01/20"
"08/01/20&&"
"08/01/20**"
"08/01/20..."
"08/01/20ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Javadocs for DateFormat.parse
州:
从给定字符串的开头解析文本以生成日期。该方法可能不会使用给定字符串的整个文本。
当然不会解析整个字符串。此外,您使用的&
字符没有什么特别之处,除了它们是无关紧要的事实。
您可以获取模式的长度,然后将其与输入字符串的长度进行比较,以查看是否存在无关字符。这适用于DateFormat.SHORT
,因为预期的字符数最多为8。
答案 1 :(得分:1)
随着 2014 年 3 月 Java SE 8 的发布,过时且容易出错的旧日期时间 API(java.util
日期时间类型及其格式类型 SimpleDateFormat
等)被取代由 java.time
、modern date-time API* 编写,强烈建议改用此新 API。
使用现代 API,您就不会遇到这个问题,例如
有效日期:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String s = "08/01/20";
DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).localizedBy(Locale.ENGLISH);
System.out.println(LocalDate.parse(s, dtf));
}
}
输出:
2020-08-01
日期无效:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String s = "08/01/20&&";
DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).localizedBy(Locale.ENGLISH);
System.out.println(LocalDate.parse(s, dtf));
}
}
输出:
Exception in thread "main" java.time.format.DateTimeParseException:
Text '08/01/20&&' could not be parsed, unparsed text found at index 8
如果我希望现代 API 的行为方式与 SimpleDateFormat
默认情况下的行为方式相同。 following rule:
从给定字符串的开头解析文本以生成日期。 该方法可能不会使用给定字符串的整个文本。
如果您需要,DateTimeFormatter#parse(CharSequence, ParsePosition)
随时为您服务:
import java.text.ParsePosition;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String s = "08/01/20&&";
DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).localizedBy(Locale.ENGLISH);
LocalDate date = LocalDate.from(dtf.parse(s, new ParsePosition(0)));
System.out.println(date);
}
}
输出:
2020-08-01
从 modern date-time API 中详细了解 java.time
,Trail: Date Time*。
这是您可以使用旧 API 完成的工作。
import java.text.DateFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws ParseException {
String s = "08/01/20&&";
ParsePosition pp = new ParsePosition(0);
Date value = DateFormat.getDateInstance(DateFormat.SHORT, Locale.ENGLISH).parse(s, pp);
if (value == null || pp.getIndex() != s.length()) {
System.out.println("The input must be a valid date in the form MM/dd/yyyy");
} else {
System.out.println("Value: " + value);
}
}
}
输出:
The input must be a valid date in the form MM/dd/yyyy
ParsePosition#getIndex
返回解析的最后一个字符之后的字符索引,即字符串 &
中第一个 08/01/20&&
的索引。
* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaring 和 How to use ThreeTenABP in Android Project。