安全的SimpleDateFormat解析

时间:2019-04-09 08:30:47

标签: java try-catch simpledateformat

我有一小段代码,它从响应本身解析响应生成时间,并将其转换为日期以供将来使用。它是这样的:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
Date responseTime = sdf.parse(RStime);

它几乎像一种魅力一样工作。确切地说,它可以在99.9%的时间内工作,除了一种情况:当毫秒部分为000时,服务器根本不会附加.000毫秒,因此我们遇到了问题。

现在,根据SimpleDateFormat docs,如果解析失败,该函数将返回null。但是,我可能会误解它,因为它只会引发异常。

我对Java和try-catch机制还很陌生,所以任何人都可以提供一种优雅的良好实践解决方案来处理这种情况吗?

谢谢!

4 个答案:

答案 0 :(得分:1)

java.time

String rsTime = "2018-04-09T10:47:16.999-02:00";
OffsetDateTime responseTime = OffsetDateTime.parse(rsTime);
System.out.println("Parsed date and time: " + responseTime);

此代码段的输出为:

  

分析日期和时间:2018-04-09T10:47:16.999-02:00

它对于省略了000毫秒的版本同样有效:

String rsTime = "2018-04-09T10:47:16-02:00";
  

分析日期和时间:2018-04-09T10:47:16-02:00

您使用的类SimpleDateFormatDate设计欠佳,而且已经过时(特别是前者非常麻烦)。因此,不仅建议在这种特殊情况下,我建议使用java.time(现代Java日期和时间API)。但是,服务器中的字符串采用ISO 8601格式,OffsetDateTime和其他java.time类将其解析为默认格式,即没有任何显式格式化程序,这已经使任务非常容易。此外,在标准中,小数秒是可选的,这就是为什么可以解析字符串的两个变体而没有任何问题的原因。 OffsetDateTime还会从其toString方法中打印出ISO 8601,这就是为什么在这两种情况下都打印与解析的相同的字符串的原因。

仅在万一您无法立即更改的旧版API必不可少的Date对象的情况下,才可以这样转换:

Instant responseInstant = responseTime.toInstant();
Date oldfashionedDateObject = Date.from(responseInstant);
System.out.println("Converted to old-fashioned Date: " + oldfashionedDateObject);

我在欧洲/哥本哈根时区的计算机上的输出是:

  

转换为老式的日期:2018年4月9日星期一14:47:16

链接: Oracle tutorial: Date Time解释了如何使用java.time。

答案 1 :(得分:0)

根据您提到的parse方法的SimpleDateFormat doc

  

public Date parse(String text, ParsePosition pos)

     

投掷:

     

NullPointerException-如果text或pos为null。

因此,一种选择是捕获该异常并在捕获中执行所需的操作,例如:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
try {
  Date responseTime = sdf.parse(RStime, position);
} catch (NullPointerException e) {
  e.printStackTrace();
  //... Do extra stuff if needed
}

或从DateFormat继承的方法:

  

public Date parse(String source)

     

投掷:

     

ParseException-如果指定字符串的开头不能为   解析。

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
try {
  Date responseTime = sdf.parse(RStime);
} catch (ParseException e) {
  e.printStackTrace();
  //... Do extra stuff if needed
}

答案 2 :(得分:0)

这真的是例外情况吗?如果不是,那么您可能不应该在这种情况下使用异常。我认为时间可以以0.0000ms结尾是正常的。在这种情况下,您可以检查字符串是否包含.(点),如果不包含,则在末尾附加.000。

if(!RStime.contains(".")){
    RStime+=".000";
}

编辑:我忘记了时间字符串中的时区。您可能需要一些更复杂的东西。这样的事情应该做到:

if(!RStime.contains(".")){
    String firstPart = RStime.substring(0, 21);
    String secondPart = RStime.substring(21);
    RStime = firstPart + ".000" + secondPart;
}

答案 3 :(得分:0)

您可以检查点,然后使用第一种或第二种格式:

String timeString = "2018-04-09T10:47:16.999-02:00";
//String timeString = "2018-04-09T10:47:16-02:00";
String format = timeString.contains(".") ? "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" : "yyyy-MM-dd'T'HH:mm:ssXXX";
Date responseTime = new SimpleDateFormat(format).parse(timeString);
System.out.println("responseTime: " + responseTime);

如果注释掉第一行,注释掉第二行并再次运行,它将全部打印出来:

responseTime: Mon Apr 09 14:47:16 CEST 2018

顺便说一句:

  • Java 7(您显然使用的版本)返回java.text.ParseException: Unparseable date: "2018-04-09T10:47:16-02:00"

  • 自Java 8开始支持可选。