在解析之前确定字符串是否为有效日期

2022-09-03 17:07:07

我有这种情况,我正在阅读大约130K条记录,其中包含存储为字符串字段的日期。有些记录包含空格(null),有些包含这样的字符串:'dd-MMM-yy',有些包含'dd/MM/yyyy'。

我写了一个这样的方法:

public Date parsedate(String date){

   if(date !== null){
      try{
        1. create a SimpleDateFormat object using 'dd-MMM-yy' as the pattern
        2. parse the date
        3. return the parsed date
      }catch(ParseException e){
          try{
              1. create a SimpleDateFormat object using 'dd/MM/yyy' as the pattern
              2. parse the date
              3. return parsed date
           }catch(ParseException e){
              return null
           }
      }
   }else{
      return null
   }

} 

因此,您可能已经发现了问题。我正在使用 try .. catch 作为我逻辑的一部分。更好的是,我可以事先确定字符串实际上包含某种格式的可解析日期,然后尝试解析它。

那么,是否有一些API或库可以帮助解决这个问题?我不介意编写几个不同的Parse类来处理不同的格式,然后创建一个工厂来选择正确的6,但是,我如何确定哪一个?

谢谢。


答案 1

有关如何使用类型消除 try/catch 块的概述,请参阅 Java 中的延迟错误处理Option

函数式Java是你的朋友。

实质上,您要做的是将日期解析包装在一个不抛出任何内容的函数中,但在其返回类型中指示解析是否成功。例如:

import fj.F; import fj.F2;
import fj.data.Option;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import static fj.Function.curry;
import static fj.Option.some;
import static fj.Option.none;
...

F<String, F<String, Option<Date>>> parseDate =
  curry(new F2<String, String, Option<Date>>() {
    public Option<Date> f(String pattern, String s) {
      try {
        return some(new SimpleDateFormat(pattern).parse(s));
      }
      catch (ParseException e) {
        return none();
      }
    }
  });

好了,现在你有一个可重用的日期解析器,它不会抛出任何东西,但通过返回类型值来指示失败。以下是它的使用方法:Option.None

import fj.data.List;
import static fj.data.Stream.stream;
import static fj.data.Option.isSome_;
....
public Option<Date> parseWithPatterns(String s, Stream<String> patterns) { 
  return stream(s).apply(patterns.map(parseDate)).find(isSome_()); 
}

这将为您提供使用第一个匹配的模式解析的日期,或者类型为 Option.None 的值,该值是类型安全的,而 null 不是。

如果您想知道什么是...这是一个懒惰的列表。这可以确保您在第一个成功模式之后忽略模式。无需做太多工作。Stream

像这样调用函数:

for (Date d: parseWithPatterns(someString, stream("dd/MM/yyyy", "dd-MM-yyyy")) {
  // Do something with the date here.
}

或。。。

Option<Date> d = parseWithPatterns(someString,
                                   stream("dd/MM/yyyy", "dd-MM-yyyy"));
if (d.isNone()) {
  // Handle the case where neither pattern matches.
} 
else {
  // Do something with d.some()
}

答案 2

不要对自己在逻辑中使用try-catch过于苛刻:这是Java强迫你这样做的情况之一,所以你对此无能为力。

但在这种情况下,你可以改用 DateFormat.parse(String, ParsePosition)。