验证Java 8日期

时间:2015-08-25 13:10:44

标签: java java-8

我想验证几种日期格式,如下例所示:

YYYY
YYYY-MM
YYYY-MM-DD

验证必须确保日期格式正确且日期存在。

我知道Java 8提供了一个新的Date API,所以我想知道它是否能够做这样的工作。

使用Java 8 date API有更好的方法吗? 将Calendar类与lenient参数一起使用仍然是一个好习惯吗?

6 个答案:

答案 0 :(得分:6)

您可以使用Private Sub cmbGetClass_SelectedIndexChanged(sender As Object, e As EventArgs) 'populate the listview showSched() dtClass.Rows.Clear() With dtClass For row As Integer = 0 To lvSched.Items.Count - 1 For col As Integer = 1 To lvSched.Columns.Count - 1 .Rows.Add((lvSched.Items(row).SubItems(col).Text)) Next Next End With crViewer_Class.ReportSource = dtClass crViewer_Class.RefreshReport() crViewer_Class.Show() End Sub 指定缺少的字段,以使所有格式化工具正常工作:

parseDefaulting

答案 1 :(得分:4)

要验证YYYY-MM-DD格式,您只需使用自JDK 8以来java.time中引入的LocalDate.parse

  

从文本字符串中获取LocalDate的实例,例如   2007-12-03。

     

字符串必须表示有效日期并使用解析   DateTimeFormatter.ISO_LOCAL_DATE。

如果日期无效,则会抛出DateTimeParseException

对于您提供给我们的其他两种格式,将抛出异常。这是合乎逻辑的,因为它们不是真正的约会,只是日期的一部分。

LocalDate还提供了一种方法of(int year, int month, int dayOfMonth),因此,如果你真的想在某些情况下简单地验证年份,在其他情况下的月份或完整日期那么你可以做这样的事情:

public static final boolean validateInputDate(final String isoDate)
{
    String[] dateProperties = isoDate.split("-");

    if(dateProperties != null)
    {
        int year = Integer.parseInt(dateProperties[0]);

        // A valid month by default in the case it is not provided.
        int month = dateProperties.length > 1 ? Integer.parseInt(dateProperties[1]) : 1;

        // A valid day by default in the case it is not provided.
        int day = dateProperties.length > 2 ? Integer.parseInt(dateProperties[2]) : 1;

        try
        {
            LocalDate.of(year, month, day);
            return true;
        }
        catch(DateTimeException e)
        {
            return false;
        }
    }

    return false;
}

请注意,您提到几种格式但没有提供它们,所以我认为这些只是3种。

答案 2 :(得分:3)

使用可选字段和parseBest

您只想验证,我理解,但之后您很可能希望以适当的方式提取数据。幸运的是,正如您所写,Java 8提供了这样一种方法parseBest

parseBest适用于可选字段。因此,首先定义要解析的格式:yyyy[-MM[-dd]],括号([])包装可选字段。

parseBest还要求您提供多个TemporalQuery<R>。实际上,它只是模板方法<R> R queryFrom(TemporalAccessor)的功能包装器。因此,我们实际上可以将TemporalQuery<R>定义为Year::from。好的:这正是我们想要的。问题是parseBest没有得到很好的命名:它将按顺序解析所有内容并在匹配的第一个正确的TemporalQuery之后停止。所以在你的情况下,我们必须从最精确到最不精确。以下是您要处理的各种类型:LocalDateYearMonthYear。因此,我们只需将TemporalQuery[]定义为LocalDate::from, YearMonth::from, Year::from即可。现在,如果parseBest无法识别您的输入,则会抛出异常。

总而言之,我们将构建parseBest,如下所示:

parseBest(DateTimeFormatter.ofPattern("yyyy[-MM[-dd]]"), LocalDate::from, YearMonth::from, Year::from);

所以让我们正确地写下来:

static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy[-MM[-dd]]");

static TemporalAccessor parseDate(String dateAsString) {
  return FORMATTER.parseBest(dateAsString, LocalDate::from, YearMonth::from, Year::from);
}

但是......你只想验证......那么在这种情况下,计算一个日期并且已经完成了昂贵的工作。因此,我们只需将验证定义如下:

public static boolean isValidDate(String dateAsString) {
  try {
    parseDate(dateAsString);
    return true;
  } catch (DateTimeParseException e) {
    return false;
  }
}

我知道,使用异常来处理这样的情况是很糟糕的,但是当前的API非常强大时,这个非常具体的情况没有被考虑在内,所以让我们坚持下去并按原样使用它。

这是完整的代码:

import java.time.*;
import java.time.format.*;
import java.time.temporal.*;
class Main {

  private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy[-MM[-dd]]");
    
  static TemporalAccessor parseDate(String dateAsString) {
    return FORMATTER.parseBest(dateAsString, LocalDate::from, YearMonth::from, Year::from);
  }

  public static boolean isValidDate(String dateAsString) {
    try {
      parseDate(dateAsString);
      return true;
    } catch (DateTimeParseException e) {
      return false;
    }
  }

  public static void main(String[] args) {    
    String[] datesAsString = {
      "2018",
      "2018-05",
      "2018-05-22",
      "abc",
      "2018-"
    };
    for (String dateAsString: datesAsString) {
      System.out.printf("%s: %s%n", dateAsString, isValidDate(dateAsString) ? "valid" : "invalid");
    }
  }
}

Try it online!

输出:

2018: valid
2018-05: valid
2018-05-22: valid
abc: invalid
2018-: invalid

您需要的不仅仅是验证,比如获取实际值?

请注意,您仍然可以使用从parseBest检索到的数据进一步使用,如下所示:

TemporalAccessor dateAccessor = parseDate(dateAsString);
if (dateAccessor instanceof Year) {
  Year year = (Year)dateAccessor;
  // Use year
} else if (dateAccessor instanceof YearMonth) {
  YearMonth yearMonth = (YearMonth)dateAccessor;
  // Use yearMonth
} else if (dateAccessor instanceof LocalDate) {
  LocalDate localDate = (LocalDate)dateAccessor;
  // Use localDate
}

答案 3 :(得分:0)

public static final boolean validateInputDate(final String isoDate, final String dateFormat){
    final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
    try {
        final Date date = simpleDateFormat.parse(isoDate);
        System.out.println("Date: " + date);
        return true;
    } catch (ParseException e) {
        e.printStackTrace();
        return false;
    }
}

答案 4 :(得分:0)

您可以使用宽大,默认为true

以SimpleDAteFormat

SimpleDateFormat sdf = new SimpleDateFormat(dateFromat);
sdf.setLenient(false);

或在JSON中验证:

@JsonFormat(lenient = OptBoolean.FALSE)

答案 5 :(得分:0)

请使用以下代码。这将进行验证,并且可以在每种格式下使用。

public class DateValidator {
    public static void main(String[] args) {

        String datetoCheck = "999999";

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMdd");
        try {
            LocalDate localDate = LocalDate.parse(datetoCheck, formatter);
            System.out.println(localDate);
        } catch ( DateTimeException ex ) {
            ex.printStackTrace();
        }
    }
}