java.text.ParseException:无法解析的日期:java.text.DateFormat.parse(DateFormat.java:579)
Posted
技术标签:
【中文标题】java.text.ParseException:无法解析的日期:java.text.DateFormat.parse(DateFormat.java:579)【英文标题】:java.text.ParseException: Unparseable date: java.text.DateFormat.parse(DateFormat.java:579) 【发布时间】:2017-02-22 20:16:41 【问题描述】:SimpleDateFormat
有问题。
SimpleDateFormat dtfmt=new SimpleDateFormat("dd MMM yyyy hh:mm a", Locale.getDefault());
Date dt=dtfmt.parse(deptdt);
在 android 模拟器中运行正常,但在手机中出现此错误:
W/System.err:java.text.ParseException:无法解析的日期:“2016 年 10 月 24 日 7:31 pm”(偏移量 3) W/System.err:在 java.text.DateFormat.parse(DateFormat.java:579)
有什么办法吗?
【问题讨论】:
【参考方案1】:您的deptdt
包含Oct
,看起来像英文月份名称。
但是您的 Locale.getDefault()
可能提供了非英语语言环境。
将其替换为Locale.ENGLISH
或Locale.US
:
SimpleDateFormat dtfmt=new SimpleDateFormat("dd MMM yyyy hh:mm a", Locale.ENGLISH);
Date dt=dtfmt.parse(deptdt);
【讨论】:
【参考方案2】:这可能是因为手机的默认语言环境不是英语,而您输入的月份名称是 (Oct
)。
解决方案是明确使用英语语言环境:
SimpleDateFormat dtfmt = new SimpleDateFormat("dd MMM yyyy hh:mm a", Locale.ENGLISH);
Date dt = dtfmt.parse("24 Oct 2016 7:31 pm");
您可以使用ThreeTen Backport,而不是直接使用SimpleDateFormat
(因为这个旧API 有lots of problems 和design issues),它是Java 8 新日期/时间类的一个很好的反向移植。要在 Android 中使用它,您还需要ThreeTenABP(详细了解如何使用它here)。
要使用的主要类是org.threeten.bp.LocalDateTime
(这似乎是最佳选择,因为您的输入中有日期和时间字段)和org.threeten.bp.format.DateTimeFormatter
(用于解析输入)。我还使用java.util.Locale
类来确保它解析英文月份名称,并使用org.threeten.bp.format.DateTimeFormatterBuilder
来确保它解析pm
(使其不区分大小写,默认为PM
):
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// case insensitive to parse "pm"
.parseCaseInsensitive()
// pattern
.appendPattern("dd MMM yyyy h:mm a")
// use English locale to parse month name (Oct)
.toFormatter(Locale.ENGLISH);
// parse input
LocalDateTime dt = LocalDateTime.parse("24 Oct 2016 7:31 pm", fmt);
System.out.println(dt); // 2016-10-24T19:31
输出将是:
2016-10-24T19:31
如果您需要将其转换为java.util.Date
,您可以使用org.threeten.bp.DateTimeUtils
类。但是您还需要知道将使用哪个时区来转换它。在下面的示例中,我使用“UTC”:
Date date = DateTimeUtils.toDate(dt.atZone(ZoneOffset.UTC).toInstant());
要切换到不同的区域,您可以:
Date date = DateTimeUtils.toDate(dt.atZone(ZoneId.of("Europe/London")).toInstant());
请注意,API 使用IANA timezones names(始终采用Continent/City
格式,如America/Sao_Paulo
或Europe/Berlin
)。
避免使用三个字母的缩写(如CST
或PST
),因为它们是ambiguous and not standard。要找到更适合每个地区的时区,请使用 ZoneId.getAvailableZoneIds()
方法并检查哪一个最适合您的用例。
PS:上面的最后一个示例 (dt.atZone(ZoneId.of("Europe/London"))
) 将在伦敦时区创建日期/时间 2016-10-24T19:31
。但是,如果您想要的是 UTC 中的 2016-10-24T19:31
,然后将其转换为另一个时区,那么您应该这样做:
Date date = DateTimeUtils.toDate(dt
// first convert it to UTC
.toInstant(ZoneOffset.UTC)
// then convert to LondonTimezone
.atZone(ZoneId.of("Europe/London")).toInstant());
【讨论】:
【参考方案3】:切勿在没有Locale
的情况下使用SimpleDateFormat
或DateTimeFormatter
由于给定的日期时间是英文的,你应该在你的日期时间解析器中使用Locale.ENGLISH
;否则解析将在使用非英语类型区域设置的系统(计算机、电话等)中失败。
另外,请注意 java.util
的日期时间 API 及其格式 API SimpleDateFormat
已过时且容易出错。建议完全停止使用,转用modern date-time API。
演示:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;
public class Main
public static void main(String[] args)
final String strDateTime = "24 Oct 2016 7:31 pm";
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.parseCaseInsensitive() // For case-insensitive (e.g. am, Am, AM) parsing
.appendPattern("d MMM uuuu h:m a") // Pattern conforming to the date-time string
.toFormatter(Locale.ENGLISH); // Locale
LocalDateTime ldt = LocalDateTime.parse(strDateTime, dtf);
System.out.println(ldt);
输出:
2016-10-24T19:31
默认情况下,DateTimeFormatter#ofPattern
使用 JVM 在启动时根据宿主环境设置的 default FORMAT locale。 SimpleDateFormat
也是如此。我试图通过下面的演示来说明这个问题:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;
public class Main
public static void main(String[] args)
final String strDateTime = "24 Oct 2016 7:31 pm";
DateTimeFormatter dtfWithDefaultLocale = null;
System.out.println("JVM's Locale: " + Locale.getDefault());
// Using DateTimeFormatter with the default Locale
dtfWithDefaultLocale = getDateTimeFormatterWithDefaultLocale();
System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
System.out.println(
"Parsed with JVM's default locale: " + LocalDateTime.parse(strDateTime, dtfWithDefaultLocale));
// Setting the JVM's default locale to Locale.FRANCE
Locale.setDefault(Locale.FRANCE);
// Using DateTimeFormatter with Locale.ENGLISH explicitly (recommended)
DateTimeFormatter dtfWithEnglishLocale = getDateTimeFormatterWithEnglishLocale();
System.out.println("JVM's Locale: " + Locale.getDefault());
System.out.println("DateTimeFormatter's Locale: " + dtfWithEnglishLocale.getLocale());
LocalDateTime zdt = LocalDateTime.parse(strDateTime, dtfWithEnglishLocale);
System.out.println("Parsed with Locale.ENGLISH: " + zdt);
System.out.println("JVM's Locale: " + Locale.getDefault());
// Using DateTimeFormatter with the default Locale
dtfWithDefaultLocale = getDateTimeFormatterWithDefaultLocale();
System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
System.out.println(
"Parsed with JVM's default locale: " + LocalDateTime.parse(strDateTime, dtfWithDefaultLocale));
static DateTimeFormatter getDateTimeFormatterWithDefaultLocale()
return new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("d MMM uuuu h:m a")
.toFormatter(); // Using default Locale
static DateTimeFormatter getDateTimeFormatterWithEnglishLocale()
return new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("d MMM uuuu h:m a")
.toFormatter(Locale.ENGLISH); // Using Locale.ENGLISH
输出:
JVM's Locale: en_GB
DateTimeFormatter's Locale: en_GB
Parsed with JVM's default locale: 2016-10-24T19:31
JVM's Locale: fr_FR
DateTimeFormatter's Locale: en
Parsed with Locale.ENGLISH: 2016-10-24T19:31
JVM's Locale: fr_FR
DateTimeFormatter's Locale: fr_FR
Exception in thread "main" java.time.format.DateTimeParseException: Text '24 Oct 2016 7:31 pm' could not be parsed at index 3
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:492)
at Main.main(Main.java:34)
以下演示,使用SimpleDateFormat
,只是为了完整起见:
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
final String strDateTime = "24 Oct 2016 7:31 pm";
SimpleDateFormat sdf = new SimpleDateFormat("d MMM yyyy h:m a", Locale.ENGLISH);
Date date = sdf.parse(strDateTime);
System.out.println(date);
输出:
Mon Oct 24 19:31:00 BST 2016
【讨论】:
以上是关于java.text.ParseException:无法解析的日期:java.text.DateFormat.parse(DateFormat.java:579)的主要内容,如果未能解决你的问题,请参考以下文章
java.text.ParseException:无法解析的日期:将 mm/dd/yyyy 字符串转换为日期
TimeFormatException:java.text.ParseException: Unparseable date: ““
服务器处理发生异常:java.text.ParseException: Unparseable date
出现错误 java.text.ParseException: Unparseable date: (at offset 0) 即使简单日期格式和字符串值相同
我收到此错误 java.text.ParseException: Unparseable date: "2017-03-09T18:30:00.000Z"