繁体   English   中英

Lenient SimpleDateFormat表现得很奇怪

[英]Lenient SimpleDateFormat acting strange

我理解,为了正确验证日期字符串,必须使DateFormat实例非宽松,以便从格式错误的日期获取所有ParseExceptions。 但考虑一下

String  dubiousDate = "2014-04-01";
DateFormat  sdf = new SimpleDateFormat( "yyyyMMdd");
Date d;
try {
    d = sdf.parse( dubiousDate);
    System.out.println( dubiousDate + " -> " + d);
} catch ( ParseException e) {
    e.printStackTrace();
    System.err.println( dubiousDate + " failed");
}

这会给

2014-04-01 - > Wed Dec 04 00:00:00 CET 2013

现在我可以理解宽松的日历试图很好并接受有趣的负数,但这种解释看起来像-01被认为是月份,即使它出现在最后,日期也是如此。 -04个月变为04天,减去忽略。

在所有宽大处理中,为什么这对任何人都有意义?

我看到另一种可能的解释:

在模式yyyyMMdd中,月份部分限于精确的两个字符,因为不同的数字字段之间没有分隔符。 因此,“-0”将被视为月份,仅为零,比1月份的一个月产生去年12月。

在“解析”假月之后,日期部分在第二个减去字符之前停止“4”。 结果是12月4日。

最后,剩下的字符“-01”被忽略了。 这是SimpleDateFormat类关于如何处理非数字尾随字符的典型情况,例如,请参阅以下代码:

String dubiousDate = "2014-04-01xyz";
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d;
try {
    d = sdf.parse(dubiousDate);
    System.out.println(dubiousDate + " -> " + d);
    // output: Tue Apr 01 00:00:00 CEST 2014
} catch (ParseException e) {
    e.printStackTrace();
    System.err.println(dubiousDate + " failed");
}

作为拇指规则,只有两个相等的符号字符MM或dd,解析器最多只消耗两个字符(如果找到数字)。

关于Java 8的一些研究:

DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
builder.parseLenient();
builder.append(DateTimeFormatter.ofPattern("yyyyMMdd"));
DateTimeFormatter dtf = builder.toFormatter();
String dubiousDate = "2014-04-01";
LocalDate date = LocalDate.parse(dubiousDate, dtf);
System.out.println(date);

根据JDK-8文档,以这种方式构造的格式化程序应该表现得很宽松,但不幸的是仍然会抛出异常:

“线程中的异常”主“java.time.format.DateTimeParseException:无法在索引3处解析文本'2014-04-01'”

最好的选择是在宽松的情况下 - 理论上 - 如果解析器只是忽略减去字符。 但显然这对JSR-310来说是不可能的(仍然太严格)。 嗯, SimpleDateFormat很宽松,但方式错误。

这没有意义。 这对我来说听起来像个错误。

我认为正确的答案是等待最终完成日期的Java 8。 例如,您的代码现在可以更改为类似下面的内容。 并且,Java会抛出异常,就像它应该的那样。

import java.util.*;
import java.lang.*;
import java.io.*;

import java.text.DateFormat;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class Main {
  public static void main(String[] args) {
    String dubiousDate = "2014-04-01";
    LocalDate d;
    try {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        d = LocalDate.parse(dubiousDate, formatter);
        System.out.println(dubiousDate + " -> " + d);
      }
      catch (Exception e) {
        e.printStackTrace();
        System.err.println(dubiousDate + " failed");
      }
    }
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM