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



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

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日期和时间API java.time来进行日期和时间工作。

DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuuu2013MMu2013dd");
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十进制(的连字符,而是字符值为2013十六进制(8211十进制(的短划线。因此,当您在格式模式字符串中指定一个常用的连字符时,它们不匹配,解析就会失败。相反,我使用Unicode转义将短划线放入格式模式字符串中。简单地将其粘贴在那里也可以(前提是您使用支持它的字符编码保存.java文件(,但我想让读者意识到这里发生了一些特殊的事情,所以我更喜欢使用u的Unicode转义。

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

链接

  • Oracle教程:日期时间,解释如何使用java.Time
  • FileFormat.info上的Unicode字符"EN DASH"(U+2013(

我一直坚持这句口头禅:使用与日期-时间字符串完全相同的格式。

在下面给出的解决方案中,我将您的日期-时间字符串复制到我为SimpleDateFormatDateTimeFormatter指定的模式中,并将数字替换为相应的字母,例如2020yyyy,同时保持其余内容(符号、空格等(不变。

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的日期时间API及其格式API、SimpleDateFormat已过时且错误。我建议您应该完全停止使用它们,并切换到现代的日期时间API。

使用现代日期时间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

有关现代日期时间API的更多信息,请访问跟踪:日期时间

如果你正在为你的Android项目做这件事,并且你的Android API级别仍然不符合Java-8,请检查通过desugaring和如何在Android项目中使用ThreeTenABP提供的Java 8+API。

最新更新