在Java中获取UTC时间戳的方法是使用以下代码:
Instant.now() //捕获当前时刻的UTC
。但这种说法以及此线程中的大多数回答都是误导性的。 Instant代表时间上的一个瞬间,它是“太阳耀斑”的时间,绝对不能代表任何人类大脑发明的东西,而UTC是一个时区,是人类的发明。宇宙、太阳、天文学——它们不知道UTC是什么,也不关心——这就是Instant的全部内容。瞬间缺乏诸如“小时”、“天数”或“时区”等人类概念。询问瞬间发生的日期毫无意义。它无法告诉你;发生了某些事件:如果我问19世纪的俄罗斯人那是哪一天,他们可能会给出完全不同的答案,而如果我问住在离这里仅有100英里的地方的人,答案也会不同。Instant不知道要应用哪种本地化,因此不允许您向其提出这个问题——这是一件好事,对象不应该暴露任何答案都是胡言乱语或至少需要了解各种令人惊讶的警告的方法。如果你告诉我“...在UTC”,你肯定可以精确地告诉我是哪个月、哪一天等。Instant不会做到这一点,这就是为什么说
java.time.Instant
代表UTC时间的瞬间是误导性的原因。它不是这样。它表示一个时间点(不属于任何特定时区)。当你想要将时间感知(年、日、月、小时、分钟、毫秒和时区)与更或多或少绝对的时间概念混合在一起时,正确的答案是
java.time.ZonedDateTime
。请注意,使用不基于
java.time.*
的任何时间表示都是有缺陷的,因为在大多数编程语言中,时间比大多数库所能表示的还要复杂。实际上,
java.time
是第四次尝试编写时间库的产物,这应该足以说明它很难弄对。
ZonedDateTime zdt = ZonedDateTime.now(ZoneOffset.UTC)
< p >
那就是你想要的——这不仅是实现细节上你想要的,而且它恰好描述了你
的意思:目前,在UTC时区存储在一个语义上不仅存储正确时间,而且还紧密纠缠于其身份的对象中,该对象特定地位于UTC并且不会被重新解释,移动到本地区域或进行任何其他类似的把戏——至少在你明确要求它这样做之前不会这样。
< blockquote >
Date currentUtcTime = Date.from(Instant.now());
请注意,Date是旧的API,因此必然存在问题。 在这种情况下,Date是撒谎的骗子-它不代表日期,而代表瞬间; 它的命名不好。 (第二个API是日历,也是有问题的。例如,那也是撒谎的骗子:它根本不代表日历。它代表一些奇怪的带时区的日期时间和瞬间的混合物,并且由于后果不适合表示任何一个)。每次使用Date API都会出现奇怪的情况,而像“我只想要某个特定时刻在UTC中的时间概念”这样简单的事情在这些API中是不可能的。您现在依赖于所有各种库链上传下传递的几乎未定义的行为-实际上,您被困在祈祷它们做正确事情或深入研究来让这些库做你想要的事情。
TL; DR:使用 java.time
。
*)请注意,ZonedDateTime不是绝对的。例如,如果您有以欧洲/阿姆斯特丹为例的时间 2023年1月20日早上8点
,以 ZonedDateTime
对象的形式,则现在和那个时刻之间将过去的秒数似乎没有变化并且不会更改,例如阿姆斯特丹进行夏令时调整。但是,如果荷兰政府命令从此不再移动时钟,并永远停留在夏令时(这很可能 - 欧盟指令已经到位,现在只是时间问题),则在榔头落地的那一刻,您的约会将准确地提前或拖后1小时。
希望这能提供关键的见解:表示事件的瞬间(因此我喜欢称其为“太阳耀斑时间”,尽可能地将其与人类时间概念分离),甚至不理解此类决定对事物产生影响的概念。另一方面,ZonedDateTime则固有地被绑定在其中-因此是 Zone
中的 ZonedDateTime
。
如果您想存储理发预约并使用 Instant
来执行此操作,则很快就会迟到或提前一小时。
System.out.println(Instant.now().toString())
时会发生什么? - EugeneMST
是GMT-7
(UTC-7
),而不是GMT-6
。 - Turing85System.out.println(Instant.now().atOffset(ZoneOffset.UTC))
。 - EugeneSystem.out.println(Instant.now().atZone(ZoneId.of("UTC")));
- matt