简体   繁体   English

我对 java 中的 SimpleDateFormat function 有疑问

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

I don't know why there is no error.我不知道为什么没有错误。 The code is代码是

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

Since the date string, 2021-01-01 , does not match the format pattern string, yyyy-MM , I had expected and wanted an exception.由于日期字符串2021-01-01与格式模式字符串yyyy-MM不匹配,我曾预料到并想要一个例外。

The console prints Fri Jan 01 00:00:00 CST 2021 .控制台打印Fri Jan 01 00:00:00 CST 2021

The opposite situation does result in an exception as expected.相反的情况确实会导致预期的异常。 I make code look like this我让代码看起来像这样

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

The console prints an error msg: Unparseable date: "2021-01"控制台打印错误消息:无法解析的Unparseable date: "2021-01"

Who can tell me why?谁能告诉我为什么?

You are describing two different scenarios:您正在描述两种不同的场景:

  1. Your input text contains more data than the pattern would consume and the extra data is at the end.您的输入文本包含数据多于模式将消耗的数据,并且额外的数据位于末尾。
  2. Your input text contains less data than the pattern would consume.您的输入文本包含的数据少于模式将消耗的数据。

#1 is not an error, since parse(String) is explicitly documented to just read from the beginning of the input until it has enough: #1 不是错误,因为parse(String)被明确记录为从输入的开头读取,直到它有足够的内容:

The method may not use the entire text of the given string.该方法可能不会使用给定字符串的整个文本。

#2 is an error, because you the pattern says it expects extra data (namely a - followed by a day) and that data is missing. #2 是一个错误,因为您的模式说它需要额外的数据(即-后跟一天)并且该数据丢失。

tl;dr tl;博士

Your formatting pattern must fit your input text.您的格式模式必须适合您的输入文本。 In the first case, "2021-01-01" does not match "yyyy-MM" .在第一种情况下, "2021-01-01""yyyy-MM"不匹配。 In the second case, "2021-01" does not match "yyyy-MM-dd" .在第二种情况下, "2021-01""yyyy-MM-dd"不匹配。

Use java.time classes instead, as wrestling with legacy classes SimpleDateFormat & Date is unwise.改用java.time类,因为与传统类SimpleDateFormatDate搏斗是不明智的。 Simpler too, with no need of formatting patterns.也更简单,不需要格式化模式。

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

See this code run live at IdeOne.com .请参阅在 IdeOne.com 上实时运行的代码

2021-01 2021-01

And parsing year-month:并解析年月:

YearMonth.parse( "2021-01" )

Details细节

You are using terrible date-time classes that were years ago supplanted by the modern java.time classes.您正在使用几年前被现代java.time类取代的糟糕的日期时间类。 Sun, Oracle, and the JCP community gave up on those closes with the unanimous adoption of JSR 310 . Sun、Oracle 和 JCP 社区因一致采用JSR 310而放弃了这些关闭。

Your inputs happen to use standard ISO 8601 formats.您的输入恰好使用标准ISO 8601格式。 The java.time classes use these formats by default when parsing/generating text. java.time类在解析/生成文本时默认使用这些格式。 So no need to specify a formatting pattern.所以不需要指定格式模式。

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

As for parsing an input of "2021-01" :至于解析"2021-01"的输入:

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

Here's a modest supplement.这是一个适度的补充。 Basil Bourque has already shown the good and modern solution to the work you are doing, and Generous Badger has explained why your code didn't behave the way you had expected. Basil Bourque 已经为您所做的工作展示了良好且现代的解决方案,并且 Generous Badger 解释了为什么您的代码没有按照您的预期运行。

The code by Basil Bourque does throw the expected exception if you feed a string in the wrong format into each of the code examples.如果您将错误格式的字符串输入到每个代码示例中,Basil Bourque 的代码确实会引发预期的异常。 For the modern version of the code you were asking about:对于您询问的代码的现代版本:

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

The result is an:结果是:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-01-01' could not be parsed, unparsed text found at index 7线程“主”java.time.format.DateTimeParseException 中的异常:无法解析文本“2021-01-01”,在索引 7 处找到未解析的文本

Please also enjoy how precise the exception message is.还请享受异常消息的精确程度。

The same thing happens if you choose to use an explicit formatter:如果您选择使用显式格式化程序,也会发生同样的事情:

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

Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-01-01' could not be parsed, unparsed text found at index 7线程“主”java.time.format.DateTimeParseException 中的异常:无法解析文本“2021-01-01”,在索引 7 处找到未解析的文本

Don't use SimpleDateFormat不要使用 SimpleDateFormat

There are a lot of confusing and ill-designed traits of SimpleDateFormat , the class that you tried to use in your two code examples. SimpleDateFormat有很多令人困惑且设计不当的特征,您尝试在两个代码示例中使用 class。 You have been hit by just of two of them:你只被其中两个击中:

  1. As Generous Badger explained, it may not parse the entire string given to it, tacitly leaving unparsed text.正如 Generous Badger 解释的那样,它可能不会解析给它的整个字符串,默认留下未解析的文本。
  2. It invents default values for the fields not parsed.它为未解析的字段创造默认值。 In your case it defaulted to the 1st of the month 00:00:00 in the default time zone of the JVM.在您的情况下,它默认为 JVM 的默认时区中的每月 1 日 00:00:00。 While java.time can be instructed to apply default values for fields that are not in the parsed string, this requires specifying them explicitly in the Java code, leading to much more predictable and less surprising behaviour.虽然可以指示 java.time 为不在解析字符串中的字段应用默认值,但这需要在 Java 代码中明确指定它们,从而导致更可预测且更少令人惊讶的行为。

Others have already mentioned why this happens (the java parsers stop parsing when they get all they need) and have also explained that this API is older and not as ergonomic.其他人已经提到了为什么会发生这种情况(java 解析器在获得所需的所有内容时停止解析)并且还解释说这个 API 较旧且不符合人体工程学。 That said, you can do what you want using the ParsePosition class.也就是说,您可以使用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