java - 如何向日历对象添加一天并考虑夏令时?

标签 java date datetime dst

我正在尝试为列表中的对象创建时间限制。这可能意味着元素的保质期可能为 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);
}

最佳答案

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

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

如果您使用的是 Java <= 7,则可以使用 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[America/Sao_Paulo]
2017-10-15T09:00-02:00[America/Sao_Paulo]

请注意,偏移量从 -03:00 更改为 -02:00 - 这是由于圣保罗时区开始实行夏令时(时钟向前移动 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)。 避免使用 3 个字母的缩写(例如 CSTPST),因为它们是 ambiguous and not standard .

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

您还可以使用ZoneId.systemDefault() - 它返回系统的默认时区。但这可能会在不通知的情况下更改 - 即使在运行时 - 因此建议使用显式时区。

关于java - 如何向日历对象添加一天并考虑夏令时?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45222363/

相关文章:

java - 如何使用字符串变量作为循环目的的条件

java - 使用 gradle 未解决 aar 库的传递依赖关系

javascript - 如何使用 javascript/jquery 反转日期格式 yyyy-mm-dd?

jquery - 指定的值不符合要求的格式yyyy-MM-dd

javascript - ".000Z"的 "yyyy-mm-ddT00:00:00.000Z"是什么意思?

java - 用Java读取wav文件的问题

java - 你如何在 Java 的日历中设置时间并且只设置时间?

ios - 如何在 Swift3 ios 中获取上周的天数

python - 属性错误: 'str' object has no attribute 'to_datetime'

java - 安全地将工作应用程序从一台电脑复制到另一台电脑