汇总Java日期时出现意外结果

时间:2018-06-19 12:25:52

标签: java datetime

使用它们的方法java.util.Date.getTime()对java Date对象求和时,得到了意外的结果。

这是示例代码:

System.out.println(d1.toString()); 
System.out.println(d2.toString());
System.out.println(new Date(d1.getTime() + d2.getTime()));

以下是输出:

Mon Mar 20 00:00:00 CET 2017
Thu Jan 01 10:44:00 CET 1970
Mon Mar 20 09:44:00 CET 2017

我希望在 2017年3月20日星期一10:44:00 ,而不是 2017年3月20日星期一9:44:00 CET

我想念什么?

谢谢。

3 个答案:

答案 0 :(得分:5)

让我们忽略以下事实:对日期进行汇总完全是胡说八道(日期是时间轴上的一个点-根本没有为日期定义加法-您可以向日期添加持续时间或将两个持续时间加起来,但是永远不会有两个约会)。

问题在于您的日期位于中欧时区(CET),所以您要提前一小时。

d1.getTime()返回自1970年1月1日GMT以来的毫秒数。,因此,如果您为此时间(1970年1月1日)创建一个新的Date对象,时区(我猜想是CET),由于时区偏移,getTime()将返回-3600000。

附加信息

如果您确实想为某个时间点添加持续时间,请考虑使用新的Java Time API。它有几种类型,分别代表日期,时间,日期+时间和持续时间。例如:

LocalDateTime now = LocalDateTime.now();
Duration fiveDays = Duration.ofDays(5);
Period oneYearTwoMonthsThreeDays = Period.of(1, 2, 3);

System.out.println(now);
System.out.println(now.plus(fiveDays));
System.out.println(now.plus(oneYearTwoMonthsThreeDays));

答案 1 :(得分:2)

据我了解,您的时区是欧洲/罗马(或其他中欧时区,如果需要,您可以在下面方便地替换)。您从公司的框架中获得了两个var num = i + scrollPosition; if(num >= projects.length){ num = i + scrollPosition - projects.length;} var x = projects[num]; 实例。它们实际上都被误用了,其中一个表示日期,并且在您所在的时区中有一天中的00:00:00,另一个在1970年1月1日和您所需要的时间中,仍然在您的时区中。您需要将前者的日期与后者的时间结合起来。尤其是由于后者,在将两者结合时,您需要考虑时区。

java.util.Date

此打印:

  

2017-03-20T10:44 + 01:00 [欧洲/罗马]

时间是您所期望的10:44, ZoneId zone = ZoneId.of("Europe/Rome"); LocalTime timeOfDay = d2.toInstant().atZone(zone).toLocalTime(); ZonedDateTime dateTime = d1.toInstant().atZone(zone).with(timeOfDay); System.out.println(dateTime); 是UTC的偏移量。

如果您确实需要+01:00对象,例如对于无法更改或不想立即更改的遗留API(仅在这种情况下),请进行如下转换:

java.util.Date

输出:

  

2017年3月20日星期一10:44:00 CET

检查假设

您应该验证我上面所做的假设,以便您在不成立的前提下抓住它们。在以下相同代码的版本中,我这样做。

    Date asOldfashionedDate = Date.from(dateTime.toInstant());
    System.out.println(asOldfashionedDate);

结果与以前相同,只是我们现在更加确信它也是正确的。

您的代码出了什么问题?

ZonedDateTime dateZdt = d1.toInstant().atZone(zone); if (! dateZdt.equals(dateZdt.toLocalDate().atStartOfDay(zone))) { System.out.println("Date was not at start of day: " + d1); } ZonedDateTime timeZdt = d2.toInstant().atZone(zone); if (! timeZdt.toLocalDate().equals(LocalDate.EPOCH)) { System.out.println("Time of day was not on January 1, 1970: " + d2); } LocalTime timeOfDay = timeZdt.toLocalTime(); ZonedDateTime dateTime = dateZdt.with(timeOfDay); 正确表示您所在时区中00:00的日期。 d1表示您所在时区中的一天中的时间。现在,如果 if d2给出了您所在时区午夜以来的毫秒数,那么您的技巧就行了。但事实并非如此。您所获得的毫秒数是从UTC的00:00开始计算的,该时间所在的时区与1970年冬天的UTC的时差为1小时。这就是导致您的结果错误1小时的原因。

链接

The Java™ Tutorials: Date Time解释了如何使用d2.getTime(),包括我使用的类:java.timeZoneIdLocalTimeZonedDateTime等。

答案 2 :(得分:1)

纪元是1970-01-01 00:00:00 UTC,而CET则是UTC +1。这是过程:

input: 2017-03-20 00:00:00 CET —--> 2017-03-19 23:00:00 UTC
input: 1970-01-01 10:44:00 CET —--> 1970-01-01 09:44:00 UTC

// change inputs to the long millis to epoch and sum them
2017-03-19 23:00:00 UTC + 1970-01-01 09:44:00 UTC = 2017-03-20 08:44:00 UTC

output: 2017-03-20 08:44:00 UTC —--> 2017-03-20 09:44:00 CET