无法将 ISO 8601 日期转换为 Android 中的字符串
Can't convert ISO 8601 date to String in Android
我有一个 Android 应用程序,它显示了票证的创建日期以及我从服务器获得的信息。
问题是我无法解析我得到的字符串当我尝试使用 SimpleDateFormat 解析它时出现异常
这是我从服务器得到的:
2017-07-04 23:59:51.486559-05
这是我用来解析它的格式:
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSX", Locale.ENGLISH);
我用这种方法得到的例外是:
java.lang.IllegalArgumentException: Unknown pattern character 'X'
at java.text.SimpleDateFormat.validatePatternCharacter(SimpleDateFormat.java:323)
at java.text.SimpleDateFormat.validatePattern(SimpleDateFormat.java:312)
at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:365)
at com.unipagos.app.wallet.payment.receipts.datamodels.PaymentReceipt.dateFromString(PaymentReceipt.java:320)
我已经用了几个小时了,我也试过
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ", Locale.ENGLISH);
无济于事,得到这个异常:
java.text.ParseException: Unparseable date: "2016-05-30 20:41:19.934959+00" (at offset 23)
at java.text.DateFormat.parse(DateFormat.java:579)
at com.unipagos.app.wallet.payment.receipts.datamodels.PaymentReceipt.dateFromString(PaymentReceipt.java:326)
at com.unipagos.app.wallet.payment.receipts.datamodels.PaymentReceipt.loadReceiptJSONObject(PaymentReceipt.java:164)
at com.unipagos.app.history.HistoryListFragment.populateTransactionList(HistoryListFragment.java:371)
at com.unipagos.app.history.HistoryListFragment.access00(HistoryListFragment.java:83)
我是不是漏掉了什么?
SimpleDateFormat
无法解析您的日期时间字符串。字符串有微秒(秒上有6位小数),其中SimpleDateFormat
只支持毫秒(3位小数)。
三十ABP
所以这似乎是您放弃早已过时的 类 Date
和 SimpleDateFormat
的好时机。一般经验表明,现代 Java 日期和时间 API 更易于使用。对于 Android,您可以在下面的 ThreeTenABP、link 中找到它。当你知道怎么做时,剩下的就很简单了:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSX", Locale.ENGLISH);
OffsetDateTime odt = OffsetDateTime.parse(creationDateFromServer, dtf);
System.out.println(odt);
这会打印
2017-07-04T23:59:51.486559-05:00
这与您的输入一致,2017-07-04 23:59:51.486559-05
。顺便说一下,打印的字符串是 ISO 8601;这就是现代 类' toString()
方法产生的结果。
老式解决方案
如果您坚持使用过时的 类,一种方法是去掉最后三位小数,这样只有三位,在时区偏移量上加上两位数,所以有四位,并且使用 Z
来解析它:
creationDateFromServer = creationDateFromServer
.replaceFirst("(\.\d{3})\d{3}((?:\+|-)\d{2})$", "0");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ", Locale.ENGLISH);
try {
Date d = df.parse(creationDateFromServer);
System.out.println(d);
} catch (ParseException pe) {
System.out.println(pe + " at offset " + pe.getErrorOffset());
}
请注意阅读正则表达式有多么困难。此外,如果有一天出现偏移量,例如 +0530,这也会中断。输出为:
Wed Jul 05 06:59:51 CEST 2017
Date
在我的本地时区 打印,在本例中偏移量为 +0200,因此打印的时间与 23:59:51.486 一致前一天 -0500。这意味着 Date
对象在内部持有正确的时间点。
Link
我有一个 Android 应用程序,它显示了票证的创建日期以及我从服务器获得的信息。
问题是我无法解析我得到的字符串当我尝试使用 SimpleDateFormat 解析它时出现异常
这是我从服务器得到的:
2017-07-04 23:59:51.486559-05
这是我用来解析它的格式:
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSX", Locale.ENGLISH);
我用这种方法得到的例外是:
java.lang.IllegalArgumentException: Unknown pattern character 'X'
at java.text.SimpleDateFormat.validatePatternCharacter(SimpleDateFormat.java:323)
at java.text.SimpleDateFormat.validatePattern(SimpleDateFormat.java:312)
at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:365)
at com.unipagos.app.wallet.payment.receipts.datamodels.PaymentReceipt.dateFromString(PaymentReceipt.java:320)
我已经用了几个小时了,我也试过
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ", Locale.ENGLISH);
无济于事,得到这个异常:
java.text.ParseException: Unparseable date: "2016-05-30 20:41:19.934959+00" (at offset 23)
at java.text.DateFormat.parse(DateFormat.java:579)
at com.unipagos.app.wallet.payment.receipts.datamodels.PaymentReceipt.dateFromString(PaymentReceipt.java:326)
at com.unipagos.app.wallet.payment.receipts.datamodels.PaymentReceipt.loadReceiptJSONObject(PaymentReceipt.java:164)
at com.unipagos.app.history.HistoryListFragment.populateTransactionList(HistoryListFragment.java:371)
at com.unipagos.app.history.HistoryListFragment.access00(HistoryListFragment.java:83)
我是不是漏掉了什么?
SimpleDateFormat
无法解析您的日期时间字符串。字符串有微秒(秒上有6位小数),其中SimpleDateFormat
只支持毫秒(3位小数)。
三十ABP
所以这似乎是您放弃早已过时的 类 Date
和 SimpleDateFormat
的好时机。一般经验表明,现代 Java 日期和时间 API 更易于使用。对于 Android,您可以在下面的 ThreeTenABP、link 中找到它。当你知道怎么做时,剩下的就很简单了:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSX", Locale.ENGLISH);
OffsetDateTime odt = OffsetDateTime.parse(creationDateFromServer, dtf);
System.out.println(odt);
这会打印
2017-07-04T23:59:51.486559-05:00
这与您的输入一致,2017-07-04 23:59:51.486559-05
。顺便说一下,打印的字符串是 ISO 8601;这就是现代 类' toString()
方法产生的结果。
老式解决方案
如果您坚持使用过时的 类,一种方法是去掉最后三位小数,这样只有三位,在时区偏移量上加上两位数,所以有四位,并且使用 Z
来解析它:
creationDateFromServer = creationDateFromServer
.replaceFirst("(\.\d{3})\d{3}((?:\+|-)\d{2})$", "0");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ", Locale.ENGLISH);
try {
Date d = df.parse(creationDateFromServer);
System.out.println(d);
} catch (ParseException pe) {
System.out.println(pe + " at offset " + pe.getErrorOffset());
}
请注意阅读正则表达式有多么困难。此外,如果有一天出现偏移量,例如 +0530,这也会中断。输出为:
Wed Jul 05 06:59:51 CEST 2017
Date
在我的本地时区 打印,在本例中偏移量为 +0200,因此打印的时间与 23:59:51.486 一致前一天 -0500。这意味着 Date
对象在内部持有正确的时间点。