23

我有这个代码:

  DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
  dateFormat.setLenient(false);
  Date date = dateFormat.parse("10/20/20128");

我希望 dateFormat.parse 调用抛出 ParseException 因为我提供的年份是 5 个字符长,而不是像我定义的格式中的 4 个字符。但出于某种原因,即使将 lenient 设置为 false,此调用也会返回 10/20/20128 的 Date 对象。

这是为什么?这对我来说没有多大意义。是否有其他设置使其更加严格?

4

5 回答 5

41

20128 年是有效的一年,Java 希望世界能活那么久。

如果模式字母的数量超过 2 个,则按字面解释年份,而不考虑位数。

参考。

如果您想验证日期是否有限制,您可以定义一个并检查 -

SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
Date maxDate = sdf.parse("01/01/2099");  // This is the limit

if(someDate.after(maxDate)){            
    System.out.println("Invalid date");            
}
于 2013-08-30T13:45:07.387 回答
11

请参阅javadoc

年份:如果格式化程序的日历是公历,则应用以下规则。

  • 对于格式化,如果模式字母的个数为2,则年份被截断为2位;否则它被解释为一个数字。
  • 对于解析,如果模式字母的数量超过 2 个,则按字面解释年份,而不考虑位数。所以使用模式 "MM/dd/yyyy", "01/11/12" 解析到公元 12 年 1 月 11 日
  • 对于使用缩写年份模式(“y”或“yy”)进行解析,SimpleDateFormat 必须解释相对于某个世纪的缩写年份。它通过将日期调整为创建 SimpleDateFormat 实例之前的 80 年和之后的 20 年来实现这一点。例如,使用“MM/dd/yy”模式和
    1997 年 1 月 1 日创建的 SimpleDateFormat 实例,字符串“01/11/12”将被
    解释为 2012 年 1 月 11 日,而字符串“05/04/ 64" 将被
    解释为 1964 年 5 月 4 日。在解析期间,只有
    由 Character.isDigit(char) 定义的正好包含两位数字的字符串才会被解析为默认世纪。任何其他数字字符串,例如
    一位数字字符串、三位或更多数字字符串或并非全为数字的两位数字字符串(例如,“-1”)按字面解释。 因此,“01/02/3”或“01/02/003”使用与公元 3 年 1 月 2 日
    相同的模式进行解析。
    同样,“01/02/-3”被解析为 Jan 2, 4 BC。
  • 否则,将应用日历系统特定的表格。对于格式化和解析,如果模式字母的数量为 4 或
    更多,则使用日历特定的长格式。否则,将使用日历
    特定的短或缩写形式。

因此,它将读取最后一个之后的所有字符/作为年份。

于 2013-08-30T13:45:22.397 回答
7

参见java.text.SimpleDateFormatAPI,pattern letter y:对于解析,如果 pattern letter 的个数超过 2 个,则按字面解释年份,而不考虑位数。

于 2013-08-30T13:44:06.017 回答
1

在 java 中使用 SimpleDateFormat,可以实现多种人类可读的格式。考虑这个代码片段:

        Date curDate = new Date();

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

        String DateToStr = format.format(curDate);
        System.out.println(DateToStr);

        format = new SimpleDateFormat("dd-M-yyyy hh:mm:ss");
        DateToStr = format.format(curDate);
        System.out.println(DateToStr);

        format = new SimpleDateFormat("dd MMMM yyyy zzzz", Locale.ENGLISH);
        DateToStr = format.format(curDate);
        System.out.println(DateToStr);

        format = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
        DateToStr = format.format(curDate);
        System.out.println(DateToStr);

查看各种格式生成的各种输出:

2014/05/11

11-5-2014 11:11:51

2014 年 5 月 11 日东欧夏令时间

2014 年 5 月 11 日星期日 23:11:51 EEST

随意修改格式字符串,您可能会得到想要的结果。

于 2015-09-18T11:53:13.180 回答
0

java.time

我始终建议您使用现代 Java 日期和时间 API java.time 进行日期工作。此外,java.time 会为您提供您要求的异常。

    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("MM/dd/uuuu")
            .withResolverStyle(ResolverStyle.LENIENT);
    LocalDate date = LocalDate.parse("10/20/20128", dateFormatter);

结果:

线程“主”java.time.format.DateTimeParseException 中的异常:无法在索引 6 处解析文本“10/20/20128”

提到的索引 6是 5 位数年份在您的字符串中的位置。

这就是说,其他人建议的范围检查仍然是一个好主意。使用 java.time 这很容易。例如说我们不想接受任何未来的日期:

    LocalDate date = LocalDate.parse("10/20/8012", dateFormatter);
    if (date.isAfter(LocalDate.now(ZoneId.systemDefault()))) {
        System.err.println("Date must not be in the future, was " + date);
    }

日期不得在未来,为 8012-10-20

教程链接: Trail: Date Time(Java™ 教程)解释如何使用 java.time。

于 2021-12-05T12:02:24.327 回答