gpt4 book ai didi

java - SimpleDateFormat 宽容导致意外行为

转载 作者:搜寻专家 更新时间:2023-11-01 02:19:41 24 4
gpt4 key购买 nike

我发现 SimpleDateFormat::parse(String source)的行为(不幸的是)默认设置为宽松:setLenient(true) .

By default, parsing is lenient: If the input is not in the form used by this object's format method but can still be parsed as a date, then the parse succeeds.

如果我将 leniency 设置为 false,文档会指出在严格解析的情况下,输入必须与该对象的格式相匹配。我在没有宽松模式的情况下使用了 SimpleDateFormat 配对,并且错误地在日期中输入了错误(字母 o 而不是数字 0) . (这里是简短的工作代码:)

// PASSED (year 199)
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.mm.yyyy");
System.out.println(simpleDateFormat.parse("03.12.199o"));
simpleDateFormat.setLenient(false);
System.out.println(simpleDateFormat.parse("03.12.199o")); //WTF?

令我惊讶的是,这已经过去了,没有 ParseException已被抛出。我会更进一步:

// PASSED (year 1990)
String string = "just a String to mess with SimpleDateFormat";

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.mm.yyyy");
System.out.println(simpleDateFormat.parse("03.12.1990" + string));
simpleDateFormat.setLenient(false);
System.out.println(simpleDateFormat.parse("03.12.1990" + string));

让我们继续:

// FAILED on the 2nd line
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd.mm.yyyy");
System.out.println(simpleDateFormat.parse("o3.12.1990"));
simpleDateFormat.setLenient(false);
System.out.println(simpleDateFormat.parse("o3.12.1990"));

最后抛出异常:Unparseable date: "o3.12.1990"。我想知道宽大程度有何不同,为什么我的第一个代码片段的最后一行没有抛出异常?文档说:

With strict parsing, inputs must match this object's format.

我的输入显然严格不匹配格式 - 我希望这种解析非常严格。为什么这(不会)发生?

最佳答案

Why does this (not) happen?

文档中没有很好地解释。

With lenient parsing, the parser may use heuristics to interpret inputs that do not precisely match this object's format. With strict parsing, inputs must match this object's format.

不过,文档确实有点帮助,它提到 DateFormat 使用的是 Calendar 对象是宽松的。 Calendar 对象本身不用于解析,而是用于将解析值解释为日期和时间(我引用 DateFormat 文档,因为 SimpleDateFormatDateFormat 的子类)。

  • SimpleDateFormat,无论是否宽松,都将接受 3 位数年份,例如 199,即使您指定了 yyyy 在格式模式字符串中。文档说的是年份:

    For parsing, if the number of pattern letters is more than 2, the year is interpreted literally, regardless of the number of digits. So using the pattern "MM/dd/yyyy", "01/11/12" parses to Jan 11, 12 A.D.

  • DateFormat,无论是否宽松,都会接受并忽略已解析文本后的文本,例如第一个示例中的小写字母 o。它反对文本之前或内部的意外文本,就像在上一个示例中将字母 o 放在前面一样。 DateFormat.parse 的文档说:

    The method may not use the entire text of the given string.

  • 正如我间接指出的那样,在将已解析的值解释为日期和时间时,宽容程度会有所不同。因此,宽松的 SimpleDateFormat 会将 29.02.2019 解释为 01.03.2019,因为 2019 年 2 月只有 28 天。严格的 SimpleDateFormat 将拒绝这样做并抛出异常.默认的宽松行为会导致非常令人惊讶和完全无法解释的结果。举个简单的例子,以错误的顺序给出日、月和年:1990.03.12 将导致 8 月 11 日公元 17 年(2001 年前)。

解决方案

VGR 已经在评论中提到 LocalDate 来自 java.time,现代 Java 日期和时间 API。根据我的经验,java.time 比旧的日期和时间类更好用,所以让我们试一试。首先尝试正确的日期字符串:

    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd.mm.yyyy");
System.out.println(LocalDate.parse("03.12.1990", dateFormatter));

我们得到:

java.time.format.DateTimeParseException: Text '03.12.1990' could not be parsed: Unable to obtain LocalDate from TemporalAccessor: {Year=1990, DayOfMonth=3, MinuteOfHour=12},ISO of type java.time.format.Parsed

这是因为我使用了你的格式模式字符串dd.mm.yyyy,其中小写的mm表示分钟。当我们足够仔细地阅读错误消息时,它确实指出 DateTimeFormatter 将 12 解释为小时的分钟,这不是我们想要的。虽然 SimpleDateFormat 默认接受了这一点(即使是严格的),java.time 更有助于指出我们的错误。该消息仅间接表示缺少月份值。我们需要为月份使用大写的 MM。同时,我正在尝试使用错误的日期字符串:

    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
System.out.println(LocalDate.parse("03.12.199o", dateFormatter));

我们得到:

java.time.format.DateTimeParseException: Text '03.12.199o' could not be parsed at index 6

索引 6 是 199 的位置。它反对,因为我们指定了 4 位数字并且只提供 3 位。文档说:

The count of letters determines the minimum field width …

它还会反对日期之后未解析的文本。简而言之,在我看来,它为您提供了您所期望的一切。

链接

关于java - SimpleDateFormat 宽容导致意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50746771/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com