英文:
Is this additional check for parsing a string to LocalDate object necessary?
问题
我正在为验证用户出生日期的一些旧代码编写一些测试。我在类中遇到了以下方法。我疑惑的是try块中的if语句是否必要。根据我的理解,如果解析函数成功返回一个LocalDate对象,那么date.toString()应该始终等于输入的dobstr,没有必要进行额外的检查。我是否漏掉了什么?我想不出任何需要这个额外检查的情况。请帮忙。谢谢!
以下是您在DateTimeFormatter.ISO_DATE源代码中找到的内容:
public static final DateTimeFormatter ISO_DATE;
static {
ISO_DATE = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(ISO_LOCAL_DATE)
.optionalStart()
.appendOffsetId()
.toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
}
英文:
I was writing some tests for some legacy code that validates a user's date of birth. I encounter the following method in the class. My doubt is that whether the if statement in the try block is necessary. From my understanding, if the parse function returns a LocalDate object successfully, then date.toString() should always equal to the input dobstr, and there's no need to do an additional check. Am I missing anything? I could not think of any case that we need this extra check. Please help. Thanks!
private LocalDate format(String dobStr) throws Exception {
LocalDate date = null;
try {
date = LocalDate.parse(dobStr, DateTimeFormatter.ISO_DATE);
if (!dobStr.equals(date.toString())) {
throw new DateTimeParseException("some message");
}
}
catch (DateTimeParseException ex) {
throw ex;
}
return date;
}
this is what I found in the source code for DateTimeFormatter.ISO_DATE
public static final DateTimeFormatter ISO_DATE;
static {
ISO_DATE = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(ISO_LOCAL_DATE)
.optionalStart()
.appendOffsetId()
.toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
}
答案1
得分: 5
唯一的原因,我认为要进行toString()
检查的唯一原因是为了避免宽松问题:解析器可能是宽松的,并尝试解释错误的值(例如:2020-12-32可能被解释为2021-01-01)。
- DateFormat允许解析器宽松
- DateTimeFormatter提供相同的行为,默认值为
ResolverStyle.SMART
。
如果你想删除它,你应该检查DateTimeFormatter.ISO_DATE
默认是否为ResolverStyle.STRICT
。假设默认情况下不是STRICT,你的代码可以是:
private LocalDate format(String dobStr) throws Exception {
return LocalDate.parse(dobStr, DateTimeFormatter.ISO_DATE.withResolverStyle(ResolverStyle.STRICT));
}
英文:
The only reason that I could see for doing a toString()
check would be to avoid lenient issue: the parser may be lenient and try to interpret wrong values (for example: 2020-12-32 could be interpreted as 2021-01-01).
- DateFormat allows the parser to be lenient
- The same behaviour is offered by DateTimeFormatter and the default value is
ResolverStyle.SMART
.
If you want to remove it, you should check if DateTimeFormatter.ISO_DATE
is ResolverStyle.STRICT
by default or not. Assuming it is not STRICT by default, your code could be:
private LocalDate format(String dobStr) throws Exception {
return LocalDate.parse(dobStr, DateTimeFormatter.ISO_DATE.withResolverStyle(ResolverStyle.STRICT));
}
答案2
得分: 2
TL;DR: 检查使得结果不同
如果字符串包含不希望的偏移ID,您仍然可以使用 DateTimeFormatter.ISO_DATE
进行解析。但是由于 LocalDate
不能具有偏移(这就是名称中的 local 的含义),toString()
的结果永远不会包含该偏移ID,因此字符串不会相等。
DateTimeFormatter.ISO_DATE
在日期后面接受一个可选的偏移ID。因此,如果您解析 2020-08-12z
或 2020-08-12+01:02:03
,则会抛出自定义异常。但是有一个细节:DateTimeParseException
没有匹配单个字符串参数的构造函数,因此代码无法编译。我认为这是从原始代码复制粘贴时出现的疏忽。
演示如下:
String dobStr = "2020-08-12+01:02:03";
LocalDate date = LocalDate.parse(dobStr, DateTimeFormatter.ISO_DATE);
String asStringAgain = date.toString();
System.out.format("Original string: %s; result of toString(): %s; equal? %s%n",
dobStr, asStringAgain, dobStr.equals(asStringAgain));
输出是:
> 原始字符串:2020-08-12+01:02:03; toString() 的结果:
> 2020-08-12; 相等吗?false
如何避免检查
除非在不希望的偏移情况下需要自定义异常,否则可以更简单地编写该方法:
private LocalDate format(String dobStr) throws Exception {
return LocalDate.parse(dobStr, DateTimeFormatter.ISO_LOCAL_DATE);
}
DateTimeFormatter.ISO_LOCAL_DATE
不接受字符串中的任何偏移。它与 DateTimeFormatter.ISO_DATE
一样严格,因此我们知道 toString()
将创建相同的字符串。
此外,您可以声明该方法为 static
,并且可以省略 throws Exception
,因为 DateTimeParseException
是一个未检查的异常。
链接
英文:
TL;DR: The check makes a difference
If the string contains an unwanted offset ID, you will still be able to parse it using DateTimeFormatter.ISO_DATE
. But since a LocalDate
cannot have an offset (this is what local in the name means), the result of toString()
will never have that offset ID, so the strings will not be equal.
DateTimeFormatter.ISO_DATE
accepts an optional offset ID after the date. So if you are parsing 2020-08-12z
or 2020-08-12+01:02:03
, the custom exception would be thrown. Except for a detail: DateTimeParseException
hasn’t got a constructor that matches a single string argument, so the code doesn’t compile. I reckon that this comes from sloppy copy-paste from the original code.
To demonstrate:
String dobStr = "2020-08-12+01:02:03";
LocalDate date = LocalDate.parse(dobStr, DateTimeFormatter.ISO_DATE);
String asStringAgain = date.toString();
System.out.format("Original string: %s; result of toString(): %s; equal? %s%n",
dobStr, asStringAgain, dobStr.equals(asStringAgain));
Output is:
> Original string: 2020-08-12+01:02:03; result of toString():
> 2020-08-12; equal? false
How to obviate the check
Unless you require a custom exception in the case of an unwanted offset, the method may be written much more simply:
private LocalDate format(String dobStr) throws Exception {
return LocalDate.parse(dobStr, DateTimeFormatter.ISO_LOCAL_DATE);
}
DateTimeFormatter.ISO_LOCAL_DATE
does not accept any offset in the string. And it is strict just like DateTimeFormatter.ISO_DATE
, so we know that toString()
would create the same string again.
Furthermore you may declare the method static
, and you may leave out throws Exception
since DateTimeParseException
is an unchecked exception.
Link
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论