DateTimeFormatter 和 SimpleDateFormat 使用相同的输入字符串产生不同的结果
DateTimeFormatter and SimpleDateFormat produce different results using same input string
我们目前正在用 DateTimeFormatter
替换 SimpleDateFormat
。
在此期间,我遇到了一个奇怪的行为。
毫秒之间存在差异,我无法向自己解释。
这是代码:
val timeString = "2021-09-17T13:37:00.09Z"
val newFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").withZone(ZoneId.of("UTC"))
val oldFormatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.US)
val zonedDateTime = newFormatter.parse(timeString)
val newFormatterDate = Date.from(zonedDateTime.toInstant())
val oldFormatterDate = oldFormatter.parse(timeString)
Assert.assertEquals(newFormatterDate, oldFormatterDate) // false
// newFormatterDate.time is 1631885820090 and
// oldFormatterDate.time is 1631885820009
我发现这里有很多帖子说我们不应该再使用 SimpleDateFormat
。
但是有人可以向我解释这是怎么发生的吗?
我们的代码中是否存在错误或误解了什么?
Edit: @Ole V.V.'s link ()提供的解决方案可能解决了我遇到的bug 但是它没有回答 question/explain 为什么这两个格式化程序会产生不同的结果。
您的输入数据有两位小数秒。您的输入模式有三个。当需要三位数时,这些实现对 09
小数秒的含义有不同的解释。
如果可能,请修改您的输入数据或输入模式以就小数位数达成一致。如果您需要接受两位或三位小数秒,请查看
现代 DateTimeFormatter
将秒后的数字视为秒的小数,而传统 SimpleDateFormat
将秒后的数字视为毫秒数。
让我们看看DateTimeFormatter
如何处理它:
0.09 seconds = 0.09 * 1000 ms = 90 ms
另一方面,SimpleDateFormat
将其处理为 09
毫秒 = 9
毫秒。
顺便说一下,在使用现代日期时间 API 时,您不需要明确使用 DateTimeFormatter
来解析您的日期时间字符串,因为它已经是 ISO 8601 格式.现代日期时间 API 基于 ISO 8601 并且不需要明确使用 DateTimeFormatter
对象,只要日期时间字符串符合 ISO 8601 标准。
演示:
import java.time.Instant;
public class Main {
public static void main(String[] args) {
System.out.println(Instant.parse("2021-09-17T13:37:00.09Z").toEpochMilli());
}
}
输出:
1631885820090
详细了解 modern Date-Time API* from Trail: Date Time。
* 如果您正在为 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请检查Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
。
我们目前正在用 DateTimeFormatter
替换 SimpleDateFormat
。
在此期间,我遇到了一个奇怪的行为。
毫秒之间存在差异,我无法向自己解释。
这是代码:
val timeString = "2021-09-17T13:37:00.09Z"
val newFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").withZone(ZoneId.of("UTC"))
val oldFormatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.US)
val zonedDateTime = newFormatter.parse(timeString)
val newFormatterDate = Date.from(zonedDateTime.toInstant())
val oldFormatterDate = oldFormatter.parse(timeString)
Assert.assertEquals(newFormatterDate, oldFormatterDate) // false
// newFormatterDate.time is 1631885820090 and
// oldFormatterDate.time is 1631885820009
我发现这里有很多帖子说我们不应该再使用 SimpleDateFormat
。
但是有人可以向我解释这是怎么发生的吗? 我们的代码中是否存在错误或误解了什么?
Edit: @Ole V.V.'s link (
您的输入数据有两位小数秒。您的输入模式有三个。当需要三位数时,这些实现对 09
小数秒的含义有不同的解释。
如果可能,请修改您的输入数据或输入模式以就小数位数达成一致。如果您需要接受两位或三位小数秒,请查看
现代 DateTimeFormatter
将秒后的数字视为秒的小数,而传统 SimpleDateFormat
将秒后的数字视为毫秒数。
让我们看看DateTimeFormatter
如何处理它:
0.09 seconds = 0.09 * 1000 ms = 90 ms
另一方面,SimpleDateFormat
将其处理为 09
毫秒 = 9
毫秒。
顺便说一下,在使用现代日期时间 API 时,您不需要明确使用 DateTimeFormatter
来解析您的日期时间字符串,因为它已经是 ISO 8601 格式.现代日期时间 API 基于 ISO 8601 并且不需要明确使用 DateTimeFormatter
对象,只要日期时间字符串符合 ISO 8601 标准。
演示:
import java.time.Instant;
public class Main {
public static void main(String[] args) {
System.out.println(Instant.parse("2021-09-17T13:37:00.09Z").toEpochMilli());
}
}
输出:
1631885820090
详细了解 modern Date-Time API* from Trail: Date Time。
* 如果您正在为 Android 项目工作,并且您的 Android API 级别仍然不符合 Java-8,请检查Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time
。