这个将字符串解析为LocalDate对象的额外检查是否必要?

huangapple go评论75阅读模式
英文:

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)。

如果你想删除它,你应该检查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).

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-12z2020-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 是一个未检查的异常。

链接

DateTimeFormatter.ISO_DATE 文档

英文:

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.

Documentation of DateTimeFormatter.ISO_DATE

huangapple
  • 本文由 发表于 2020年8月12日 06:37:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/63367295.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定