为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

白衣染霜花 2023-05-24 15:58:17
我有 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 回答

?
慕标琳琳

TA贡献1830条经验 获得超9个赞

保留时间与保留时刻

我会一一解释中心线。

    Calendar calendar = Calendar.getInstance();

这将创建一个Calendar与 JVM 默认时区相同的时区。不像DateaCalendar 一个时区。

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

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

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

    Date d2 = Date.from(instant);

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

在您的问题中可能已经理解了,但是对于阅读的任何人,我想直接声明:Date并且Calendar设计不佳且早已过时。您不应使用它们,除非需要与您现在无法更改或不想升级的遗留 API 进行交互。对于所有其他用途,请坚持使用现代 Java 日期和时间 API java.time。


查看完整回答
反对 回复 2023-05-24
?
繁花不似锦

TA贡献1851条经验 获得超4个赞

博士

  • 正如其他人所说,ajava.util.Date代表 UTC 中的一个时刻。它的toString方法是通过在生成格式不正确的字符串时动态应用 JVM 当前的默认时区来欺骗您。从不使用此类的众多原因之一。

  • 不要浪费你的时间去理解那些可怕的类DateCalendar。它们现在是legacy,要避免。

  • 仅对所有日期时间处理使用java.time类。

细节

您将糟糕的遗留日期时间类 ( DateCalendar) 与其现代替代品 ( InstantZonedDateTime) 混合在一起。不要混合这些。随着JSR 310的采用,遗留类完全被java.time类取代。

无需使用DateCalendar再次使用。不要浪费时间去理解它们。它们被替换是有原因的——实际上有很多原因。动用您的智慧和时间来完成更有成效的工作。

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

该类java.util.Date被替换为Instant.

java.util.Date d = Date.from( instant ) ;     // From  modern to legacy.
Instant instant = d.toInstant() ;             // From legacy to modern.

该类Calendar,或者更确切地说是其常用的子类GregorianCalendar,被替换为ZonedDateTime。假设你的Calendar对象真的是一个GregorianCalendar底层,你可以投射,然后转换。

Calendar c = GregorianCalendar.from( zonedDateTime ) ;                        // From  modern to legacy.
ZonedDateTime zonedDateTime = ( (GregorianCalendar) c ).toZonedDateTime() ;   // From legacy to modern.

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

//img2.sycdn.imooc.com/646dc3c80001d73106530375.jpg

查看完整回答
反对 回复 2023-05-24
  • 2 回答
  • 0 关注
  • 112 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信