我使用SimpleDateFormat
将字符串解析为Date
个对象,我想知道为什么结果不符合我的预期。
例如:
DateFormat yyyyMMdd = new SimpleDateFormat("yyyyMMdd");
Date date = yyyyMMdd.parse("20100725");
System.out.println(date);
按预期工作和输出
Sun Jul 25 00:00:00 CEST 2010
但是
Date date = yyyyMMdd.parse("2010-07-25");
System.out.println(date);
也可以工作和输出
Mon Dec 07 00:00:00 CET 2009
我预计会有ParseException
,但似乎SimpleDateFormat
会将月份-07
和日期-25
解释为负数。首先,我无法弄清楚它是如何到达12月7日的。所以我尝试了另一个值:
Date date = yyyyMMdd.parse("2010-7-25");
System.out.println(date);
并且它outpus
Sun Apr 05 00:00:00 CEST 2009
所以它似乎以某种方式从7
中减去2010
个月,这可能是5月1日,25
天所以结果是2009年4月5日。
您在服务实现中使用模式yyyyMMdd
的图像,而某个客户端意外地将日期发送为yyyy-MM-dd
。你不会得到例外。相反,你会得到完全不同的日期。我猜这不是你所期望的。
E.g。
String clientData = "2010-05-23";
DateFormat yyyyMMdd = new SimpleDateFormat("yyyyMMdd");
Date parsedDate = yyyyMMdd.parse(clientData);
System.out.println("Client : " + clientData);
System.out.println("Service : " + yyyyMMdd.format(parsedDate));
我错过了什么吗?
如何阻止SimpleDateFormat
解析错误的'日期吗
当然我可以先使用正则表达式进行检查,但是有更好的方法吗?
答案 0 :(得分:5)
使用SimpleDateFormat.setLenient(false);
获取例外。否则它将尝试尽可能最好地解析输入,这通常是错误的。
出于某种原因,他们认为默认情况下宽大处理应该是真的,但那是hardly a surprise。
指定日期/时间解析是否宽松。同 宽松解析,解析器可以使用启发式来解释输入 与该对象的格式不完全匹配。严格要求 解析时,输入必须与此对象的格式匹配。
答案 1 :(得分:2)
SimpleDateFormat.setLenient(false);
需要做什么,或者尝试解析输入,如您所知,这并不总是有效。使用上面的函数,编译器将严格格式化。
答案 2 :(得分:1)
accepted Answer by Cayman是正确的:默认解析是宽容的问题。
您正在使用现在由java.time类取代的麻烦的旧日期时间类。
java.time中没有这种默认的宽大问题。如果输入与格式化模式不完全匹配,则抛出DateTimeParseException
。
LocalDate
类表示没有时间且没有时区的仅限日期的值。
对于YYYY-MM-DD的标准ISO 8601格式输入,只需直接拨打parse
。
String input = "2010-05-23";
try {
LocalDate ld = LocalDate.parse( input ); // Expects standard ISO 8601 input format.
} catch ( DateTimeParseException e ) {
…
}
ISO 8601标准允许“基本”格式,以最大限度地减少分隔符的使用。不是我推荐这些变化,但它们存在。
目前,java.time仅预定义了这些“基本”变体中的一个DateTimeFormatter.BASIC_ISO_DATE
。
String input = "20100725";
try {
LocalDate ld = LocalDate.parse( input , DateTimeFormatter.BASIC_ISO_DATE );
} catch ( DateTimeParseException e ) {
…
}
对于其他格式,请指定格式化程序。
String input = "2010/07/25";
try {
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu/MM/dd" );
LocalDate ld = LocalDate.parse( input , f ); // Custom format.
} catch ( DateTimeParseException e ) {
…
}
或者让java.time确定本地化格式。
String input = … ;
try {
Locale l = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDate( FormatStyle.MEDIUM ).withLocale( l );
LocalDate ld = LocalDate.parse( input , f ); // Localized format.
} catch ( DateTimeParseException e ) {
…
}
答案 3 :(得分:0)
首先,如果你想解析String" 2010-05-23"你的面具应该是" yyyy-MM-dd"而不是" yyyyMMdd"。第二个SimpleDateFormat存在严重问题,因为它不是Thread安全的。如果你使用java 8,那么使用learn并使用new package" java.time"。如果您使用早期版本8之前的任何Java,则使用其他一些框架来解析日期。其中最受欢迎的是Joda时间。效果更好。