System.currentTimeMillis() 返回的是UTC时间吗?

116

我想获取当前的UTC时间,以毫秒为单位。我在谷歌上搜索并得到一些回答说System.currentTimeMillis()可以返回UTC时间,但实际上不是这样的。如果我执行以下操作:

long t1 = System.currentTimeMillis();
long t2 = new Date().getTime();
long t3 = Calendar.getInstance().getTimeInMillis();

所有三个时间几乎相同(由于调用而导致的毫秒级差异)。

t1 = 1372060916
t2 = 1372060917
t3 = 1372060918

这个时间不是UTC时间,而是我的时区时间。如何在安卓设备上获取当前的UTC时间?


5
返回自1970年1月1日00:00:00 UTC以来的当前系统时间(以毫秒为单位)。 - Blackbelt
2
http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/System.html#currentTimeMillis%28%29 - Marco Forberg
这是一个问题。它返回什么?UTC时间还是调整后的时区时间?如果它返回UTC时间,那么t1和t2、t3不应该与t2和t3相同,因为t3返回你的时区时间。 - g.revolution
3
long t3 = Calendar.getInstance(TimeZone.getTimeZone("UTC")).getTimeInMillis(); (翻译):获取当前UTC时间的毫秒数,存储在变量t3中。 - Blackbelt
3
上述链接提到:“请参阅Date类的描述,了解可能在“计算机时间”和协调世界时(UTC)之间出现的轻微差异的讨论。”在java.util.Date文档中,您可以找到以下内容:“尽管Date类旨在反映协调世界时(UTC),但根据Java虚拟机的主机环境,它可能无法完全反映。”因此,您的计算机返回非UTC时间是有可能的。 - Marco Forberg
5
“自1970年1月1日00:00:00 UTC起经过的毫秒数” - 如果要调整时区,您会如何期望?您的本地时区不会影响自那个纪元以来经过了多少毫秒。 - Jon Skeet
3个回答

161

你展示的这三行代码都会返回自 Unix 纪元以来经过的毫秒数,这是一个固定的时间点,不受本地时区的影响。

你说 "这个时间不是 UTC 时间" - 我认为你的诊断结果可能是错误的。我建议使用 epochconverter.com 进行验证。例如,在你的例子中:

1372060916 = Mon, 24 Jun 2013 08:01:56 GMT

我们不知道您生成该值的时间,但是除非它实际上是在UTC时间8:01am,否则这是您系统时钟的问题。

System.currentTimeMillisDate中的值本身不受时区影响。然而,您应该知道Date.toString()使用本地时区,这会误导很多开发人员认为Date与时区本质上是相关联的 - 实际上并不是,它只是一个瞬间,在没有关联时区或甚至日历系统的情况下。


6
基本上,也就是说,如果在不同的时区内从内部调用此函数的时间相同,无论主机的时钟如何,该函数将返回相同的值,对吗? - Phillip
30
这让我希望全世界能采用一个统一的时区。当大亮光出现在天空中时,时钟显示00:00或08:00又有什么关系呢?这个历史遗留问题会浪费许多本可以用来工作的时间,真是让人气愤。 - corsiKa
关于这一点,请注意底层调用操作系统时钟函数存在几毫秒的记录“漂移”。如果意图获取高度精确的操作持续时间(计算任务开始和结束的时间,差值即为经过的时间),Java具有“高性能计时器”。请参见:https://docs.oracle.com/javase/7/docs/api/java/lang/System.html#nanoTime()。 - Darrell Teague
@JonSkeet 如果toString()内部使用时区,那么我如何在没有时区的情况下构建字符串。实际上,我正在REST服务器中生成文件,其文件名恰好为午夜时间值,例如“1551139200.json”(2019年2月26日上午12:00:00),并且需要在设备的System.currentTimeMillis()返回确切时间后从Android应用程序中访问它。 - kiranking
@kiranking:使用Date.getTime()来查找自Unix纪元以来的毫秒数,除以1000(因为该文件名是自Unix纪元以来的秒数),然后将该整数格式化为字符串。 - Jon Skeet
显示剩余6条评论

2
我可以确认,考虑到时代因素而非“Date.toString()”或任何类似的方法,所有三个调用都可能依赖于本地时间。我曾经看到它们在运行Android 2.3的特定设备上依赖于本地时间。我没有在其他设备和Android版本上进行过测试。在这种情况下,本地时间是手动设置的。
获取独立的UTC时间的唯一可靠方法是使用“GPS_PROVIDER”请求位置更新。从“NETWORK_PROVIDER”检索到的位置的“getTime()”值也取决于本地时间。另一个选项是ping一个返回UTC时间戳的服务器,例如。
所以,我所做的是:
public static String getUTCstring(Location location) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
    String date = sdf.format(new Date(location.getTime()));
    // Append the string "UTC" to the date
    if(!date.contains("UTC")) {
        date += " UTC";
    }
    return date;
}

3
System.currentTimeMillis() 返回的是基于协调世界时(UTC)的值。至于操作系统时钟的“精度”或准确性,虽然会影响结果,但与系统或Java环境的时区值没有任何关系。 - Darrell Teague
@DarrellTeague 我坚持认为,在某些华为设备上,我看到了不同的UTC时间值。所以,它并不总是返回正确的UTC时间(抛开精度差异)。 - jlhonora
OP的问题是关于Java类时区使用的。这不涉及硬件或返回时间值的准确性。简单地说,JVM从(抽象的)操作“系统时钟”获取时间(在功能上因操作系统而异)。另请参见:http://www.drdobbs.com/embedded-systems/measuring-execution-time-and-real-time-p/193502123和操作系统上的“C”实现https://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_17.html。 - Darrell Teague

0
只回答标题问题,“System.currentTimeMillis()返回的是UTC时间吗?”...
是的。Java API文档实际上说它是UTC时间:
currentTimeMillis
...
Returns: the difference, measured in milliseconds, between the current time and
midnight, January 1, 1970 UTC.
                          ^^^

虽然我有一些疑问,这可能是为什么这个问题没有被直接回答的原因。

currentTimeMillis()的值是从系统板上由电池供电的硬件时钟派生出来的。实际值可以设置为任何值,但唯一真正明智的做法是将其设置为相对于UTC的EPOCH,以便设备不受特定时区的限制(设备经常在不同时区之间旅行和传输数据)。

然而,硬件时钟可以被更改,在过去,将其设置为本地时间并不罕见。我相信今天人们仍然使用本地时间有其原因。

如果你恰好使用Linux,你可以检查一下你的机器的硬件时钟是使用本地时间还是UTC:

# timedatectl
               Local time: Sat 2023-06-17 11:34:51 EDT
           Universal time: Sat 2023-06-17 15:34:51 UTC
                 RTC time: Sat 2023-06-17 15:34:51
                Time zone: America/New_York (EDT, -0400)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no
                           ^^

我不知道是否存在这样的情况,即如果硬件时钟设置为本地时区,currentTimeMillis()会返回基于本地时间的值。我的感觉是操作系统会对这些事情进行抽象处理,Java只是向操作系统询问。因此,如果System.currentTimeMillis()没有返回UTC值,那是因为操作系统配置不正确。
所以在大多数情况下,是的,System.currentTimeMillis()应该在各个时区返回相同的值(除了常规的漂移、闰秒等)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接