如何在Java中检查日期的健全性

2022-08-31 11:26:56

我感到奇怪的是,在Java中创建对象的最明显方法已被弃用,并且似乎已经被“取代”为不太明显的宽松日历。Date

如何检查以日、月和年的组合给出的日期是否为有效日期?

例如,2008-02-31(如 yyyy-mm-dd 中所示)将是无效日期。


答案 1

Key is df.setLenient(false);.对于简单的案例来说,这绰绰有余。如果你正在寻找一个更健壮(我怀疑)和/或替代库,如joda-time,那么看看用户“tardate”的答案

final static String DATE_FORMAT = "dd-MM-yyyy";

public static boolean isDateValid(String date) 
{
        try {
            DateFormat df = new SimpleDateFormat(DATE_FORMAT);
            df.setLenient(false);
            df.parse(date);
            return true;
        } catch (ParseException e) {
            return false;
        }
}

答案 2

如@Maglob所示,基本方法是使用 SimpleDateFormat.parse 测试从字符串到日期的转换。这将捕获无效的日/月组合,如 2008-02-31。

然而,在实践中,这很少足够,因为SimpleDateFormat.parse是非常自由的。您可能会关注两种行为:

日期字符串中的字符无效令人惊讶的是,2008-02-2x将“传递”为有效日期,例如,区域设置格式= “yyyy-MM-dd”。即使 islenient==false。

年份:2、3 或 4 位数字?您可能还希望强制实施 4 位数年份,而不是允许默认的 SimpleDateFormat 行为(根据您的格式是“yyyy-MM-dd”还是“yy-MM-dd”,这将对“12-02-31”有不同的解释)

标准库的严格解决方案

因此,完整的字符串到日期测试可能如下所示:正则表达式匹配的组合,然后是强制日期转换。正则表达式的诀窍是使其对区域设置友好。

  Date parseDate(String maybeDate, String format, boolean lenient) {
    Date date = null;

    // test date string matches format structure using regex
    // - weed out illegal characters and enforce 4-digit year
    // - create the regex based on the local format string
    String reFormat = Pattern.compile("d+|M+").matcher(Matcher.quoteReplacement(format)).replaceAll("\\\\d{1,2}");
    reFormat = Pattern.compile("y+").matcher(reFormat).replaceAll("\\\\d{4}");
    if ( Pattern.compile(reFormat).matcher(maybeDate).matches() ) {

      // date string matches format structure, 
      // - now test it can be converted to a valid date
      SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance();
      sdf.applyPattern(format);
      sdf.setLenient(lenient);
      try { date = sdf.parse(maybeDate); } catch (ParseException e) { }
    } 
    return date;
  } 

  // used like this:
  Date date = parseDate( "21/5/2009", "d/M/yyyy", false);

请注意,正则表达式假定格式字符串仅包含日、月、年和分隔符。除此之外,格式可以是任何区域设置格式:“d/MM/yy”、“yyyy-MM-dd”等。当前区域设置的格式字符串可以按如下方式获取:

Locale locale = Locale.getDefault();
SimpleDateFormat sdf = (SimpleDateFormat)DateFormat.getDateInstance(DateFormat.SHORT, locale );
String format = sdf.toPattern();

Joda Time - 更好的选择?

我最近一直在听说joda时间,并认为我会比较。两点:

  1. 似乎更擅长严格控制日期字符串中的无效字符,这与 SimpleDateFormat 不同
  2. 目前还看不到强制执行4位数年份的方法(但我想您可以为此目的创建自己的DateTimeFormatter

它使用起来非常简单:

import org.joda.time.format.*;
import org.joda.time.DateTime;

org.joda.time.DateTime parseDate(String maybeDate, String format) {
  org.joda.time.DateTime date = null;
  try {
    DateTimeFormatter fmt = DateTimeFormat.forPattern(format);
    date =  fmt.parseDateTime(maybeDate);
  } catch (Exception e) { }
  return date;
}