java 获取UTC时间戳

yqkkidmi  于 2023-04-10  发布在  Java
关注(0)|答案(7)|浏览(178)

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
kxkpmulp

kxkpmulp1#

密码:

Date.from(Instant.now())

您将可怕的遗留类与它们的替代品(现代的 java.time 类)混合在一起。
别说了
千万不要用Date,当然也不需要和java.time.Instant混用。
要解释您的特定示例,请理解Date类的许多糟糕设计选择中的一个反功能是**Date#toString方法在生成文本时隐式应用JVM的当前默认时区**。
您在两个不同的JVM上运行代码,这两个JVM具有不同的当前默认时区,因此得到不同的输出。
Sun、Oracle和JCP放弃了遗留的日期-时间类,我们也应该放弃。我建议你不要花时间去理解DateCalendarSimpleDateFormat等。
你问:
问:如何在Java程序中显示UTC时间戳?

Instant.now().toString()

看这个code run live at IdeOne.com
2021-01-22T21:50:18.887335Z
你说:
在Windows上:...
在Linux上:...
您将在Windows、Linux、BSD、macOS、iOS、Android、AIX等平台上从Instant.now().toString()获得相同的一致结果。
下面是我制作的一个表,用于指导您从遗留类进行转换。

mnemlml8

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:

import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) {
        Date currentUtcTime = Date.from(Instant.now());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
        sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
        System.out.println("Current UTC time is " + sdf.format(currentUtcTime));
    }
}

输出:

Current UTC time is 2021-01-22 21:53:07 UTC
67up9zun

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’很难把它做对。

ZonedDateTime zdt = ZonedDateTime.now(ZoneOffset.UTC);
  • 这就是你想要的-这不仅仅是你想要的实现细节,而是准确描述你的意思的代码:现在,在UTC时区,存储在一个对象中,该对象在语义上不仅存储正确的时间,而且还存储,并紧密地纠缠于其身份,即它是专门在UTC中的,并且不被重新解释,移动到本地区域,或任何其他类似的诡计-至少,除非你明确要求它这样做。

Date currentUtcTime = Date.from(Instant.now());
注意,Date是旧的API,因此必然会被破坏。在这种情况下,Date是一个说谎的骗子--它不代表日期,它代表一个瞬间;它的命名很糟糕。(第二个API是Calendar,也是坏的。例如,那也是一个说谎的骗子谁说谎:它并不代表任何日历。它代表了分区日期时间和瞬间的一些奇怪的融合,并且适合于代表两者)。任何时候你去Date API都会发生奇怪的事情,就像“我只是想要时间的概念,在某个特定的时刻,”这样简单的事情。你现在依赖于链上和链下所有各种库的几乎没有定义的行为-你实际上被困在祈祷它们做正确的事情,或者深入研究异国情调的设置,试图哄骗这些库做你想做的事情。
TL;DR:使用java.time

  • )请注意,ZonedDateTime不是绝对的。例如,如果您有时间January 20th, 2023, 8 in the morning, at Europe/Amsterdam,以ZonedDateTime对象的形式,那么从现在到那一刻之间将经过的秒数肯定看起来不会改变,并且当例如阿姆斯特丹因夏令时而经历小时变化时也不会改变。然而,如果荷兰政府颁布法令,从此荷兰将不再移动时钟,并将永远停留在夏令时(这是可能-欧盟指令已经到位,现在只是时间问题),那么在木槌落地的那一刻,你的预约时间正好错开一个小时

希望这能提供关键的差异洞察力:Instant表示事件(因此我喜欢称之为“solarflares time”,以便尽可能地将其与人类的计时概念区分开来),甚至不理解这种决定对事物产生影响的概念。另一方面,ZonedDateTime本质上与之绑定在一起-因此ZonedDateTime中的Zone
如果你想存储理发预约,并使用Instant来做,你会迟到或早到一个小时。

eoigrqb6

eoigrqb64#

一个Instant对象和一个Date对象本身只包含一个时间点,但没有时区信息。此外,Date类的toString()方法隐式地选择了系统环境提供的时区,这不是你想要的。
因此,您需要显式选择时区(在您的情况下为UTC)。例如:

Instant instant = Instant.now();
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.UTC);
System.out.println("Current UTC time is " + offsetDateTime);

这将(独立于操作系统)打印

Current UTC time is 2021-01-22T22:37:21.950354100Z

其中尾部Z表示零时区偏移(即UTC)。

x6yk4ghg

x6yk4ghg5#

一个简单可行的方法!
我的要求是以毫秒为单位的日期时间
2021-11-25 19:55:00.743

private String getUTCTimestamp() {
        ZonedDateTime utc = ZonedDateTime.now(ZoneOffset.UTC);
        return utc.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"));
    }
ep6jt1vc

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。

wtzytmuj

wtzytmuj7#

有时候你的程序必须使用较旧的Java版本,所以这里有一个1.5的例子:

java.text.SimpleDateFormat tfGMT = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    java.util.Calendar cUTC = java.util.Calendar.getInstance (java.util.TimeZone.getTimeZone ("GMT+0"));
    tfGMT.setCalendar (cUTC);
    java.util.Date d= new java.util.Date ();
    String s= tfGMT.format (d);
    System.out.printf ("now=%s [unix ts=%d.%03d]\n", s, d.getTime()/1000, d.getTime()%1000);

请注意,前三行不必在每次调用时重复,但请记住SimpleDateFormat不是线程安全的。(简单的解决方案:为每个线程创建一个。)
示例用法(它表明设置TZ不会影响UTC时间戳):

$ TZ=GMT+3 java5 now_utc; TZ=GMT-3 java5 now_utc
now=2021-01-24 12:56:14 [unix ts=1611492974.264]
now=2021-01-24 12:56:14 [unix ts=1611492974.726]

相关问题