KitKat中的时间格式不起作用

时间:2018-02-23 16:01:43

标签: android simpledateformat

我有一个从我的服务器转换时间的函数,它在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

这里的任何帮助或想法将不胜感激

3 个答案:

答案 0 :(得分:1)

S格式字符指定毫秒,而不是任何秒数。您的时间戳有100纳秒的分辨率。

然后存在实施差异:

一些修复选项:

  • 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)

java.time

    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作为解决问题的第一种方法。我只想详细说明原因和方法。

  • 课程DateSimpleDateFormat已过时。因为人们意识到它们的设计很差,所以2014年它们的替换版本来自于java.time和Java 8。这个现代API非常适合使用。
  • SimpleDateFormat尤其令人头疼。
  • 老式的类(java.sql.Timestamp除外)只支持毫秒级的procision,因此他们无法解析或只保持时间戳的完整精度,并且秒数为7位小数。
  • 您的字符串采用ISO 8601格式。现代类将此格式解析并打印为默认格式,即没有任何明确的格式化程序。而且重要的是,他们在正确解析秒数0到9位小数时没有任何问题。

您的代码出了什么问题

API 19(与文档一致!)将小数点后的数字解析为9643834毫秒,即2小时40分43秒834毫秒。实际上,我很惊讶地从您的问题和laalto’s answer in particular中了解到这种不适当的行为已在以后的Android版本中得到修复。在我的Java 9中它仍然有规则。

问题:我可以在Android上使用java.time吗?

是的,java.time在Android设备上运行良好。它至少需要 Java 6

  • 在Java 8及更高版本和新的Android设备上(来自API级别26,我被告知)新的API内置。
  • 在Java 6和7中获取ThreeTen Backport,这是新类的后端(JST 310的ThreeTen,其中首次描述了现代API)。
  • 在(较旧的)Android上,使用Android版的ThreeTen Backport。它被称为ThreeTenABP。确保从包org.threeten.bp和子包中导入日期和时间类。

链接