【问题标题】:Unexacte parsing in SimpleDateFormatSimpleDateFormat 中的不精确解析
【发布时间】:2014-01-21 16:56:49
【问题描述】:

如何解析始终具有不同日期格式的字符串(有时是“yyyy-MM-dd HH:mm:ss”或“yyyy-MM-dd'T'HH:mm”或“yyyy-MM- dd HH:mm")?

如果我使用以下代码 - 如果 value 中的字符串的格式不是“yyyy-MM-dd HH:mm”,则会失败

public static Date test(String value) throws ... {

  SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
  return df.parse(value);


}

【问题讨论】:

    标签: java parsing date datetime simpledateformat


    【解决方案1】:

    我建议您尝试解析每种特定格式,捕获 ParseException 并转到下一种格式:

    private static final String[] patterns = {
        "yyyy-MM-dd HH:mm",
        "yyyy-MM-dd'T'HH:mm",
        "yyyy-MM-dd HH:mm"
    };
    
    public static Date test(String value) throws ... {
        for (String pattern : patterns) {
            try {
               DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
               return df.parse(value);
            } catch (ParseException e) {
               // No-op - move onto the next pattern
            }
        }
        // Do whatever you want here - throw ParseException, or return null
    }
    

    这很简单,但是滥用了异常。您可以改用更晦涩的parse(String, ParsePosition) 调用:

    public static Date test(String value) throws ... {
        for (String pattern : patterns) {
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            Date date = df.parse(value, new ParsePosition(0));
            if (date != null) {
                return date;
            }
        }
        // Do whatever you want here - throw ParseException, or return null
    }
    

    可能表现更好 - 你必须对其进行基准测试才能确定。

    不幸的是,您必须在每次调用时重新创建 SimpleDateFormat 对象,但这是一个问题,因为它不是线程安全的。另一种选择是使用Joda Time - 这是一个非常 整体上更好的API - 但目前还不清楚你将如何在那里执行无异常方法。 (很有可能,只是有点晦涩难懂。我怀疑DateTimeFormatter.parseInto 会是你的朋友。)

    【讨论】:

    • 如果出现新的未知模式怎么办?
    • @Igor:那么它来自哪里? (顺便说一句,如果您想回答某些问题,它应该在您的问题中。)您需要有一个您期望somewhere 的模式列表。如果你真的想让它们变得非常动态,你可以从文件或数据库中加载它们。
    • 这是我们的服务器应用程序源代码的一部分,带有不同格式日期的字符串来自客户端(IPhones/iPad 上的客户端应用程序)我们一直只有“yyyy-MM-dd HH :mm:ss" 作为传入模式,但昨天我在日志中也看到了这个模式 "yyyy-MM-dd HH:mm" 和错误 "Unparseable date..." 我不知道我们还会遇到什么样的模式。我们的 IOS 开发人员将在下一个版本中修复日期的创建(他将使其独立于 Iphone 设置),但现在我应该立即在服务器端更正它。当然,我必须在我的问题中写出来。对不起
    • @Igor:我非常不愿意尝试编写任何会根据任意数据猜测格式的代码。在某些情况下,您可能会发现它在不同文化之间是模棱两可的,例如MM/dd/yyyy 和 dd/MM/yyyy。
    【解决方案2】:

    java.time

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

    另外,下面引用的是来自home page of Joda-Time的通知:

    请注意,从 Java SE 8 开始,用户被要求迁移到 java.time (JSR-310) - JDK 的核心部分,它取代了这个项目。

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

    DateTimeFormatterBuilder 允许使用默认时间单位构建DateTimeFormatter。此外,您可以使用方括号或使用DateTimeFormatterBuilder.optionalXXX 函数指定模式的可选部分。

    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;
    import java.time.format.DateTimeFormatterBuilder;
    import java.time.temporal.ChronoField;
    import java.util.Locale;
    import java.util.stream.Stream;
    
    public class Main {
        public static void main(String[] args) {
            DateTimeFormatter parser = new DateTimeFormatterBuilder()
                    .appendPattern("uuuu-MM-dd['T'][ ]HH:mm[:ss]")
                    .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)                                                                       
                    .toFormatter(Locale.ENGLISH);
            
            // Test
            Stream.of(
                        "2021-07-10T10:20:30",
                        "2021-07-10 10:20:30",
                        "2021-07-10T10:20",
                        "2021-07-10 10:20"
            ).forEach(s -> System.out.println(LocalDateTime.parse(s,  parser)));
        }
    }
    

    输出:

    2021-07-10T10:20:30
    2021-07-10T10:20:30
    2021-07-10T10:20
    2021-07-10T10:20
    

    ONLINE DEMO

    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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-28
      • 2011-11-01
      相关资源
      最近更新 更多