我有一个从我的服务器转换时间的函数,它在android api 24上工作正常,但现在我在KitKat(Api 19)上测试并且时间转换不能正常工作。两个设备都接收相同的数据,但转换不一样。两台设备都设置了“自动日期和时间”,两台设备的时间相同。
从服务器接收字符串:
(Api 19) -> CurrentTimeStamp:2018-02-23T15:50:15.9643834Z
(Api 24) -> CurrentTimeStamp:2018-02-23T15:50:15.9373834Z
转换
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
try {
Date dateServer = dateFormat.parse(currentTimeStamp);
String currentDate = dateServer.toString();
} catch (ParseException e) {
e.printStackTrace();
}
打印:
(Api 19) -> DateServer:Fri Feb 23 12:26:28 CST 2018
(Api 24) -> DateServer:Fri Feb 23 09:50:15 CST 2018 <- this time is correct
这里的任何帮助或想法将不胜感激
答案 0 :(得分:1)
S
格式字符指定毫秒,而不是任何秒数。您的时间戳有100纳秒的分辨率。
然后存在实施差异:
API 19:S
部分只是作为数字读取并输入Calendar
的{{1}}字段。由于该数字实际上是> 1000,最终溢出到其他领域。参考:http://androidxref.com/4.4.4_r1/xref/libcore/luni/src/main/java/java/text/SimpleDateFormat.java#907
后来的API:这个数字实际上是截断/填充到3位数。参考:http://androidxref.com/8.0.0_r4/xref/libcore/ojluni/src/main/java/java/text/SimpleDateFormat.java#1347
一些修复选项:
Java 8 MILLISECONDS
DateTimeFormatter
支持纳秒但在Android上需要API 26。对于较旧的机器人,有ThreeTenABP。
在尝试使用java.time
进行解析之前,您可以自己将时间戳字符串截断为毫秒分辨率小数秒。
答案 1 :(得分:1)
SimpleDateFormat
的精度为毫秒,因此在几分之一秒内无法处理超过3位数。请检查此答案:String-Date conversion with nanoseconds
此外,最后的“Z”表示日期是UTC格式,所以如果您只是将其视为文字(内部引号),则会忽略此信息(以UTC为单位)(当然,您执行此操作)通过在格式化程序中设置时区来解决此问题,但正确的方法是使用“X”模式来解析它。)
无论如何,要解析超过3个小数位数,您可以使用ThreeTen Backport。只需按照此答案中的链接进行安装即可:How to add Duration to LocalDateTime for API level lower than 26
或者,如果您的API级别已经有java.time
个类,那就更好了。无论如何,java.time
和ThreeTen Backport的代码是相同的:
Instant instant = Instant.parse("2018-02-23T15:50:15.9643834Z");
如果您仍然需要使用java.util.Date
,则很容易转换:
// java.time
Date date = Date.from(instant);
// ThreeTenBackport
Date date = DateTimeUtils.toDate(instant);
请记住,转换为Date
时,由于API的限制,只保留前3个小数位,其他小数位丢失。
答案 2 :(得分:1)
String currentTimestamp = "2018-02-23T15:50:15.9643834Z";
String currentDate = Instant.parse(currentTimestamp)
.atZone(ZoneId.systemDefault())
.toString();
System.out.println(currentDate);
在我的电脑上打印
2018-02-23T16:50:15.964383400+01:00[Europe/Berlin]
如果您希望输出的格式与Date.toString()
:
DateTimeFormatter dateFormatter
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH);
String currentDate = Instant.parse(currentTimestamp)
.atZone(ZoneId.systemDefault())
.format(dateFormatter);
这给出了:
Fri Feb 23 16:50:15 CET 2018
其他两个答案都已经提供java.time
作为解决问题的第一种方法。我只想详细说明原因和方法。
Date
和SimpleDateFormat
已过时。因为人们意识到它们的设计很差,所以2014年它们的替换版本来自于java.time
和Java 8。这个现代API非常适合使用。SimpleDateFormat
尤其令人头疼。java.sql.Timestamp
除外)只支持毫秒级的procision,因此他们无法解析或只保持时间戳的完整精度,并且秒数为7位小数。API 19(与文档一致!)将小数点后的数字解析为9643834毫秒,即2小时40分43秒834毫秒。实际上,我很惊讶地从您的问题和laalto’s answer in particular中了解到这种不适当的行为已在以后的Android版本中得到修复。在我的Java 9中它仍然有规则。
java.time
吗?是的,java.time
在Android设备上运行良好。它至少需要 Java 6 。
org.threeten.bp
和子包中导入日期和时间类。java.time
。