【发布时间】:2011-01-25 01:51:04
【问题描述】:
我有一个代表 UTC 时间的 Date 对象。当我使用 getTime() 方法获取该对象的 long 值时,返回的值对应于我们的本地时间(美国中部)。获取与原始 UTC 时间相对应的值的正确方法是什么?
谢谢
【问题讨论】:
-
date.getTime() 始终只返回 UTC 时间。但 date.toString() 会将该日期转换为本地时区并显示。
我有一个代表 UTC 时间的 Date 对象。当我使用 getTime() 方法获取该对象的 long 值时,返回的值对应于我们的本地时间(美国中部)。获取与原始 UTC 时间相对应的值的正确方法是什么?
谢谢
【问题讨论】:
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);
【讨论】:
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 类。
InstantInstant 类表示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 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
从哪里获得 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。
【讨论】:
lastModified() 会是一样的吗?
Instant.ofEpochMilli( millisecondsSinceEpoch ) 代码。
java.util.Date 没有时区的概念。它只是保持相对于纪元的时间,即 1970 年 1 月 1 日 00:00:00 UTC。 Date 是一个模型,与视图分开。当您显示日期时,将应用时区的概念。 Date 的 toString() 在默认时区显示人类可读的日期。您可以使用 DateFormat 在不同的时区(例如 UTC)中显示日期,或者更改 JVM 的默认时区。
【讨论】:
java.util.Date 类现在是遗留的,被java.time.Instant 取代。两者都代表 UTC 时间线上的一个点,Instant 具有更精细的纳秒分辨率。
getTime() 返回“自 1970 年 1 月 1 日 00:00:00 GMT 以来的毫秒数”,仅此而已(显然,您必须正确创建它)。您可以根据需要对其进行格式化,例如GregorianCalendar(TimeZone) 构造函数。
【讨论】:
大多数 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 年使用它是一个糟糕的建议。旧的旧日期时间类很麻烦、令人困惑、设计不佳且存在缺陷。
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 中介绍的那样。