old Stack Overflow posting建议在Java中获取UTC时间戳的方法如下:
Instant.now() // Capture the current moment in UTC.
不幸的是,这对我不起作用。我有一个非常简单的程序(复制如下),它演示了不同的行为。
Windows系统:时间是本地时间,并标有GMT的偏移量
Linux平台:该时间也是本地时间,并且已正确标记为本地时区
**问题:**如何在Java程序中显示UTC时间戳?
我的示例源代码如下:
import java.time.Instant;
import java.util.Date;
public class UTCTimeDisplayer {
public static void main(String[] args) {
System.out.println(System.getProperty("os.name"));
Date currentUtcTime = Date.from(Instant.now());
System.out.println("Current UTC time is " + currentUtcTime);
}
}
Windows输出:
C:\tmp>java UTCTimeDisplayer
Windows 10
Current UTC time is Fri Jan 22 14:28:59 GMT-06:00 2021
Linux输出:
/tmp> java UTCTimeDisplayer
Linux
Current UTC time is Fri Jan 22 14:31:10 MST 2021
7条答案
按热度按时间kxkpmulp1#
密码:
您将可怕的遗留类与它们的替代品(现代的 java.time 类)混合在一起。
别说了
千万不要用
Date
,当然也不需要和java.time.Instant
混用。要解释您的特定示例,请理解
Date
类的许多糟糕设计选择中的一个反功能是**Date#toString
方法在生成文本时隐式应用JVM的当前默认时区**。您在两个不同的JVM上运行代码,这两个JVM具有不同的当前默认时区,因此得到不同的输出。
Sun、Oracle和JCP放弃了遗留的日期-时间类,我们也应该放弃。我建议你不要花时间去理解
Date
、Calendar
、SimpleDateFormat
等。你问:
问:如何在Java程序中显示UTC时间戳?
看这个code run live at IdeOne.com。
2021-01-22T21:50:18.887335Z
你说:
在Windows上:...
在Linux上:...
您将在Windows、Linux、BSD、macOS、iOS、Android、AIX等平台上从
Instant.now().toString()
获得相同的一致结果。下面是我制作的一个表,用于指导您从遗留类进行转换。
mnemlml82#
java.util.Date
对象不是像modern date-time types那样的真实的日期-时间对象;而是表示自称为“历元”的标准基准时间(即January 1, 1970, 00:00:00 GMT
)起的毫秒数(或UTC)。当您打印java.util.Date
的对象时,其toString
方法将返回JVM时区中的日期-时间,根据此毫秒值计算。如果您需要打印不同时区中的日期-时间,你需要将时区设置为SimpleDateFormat
并从中获取格式化的字符串。我建议你简单地使用
Instant.now()
,你可以转换成其他 java.time 类型。java.util
的日期时间API和格式接口SimpleDateFormat
已经过时且容易出错,建议彻底停用,改用modern date-time API。但是,如果您仍然想使用
java.util.Date
,请使用上面提到的SimpleDateFormat
。Demo:
输出:
67up9zun3#
建议在Java中获取UTC时间戳的方法如下:
Instant.now() // Capture the current moment in UTC.
这一点,以及这个帖子中的大多数答案,都是误导。
Instant代表时间上的瞬间。它是“solarflares”时间:绝对没有一点是人类大脑发明的,UTC是一个时区:人类的发明。宇宙、太阳、天文学--他们不知道UTC是什么,也不在乎--这就是Instant的意义所在。Instant没有诸如“小时”、“天”或“时区”之类的人类概念。问Instant发生在哪一天是没有意义的。它不能告诉你;发生了一些事件:如果我问一个19世纪的俄罗斯人这是什么时候发生的,他们可能会给予一个完全不同的答案。如果我问一个住在西边100英里的人,例如。Instant不知道该应用哪个本地化,因此不让你问这个问题--这是一件好事。对象不应该公开那些它给出的答案要么是官样文章,要么至少需要知道各种令人惊讶的警告的方法。
重要的是,如果你告诉我“...在UTC中”,你肯定能准确地说出哪个月,哪一天等等。而Instant不能做到这一点,这就是为什么说
java.time.Instant
代表UTC中的某个时刻是误导性的。它不是。它代表的是时间中的某个时刻(不是在任何特定的时区)。是的,在内部,Instant就像Date一样,只是
System.currentTimeMillis()
返回的一个简单 Package :“米利斯since epoch”,但要理解它的关键是,'UTC'不是它的一部分 * 意思 *,因此,当您将Instant示例提供给其他方法(例如System.out.println,通过JDBC提供给数据库等)时,该方法绝对没有义务假设UTC在语义上相关。当你想把人类对时间的观念(年、日、月、小时、分钟、毫秒,还有时区),如果有绝对时间的概念,正确答案是
java.time.ZonedDateTime
。请注意,任何不基于java.time.*
的时间表示都是不完整的,就像在大多数编程语言中一样-事实证明时间比大多数用库来表示它所实现的要复杂得多。java.time
实际上是第四次尝试编写时间库的事实应该充分表明它“It’很难把它做对。Date currentUtcTime = Date.from(Instant.now());
注意,Date是旧的API,因此必然会被破坏。在这种情况下,Date是一个说谎的骗子--它不代表日期,它代表一个瞬间;它的命名很糟糕。(第二个API是Calendar,也是坏的。例如,那也是一个说谎的骗子谁说谎:它并不代表任何日历。它代表了分区日期时间和瞬间的一些奇怪的融合,并且适合于代表两者)。任何时候你去Date API都会发生奇怪的事情,就像“我只是想要时间的概念,在某个特定的时刻,”这样简单的事情。你现在依赖于链上和链下所有各种库的几乎没有定义的行为-你实际上被困在祈祷它们做正确的事情,或者深入研究异国情调的设置,试图哄骗这些库做你想做的事情。
TL;DR:使用
java.time
。January 20th, 2023, 8 in the morning, at Europe/Amsterdam
,以ZonedDateTime
对象的形式,那么从现在到那一刻之间将经过的秒数肯定看起来不会改变,并且当例如阿姆斯特丹因夏令时而经历小时变化时也不会改变。然而,如果荷兰政府颁布法令,从此荷兰将不再移动时钟,并将永远停留在夏令时(这是可能-欧盟指令已经到位,现在只是时间问题),那么在木槌落地的那一刻,你的预约时间正好错开一个小时希望这能提供关键的差异洞察力:Instant表示事件(因此我喜欢称之为“solarflares time”,以便尽可能地将其与人类的计时概念区分开来),甚至不理解这种决定对事物产生影响的概念。另一方面,ZonedDateTime本质上与之绑定在一起-因此
ZonedDateTime
中的Zone
。如果你想存储理发预约,并使用
Instant
来做,你会迟到或早到一个小时。eoigrqb64#
一个
Instant
对象和一个Date
对象本身只包含一个时间点,但没有时区信息。此外,Date
类的toString()
方法隐式地选择了系统环境提供的时区,这不是你想要的。因此,您需要显式选择时区(在您的情况下为UTC)。例如:
这将(独立于操作系统)打印
其中尾部
Z
表示零时区偏移(即UTC)。x6yk4ghg5#
一个简单可行的方法!
我的要求是以毫秒为单位的日期时间
2021-11-25 19:55:00.743
ep6jt1vc6#
Instant.now()本质上是从纪元开始的一段时间,(UTC时间为1970年1月1日午夜),但您使用的是Date来表示该时刻。Date是以毫秒精度反映该时刻,但如https://docs.oracle.com/javase/8/docs/api/java/util/Date.html文档中所述,应使用Calendar来表示日期,因为Date的呈现取决于主机。本质上Date Package 了即时,但根据其他因素显示。
现在,如果你想输出instant,最简单的方法是使用OffsetDateTime,这样你就可以选择在你想要的时区(在你的例子中是UTC)中显示instant。使用
OffsetDateTime.now()
或OffsetDateTime.ofInstant()
,但是如果你在应用程序逻辑中使用instant,那么就坚持使用Instant。wtzytmuj7#
有时候你的程序必须使用较旧的Java版本,所以这里有一个1.5的例子:
请注意,前三行不必在每次调用时重复,但请记住
SimpleDateFormat
不是线程安全的。(简单的解决方案:为每个线程创建一个。)示例用法(它表明设置
TZ
不会影响UTC时间戳):