【问题标题】:How to check validity of Date String?如何检查日期字符串的有效性?
【发布时间】:2010-10-24 20:21:13
【问题描述】:

在我的项目中,我需要检查日期字符串是否计算为正确的 Date 对象。我决定允许 yyyy-MM-dd 和日期格式 [(年、月、日)和(年、月、日、小时、分钟)]。我如何检查它们是否有效?我的代码为“1980-01-01”和一些奇怪的日期(如 3837.05.01)返回 null,它们给出了一个用逗号分隔的字符串:

private Date parseDate(String date){
    Date data = null;

    // yyy-mm-dd
    try {
        DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
        df.setLenient(false);
        df.parse(date);
        return data;
    }
    catch (Exception e) {
        try{
            int[] datArr = parseStringForDate(date);
            int len = datArr.length;
            // year, month, day
            if(len == 3){
                return new Date(datArr[0], datArr[1], datArr[2]);
            }
            // year, montd, day, hours, mins
            else if(len ==5){
                return new Date(datArr[0], datArr[1], datArr[2], datArr[3], datArr[4]);
            }
            // year, month, day, hours, mins, secs
            else if(len == 6){
                return new Date(datArr[0], datArr[1], datArr[2], datArr[3], datArr[4], datArr[5]);
            }
            else {
                return data;
            }
        }
        catch (Exception f){
            return data;
        }
    }
}

private int[] parseStringForDate(String s){
    String[] sArr = s.split(",");
    int[] dateArr = new int[sArr.length];

    for(int i=0; i< dateArr.length; i++){
        dateArr[i] = Integer.parseInt(sArr[i]);
    }

    return dateArr;
}

我记得我必须从年份日期中减去 1900,但我也看到月份不同等,我想避免从日期字符串中检查整数数组的每个元素。是否可以在日历或日期对象中自动解析它们?

【问题讨论】:

  • 欢迎来到 Stack Overflow!这不会直接解决您的问题,但您正在使用 try-catch 块来实现您的逻辑;如果您为特殊情况保留例外,您可能会发现事情会变得更加清晰。
  • 与您的问题更相关:yyy-mm-dd 格式是什么? “999-10-10”是指 1999 年 10 月 10 日吗?还是 999 年 10 月 10 日? 2099 年 10 月 10 日?
  • 哎呀应该是 yyyy

标签: java validation date


【解决方案1】:

您可以像这样为您的不同字符串格式构造SimpleDateFormat 对象(如果无法将参数解析为有效日期,则返回null):

// Initializing possibleFormats somewhere only once
SimpleDateFormat[] possibleFormats = new SimpleDateFormat[] {
  new SimpleDateFormat("yyyy-MM-dd"),
  new SimpleDateFormat("yyyy,MM,dd"),
  new SimpleDateFormat("yyyy,MM,dd,HH,mm") };
for (SimpleDateFormat format: possibleFormats)
{
  format.setLenient(false);
}
// initializing ends

public Date parseDate(String date) {
  Date retVal = null;
  int index = 0;
  while (retVal == null && index < possibleFormats.length) {
    try {
      retVal = possibleFormats[index++].parse(date);
    } catch (ParseException ex) { /* Do nothing */ }
  }
  return retVal;
}

【讨论】:

  • 顺便说一句,您可以使用 for 循环 (for (Format f: possibleFormat) { ... }) 代替所有的 while 循环逻辑。
  • 哇,这是解决问题的好方法。我看到的唯一问题是 OP 谈到在 1980 年和 3837 年获得奇怪的日期,但您只检查日期是否为空。
  • 如果抛出 ParseException,这将在一个永无止境的循环中结束 - 应该在 try-catch 之外递增。这也会将无效日期解析为2010-14-24(返回Feb. 24, 2011) - SimpleDateFormat 必须设置为 non-lenient。
  • @Steve:我不喜欢在 for 中间使用 return,这就是我使用一段时间的原因。 @Carlos:你是对的,谢谢,我已经更新了代码。
  • 您可以使用 break 提前终止 for 循环。
【解决方案2】:

对于 2017 年或以后出现的任何人,这里是 Java 8 解决方案:

private static DateTimeFormatter[] possibleFormats = {
    DateTimeFormatter.ofPattern("uuuu-MM-dd").withResolverStyle(ResolverStyle.STRICT),
    DateTimeFormatter.ofPattern("uuuu,MM,dd").withResolverStyle(ResolverStyle.STRICT),
    DateTimeFormatter.ofPattern("uuuu,MM,dd,HH,mm").withResolverStyle(ResolverStyle.STRICT),
    DateTimeFormatter.ofPattern("uuuu,MM,dd,HH,mm,ss").withResolverStyle(ResolverStyle.STRICT)
};

public Optional<LocalDate> parseDate(String date) {
    for (DateTimeFormatter format : possibleFormats) {
        try {
            LocalDate result = LocalDate.parse(date, format);
            return Optional.of(result);
        } catch (DateTimeParseException dtpe) {
            // ignore, try next format
        }
    }
    return Optional.empty();
}

使用DateTimeFormatter,即使在多线程环境中,您也可以安全地让格式化程序数组保持静态:与SimpleDateFormat 不同,DateTimeFormatter 是线程安全的。

LocalDate 是一个没有时间的日期,因此如果字符串中存在任何小时和分钟,它们就会丢失。要获得小时、分钟和秒,您还需要一个LocalDateTime,然后您需要一些技巧来使解析在字符串中没有小时和分钟的情况下工作。您可以同时尝试LocalDate.parse()LocalDateTime.parse(),或者您可以构建一个格式化程序,当不在字符串中时可以使用几个小时。 DateTimeFormatterBuilder 可以做到。

【讨论】:

    【解决方案3】:

    你这样做是错误的。你应该使用SimpleDateFormat

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    try {
        Date test = sdf.parse(input);
    } catch (ParseException pe) {
       //Date is invalid, try next format
    }
    

    【讨论】:

    • 好的,我看到你已经更新了。但是 OP 使用的是某种三位数的年份格式,所以这个答案可能没有用。
    • 失败时不返回null
    • 如果是这种情况而不是拼写错误,我想它仍然有用,您可以拆分有效的分隔符并根据读取值添加 1 或 2,然后应用 SimpleDateFormat 让它照顾闰年等等。
    【解决方案4】:

    只是为了展示最终结果,感谢 Csaba_H 和 Steve Kuo。

    private Date parseDate(String date){
    
        SimpleDateFormat[] possibleFormats = new SimpleDateFormat[] {
            new SimpleDateFormat("yyyy-MM-dd"),
            new SimpleDateFormat("yyyy,MM,dd"),
            new SimpleDateFormat("yyyy,MM,dd,HH,mm") };
    
        Date retVal = null;
        for (SimpleDateFormat f: possibleFormats) {
            f.setLenient(false);
            try {
                retVal = f.parse(date);
            } catch (ParseException e) {}
        }
        return retVal;
    }
    

    【讨论】:

    • 我很乐意提供帮助。最后一句话:您应该只构造一次 possibleFormats (如果您不在多线程上下文中,可能是静态的)以避免构造许多“丢弃”对象;并且您应该在成功解析后返回以避免不必要的异常创建和捕获。
    猜你喜欢
    • 2011-02-26
    • 2018-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多