如何使用日期格式 yyyy-MM-dd hh:mm a 解决 Java 8 中无法解析的日期异常

How to resolve Unparseable date Exception in Java 8 with Date format yyyy-MM-dd hh:mm a

我有一个文本文件,我正在从中读取和设置事务 POJO class 数据,为了获得开始时间和结束时间之间的差异,我需要解析日期对象中的时间信息。

DateFormat format = new SimpleDateFormat(dateFormat);
System.out.println("Date format in play:"+dateFormat);
Transaction transaction = storageRepositroy.getTransaction(key);
Date start = format.parse(transaction.getStartDate() + " " + transaction.getStartTime());//line no. 29
Date end = format.parse(transaction.getEndDate() + " " + transaction.getEndTime());

我在运行这段代码

时遇到异常

例外是

Date format in play:yyyy-MM-dd hh:mm a
java.text.ParseException: Unparseable date: "2020–03–01 03:15 PM"
    at java.text.DateFormat.parse(DateFormat.java:366)
    at dc.tech.transaction.util.TimeUtil.calculateAverageTime(TimeUtil.java:29)

yyyy-MM-dd hh:mm a 是我传递给 SimleDateFormat 构造函数的日期格式。我无法理解和调试为什么会出现此错误。

java.time

我建议您使用 java.time,现代 Java 日期和时间 API,作为您的日期和时间工作。

    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuu\u2013MM\u2013dd");
    DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm a", Locale.ENGLISH);
    
    String dateString = "2020–03–01";
    String timeString = "03:15 PM";
    
    LocalDate date = LocalDate.parse(dateString, dateFormatter);
    LocalTime time = LocalTime.parse(timeString, timeFormatter);
    LocalDateTime dateTime = date.atTime(time);
    
    System.out.println(dateTime);

输出:

2020-03-01T15:15

使用java.time解析后合并日期和时间很简单,所以我更喜欢单独解析它们。

你的代码出了什么问题?

感谢 Ajeetkumar 在评论中的注意和报告:日期字符串中的连字符不是通常的减号或字符值为 2D 十六进制(45 十进制)的连字符,而是 en dash 字符值为 2013 十六进制(8211 十进制)。因此,当您在格式模式字符串中指定一个常用的连字符时,它们不匹配,并且解析失败。相反,我使用 Unicode 转义符将破折号放入格式模式字符串中。简单地将它粘贴到那里也可以工作(前提是你用支持它的字符编码保存你的 .java 文件),但我想让 reader 意识到这里发生了一些特别的事情,所以我更喜欢使用 \u.

的 Unicode 转义

您的代码还有另一个问题:您没有为格式化程序提供任何语言环境。所以它使用 JVM 的默认语言环境。只要该语言环境需要 PM,解析就会起作用。如果有一天您更改了语言环境设置或 运行 您在具有不同默认语言环境的计算机或 JVM 上的代码,解析将突然失败,您可能很难找出原因。我已经指定了英语语言环境来解析时间。有些人更喜欢在约会时这样做,尽管从技术上讲这不是必需的。

链接

我一直坚持这个原则: 使用与 date-time 字符串完全相同的格式。

在下面给出的解决方案中,我已将您的 date-time 字符串复制到我为 SimpleDateFormatDateTimeFormatter 指定的模式中,并将数字替换为相应的字母,例如2020yyyy 同时保持其余部分(符号、space 等)完整无缺。

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

public class Main {
    public static void main(String[] args) throws ParseException {
        DateFormat sdf = new SimpleDateFormat("yyyy–MM–dd hh:mm a", Locale.ENGLISH);// Make sure to use Locale
        String dateTimeString = "2020–03–01 03:15 PM";// The string copied from the exception you have got
        Date date = sdf.parse(dateTimeString);
        System.out.println(sdf.format(date));
    }
}

输出:

2020–03–01 03:15 PM

注:java.util的date-timeAPI及其格式API、SimpleDateFormat已过时和 error-prone。我建议你应该完全停止使用它们并切换到 modern date-time API.

使用现代date-time API:

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

public class Main {
    public static void main(String[] args) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy–MM–dd hh:mm a", Locale.ENGLISH);// Make sure to use Locale
        String dateTimeString = "2020–03–01 03:15 PM";// The string copied from the exception you have got
        System.out.println(LocalDateTime.parse(dateTimeString, dtf));
    }
}

输出:

2020-03-01T15:15

Trail: Date Time.

了解有关现代 date-time API 的更多信息

如果您正在为您的 Android 项目执行此操作,并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaring and .