语言间的Unix时间转换
Unix Time Conversion between Language
我有这个以毫秒为单位的 unix 时间戳: -62135769600000
我尝试使用 java 和 java 脚本转换时间戳,但我得到了两个不同的响应。看下面:
Date d = new Date(-62135769600000L);
System.out.println(d); // output = Sat Jan 01 00:00:00 GMT 1
d = new Date(-62135769600000L)
console.log(d) // output = Fri Dec 29 0000 19:00:00 GMT-0500 (EST)
如您所见,我们有两个不同的结果。我想了解为什么以及如何解决这个问题。
那是因为 Date
和 Date
有两个非常不同的实现。
这里其实有两个区别:输出文本的格式和输出所代表的实际日期。
不同的日期
我还在调查为什么 Java 的 Date
会 return 1 January 0001 好吧,rzwitserloot 已经发现并提到了这是他在我吃饭时的回答。 Java 的 Date
使用当时使用的日历,而 Java 的 JSR 310 日期和时间 API 和 JavaScript 的 Date
使用公历。这称为 proleptic calendar – 一种适用于引入之前日期的日历。
我知道Java脚本return是正确的日期值。 Java的Date
is broken,不要用。相反,您应该使用 java.time
包中提供的现代 Java 日期和时间 API。
以下 Java 代码 return 是正确的日期:
OffsetDateTime odt = Instant.ofEpochMilli(-62135769600000L)
.atOffset(ZoneOffset.ofHours(-5));
System.out.println(odt);
格式不同
Java 和 JavaScript 的 Date
都以不同的方式实现 toString()
。 toString().
toString()` 总是 return 调用该方法的对象的文本表示 — 但 如何 完全取决于作者拥有的内容记住了。
您永远不应该依赖 toString()
采用某种格式。如果您确实想要格式化您的字符串,请在Java.
中使用DateTimeFormatter
首先,一个教训:java.util.Date
是愚蠢的,破烂的,永远不应该使用 。在 java 中处理时间的正确方法是使用 java.time
包。
然后,解释您观察到的差异:
- java脚本通过转换使用公历表示的时刻来报告时间,就好像您处于美国东部时间时区一样。
- java 的 Date 正在报告时间,就好像它是儒略历一样,并且在 GMT 时区。
时区差异解释了为什么 java 脚本打印 19:00 而 java 打印 00:00,以及 1 个日期的差异。 12 月 29 日,当你在纽约 19:00 拍手时,恰好是伦敦 12 月 30 日午夜。剩下正好 48 小时(2 天)的差异是因为儒略历。
正确的方法,在java:
Instant i = Instant.ofEpochMilli(-62135769600000L);
System.out.println(i.atZone(ZoneOffset.UTC));
> 0000-12-30T00:00Z
今天普遍使用的日历系统称为公历。它是对之前使用的儒略历的修改,罗马时代使用的儒略历。
世界并没有在同一天从儒略转换到公历。事实上,俄罗斯很晚,直到 1918 年才开始转变:你在莫斯科买了一份报纸,上面写着 'January 31st, 1918'(但是俄语)。如果你然后跳上一匹马向西骑到布拉格或柏林或阿姆斯特丹,一整夜,然后问:嘿,今天是几号?他们会告诉你:今天是 2 月 13 日。
然后你第二天骑车回莫斯科,再买一份报纸。它显示为 'February 14th, 1918'。 2 月 1 日至 13 日发生了什么? 它们从未存在过。那是俄罗斯转变的时间。
小花絮:'october revolution',指的是沙皇被推翻的时间,发生在 11 月。发生这种情况时,俄罗斯还在 julian 上,是在 10 月。世界上其他使用罗马日历的国家都使用格里高利历,他们称其为十一月。
尽管这是一件愚蠢的事情,java.util.Date
会尝试推测您真正想要的东西并具有任意时间戳:当您创建早于此的 Date 对象时,它会以儒略历呈现时间。
这很愚蠢(世界不会一下子全部切换),所以 javascript 和 java.time
都不会这样做。
这解释了这 2 天。
我有这个以毫秒为单位的 unix 时间戳: -62135769600000
我尝试使用 java 和 java 脚本转换时间戳,但我得到了两个不同的响应。看下面:
Date d = new Date(-62135769600000L);
System.out.println(d); // output = Sat Jan 01 00:00:00 GMT 1
d = new Date(-62135769600000L)
console.log(d) // output = Fri Dec 29 0000 19:00:00 GMT-0500 (EST)
如您所见,我们有两个不同的结果。我想了解为什么以及如何解决这个问题。
那是因为 Date
和 Date
有两个非常不同的实现。
这里其实有两个区别:输出文本的格式和输出所代表的实际日期。
不同的日期
我还在调查为什么 Java 的 好吧,rzwitserloot 已经发现并提到了这是他在我吃饭时的回答。 Java 的 Date
会 return 1 January 0001Date
使用当时使用的日历,而 Java 的 JSR 310 日期和时间 API 和 JavaScript 的 Date
使用公历。这称为 proleptic calendar – 一种适用于引入之前日期的日历。
我知道Java脚本return是正确的日期值。 Java的Date
is broken,不要用。相反,您应该使用 java.time
包中提供的现代 Java 日期和时间 API。
以下 Java 代码 return 是正确的日期:
OffsetDateTime odt = Instant.ofEpochMilli(-62135769600000L)
.atOffset(ZoneOffset.ofHours(-5));
System.out.println(odt);
格式不同
Java 和 JavaScript 的 Date
都以不同的方式实现 toString()
。 toString().
toString()` 总是 return 调用该方法的对象的文本表示 — 但 如何 完全取决于作者拥有的内容记住了。
您永远不应该依赖 toString()
采用某种格式。如果您确实想要格式化您的字符串,请在Java.
DateTimeFormatter
首先,一个教训:java.util.Date
是愚蠢的,破烂的,永远不应该使用 。在 java 中处理时间的正确方法是使用 java.time
包。
然后,解释您观察到的差异:
- java脚本通过转换使用公历表示的时刻来报告时间,就好像您处于美国东部时间时区一样。
- java 的 Date 正在报告时间,就好像它是儒略历一样,并且在 GMT 时区。
时区差异解释了为什么 java 脚本打印 19:00 而 java 打印 00:00,以及 1 个日期的差异。 12 月 29 日,当你在纽约 19:00 拍手时,恰好是伦敦 12 月 30 日午夜。剩下正好 48 小时(2 天)的差异是因为儒略历。
正确的方法,在java:
Instant i = Instant.ofEpochMilli(-62135769600000L);
System.out.println(i.atZone(ZoneOffset.UTC));
> 0000-12-30T00:00Z
今天普遍使用的日历系统称为公历。它是对之前使用的儒略历的修改,罗马时代使用的儒略历。
世界并没有在同一天从儒略转换到公历。事实上,俄罗斯很晚,直到 1918 年才开始转变:你在莫斯科买了一份报纸,上面写着 'January 31st, 1918'(但是俄语)。如果你然后跳上一匹马向西骑到布拉格或柏林或阿姆斯特丹,一整夜,然后问:嘿,今天是几号?他们会告诉你:今天是 2 月 13 日。
然后你第二天骑车回莫斯科,再买一份报纸。它显示为 'February 14th, 1918'。 2 月 1 日至 13 日发生了什么? 它们从未存在过。那是俄罗斯转变的时间。
小花絮:'october revolution',指的是沙皇被推翻的时间,发生在 11 月。发生这种情况时,俄罗斯还在 julian 上,是在 10 月。世界上其他使用罗马日历的国家都使用格里高利历,他们称其为十一月。
尽管这是一件愚蠢的事情,java.util.Date
会尝试推测您真正想要的东西并具有任意时间戳:当您创建早于此的 Date 对象时,它会以儒略历呈现时间。
这很愚蠢(世界不会一下子全部切换),所以 javascript 和 java.time
都不会这样做。
这解释了这 2 天。