【问题标题】:Getting unable to parse date exception无法解析日期异常
【发布时间】:2018-03-27 13:00:52
【问题描述】:

我在字符串类型20/03/2018, 18:20:44 上有日期和时间是否可以在java 中将其更改为日期格式?我试过这段代码:

public static Date getDate(String dateString) {
    DateFormat formatter = new SimpleDateFormat("dd/mm/yyyy hh:mm:ss");
    formatter.setTimeZone(TimeZone.getTimeZone("PST"));
    try {
        Date date = formatter.parse(dateString);
        return date;
    } catch (ParseException e) {
        logger.error("error while parsing milliseconds to date" + dateString, e);
    }
    return null;
}

我无法解析异常并返回 null

【问题讨论】:

  • dd/MM/yyyy, hh:mm:ss
  • mm 代表分钟而不是月。 MM 代表月份
  • 没错,参考SimpleDateFormat javadoc部分Date and Time Patterns
  • 尝试用 'MM' 替换 'mm' 数月仍然无效
  • 错误消息“解析毫秒至今的错误”似乎与此处的代码无关。

标签: java date date-format


【解决方案1】:

您在简单日期格式中使用了错误的字符串替换,它应该是dd/MM/yyyy, HH:mm:ss。还要注意 HH 的大小写,您的时间是 24 小时格式,所以它必须是 HH 而不是 hh

因此,应用更改后,您的代码将如下所示:

public static Date getDate(String dateString) {
  DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy, HH:mm:ss");
  formatter.setTimeZone(TimeZone.getTimeZone("PST"));
  try {
    return formatter.parse(dateString);
  } catch (ParseException e) {
    logger.error("error while parsing milliseconds to date" + dateString, e);
  }
  return null;
}

阅读更多关于可用的各种模式here,顺便说一句,通常建议使用ISO 8601 格式的日期,所以你的格式是yyyy-MM-ddTHH:mm:ss

【讨论】:

    【解决方案2】:

    您应该使用与输入字符串相同的格式:

    DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy, hh:mm:ss");
    

    【讨论】:

      【解决方案3】:

      你犯了两个错误:

      • mm 代表分钟。 MM 代表月份。
        但是您在日期格式的月份部分指定了mm
      • 输入中提供的逗号字符:, 也必须以日期格式显示。

      因此,对于这种形式的字符串输入:"20/03/2018, 18:20:44",您应该使用此 DateFormat:

      DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy, hh:mm:ss");
      

      【讨论】:

        【解决方案4】:

        tl;博士

        您的格式不正确,使用了错误的大小写并省略了逗号。

        此外,您正在使用多年前被 java.time 类取代的麻烦类。

        LocalDateTime.parse(                                       // Create a `LocalDateTime` object as the input string lacks any time zone or offset-from-UTC.
            "20/03/2018, 18:20:44" , 
            DateTimeFormatter.ofPattern( "dd/MM/uuuu, HH:mm:ss" )  // Define a formatting pattern to match the input.
        )
        .atZone(                                                   // Assign a time zone to the `LocalDateTime` to create a `ZonedDateTime` object.
            ZoneId.of( "America/Los_Angeles" )                     // Specify time zone to be assigned. Always use proper zone names `continent/region`; never use 3-4 character pseudo-zones.
        )
        

        2018-03-20T18:20:44-07:00[美国/洛杉矶]

        java.time

        您正在使用麻烦的旧日期时间类,这些类现在已被 java.time 类取代。

        将您的字符串解析为LocalDateTime,因为它缺少time zoneoffset-from-UTC 的指示符。

        String input = "20/03/2018, 18:20:44" ;
        DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu, HH:mm:ss" ) ;
        LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
        

        ldt.toString(): 2018-03-20T18:20:44

        缺少时区或与 UTC 的偏移意味着这 代表一个时刻,不是时间线上的一个点。如果没有区域/偏移的上下文,这仅代表关于 26-27 小时范围内潜在时刻的模糊概念。

        显然,您确定此输入实际上是在某个时区。将ZoneId 应用于此LocalDateTime 以获取ZonedDateTime 对象。

        continent/region 的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

        ZoneId z = ZoneId.of( "America/Los_Angeles" ) ; 
        ZonedDateTime zdt = ldt.atZone( z ) ;
        

        转化

        最好避免麻烦的遗留类。但是如果您必须生成一个java.util.Date 以与尚未针对java.time 更新的旧代码进行互操作,您可以进行转换。要来回转换,请在旧类上调用新方法。

        java.util.Date 表示时间线上的一个点,采用 UTC,分辨率为毫秒。所以它在 java.time 中的替换是InstantInstant 也是 UTC 时间线上的一个点,具有更精细的纳秒分辨率。要获得Date,我们需要一个Instant,我们可以从ZonedDateTime 中提取它。

        Instant instant = zdt.toInstant() ;  // Same moment, same point on the timeline, different wall-clock time.
        

        现在我们可以通过调用Date.from 来获取遗留类对象Date

        java.util.Date date = Date.from( instant ) ;  // Do this only if you *must* work with `Date` class.
        

        关于java.time

        java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

        Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

        要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

        您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

        从哪里获得 java.time 类?

        • Java SE 8Java SE 9 及更高版本
          • 内置。
          • 标准 Java API 的一部分,带有捆绑实现。
          • Java 9 添加了一些次要功能和修复。
        • Java SE 6Java SE 7
          • 大部分 java.time 功能都在ThreeTen-Backport 中向后移植到 Java 6 和 7。
        • Android
          • 更高版本的 Android 捆绑包实现 java.time 类。
          • 对于早期的 Android (ThreeTenABP 项目采用 ThreeTen-Backport(如上所述)。见How to use ThreeTenABP…

        ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

        【讨论】:

        • 嗯,虽然我看到并理解您是新 java.time-package 的忠实粉丝,但遗憾的是,您对使用它的建议不会阻止 OP 使用错误的模式。所以事实仍然是java.time 仍然不够聪明,无法防止此类用户错误(尽管与SimpleDateFormat 相比肯定是更好的库)。在大多数与时间相关的帖子中,像往常一样,宣传一个额外的 3rd-party-libr 虽然与 OP 的具体问题完全无关,但至少可以说是多余的。
        • 我之前评论的一个细节是不准确的。 java.time 会通过抛出运行时异常来拒绝解析模式,该异常可能对许多用户来说不是很清楚。对于格式化/打印,java.time 甚至不会抱怨这种明显错误的模式!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-20
        • 1970-01-01
        相关资源
        最近更新 更多