5

我试图理解两件事:

  1. 为什么下面的代码不抛出异常(因为SimpleDateFormat不宽容)
  2. 它没有抛出异常,但是为什么将年份解析为 0013 (而不是使用此处的规则,即从今天开始的 +80:-20 年规则)

这是代码

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class TestDate {
    public static void main(String[] args) throws Exception {
        SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
        format.setLenient(false);
        Date date = format.parse("01/01/13"); // Since this only has a 2 digit year, I would expect an exception to be thrown

        System.out.println(date); // Prints Sun Jan 01 00:00:00 GMT 13

        Calendar cal = Calendar.getInstance();
        cal.setTime(date);

        System.out.println(cal.get(Calendar.YEAR)); // Prints 13
    }
}

如果它有所作为,我在 Ubuntu 上使用 java 1.6.0_38-b05

4

4 回答 4

3

问题 1.这是Java 的 SimpleDateFormat 解析 this的部分副本。关于这个问题的第二个答案很好地回答了这个问题。它的症结在于:

Number:解析时忽略模式字母的数量,除非需要分隔两个相邻字段。 年份:在解析过程中,只有恰好包含两位数字 […] 的字符串才会被解析为默认世纪。任何其他数字字符串,例如一位数字字符串、三位或更多数字字符串或并非全为数字的两位数字字符串(例如,“-1”),都按字面意思解释。所以“01/02/3”或“01/02/003”被解析,使用相同的模式

问题2.仔细看:您的输入格式与您传递给函数的格式不同。

new SimpleDateFormat("dd/MM/yyyy");

对比

format.parse("01/01/13");

解析01/01/2013或使用日期格式'dd/MM/yy'

于 2013-08-08T13:55:41.730 回答
3

根据 JDK 1.6 的SimpleDateFormat javadoc

对于解析,模式字母的数量将被忽略,除非需要分隔两个相邻的字段。

查看完成工作的方法的源代码SimpleDateFormat.parse(String, ParsePosition),确认了这一点。obeyCount如果模式没有分隔符,则有一个变量为真,如“yyyyMMdd”,否则为假。使用您的模式,解析器会查找由 2 个分隔符分隔的 3 个数字,而不关心每个位置的位数。

您的问题的答案:

  1. Lenient不是使用分隔符时的一个因素。
  2. 你没有打电话SimpleDateFormat.set2DigitYearStart,为什么代码应该做你没有告诉它做的事情?
于 2013-08-08T14:15:49.857 回答
3

简单日期格式 API:

对于解析,如果模式字母的数量超过 2 个,则按字面解释年份,而不考虑位数。所以使用模式 "MM/dd/yyyy", "01/11/12" 解析到公元 12 年 1 月 11 日

至于 lenient,当它设置为 false 时,解析会抛出无效日期的异常,例如 01/32/12,而在 lenient 模式下,此日期被视为 02/01/12。SimpleDateFormat 在内部使用 Calendar,有关宽大处理的详细信息可以在 Calendar API 中找到。

于 2013-08-08T14:09:39.580 回答
1

java.time

使用 java.time,现代 Java 日期和时间 API,您所期望的异常肯定会出现:

    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
    String strToParse = "01/01/13";
    LocalDate date = LocalDate.parse(strToParse, dateFormatter);

结果:

Exception in thread "main" java.time.format.DateTimeParseException: Text '01/01/13' could not be parsed at index 6
  at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
  at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
  at java.base/java.time.LocalDate.parse(LocalDate.java:428)

如果向右滚动,您将看到异常消息提到“无法在索引 6 处解析”。字符串中的索引 6 是两位数年份所在的位置,预计四位数。

当这个问题在将近 7 年前被问到时,使用SimpleDateFormatandDate是可以接受的。它们的设计总是很糟糕,并且在提出问题 7 个月后更换了它们,因此它们现在被认为已经过时了。我强烈建议改用 java.time。

关联

Oracle 教程:日期时间解释如何使用 java.time。

于 2020-06-08T18:35:07.670 回答