【问题标题】:Java unable to parse date when using dots "." instead of dashes "-"使用点“。”时,Java 无法解析日期。而不是破折号“-”
【发布时间】:2021-07-26 01:52:01
【问题描述】:

我有一个令人困惑的问题,请考虑以下工作代码:

package com.mycompany.mavenproject2;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {
  public static void main(String[] args) throws ParseException {
    SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
    
    Date date = formatter.parse("01-Jan-2017 00:47:13");
    System.out.println(date);
  }
}

按预期执行时打印Sun Jan 01 00:47:13 CET 2017

但是,当我在日期中将每个 - 替换为 . 点时:

package com.mycompany.mavenproject2;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {
  public static void main(String[] args) throws ParseException {
    SimpleDateFormat formatter = new SimpleDateFormat("dd.MMM.yyyy HH:mm:ss");
    
    Date date = formatter.parse("01.Jan.2017 00:47:13");
    System.out.println(date);
  }
}

代码在执行时抛出异常:

Exception in thread "main" java.text.ParseException: Unparseable date: "01.Jan.2017 00:47:13"
    at java.base/java.text.DateFormat.parse(DateFormat.java:395)
    at com.mycompany.mavenproject2.Main.main(Main.java:11)

我使用的是 Java 版本 12 和德语语言环境。

有人有想法吗?

【问题讨论】:

  • 如果我正确阅读了文档,则输入中的任何纯文本都必须与格式字符串完全匹配。似乎没有非此即彼的运算符,也没有匹配任何运算符。对于复杂的字符串,您可能必须找到另一个类或自己进行解析。
  • 始终将Locale 与日期时间解析/格式化类型一起使用。检查answers to this question 了解更多信息。您的代码对我有用,因为我的默认 Locale 支持它。但是,我强烈建议您按照this solution 中的方式进行操作。
  • @markspace - 但他希望格式中的文字点与输入中的文字点匹配。
  • 另外,请注意旧的日期时间 API(java.util 日期时间类型及其格式化 API,SimpleDateFormat)已过时且容易出错。建议彻底停止使用,改用java.timemodern date-time API
  • 我已经在 J​​ava 11 上重现了所描述的行为,默认为德语区域设置。

标签: java date format simpledateformat


【解决方案1】:

java.time

我非常同意 cmets 推荐 java.time,现代 Java 日期和时间 API,用于您的日期和时间工作。

使用此格式化程序:

private static final DateTimeFormatter FORMATTER
        = DateTimeFormatter.ofPattern("dd.MMMuuuu HH:mm:ss", Locale.GERMAN);

做:

    LocalDateTime dateTime = LocalDateTime.parse("01.Jan.2017 00:47:13", FORMATTER);
    System.out.println(dateTime);

在使用德语语言环境的 Java 11 上运行时的输出:

2017-01-01T00:47:13

您可能想知道为什么与您的格式模式字符串相比,我省略了第二个点?在 Java 11 上(也可能接近 Java 版本,可能从 Java 9 到 16)德语月份缩写用点表示缩写,所以 Jan. 表示 Januar(一月)等。所以在我的格式中 MMM 匹配 @ 987654329@ 然后 uuuu 匹配 2017。

为了更全面,Java 从多达四个来源获取其语言环境数据,包括在不同语言环境中使用的月份缩写,并且并非所有来源都同意德语月份缩写的样子。从 Java 9 开始,默认值为 CLDR,COMPAT,这意味着首选来自 CLDR(Unicode 通用语言环境数据存储库)的语言环境数据。这些包括我提到的点。您可以通过将系统属性java.locale-providers 设置为不以CLDR 开头的值来获得不同的结果。

你的代码出了什么问题?

我已经给了你一个提示:在某些 Java 版本中,德语月份缩写带有一个点。因此,在以点为分隔符的示例中,SimpleDateFormat 匹配 dd.MMM(没有第二个点)到 01.Jan.(第二个点)。根据格式,现在应该出现一个点,但由于该点已经被消耗,SimpleDateFOrmat 看了2017,确定它不是一个点并抛出了你看到的异常。

真正令人惊讶的行为是在您的第一个示例中,SimpleDateFormat 能够在没有任何点的情况下解析 01-Jan-2017 00:47:13,即使它认为月份缩写应该以点结尾。我之前已经看到了数百个 SimpleDateFormat 令人惊讶的行为示例,但从来没有与此类似。

所有这些惊喜让我说:一定要避免使用SimpleDateFormat

如果你持怀疑态度,我不怪你。所以来证明:

    SimpleDateFormat formatter = new SimpleDateFormat("MMMyyyy", Locale.GERMAN);
    
    System.out.println(formatter.format(0L));
    
    System.out.println(formatter.parse("Jan2017"));
    System.out.println(formatter.parse("Jan.2017"));

输出,仍在 Java 11 上:

Jan.1970
Sun Jan 01 00:00:00 CET 2017
Sun Jan 01 00:00:00 CET 2017

我们看到SimpleDateFormat 用点格式化月份,并且能够解析带点和不带点的字符串。

这还不是全部。

    SimpleDateFormat formatter = new SimpleDateFormat("MMM", Locale.GERMAN);

    System.out.println(formatter.format(0L));

输出:

Jan

这次月份缩写的格式没有点。我不知道发生了什么事。我再说一遍,忘记令人困惑的SimpleDateFormat 类。这是一个臭名昭著的麻烦制造者。

链接

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-22
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多