旧类(Date、Calendar 和 SimpleDateFormat)具有 lots of problems 和 design 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_Paulo 或 Europe/Berlin)。
避免使用三个字母的缩写(如CST 或PST),因为它们是ambiguous and not standard。
您可以使用ZoneId.getAvailableZoneIds() 获取时区名称列表 - 然后选择最适合您的情况。
您也可以使用ZoneId.systemDefault() - 它返回系统的默认时区。但这可以在没有通知的情况下更改 - 即使在运行时 - 所以建议使用明确的时区。