【问题标题】:Check if a string contains only date检查字符串是否仅包含日期
【发布时间】:2015-02-02 07:23:50
【问题描述】:

我有一个字符串,它可以包含相应格式的日期(yyyy-MM-dd)或日期和时间(yyyy-MM-dd HH:mm:ss)。

我想知道哪些字符串只包含日期。

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(dateFormat.parse("2015-02-02"));
System.out.println(dateFormat.parse("2015-02-02 23:23:23"));

在上面的代码中,两个字符串都解析成功,而格式相同,只是第一个。

【问题讨论】:

  • 使用正则表达式。
  • 对于该特定模式,您只需检查输入的长度是否为 10。对于可变长度模式,它会稍微困难一些 - 有其他解析方法可以让您查看有多少字符串已被解析。 (见parse(String, ParsePosition)。)
  • @JonSkeet 我也想到了那个解决方案,但它似乎更像是一个替代方案。
  • @Jon,稍微好一点的 IMO 正在检查字符串是否包含 ':',(如果某个奇怪的地方的有效时间是 10 长)但两者都可能没问题。
  • @user949300 我根据传入的字符串指向不同的数据库列。

标签: java date date-format


【解决方案1】:

java.time

java.util 日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用,改用modern Date-Time API*

使用现代日期时间 API java.time 的解决方案:

让我们首先尝试按照您的方式进行操作:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String[] arr = { "2015-02-02", "2015-02-02 23:23:23" };
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd", Locale.ENGLISH);

        for (String s : arr) {
            System.out.println("Attempting to parse '" + s + "':");
            LocalDate date = LocalDate.parse(s, dtf);
            System.out.println("Parsed successfully: " + date);
        }
    }
}

输出:

尝试解析“2015-02-02”:
解析成功:2015-02-02
尝试解析“2015-02-02 23:23:23”:
线程“main”中的异常 java.time.format.DateTimeParseException: Text
'2015-02-02 23:23:23' 无法解析,在索引 10 处找到未解析的文本

如您所见,java.time API 正确地引发了异常,通知您该问题。另一方面,SimpleDateFormat 会静默解析输入字符串,这会导致您发布的问题。

因此,使用现代日期时间 API,您有两个简单的选择:

  1. 只需捕获异常并说第二个输入(即2015-02-02 23:23:23)不是指定日期模式的日期字符串。
  2. 使用函数DateTimeFormatter#parse(CharSequence, ParsePosition) 并将ParsePosition 索引设置为0

下面是第二个选项的演示:

import java.text.ParsePosition;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String[] arr = { "2015-02-02", "2015-02-02 23:23:23" };
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd", Locale.ENGLISH);

        for (String s : arr) {
            ParsePosition pp = new ParsePosition(0);
            LocalDate.from(dtf.parse(s, pp));
            if (pp.getIndex() < s.length()) {
                System.out.println("'" + s + "' is not a date string as per the specified date pattern.");
            }
        }
    }
}

输出:

'2015-02-02 23:23:23' 不是指定日期模式的日期字符串。

ONLINE DEMO

注意:Never use SimpleDateFormat or DateTimeFormatter without a Locale.

Trail: Date Time 了解有关现代日期时间 API 的更多信息。


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 和 7 . 如果您正在为一个 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

【讨论】:

    【解决方案2】:
    public static void main(String[] args) {
            String dateOnly = "2015-02-02";
            String dateAndTimeOnly = "2015-02-02 23:23:23";
            System.out.println("Date Only = " + validateDateFormat(dateOnly));
            System.out.println("Date And time Only = " + validateDateFormat(dateAndTimeOnly));
        }
    
        public static boolean validateDateFormat(String input) {
    
            return input.matches("([0-9]{4})-([0-9]{2})-([0-9]{2})");
        }
    

    输出

    Date Only = true
    Date And time Only = false
    

    正则表达式是不言自明的 - 输入将由- 分隔,第一部分([0-9]{4})可以包含 4 位,第二部分可以包含 2 位 [0-9]{2},如第三部分。

    【讨论】:

    • 在检查长度 10 或是否存在时似乎有点矫枉过正。 ':' 也行。这个正则表达式会在那些失败的地方捕获什么?
    • @user949300 例如用于输入
    • 好吧,是的,一般情况下,或者如果我们正在输入的用户,你会想要一个正则表达式。但是,OP 指出字符串已经非常有限和结构化。
    • @user949300 我同意你的观点,阅读 OP 问题,他的解决方案不起作用,San Krish 解释了为什么它不起作用,他还想有替代解决方案,这可以是很多考虑您的输入和考虑到 OP 输入的结构非常好。
    • 这也允许无效日期。如果您真的不打算验证这是一个日期,为什么不检查长度?
    【解决方案3】:

    我会使用 parse 的重载,它需要一个 ParsePosition - 然后您可以在之后检查位置:

    import java.util.*;
    import java.text.*;
    
    public class Test {
    
        public static void main(String[] args) throws Exception {
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            dateFormat.setLenient(false);
            System.out.println(parseFully(dateFormat, "2015-02-02"));
            System.out.println(parseFully(dateFormat, "2015-02-02 23:23:23"));
        }
    
        private static Date parseFully(DateFormat format, String text) 
              throws ParseException {
            ParsePosition position = new ParsePosition(0);
            Date date = format.parse(text, position);
            if (position.getIndex() == text.length()) {
                return date;
            }
            if (date == null) {
                throw new ParseException("Date could not be parsed: " + text,
                                         position.getErrorIndex());
            }
            throw new ParseException("Date was parsed incompletely: " + text,
                                     position.getIndex());
        }
    }
    

    【讨论】:

    • 感谢乔恩的想法。我认为比较模式长度和日期字符串长度是迄今为止最好的解决方案。
    • @SahilJain:没关系如果它是一个固定长度的模式。如果你有像"EEE dd MMM yyyy" 这样的模式,那么它就行不通了。
    • 我可能会争辩说,这对于末尾带有空格的输入会失败(我认为???),这可能很常见,您可能希望考虑“合法”。如果是这样,请务必先致电trim()
    • @user949300:在这种情况下,我个人希望它失败 - 这不是“只是一个约会”。但是,是的,你总是可以修剪它......
    【解决方案4】:

    一旦达到所需的 formatSimpleDateFormat 就不会格式化 String 的其余部分。这就是解析第二个字符串的原因。

    这个帖子SimpleDateFormat parse(string str) doesn't throw an exception when str = 2011/12/12aaaaaaaaa?可能对你有所帮助。

    还要检查 java 文档中的 DateFormat#parse 方法

    【讨论】:

    • 是的,我了解 java 在那里做什么。但我正在为我的问题寻找一个好的解决方案,并且还想了解为什么 java 不检查整个字符串。我也尝试将 lenient 设置为 false,仍然无法找到所需的输出
    • 您是否阅读了链接帖子中的答案,它会让您清楚。不明白的请评论:)
    猜你喜欢
    • 1970-01-01
    • 2010-12-19
    • 1970-01-01
    • 2014-03-02
    • 2011-01-25
    • 1970-01-01
    • 2023-03-27
    • 2014-05-07
    相关资源
    最近更新 更多