为什么这个转换后的 Jackson 时间与预期的 Unix 时间不同?
Why is this converted Jackson time different to expected Unix time?
编辑: 原来不是杰克逊的问题,而是1920年4月1日泰国时间调整的问题
com.fasterxml.jackson.databind.ObjectMapper 是如何运作的?我以为它使用了 Unix 时间戳。
我尝试用 mapper.writeValueAsString() 转换 java.util.Date。
当我使用 mapper.readerFor(Date.class).readValue() 将字符串转换回 Date 时,结果是正确的。
但是,当我尝试删除最后 3 位数字并将相同的字符串放入某些转换器网站时,结果会关闭几分钟和几秒钟。
请看下面的代码。
Date wayBack = new SimpleDateFormat("yyyy-MM-dd").parse("1900-01-31");
System.out.println(wayBack); // Wed Jan 31 00:00:00 ICT 1900
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(wayBack)); // -2206420924000
Date deserialised = mapper.readerFor(Date.class).readValue(mapper.writeValueAsString(wayBack));
System.out.println(deserialised); // Wed Jan 31 00:00:00 ICT 1900
下面是来自http://www.onlineconversion.com/unix_time.htm
的截图
请注意,由于我所在的时区,预计会有 7 小时的休息时间,但我不明白 17:56 分钟的不同。
编辑 - 这是我试图提供比第一个更好的答案的尝试。
背景
在查看问题中的代码之前,一些背景说明:
曼谷 1900 年 1 月 31 日午夜的纪元值(以秒为单位)为 -2206420924:
LocalDateTime localDateTime = LocalDateTime.parse("1900-01-31T00:00:00");
ZoneId z = ZoneId.of("Asia/Bangkok");
ZonedDateTime ict_1 = ZonedDateTime.of(localDateTime, z);
System.out.println("Epoch seconds: " + ict_1.toEpochSecond());
System.out.println("ICT datetime : " + ict_1);
上面打印了这个:
Epoch seconds: -2206420924
ICT datetime : 1900-01-31T00:00+06:42:04[Asia/Bangkok]
同一日期 UTC 午夜的纪元值(以秒为单位)为 -1570060800:
ZonedDateTime utcDateTime = ZonedDateTime.parse("1900-01-31T00:00:00Z");
System.out.println("Epoch seconds: " + utcDateTime.toEpochSecond());
System.out.println("UTC datetime : " + utcDateTime);
上面打印了这个:
Epoch seconds: -2206396800
UTC datetime : 1900-01-31T00:00Z
1900 年 1 月 31 日曼谷的午夜时间比英国格林威治的午夜时间(本初子午线 - 或 UTC)晚 24,124 秒。
也就是说,那天曼谷比 UTC 时间(或我认为当时称为 GMT - 因为当时 UTC 尚未建立)早 6 小时 42 分 4 秒。
问题中的具体代码
首先,我更改了默认时区以匹配问题中使用的时区:
System.setProperty("user.timezone", "Asia/Bangkok");
问题中的以下行执行以下操作:
(1)SimpleDateFormat
构造函数,其中日期格式字符串没有指定语言环境,使用默认语言环境。
(2) 然后parse()
方法创建Date对象:
Date wayBack = new SimpleDateFormat("yyyy-MM-dd").parse("1900-01-31");
此时我们可以检查日期对象:
System.out.println(wayBack);
System.out.println(wayBack.getTime());
这将打印以下内容:
Wed Jan 31 00:00:00 ICT 1900
-2206420924000 // epoch milliseconds
这与我们之前在背景部分看到的相符。
当您使用问题中提到的在线工具时,您会看到上述毫秒值报告为以下 GMT (UTC) 日期时间:
GMT: Tuesday, January 30, 1900 5:17:56 PM
对于上面的输出,我使用了 this tool。
同样,这正是我们所期望的 - 当曼谷的午夜时分,它仍然是前一天在英国格林威治的下午。
其余代码(包括 Jackson 对象映射器转换)都受制于您的 Date
对象的初始设置。
对于问题:“com.fasterxml.jackson.databind.ObjectMapper 是如何工作的?我认为它使用了 Unix 时间戳。”它显示了与核心 Java 相同的行为日期对象。我相信你的假设是正确的。
关于异常偏移
关于上图+06:42:04
的ICT抵消:
1920 年 4 月 1 日,对当地的 ICT(印度支那时间)进行了调整,使其与 UTC 时间保持一致(如您所述,偏移 +7 小时)。本地时钟 向前 设置了 17 分 56 秒,以将 UTC (GMT) 偏移四舍五入为 7 小时。
有关 17 分 56 秒更改的具体参考,请参阅 this link。
这就是为什么从 1920 年 4 月开始您将看不到异常偏移的原因。
更多链接
请参阅 关于较新的 java.time
类 应该使用它而不是 java.util.Date
。
请参阅此 question and its answers 以深入了解历史时区调整主题。
编辑: 原来不是杰克逊的问题,而是1920年4月1日泰国时间调整的问题
com.fasterxml.jackson.databind.ObjectMapper 是如何运作的?我以为它使用了 Unix 时间戳。
我尝试用 mapper.writeValueAsString() 转换 java.util.Date。
当我使用 mapper.readerFor(Date.class).readValue() 将字符串转换回 Date 时,结果是正确的。
但是,当我尝试删除最后 3 位数字并将相同的字符串放入某些转换器网站时,结果会关闭几分钟和几秒钟。
请看下面的代码。
Date wayBack = new SimpleDateFormat("yyyy-MM-dd").parse("1900-01-31");
System.out.println(wayBack); // Wed Jan 31 00:00:00 ICT 1900
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(wayBack)); // -2206420924000
Date deserialised = mapper.readerFor(Date.class).readValue(mapper.writeValueAsString(wayBack));
System.out.println(deserialised); // Wed Jan 31 00:00:00 ICT 1900
下面是来自http://www.onlineconversion.com/unix_time.htm
的截图请注意,由于我所在的时区,预计会有 7 小时的休息时间,但我不明白 17:56 分钟的不同。
编辑 - 这是我试图提供比第一个更好的答案的尝试。
背景
在查看问题中的代码之前,一些背景说明:
曼谷 1900 年 1 月 31 日午夜的纪元值(以秒为单位)为 -2206420924:
LocalDateTime localDateTime = LocalDateTime.parse("1900-01-31T00:00:00");
ZoneId z = ZoneId.of("Asia/Bangkok");
ZonedDateTime ict_1 = ZonedDateTime.of(localDateTime, z);
System.out.println("Epoch seconds: " + ict_1.toEpochSecond());
System.out.println("ICT datetime : " + ict_1);
上面打印了这个:
Epoch seconds: -2206420924
ICT datetime : 1900-01-31T00:00+06:42:04[Asia/Bangkok]
同一日期 UTC 午夜的纪元值(以秒为单位)为 -1570060800:
ZonedDateTime utcDateTime = ZonedDateTime.parse("1900-01-31T00:00:00Z");
System.out.println("Epoch seconds: " + utcDateTime.toEpochSecond());
System.out.println("UTC datetime : " + utcDateTime);
上面打印了这个:
Epoch seconds: -2206396800
UTC datetime : 1900-01-31T00:00Z
1900 年 1 月 31 日曼谷的午夜时间比英国格林威治的午夜时间(本初子午线 - 或 UTC)晚 24,124 秒。
也就是说,那天曼谷比 UTC 时间(或我认为当时称为 GMT - 因为当时 UTC 尚未建立)早 6 小时 42 分 4 秒。
问题中的具体代码
首先,我更改了默认时区以匹配问题中使用的时区:
System.setProperty("user.timezone", "Asia/Bangkok");
问题中的以下行执行以下操作:
(1)SimpleDateFormat
构造函数,其中日期格式字符串没有指定语言环境,使用默认语言环境。
(2) 然后parse()
方法创建Date对象:
Date wayBack = new SimpleDateFormat("yyyy-MM-dd").parse("1900-01-31");
此时我们可以检查日期对象:
System.out.println(wayBack);
System.out.println(wayBack.getTime());
这将打印以下内容:
Wed Jan 31 00:00:00 ICT 1900
-2206420924000 // epoch milliseconds
这与我们之前在背景部分看到的相符。
当您使用问题中提到的在线工具时,您会看到上述毫秒值报告为以下 GMT (UTC) 日期时间:
GMT: Tuesday, January 30, 1900 5:17:56 PM
对于上面的输出,我使用了 this tool。
同样,这正是我们所期望的 - 当曼谷的午夜时分,它仍然是前一天在英国格林威治的下午。
其余代码(包括 Jackson 对象映射器转换)都受制于您的 Date
对象的初始设置。
对于问题:“com.fasterxml.jackson.databind.ObjectMapper 是如何工作的?我认为它使用了 Unix 时间戳。”它显示了与核心 Java 相同的行为日期对象。我相信你的假设是正确的。
关于异常偏移
关于上图+06:42:04
的ICT抵消:
1920 年 4 月 1 日,对当地的 ICT(印度支那时间)进行了调整,使其与 UTC 时间保持一致(如您所述,偏移 +7 小时)。本地时钟 向前 设置了 17 分 56 秒,以将 UTC (GMT) 偏移四舍五入为 7 小时。
有关 17 分 56 秒更改的具体参考,请参阅 this link。
这就是为什么从 1920 年 4 月开始您将看不到异常偏移的原因。
更多链接
请参阅 java.time
类 应该使用它而不是 java.util.Date
。
请参阅此 question and its answers 以深入了解历史时区调整主题。