parseStrict() 与 parseLenient() DateTimeFormatterBuilder java

问题描述 投票:0回答:1

鉴于:

String validInput = "2023-12-31";

String lenientInput = "2023-12-31  "; // Extra space

DateTimeFormatter strictFormatter = new DateTimeFormatterBuilder()
   .appendPattern("yyyy-MM-dd")
   .parseStrict()
   .toFormatter();

DateTimeFormatter lenientFormatter = new DateTimeFormatterBuilder()
  .appendPattern("yyyy-MM-dd")
  .parseLenient()
  .toFormatter();

LocalDate strictDate = LocalDate.parse(validInput, strictFormatter);

System.out.println("Strict: " + strictDate);   //OK WORKS

LocalDate lenientDate = LocalDate.parse(lenientInput, lenientFormatter);

System.out.println("Lenient: " + lenientDate); // 但失败了

我无法理解

parseStrict()
parseLenient()
之间的确切区别。

我尝试了很多模式,发现“宽松”和“严格”似乎没有什么区别。

parseLenient()
的作用是什么?我可以使用什么模式才能将
LocalDate.parse("2023-12-31    ", whatFormatterToUseHere)
解析为 2023 年 12 月 31 日?

编辑:-

DateTimeFormatterBuilder dfb=new DateTimeFormatterBuilder();
dfb.parseLenient();
dfb.appendPattern("MMyydd");
String s="092430";
System.out.println(dfb.toFormatter().parse(s));

为什么我会得到

java.time.format.DateTimeParseException: Text '092430' could not be parsed at index 6  
java
1个回答
3
投票

API 有点不幸;对于两个“完全”不相关的概念,“严格与宽松”的概念出现了两次。 越界宽大处理

宽松的一种“感觉”是超出界限的值。日期“2024-02-30”不存在。然而,它解析得很好:解析是逐段完成的,并且它有一个有效的年份(2024,完全有效的年份),一个有效的月份(02,没有问题)和一个有效的日期(30 就可以了。当然。 ,

在“哦,我们现在是 2024 年 02 月”的上下文中,这没有任何意义,但这不是我们正在做的事情,我们只是将字符映射到此处的字段。

在严格模式下,将这些单独的值解析为单个日期会失败,因为 2024 年 2 月 30 日不存在。在宽松模式下,解析器会捏造它并最终生成一个 LocalDate,它是 2024-02-29 或 2024-03-01 (我不确定是哪一个;如果你关心的话,这非常表明你不希望宽松从这个意义上来说)。

但这根本不是parseLenient()所做的;为了得到你使用

withResolverStyle(ResolverStyle.LENIENT)

.

字段解析宽松
 

parseLenient()

的意义在于更自由一点,特别是在如何将某些给定输入解释为我们正在解析的字段的有效值方面。例如,解析

MMM

时“02”是否为有效值(假设

MMM
表示:
月份 
作为文本
 而 02 不是文本?
在您的代码片段中,您误解了 parseLenient() 的作用

并且

您误解了如何使用它。

如何运作
您在

parseLenient()

之前

致电
appendPattern。它会修改所有进一步的 append
 调用。 
parseStrict()
 根本不执行任何操作(因为严格是默认值),
除了
 作为“取消设置”宽松模式的一种方式。你可以这样做:
DateTimeFormatter lenientFormatter = new DateTimeFormatterBuilder() .parseLenient() .appendPattern("yyyy-") .parseStrict() .appendPattern("MM-dd") .toFormatter();

这将为您提供一个格式化程序,它可以宽松地解析年份(以及分隔年份和月份的破折号),然后解析月份、日期以及严格分隔它们的破折号。调用
parseLenient()
然后调用

toFormatter()

 不会执行任何操作。
它有什么作用

它并没有像你想象的那样做。即使您向上移动

parseLenient()

以使其适用于您的模式,这些尾随空格仍然无效。

在严格模式下,如果将月份部分配置为文本,那么在解析月份时
必须采用文本形式

。在宽松模式下,如果是数字就好了。

DateTimeFormatter lenientFormatter = new DateTimeFormatterBuilder() .parseLenient() .parseCaseInsensitive() .appendPattern("yyyy-MMM-dd") .toFormatter(Locale.ENGLISH); System.out.println(LocalDate.parse("2024-Feb-20", lenientFormatter)); System.out.println(LocalDate.parse("2024-02-20", lenientFormatter)); DateTimeFormatter strictFormatter = new DateTimeFormatterBuilder() .parseCaseInsensitive() .appendPattern("yyyy-MMM-dd") .toFormatter(Locale.ENGLISH); System.out.println(LocalDate.parse("2024-Feb-20", strictFormatter)); System.out.println(LocalDate.parse("2024-02-20", strictFormatter));

运行上面的代码。最后一行是唯一失败的一行。因为它处于严格模式,并且
MMM
表示您需要文本月份,而不是数字月份。在宽松模式下,这并不重要,在严格模式下,这并不重要,并且

2024-02-20

 无法解析。
无论你设置得多么宽松,
LocalDate.parse("2024-02-20   ", lenientFormatter)

都会失败。解决这个问题的最佳方法就是简单地将它们

.trim()

去掉,而不是试图想出一个处理它的模式。
	

© www.soinside.com 2019 - 2024. All rights reserved.