我想测试我的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)
}
currentDate
和convertedDate
之间的差异大约为900秒。
为什么和如何修复?
答案 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)
Instant.ofEpochMilli( 1_514_285_741_928L )
.atZone( ZoneId.of( "Pacific/Auckland" ) )
正如其他人所说,从纪元参考日期开始的计数是以毫秒为单位,而不是整秒。
您正在使用现在已经过时的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格式。