如何修复转换后的日期丢失时间?

时间:2017-12-26 10:59:19

标签: java android date kotlin

我想测试我的DateUtil课程并且我收到错误 - 将我的Date转换为String并返回日期后我丢失了大约900秒。

这是我的代码:

  fun convertStringToDate() {
    // here I get current Date
    val currentDate = Date() // 1514285741928
    // see apiDateFormatter declaration below this code
    val dateStr = apiDateFormatter.format(currentDate) // Tue, 26 Dec 2017 12:55:41 GMT+02:00
    // see convertStringToDate() method declaration below this code
    val convertedDate = DateUtil.convertStringToDate(dateStr) // 1514285741000
    assertEquals(currentDate == convertedDate, true)
}

apiDateFormatter

val DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz"
val apiDateFormatter = SimpleDateFormat(DATE_FORMAT, Locale.ENGLISH)

DateUtil。的 convertStringToDate (dateStr)

fun convertStringToDate(dateStr: String): Date {
    return apiDateFormatter.parse(dateStr)
}

currentDateconvertedDate之间的差异大约为900秒。

为什么和如何修复

3 个答案:

答案 0 :(得分:3)

您拥有的两个UNIX纪元时间戳实际上是毫秒,而不是秒。以下是两个值:

1514285741928 - before
1514285741000 - after

两个时间戳之间的差异在928毫秒。所有发生的事情都是毫秒级的组件被截断了。在此行应用秒级精度日期掩码时发生截断:

val dateStr = apiDateFormatter.format(currentDate)

要解决此问题,您可以尝试将SimpleDateFormat掩码更改为包含毫秒:

val DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss.SSS zzz"
//                                           ^^^ add this
val apiDateFormatter = SimpleDateFormat(DATE_FORMAT, Locale.ENGLISH)

答案 1 :(得分:2)

Date()将以毫秒为单位返回当前时间。但是,当您将此毫秒转换为dateString时,您将消除毫秒部分。所以dateString将不包含毫秒部分。因此,当您将dateString重新转换为Date对象时,您将丢失毫秒部分或部分秒数。

假设Date()返回的当前时间为1514287787103。转换为字符串dateString后,将存储与Tue, 26 Dec 2017 17:29:47等价的1514287787000。在这里你失去了几毫秒,这将导致你的差异。

要解决此问题,您必须考虑转换时的毫秒部分。您只需在DATE_FORMAT

中添加毫秒部分即可

val DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss.SSS"

在显示日期时,您可以消除此毫秒部分,但您必须在转换时考虑它。

答案 2 :(得分:2)

(Java语法,而不是Kotlin)

TL;博士

Instant.ofEpochMilli( 1_514_285_741_928L ) 
       .atZone( ZoneId.of( "Pacific/Auckland" ) ) 

java.time

正如其他人所说,从纪元参考日期开始的计数是以毫秒为单位,而不是整秒。

您正在使用现在已经过时的java.time类过时的麻烦旧类。对于较旧的Android,请参阅 ThreeTen-Backport ThreeTenABP 项目。

java.time类使用的分辨率为纳秒,所以毫无问题地保持毫秒。

Instant instant = Instant.ofEpochMilli( 1_514_285_741_928L ) ;

或以UTC记录当前时刻。

Instant instant = Instant.now() ;

要在时区而不是UTC中查看该时刻,请应用ZoneId来获取ZonedDateTime个对象。同一时刻,时间轴上的相同点,不同的挂钟时间。

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

提示:您在问题中使用了一种糟糕的格式。要将日期时间值作为文本进行交换,请仅使用标准ISO 8601格式。