问题 为什么Java的SimpleDateFormat会解析这个问题


嗨,我有一个简单的日期格式设置自定义格式字符串: MMDDYY

我给它以下值来解析: 4 1 01

我不认为它应该解析这个因为空格,但简单日期格式返回日期

4月4日0001AD

任何想法为什么?


3399
2018-04-06 10:01


起源

建议使用DateFormat而不是SimpleDateFormat,我建议通过JavaDoc来解释这种行为。 - Mahmoud Hossam
SimpleDateFormat 扩展 DateFormat 并且使用没有任何问题 SimpleDateFormat 直 - a_horse_with_no_name


答案:


这是预期的行为 - 你告诉DateFormat对象期望一个6字符的字符串表示日期,这是你传入的。空格被解析好。但是,如果您使用“4x1x01”,则会出错。请注意,在解析时,leniency默认为true,例如

DateFormat df = new SimpleDateFormat("MMddyy");
Date date = df.parse("4 1 01"); // runs successfully (as you know)

DateFormat df = new SimpleDateFormat("MMddyy");
Date date = df.parse("41 01"); // 5 character String - runs successfully

DateFormat df = new SimpleDateFormat("MMddyy");
df.setLenient(false);
Date date = df.parse("41 01"); // 5 character String - causes exception

DateFormat df = new SimpleDateFormat("MMddyy");
Date date = df.parse("999999"); // 6 character String - runs successfully

DateFormat df = new SimpleDateFormat("MMddyy");
df.setLenient(false);
Date date = df.parse("999999"); // 6 character String - causes exception

当leniency设置为true(默认行为)时,解析会尝试解密无效输入,例如31个月的第35天成为下个月的第4天。


10
2018-04-06 10:44



Lenient设置为false,我将SimpleDateFormats 2DigitYearStart设置为1950但它仍然将“4 1 01”视为第一个0001 - Craig Warren
你在哪一年期待? - CodeClimber
好吧,我已经将2digityearstart设置为1950年1月1日,所以我希望它能在规则之前使用80之后才能确定01应该被视为2001 - Craig Warren
我认为它是在1之后读取空间作为年度的第一个字符,因此它将年份视为3位数。你可以在你的DateFormat对象中包含空格,即“new SimpleDateFormat(”MM dd yy“) - 这应该有效。或者甚至更好,从String中删除空格。 - CodeClimber
注意:DateFormat实际上不是指望6个字符。模式的大小(重复字母的数量)控制格式化/解析,但它不是生成/预期文本的长度。它只是最小长度 格式化 数字演示(周,日,小时......),用于 解析 该演示文稿被“忽略,除非需要将相邻的字段分开。” - Carlos Heuberger


对于 解析 模式的大小(重复字符的数量)不是相应文本的预期大小。从javadoc中,针对不同的相关表示类型:

  • :对于解析,模式字母的数量是 忽视 除非需要将两个相邻的区域分开。
  • :在解析期间,只有字符串组成 正好两位数 [...]将被解析为默认世纪。 任何其他 数字字符串,例如一位数字符串,三位或更多位数字符串,或者不是所有数字的两位数字符串(例如,“ - 1”),按字面解释。所以使用相同的模式解析“01/02/3”或“01/02/003”
  • :如果模式字母的数量为3或更多,则将月份解释为文本;否则,它被解释为一个数字。

空格导致解析器停止解析实际的 领域 (尾随空格对数字无效)并从下一个开始。由于模式在这两个字段之间没有空格,因此不会消耗它并且是第二个字段的一部分(前导空格有效)。因此,得到的年份不是“正好两位数”,并且不会被解析为默认世纪。

解析测试(lenient 设置 false):

FORMAT   TEXT     RESULT (ISO yyyy-MM-dd)
-------------------------------------------------
dddyy    01011    2011-01-10  
dddyy    10 11    0011-01-10  (year is 3 chars: " 11")
dddyy    10 1     0001-01-10  (year is 2 char but not 2 digits: " 1")

dddy     01011    2011-01-10  ("y" same as "yy")

dd yy    10 11    2011-01-10  (ok, whitespace is consumed, year: "11")

d/y      3/4      0004-01-03  (year is not 2 digits)
d/y      3/04     2004-01-03  

M/d/y    4/6/11   2011-04-06

2
2018-04-06 14:05





2位数的年份是模糊的 - 因此它假定为0001 - 第一年将在01结束。你能转换成4位数 - 可能使用字符串操作?


0
2018-04-06 10:11



我只使用了两位数的年份,这样用户就不必输入特定的年份,如果他们只输入2位数我将2位数年份设置为1950年,但我仍然获得0001作为年份 - Craig Warren