【问题标题】:Strict two digit day and month parsing for SimpleDateFormatSimpleDateFormat 的严格两位数日和月解析
【发布时间】:2016-12-15 17:41:23
【问题描述】:

我正在尝试验证日期输入,如果日期和月份始终为两位数,我只希望它们通过。到目前为止,我一直在使用 SimpleDateFormat:

    SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy");
    df.setLenient(false);

    try
    {
        df.parse("10/1/1987");
        df.parse("1/1/1987");
        df.parse("1/10/1987");
        df.parse("1/1/19");
    }

    catch (ParseException e)
    {
        e.printStackTrace();
    }

不过,所有这些案例都在通过,我不希望其中任何一个通过。

有没有一种简单的方法来解决这个问题,或者我必须先用反斜杠上的字符串标记:

String[] dateParts = date.split("/");
if (dateParts.length != 3 && dateParts[0].length() != 2 && dateParts[1].length() != 2 && dateParts[2].length() != 4)
    System.out.println("Invalid date format");

【问题讨论】:

  • 您可以使用Pattern Matcher,并匹配适当的正则表达式...例如"\d{2}/\d{2}/\d{4}"。例如)if (date.matches("\\d{2}/\\d{2}/\\d{4}")) { ... }
  • 您可以使用正则表达式,例如 ([0-9]{2})/([0-9]{2})/([0-9]{4})
  • 你搞定了吗?
  • @ItamarGreen 是的,谢谢。
  • @JimmyP 那么你应该接受一个答案,那个帮助你让它工作的答案

标签: java validation date


【解决方案1】:

改用新的java.time

public static void main(String[] args) {
    test("10/10/1987");
    test("10/1/1987");
    test("1/1/1987");
    test("1/10/1987");
    test("1/1/19");
}
private static void test(String date) {
    DateTimeFormatter fmt = DateTimeFormatter.ofPattern("MM/dd/uuuu");
    try {
        System.out.println(LocalDate.parse(date, fmt));
    } catch (Exception e) {
        System.out.println(e);
    }
}

输出

1987-10-10
java.time.format.DateTimeParseException: Text '10/1/1987' could not be parsed at index 3
java.time.format.DateTimeParseException: Text '1/1/1987' could not be parsed at index 0
java.time.format.DateTimeParseException: Text '1/10/1987' could not be parsed at index 0
java.time.format.DateTimeParseException: Text '1/1/19' could not be parsed at index 0

【讨论】:

  • “uuuu”和“yyyy”有什么区别?
  • @JimmyP 你为什么不看看javadoc 自己看看?
  • 我做到了。符号表中的Presentation和Example都相同,年份的解释不区分它们。我看到的唯一区别是一个是“年份”,另一个是“时代”,我不确定这到底是什么意思。
  • 你了解day-of-weekday-of-monthday-of-year,即给定范围(周、月、年)内的天数吗?因此,year-of-era 表示给定范围(时代)内的年份编号,在其正上方 era 显示为示例值AD(另一个值当然是BC)。那么,朱利叶斯·凯撒是什么时候被暗杀的呢?公元前 44 年 3 月 15 日 (MMMM d, y GG) -43 年 3 月 15 日 (MMMM d, u)?如果你使用y,你也应该使用G。由于G 很少使用,因此正确的年份符号是u,而不是y
  • @Andreas 我刚刚发布了a Question on this matter of uuuu versus yyyy。我发现没有其他问题明确涉及这个问题。也许你想在那里发布一个正式的答案。
【解决方案2】:

一种方法是验证输入,在解析之前确保它与所需格式匹配。

if (date.matches("\\d{2}/\\d{2}/\\d{4}")) {
    SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy");
    df.parse(date);
}

【讨论】:

  • 正则表达式会比拆分字符串并以这种方式检查更快吗?
  • 可读性还是速度?如果您在 / 字符上拆分字符串,您需要检查 (a) 字符串是否拆分为 3 个部分,(b) 每个部分仅包含数字,(c) 前两个部分是长度为 2,第三部分的长度为 4。正则表达式在一个简单、清晰、可读的 if 语句中完成了所有这些工作。如果速度是一个问题,正则表达式可以编译一次并存储为final static Matcher
  • 如果我们谈论的是单行代码,我会更关心速度而不是可读性,但是对于只有 10 个字符的字符串真的重要吗?
  • 如果您担心正则表达式的速度,您打算如何拆分字符串? String#split(String regex) 通过正则表达式定义分割点。
【解决方案3】:

你可以使用正则表达式,

String regex = "(\\d{2})\\/(\\d{2})\\/(\\d{2,4})$";
Pattern p = Pattern.compile(regex);
String input = "10/12/1987";
Matcher m = p.matcher(input);
while (m.find()) {
    //if it got here, then the date is in the right format
    System.out.println(m.group(0));
}

该模式检查 2 位数字(\\d{2} 匹配数字,正好 2 次)后跟一个斜杠 (\/),然后再检查 2 位数字,然后再跟一个斜杠,然后是 2-4 个数字 (年)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-09
    • 1970-01-01
    • 2019-04-10
    • 1970-01-01
    • 2012-10-16
    相关资源
    最近更新 更多