繁体   English   中英

我对 java 中的 SimpleDateFormat function 有疑问

[英]I have a problem about SimpleDateFormat function in java

我不知道为什么没有错误。 代码是

String datestr = "2021-01-01";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
try {
    System.out.println(sdf.parse(datestr));
} catch (ParseException e) {
    e.printStackTrace();
}

由于日期字符串2021-01-01与格式模式字符串yyyy-MM不匹配,我曾预料到并想要一个例外。

控制台打印Fri Jan 01 00:00:00 CST 2021

相反的情况确实会导致预期的异常。 我让代码看起来像这样

        String datestr = "2021-01";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            System.out.println(sdf.parse(datestr));
        } catch (ParseException e) {
            e.printStackTrace();
        }

控制台打印错误消息:无法解析的Unparseable date: "2021-01"

谁能告诉我为什么?

您正在描述两种不同的场景:

  1. 您的输入文本包含数据多于模式将消耗的数据,并且额外的数据位于末尾。
  2. 您的输入文本包含的数据少于模式将消耗的数据。

#1 不是错误,因为parse(String)被明确记录为从输入的开头读取,直到它有足够的内容:

该方法可能不会使用给定字符串的整个文本。

#2 是一个错误,因为您的模式说它需要额外的数据(即-后跟一天)并且该数据丢失。

tl;博士

您的格式模式必须适合您的输入文本。 在第一种情况下, "2021-01-01""yyyy-MM"不匹配。 在第二种情况下, "2021-01""yyyy-MM-dd"不匹配。

改用java.time类,因为与传统类SimpleDateFormatDate搏斗是不明智的。 也更简单,不需要格式化模式。

YearMonth
.from( 
    LocalDate.parse( "2021-01-01" ) 
)
.toString()

请参阅在 IdeOne.com 上实时运行的代码

2021-01

并解析年月:

YearMonth.parse( "2021-01" )

细节

您正在使用几年前被现代java.time类取代的糟糕的日期时间类。 Sun、Oracle 和 JCP 社区因一致采用JSR 310而放弃了这些关闭。

您的输入恰好使用标准ISO 8601格式。 java.time类在解析/生成文本时默认使用这些格式。 所以不需要指定格式模式。

LocalDate ld = LocalDate.parse( "2021-01-01" ) ;
YearMonth ym = YearMonth.from( ld ) ;
String output = ym.toString() ;

至于解析"2021-01"的输入:

YearMonth ym = YearMonth.parse( "2021-01" ) ;

这是一个适度的补充。 Basil Bourque 已经为您所做的工作展示了良好且现代的解决方案,并且 Generous Badger 解释了为什么您的代码没有按照您的预期运行。

如果您将错误格式的字符串输入到每个代码示例中,Basil Bourque 的代码确实会引发预期的异常。 对于您询问的代码的现代版本:

    String datestr = "2021-01-01";
    YearMonth.parse(datestr);

结果是:

线程“主”java.time.format.DateTimeParseException 中的异常:无法解析文本“2021-01-01”,在索引 7 处找到未解析的文本

还请享受异常消息的精确程度。

如果您选择使用显式格式化程序,也会发生同样的事情:

    YearMonth.parse(datestr, DateTimeFormatter.ofPattern("uuuu-MM"));

线程“主”java.time.format.DateTimeParseException 中的异常:无法解析文本“2021-01-01”,在索引 7 处找到未解析的文本

不要使用 SimpleDateFormat

SimpleDateFormat有很多令人困惑且设计不当的特征,您尝试在两个代码示例中使用 class。 你只被其中两个击中:

  1. 正如 Generous Badger 解释的那样,它可能不会解析给它的整个字符串,默认留下未解析的文本。
  2. 它为未解析的字段创造默认值。 在您的情况下,它默认为 JVM 的默认时区中的每月 1 日 00:00:00。 虽然可以指示 java.time 为不在解析字符串中的字段应用默认值,但这需要在 Java 代码中明确指定它们,从而导致更可预测且更少令人惊讶的行为。

其他人已经提到了为什么会发生这种情况(java 解析器在获得所需的所有内容时停止解析)并且还解释说这个 API 较旧且不符合人体工程学。 也就是说,您可以使用ParsePosition class 做您想做的事。

String datestr = "2021-01-01";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
ParsePosition pp = new ParsePosition(0);
sdf.parse(datestr, pp);
if(pp.getIndex() < dateStr.length()) {
  throw new ParseException("Parsing failed...");
}

暂无
暂无

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

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