【问题标题】:Force SimpleDateFormat to parse the whole string强制 SimpleDateFormat 解析整个字符串
【发布时间】:2015-09-25 07:58:23
【问题描述】:

我有一个格式如下的日期字符串:"dd/MM/yyyy HH:mm:ss"。我想从中创建一个Date 对象,并且我正在使用SimpleDateFormat 类。我们的应用程序接受存储在String 数组中的许多不同日期格式。我们所做的是遍历该数组,使用applyPattern 到我们的SimpleDateFormat 对象并尝试parse 给定的日期字符串。如果它抛出异常,我们会尝试数组中的下一个日期格式等。

但是我发现SimpleDateFormat 类的parse 方法不一定会尝试解析整个字符串。如果它成功地从字符串的某些部分创建了一个 Date 对象,那么它将返回它。这里的问题是我们给定的日期字符串同时包含日期和时间数据,但是在我们的第一次parse 尝试中,SimpleDateFormat 使用了一个更简单的模式:"dd/MM/yyyy"。由于在解析过程中它会在给定的日期字符串中找到匹配的日期,因此它会停在那里并创建一个没有时间信息的 Date 对象。

有没有办法强制SimpleDateFormat 解析它给出的整个字符串?

String dateString = "01/01/2015 05:30:00";
Date date = null;
for (String format : Constants.DATE_FORMATS) {//String Array that contains many date format strings.
    try {
        simpleDateFormat.applyPattern(format);//First format applied is "dd/MM/yyyy".
        date = simpleDateFormat.parse(dateString);
        //No exception thrown it accepts the "dd/MM/yyyy" part of the dateString even though the string itself contains even more data.
    }
    catch (Exception e) {}
}
//Returns a date object with the time set to 00:00:00

【问题讨论】:

  • 您能否展示一些代码以便我们更好地了解您的问题是什么?
  • 并显示示例数据。
  • @Tunaki 不是已经很清楚了吗? OP 喜欢防止像 "dd/MM/yyyy" 这样的模式来解析具有模式 "dd/MM/yyyy HH:mm:ss" 的字符串(例如 "25/ 09/2015 10:00:00"),因为他会失去时间价值。
  • @Tom 没错。我想将格式与给出的字符串完美匹配,否则抛出异常。
  • 你能改变测试模式的顺序,最后使用这个吗?或者您可以扩展SimpleDateFormat 并在解析之前测试字符串长度吗?

标签: java date parsing datetime


【解决方案1】:

您可以通过提供ParsePosition 来检查解析了多少输入。 parse 方法更新位置以告诉您它解析了多少。

ParsePosition pos = new ParsePosition(0);
date = simpleDateFormat.parse(dateString, pos);

if (pos.getIndex() < dateString.length()) {
    // did not parse all of dateString
}

【讨论】:

    【解决方案2】:

    对于那些想要取回 java.util.Date 对象并避免使用第 3 方库的人,我使用了答案的压缩版本:

    for (String format : Constants.DATE_FORMATS) {
            try {
                return Date.from(LocalDateTime.parse(dateString, DateTimeFormatter.ofPattern(format)).atZone(ZoneId.systemDefault()).toInstant());
            } catch (DateTimeParseException e) {}
        }
    

    有了这个代码块,它将使用正确的格式,使用正确匹配格式的 java 8 自己的 java.time 库。不要忘记添加 try-catch 块! IDE 不会请求它,因为 DateTimeParseException 是一个运行时异常,但我们想要处理它以便进入下一个循环迭代。

    【讨论】:

    • 如果你能完全避免Date类,那就更好了。如果确实需要 Date 来获取旧版 API,我推荐这个答案。
    【解决方案3】:

    我认为没有办法强制SimpleDateFormat 解析整个String,但是您可以将格式的长度与输入的长度进行比较

    String[] formats = new String[] {"dd/MM/yyyy", "dd/MM/yyyy HH:mm:ss"};
    String input = "25/09/2015 10:25:31";
    Date result = null;
    
    for (String format: formats) {
        if (input != null && format.length() == input.length()) {
            try {
                SimpleDateFormat sdFormat = new SimpleDateFormat(format);
                result = sdFormat.parse(input);
                break;
            }
            catch (ParseException e) {
            }
        }
    }
    

    编辑 另一种方法是使用JodaTime 来解析String。

    String[] formats = new String[] { "dd/MM/yyyy", "dd/MM/yyyy HH:mm:ss" };
    String input = "25/09/2015 10:25:31";
    LocalDateTime result = null;
    
    for (String format : formats) {
        try {
            DateTimeFormatter sdFormat = DateTimeFormat.forPattern(format);
            result = sdFormat.parseLocalDateTime(input);
            break;
        }
        catch (IllegalArgumentException e) {
        }
    }
    System.out.println(result);
    
    Date resultDate = result.toDate();
    System.out.println(resultDate);
    

    这给了你

    2015-09-25T10:25:31.000
    Fri Sep 25 10:25:31 CEST 2015
    

    【讨论】:

    • 这也是我们提出的解决方案,但我们希望避免解析后检查。如果没有办法强制进行完整的字符串解析,那么我们将继续这样做。
    • @Konstantine 好的,那么我想到的唯一其他解决方案是使用 JodaTime(如我的编辑中所述)。但这会导致使用外部库
    • JodaTime 现在不是 Java 8 的核心库了吗?我认为这是Time 类及其所有从属关系。
    • 不,Java 8 只是使用相同的 Classnames,但与 JodaTime 不同
    • 对于非 Joda 版本,您将如何处理更复杂的模式,例如匹配多个字符的“Z”?
    【解决方案4】:

    你可以用类似的东西代替SimpleDateFormat:

    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    class StrictDateFormat extends SimpleDateFormat {
        private String pattern;
    
        public void applyPattern(String pattern) {
            super.applyPattern(pattern);
            this.pattern = pattern;
        }
    
        @Override
        public Date parse(String source) throws ParseException {
            if (source.length() != pattern.length()) {
                throw new ParseException("Wrong size", pattern.length());
            }
            return super.parse(source);
        }
    }
    

    如果您解析的字符串与模式的长度不同,这将引发异常。这应该可以防止"01/01/2015 05:30:00""dd/MM/yyyy" 解析。这将是始终严格的,不仅适用于"dd/MM/yyyy"

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多