猿问

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

我有 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在我的默认时区中表示的日期相同,为什么会这样?为什么一个没有皈依而另一个被皈依了?


感谢您的解释!


白衣染霜花
浏览 113回答 2
2回答

慕标琳琳

保留时间与保留时刻我会一一解释中心线。    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。

繁花不似锦

博士正如其他人所说,ajava.util.Date代表 UTC 中的一个时刻。它的toString方法是通过在生成格式不正确的字符串时动态应用 JVM 当前的默认时区来欺骗您。从不使用此类的众多原因之一。不要浪费你的时间去理解那些可怕的类Date& Calendar。它们现在是legacy,要避免。仅对所有日期时间处理使用java.time类。细节您将糟糕的遗留日期时间类 ( Date, Calendar) 与其现代替代品 ( Instant, ZonedDateTime) 混合在一起。不要混合这些。随着JSR 310的采用,遗留类完全被java.time类取代。无需使用Date或Calendar再次使用。不要浪费时间去理解它们。它们被替换是有原因的——实际上有很多原因。动用您的智慧和时间来完成更有成效的工作。如果您必须使用遗留类与尚未更新到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.这是一张将遗留类映射到现代类的图表。
随时随地看视频慕课网APP

相关分类

Java
我要回答