Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
验证Java8日期_Java_Java 8 - Fatal编程技术网

验证Java8日期

验证Java8日期,java,java-8,Java,Java 8,我想验证几种日期格式,如下示例: YYYY YYYY-MM YYYY-MM-DD 验证必须确保日期格式正确且日期存在 我知道Java8提供了一个新的日期API,所以我想知道它是否能够完成这样的工作 有没有更好的方法使用Java8DateAPI? 使用带有宽松参数的Calendar类仍然是一种好做法吗?要验证YYYY-MM-DD格式,您只需使用JDK 8以来的java.time中引入的 从文本字符串获取LocalDate的实例,例如 2007-12-03. 字符串必须表示有效日期,并使用 Da

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

YYYY
YYYY-MM
YYYY-MM-DD
验证必须确保日期格式正确且日期存在

我知道Java8提供了一个新的日期API,所以我想知道它是否能够完成这样的工作

有没有更好的方法使用Java8DateAPI?
使用带有宽松参数的Calendar类仍然是一种好做法吗?

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

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

字符串必须表示有效日期,并使用 DateTimeFormatter.ISO\u本地\u日期

如果日期无效,将抛出一个

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


LocalDate还提供了(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种格式。

您可以使用
parseDefaulting
指定缺少的字段,以使所有格式设置程序正常工作:

public static boolean isValid(String input) {
    DateTimeFormatter[] formatters = {
            new DateTimeFormatterBuilder().appendPattern("yyyy")
                    .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
                    .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
                    .toFormatter(),
            new DateTimeFormatterBuilder().appendPattern("yyyy-MM")
                    .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
                    .toFormatter(),
            new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd")
                    .parseStrict().toFormatter() };
    for(DateTimeFormatter formatter : formatters) {
        try {
            LocalDate.parse(input, formatter);
            return true;
        } catch (DateTimeParseException e) {
        }
    }
    return false;
}
使用可选字段和 我理解,您只想验证,但之后您很可能希望以适当的方式提取数据。幸运的是,正如您所写,Java8提供了这样一种方法,
parseBest

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

parseBest
还要求您提供几个
TemporalQuery
。实际上,它只是一个围绕模板方法
R queryFrom(TemporalAccessor)
的函数包装器。因此,我们实际上可以将
临时查询定义为
Year::from
。好:那正是我们想要的。问题是,
parseBest
的名称不是很好:它将按顺序解析所有内容,并在匹配的第一个适当的
TemporalQuery
之后停止。所以在你的情况下,我们必须从最精确到不太精确。以下是您要处理的各种类型:
LocalDate
YearMonth
Year
。因此,让我们将
TemporalQuery[]
定义为
LocalDate::from,YearMonth::from,Year::from
。现在,如果
parseBest
无法识别您的输入,它将抛出异常

总之,我们将按照如下方式构造
parseBest

parseBest(DateTimeFormatter.ofPattern("yyyy[-MM[-dd]]"), LocalDate::from, YearMonth::from, Year::from);
public static boolean isValidDate(String dateAsString) {
  try {
    parseDate(dateAsString);
    return true;
  } catch (DateTimeParseException e) {
    return false;
  }
}
因此,让我们正确地写它:

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

static TemporalAccessor parseDate(String dateAsString) {
  return FORMATTER.parseBest(dateAsString, LocalDate::from, YearMonth::from, Year::from);
}
但是。。。您只想验证。。。那么在这种情况下,一个日期被计算出来,昂贵的工作已经完成了。那么,让我们按照如下方式定义验证:

parseBest(DateTimeFormatter.ofPattern("yyyy[-MM[-dd]]"), LocalDate::from, YearMonth::from, Year::from);
public static boolean isValidDate(String dateAsString) {
  try {
    parseDate(dateAsString);
    return true;
  } catch (DateTimeParseException e) {
    return false;
  }
}
我知道,使用异常来处理这样的情况是不好的,但是虽然当前的API非常强大,但是没有考虑到这个非常具体的情况,所以让我们继续使用它

但现在,我们遇到了这个问题:可以解析无效日期。例如,
“2018-15”
将被解析为
年{2018}
,因为
是解析器可以使用的最好的
临时附件:
年月
将失败,但它是
年月
,因此根据这一点,它必须是有效的。让我们在
格式化程序中再次传递它

public static boolean isValidDate(String dateAsString) {
  try {
    TemporalAccessor date = parseDate(dateAsString);
    return FORMATTER.format(date).equals(dateAsString);
  } catch (DateTimeParseException e) {
    return false;
  }
}
以下是完整的代码:

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 {
      TemporalAccessor parsedDate = parseDate(dateAsString);
      return FORMATTER.format(parsedDate).equals(dateAsString);
    } catch (DateTimeParseException e) {
      return false;
    }
  }

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

输出:

2018: valid
2018-05: valid
2018-05-22: valid
abc: invalid
2018-: invalid
2018-15: 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
}

但要小心,因为如前所述,
“2018-15”
仍将被解析,因为
年{2018}
而不是
年{2018,15}
,或
“2018-02-30”
仍将被解析为
而不是
本地日期
您可以使用lenient,如果默认值为true:

简化格式

SimpleDateFormat sdf = new SimpleDateFormat(dateFromat);
sdf.setLenient(false);
或在JSON验证中:

@JsonFormat(lenient = OptBoolean.FALSE)

请使用下面的代码。这将验证并适用于每种格式

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();
        }
    }
}

您希望“YYYY”的日期是什么?“YYYY-01-01”?“YYYY-MM”也有同样的问题。使用
Calendar
class从来都不是一个好的实践
DateFormat
始终是要使用的工具。您应该使用中引入的新工具。您应该避免前面的Java8日期实用程序,如“代码>日历>代码>。如果YYYY,确认今年“存在”(OK…我们可以考虑每个YYYY年存在……)如果您想测试表单,ReGEX是很好的。但是,如果您想测试详细内容,如
2222-33-44
2000-02-30
,那么它很可能会失败。我们如何使用parseBest验证两种格式“yyyy-MM-dd[\'T\HH:MM:SSX]”?当试图验证它时,它只是将它转换为LocalDate并切分时间部分。@Vishwaksena我相信你的问题本身就值得一个完整的问题,而不仅仅是一个评论。请确保指定要使用
parseBest
。如果月份无效,此操作将失败“2018-15”@PanditBiradar这是个什么问题?“2018-15”无效,必须失败!