为什么Date对象不能在JVM的时区中表示日期?

时间:2019-08-08 15:05:36

标签: java time timezone

我有UTC日期,我需要创建与UTC值完全相同的Date对象(旧有原因)。

我设法做到了:

String date = "2012-05-05 12:13:14";
TemporalAccessor formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
        .withZone(ZoneId.of("UTC"))
        .parse(date);
Instant instant = Instant.from(
        formatter
); //
ZonedDateTime zdf = ZonedDateTime.ofInstant(instant,ZoneId.of("UTC"));
Calendar calendar = Calendar.getInstance();
calendar.set(zdf.getYear(),zdf.getMonthValue(),zdf.getDayOfMonth(),zdf.getHour(),zdf.getMinute(),zdf.getSecond());
Date dt = calendar.getTime();

Date d2 = Date.from(instant);

但是,什么困扰着我-

当我创建日期对象时,它应该在JVM的默认时区中显示日期。但是这里dt与我输入的UTC日期具有完全相同的值,但是dt2具有默认时区中表示的相同日期,为什么会发生这种情况?为什么一个不转换而另一个不转换?

感谢您的解释!

2 个答案:

答案 0 :(得分:1)

保留一天中的小时与保留时刻

我将一一解释中心线。

    Calendar calendar = Calendar.getInstance();

这将创建一个Calendar,其时区与JVM的默认时区相同。与Date不同,Calendar有一个时区。

    calendar.set(zdf.getYear(),zdf.getMonthValue(),zdf.getDayOfMonth(),
            zdf.getHour(),zdf.getMinute(),zdf.getSecond());

这会将您的Calendar设置为与ZonedDateTime相同的挂钟时间,即12:13:14。由于ZonedDateTimeCalendar具有不同的时区(分别为UTC和您的本地时区),因此会产生不同的时刻。

@VGR也正确:ZonedDateTIme的日期为5月(第5个月),但您将Calendar的月份设置为6月,因为Calendar的月份令人困惑,0-从1月的0到12月的11。

    Date d2 = Date.from(instant);

这是从InstantDate的正确转换,并为您提供与Instant相同的时间点和相同的时刻。因此,不是Calendardt相同的时刻。

您的问题中可能已经理解了这一点,但是对于那些一直阅读的人,我想直接声明:DateCalendar的设计很差,已经过时了。除非有必要与无法更改或不想立即升级的旧版API交互时,否则不要使用它们。对于其他所有用途,请遵循现代的Java日期和时间API java.time。

链接

答案 1 :(得分:1)

tl; dr

  • 正如其他人所说,java.util.Date代表UTC的时刻。它的toString方法在生成格式不正确的字符串时动态地应用JVM的当前默认时区,从而为您带来好处。 很多原因之一是从不使用此类。
  • 不要浪费时间尝试理解可怕的类DateCalendar。现在应避免使用它们legacy
  • 所有java.time classes仅使用date-time handling

详细信息

Answer by Ole V.V.是正确的,应该接受。我会加一些想法。

您正在将可怕的旧式日期时间类(DateCalendar)与它们的现代替代品(InstantZonedDateTime)混合在一起。 请勿混用。通过使用JSR 310 java.time 类完全取代了旧类。

无需再使用DateCalendar不要浪费时间尝试理解它们。替换它们是有原因的-实际上有很多原因。用你的大脑和时间进行更有成效的工作。

如果必须使用旧类与尚未更新为 java.time 的旧代码进行互操作,请通过调用新的to… / {{1}来回转换}转换方法已添加到旧类中。使用 java.time 类执行业务逻辑,数据交换和数据存储。

from…类被java.util.Date替换。

Instant

java.util.Date d = Date.from( instant ) ; // From modern to legacy. Instant instant = d.toInstant() ; // From legacy to modern. 类或其更常用的子类GregorianCalendarCalendar取代。假设您的ZonedDateTime对象实际上是下面的Calendar,则可以进行投射然后进行转换。

GregorianCalendar

这是一张将旧类映射到现代类的图表。

Table of date-time types in Java (both legacy & modern) and in standard SQL.