【问题标题】:How to make date.getTime() returns UTC time?如何使 date.getTime() 返回 UTC 时间?
【发布时间】:2011-01-25 01:51:04
【问题描述】:

我有一个代表 UTC 时间的 Date 对象。当我使用 getTime() 方法获取该对象的 long 值时,返回的值对应于我们的本地时间(美国中部)。获取与原始 UTC 时间相对应的值的正确方法是什么?

谢谢

【问题讨论】:

  • date.getTime() 始终只返回 UTC 时间。但 date.toString() 会将该日期转换为本地时区并显示。

标签: java date utc


【解决方案1】:

DateFormat 类有a method for setting your preferred time zone,还有一个时区类有a setting for UTC time

例如,

SimpleDateFormat sdf = new SimpleDateFormat();
sdf.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
Date yourUtcDate = sdf.parse(yourOriginalDate);

【讨论】:

  • 仅供参考,这里显示的麻烦的旧日期时间类现在是遗留的。被 java.time 类取代。
【解决方案2】:

tl;博士

Instant.now()

……和……

Instant.ofEpochMilli( n ) 

……和……

instant.toEpochMilli()

Date 始终采用 UTC

当我使用 getTime() 方法获取该对象的 long 值时,返回的值对应于我们的本地时间(美国中部)。

不,Date::getTime() 返回的值始终对应于UTC(在此上下文中与 GMT 几乎相同)。引用类文档:

返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。

所以你的问题是荒谬的,因为 Date 已经在 UTC 中。无需“取回原始UTC时间对应的值”,

您可能会将getTime 的行为与toString 方法的行为混淆。 toString 方法在生成字符串的过程中应用当前的默认时区令人讨厌且令人困惑。因此,字符串输出出现时区,而实际上没有时区要设置或从Date 本身获取。 (实际上Date 深处有一个区域,但这与这里的讨论无关。这个类是一团混乱!)

java.time

执行此操作的现代方法是使用 java.time 类。

Instant

Instant 类表示UTC 时间线上的时刻,分辨率为nanoseconds(最多九 (9) 位小数)。

获取当前时刻。

Instant instant = Instant.now();

您可以通过调用添加到旧日期时间类的新转换方法之一,将Date 转换为现代替换。只需拨打toInstant,很简单。

Instant instant = myJavaUtilDate.toInstant();  

我完全不建议使用从纪元开始计数的数字作为跟踪时间的方式。改用 java.time 对象。在 Java 之外时,使用ISO 8601 格式序列化为文本。

但如果必须,您可以提取自 1970-01-01T00:00:00Z 纪元以来的毫秒数。请注意,这可能涉及数据丢失! Instant 具有更精细的纳秒分辨率。所以到毫秒可能会减少几分之一秒。

long millisecondsSinceEpoch = instant.toEpochMilli();  // Caution: Possible data-loss in going from nanoseconds to milliseconds.

换个方向,从计数到Instant

Instant instant = Instant.ofEpochMilli( millisecondsSinceEpoch ) ;

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

  • 所以如果我在巴黎和马尼拉同时“时间”创建一个文件,他们的lastModified() 会是一样的吗?
  • @Matthieu 是的,一个在巴黎的人和一个在马尼拉的人同时在同一时刻创建一个文件夹,同时通过电话互相交谈,他们看到的都是相同的@ 987654381@ 此命令返回的数字(假设他们的计算机时钟设置准确,并且假设每个动作都完美同步)。该命令记录为返回自 1970 UTC 的第一时刻的纪元参考日期以来的毫秒计数,与 java.time 相同的纪元。使用上面这个答案中看到的Instant.ofEpochMilli( millisecondsSinceEpoch ) 代码。
【解决方案3】:

java.util.Date 没有时区的概念。它只是保持相对于纪元的时间,即 1970 年 1 月 1 日 00:00:00 UTC。 Date 是一个模型,与视图分开。当您显示日期时,将应用时区的概念。 Date 的 toString() 在默认时区显示人类可读的日期。您可以使用 DateFormat 在不同的时区(例如 UTC)中显示日期,或者更改 JVM 的默认时区。

【讨论】:

  • 更新:麻烦的java.util.Date 类现在是遗留的,被java.time.Instant 取代。两者都代表 UTC 时间线上的一个点,Instant 具有更精细的纳秒分辨率。
【解决方案4】:

getTime() 返回“自 1970 年 1 月 1 日 00:00:00 GMT 以来的毫秒数”,仅此而已(显然,您必须正确创建它)。您可以根据需要对其进行格式化,例如GregorianCalendar(TimeZone) 构造函数。

【讨论】:

    【解决方案5】:

    大多数 Date 类函数已被弃用,因为它们现在已转移到 Calendar 类中。

    这是从日历获取 UTC 时间的代码。

    Date date = new Date(timeStamp);
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
    calendar.setTime(date);
    

    这是获取年、月等的示例代码。

    System.out.println(calendar.get(Calendar.YEAR));
    System.out.println(calendar.get(Calendar.MONTH));
    

    日历还支持许多其他有用的信息,例如 TIME、DAY_OF_MONTH 等。documentation 列出了所有这些信息 请注意,月份是从 0 开始的。一月是第 0 个月。

    【讨论】:

    • 实际上,Calendar 类本身已经存在多年,被 JSR 310 中定义的 java.time 类所取代。建议在 2018 年使用它是一个糟糕的建议。旧的旧日期时间类很麻烦、令人困惑、设计不佳且存在缺陷。
    【解决方案6】:
        LocalDateTime now = LocalDateTime.now(Clock.systemUTC());
        Instant instant = now.atZone(ZoneId.systemDefault()).toInstant();
        Date formattedDate = Date.from(instant);
    
        return formattedDate;
    

    【讨论】:

    • ???为什么不只是 Instant.now() 并完成它?正如我在my year-old Answer 中介绍的那样。
    • 这个答案是错误的。该代码正在执行时区转换,这会导致(在大多数时区中)结果不正确。
    猜你喜欢
    • 2014-02-16
    • 2013-06-20
    • 2018-08-08
    • 1970-01-01
    • 2014-09-09
    • 1970-01-01
    • 2015-06-10
    • 2011-10-27
    • 1970-01-01
    相关资源
    最近更新 更多