【问题标题】:How do I add one day to a Calendar object and also account for daylight savings time?如何将一天添加到日历对象并考虑夏令时?
【发布时间】:2017-12-26 14:27:39
【问题描述】:

我正在尝试为列表中的对象创建时间限制。这可能意味着物品的保质期可能是 23、24 或 25 小时。是否有任何可用的 Java 库?这是我目前所拥有的。

我的问题是,例如,当我在上午 9:30 创建记录时,必须在第二天上午 9:30 将其删除。在 DST 生效期间,我会得到差异。记录是在 8:30 或 10:30 删除,这取决于我是向前还是向后弹跳。

//baseValue = object that I want to check

Date dt = new Date();
Calendar c = Calendar.getInstance(); 
c.setTime(dt); 
c.add(Calendar.DATE, -1);

if(baseValue.getTime() < c.getTime()){
    array.remove(baseValue);
}

【问题讨论】:

  • 这篇文章需要有一些你已经尝试过的代码,或者至少需要一些代码设置来解决这个问题。
  • 很抱歉。
  • 如果您使用的是 java 8,我建议您使用新的 Temporal 框架(即 ZonedDateTime),它可以满足您的所有需求。
  • 你的代码能胜任吗?如果不是,那么期望行为和观察到的行为之间究竟有什么区别?
  • 嗨,我已经更新了这个问题。谢谢。

标签: java date datetime dst


【解决方案1】:

旧类(DateCalendarSimpleDateFormat)具有 lots of problemsdesign issues,包括难以处理 DST 更改,并且它们正在被新的 API 取代。

如果您使用的是 Java 8,请考虑使用 new java.time API。更简单,less bugged and less error-prone than the old APIs

如果您使用的是 Java ,则可以使用 ThreeTen Backport,这是 Java 8 新日期/时间类的一个很好的向后移植。对于Android,还有ThreeTenABP(更多关于如何使用它here)。

下面的代码适用于两者。 唯一的区别是 包名称(在 Java 8 中是 java.time,而在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp),但类和方法 名称是一样的。


要处理 DST 更改,理想的类是 ZonedDateTime,它表示特定时区中的日期和时间。我还使用了ZoneId 类,它代表时区本身。

我正在使用我的时区 (America/Sao_Paulo),因为这里我们也有夏令时,但您可以用您的时区替换(更多内容见下文):

// create a date 1 day before DST change in Sao Paulo, at 9 AM
ZoneId zone = ZoneId.of("America/Sao_Paulo");
ZonedDateTime z = ZonedDateTime.of(2017, 10, 14, 9, 0, 0, 0, zone);

// get the next day, at 9 AM
ZonedDateTime nextDay = z.plusDays(1);

System.out.println(z);
System.out.println(nextDay);

输出是:

2017-10-14T09:00-03:00[美国/圣保罗]
2017-10-15T09:00-02:00[美国/圣保罗]

请注意,偏移量从 -03:00 更改为 -02:00 - 这是由于 DST 从圣保罗时区开始(时钟向前移动 1 小时)。但也请注意,时间(上午 9 点)保存正确。

如果我们以小时为单位,我们可以看到它是正确的:

System.out.println(ChronoUnit.HOURS.between(z, nextDay));

输出是:

23

这正确意味着这两个日期之间已经过去了 23 小时(因为时钟向前移动 1 小时,所以 1 小时被“丢失”)。


在您的情况下,您需要知道是否已经过了 1 天,所以您只需致电:

long days = ChronoUnit.DAYS.between(z, nextDay);

在这种情况下,days 将是 1(即使上面计算的小时差是 23,因为 API 足够聪明,可以考虑 DST 影响)。

因此,在您的情况下,您只需要检查天数的差异是否为 1(或大于 1,我不知道)并执行所有需要完成的操作。

如果需要获取当前日期/时间,可以拨打ZonedDateTime.now(zone)


要使用您的时区而不是我的时区,请首先注意 API 使用 IANA timezones names(始终采用 Continent/City 格式,例如 America/Sao_PauloEurope/Berlin)。 避免使用三个字母的缩写(如CSTPST),因为它们是ambiguous and not standard

您可以使用ZoneId.getAvailableZoneIds() 获取时区名称列表 - 然后选择最适合您的情况。

您也可以使用ZoneId.systemDefault() - 它返回系统的默认时区。但这可以在没有通知的情况下更改 - 即使在运行时 - 所以建议使用明确的时区。

【讨论】:

  • @CalvinR​​aveenthran 不客气。如果您发现答案有用并且解决了您的问题,您可以接受和/或投票:stackoverflow.com/help/someone-answers
  • 我刚加入时没有足够的声誉。但是当我这样做时,我一定会重新访问。
  • @CalvinR​​aveenthran 实际上你可以接受它,因为这是你的问题。默认情况下,所有用户都可以接受自己的问题,无论他们有多少声望:meta.stackexchange.com/questions/5234/…(实际上,只有提出问题的用户才能接受)。
猜你喜欢
  • 2023-03-26
  • 2013-01-15
  • 2020-03-01
  • 1970-01-01
  • 2018-02-04
  • 2012-05-01
  • 2011-08-14
  • 2014-03-22
  • 1970-01-01
相关资源
最近更新 更多