您可以使用ChronoUnit.DAYS
(在org.threeten.bp.temporal
包中,或者java.time.temporal
如果您使用 java 8 本机类)来计算 2 个LocalDate
对象之间的天数:
if (savedDate != null && currentDate != null) {
if (ChronoUnit.DAYS.between(savedDate, currentDate) > days) {
hasExpired = true;
}
}
编辑(赏金解释后)
对于这个测试,我使用的是threetenbp 1.3.4版本
由于您想要一个即使用户在不同时区也能工作的解决方案,所以您不应该使用LocalDate
,因为此类不处理时区问题。
我认为最好的解决方案是使用Instant
类。它代表一个时间点,无论您在哪个时区(此时,世界上的每个人都在同一时刻,尽管本地日期和时间可能因您所在的位置而异)。
实际上Instant
总是在UTC 时间- 一个独立于时区的标准,因此非常适合您的情况(因为您想要一个独立于用户所在时区的计算)。
所以 yoursavedDate
和currentDate
must be都是Instant
,你应该计算它们之间的差异。
现在,一个微妙的细节。您希望在 3 天后到期。对于我所做的代码,我做出以下假设:
- 3 天 = 72 小时
- 72 小时后的 1 分之一秒,过期了
第二个假设对于我实现解决方案的方式很重要。我正在考虑以下情况:
currentDate
不到 72 小时后savedDate
-未过期
currentDate
正好是 72 小时后savedDate
-未过期(或过期?请参阅下面的评论)
currentDate
超过 72 小时后savedDate
(甚至几分之一秒) -过期
该类Instant
具有纳秒精度,因此在案例3中,我认为它已过期,即使 72 小时后为 1 纳秒:
import org.threeten.bp.Instant;
import org.threeten.bp.temporal.ChronoUnit;
public static boolean hasDateExpired(int days, Instant savedDate, Instant currentDate) {
boolean hasExpired = false;
if (savedDate != null && currentDate != null) {
// nanoseconds between savedDate and currentDate > number of nanoseconds in the specified number of days
if (ChronoUnit.NANOS.between(savedDate, currentDate) > days * ChronoUnit.DAYS.getDuration().toNanos()) {
hasExpired = true;
}
}
return hasExpired;
}
请注意,我曾经ChronoUnit.DAYS.getDuration().toNanos()
获得一天中的纳秒数。最好依赖 API,而不是硬编码容易出错的大数字。
我做了一些测试,使用相同时区和不同时区的日期。我使用ZonedDateTime.toInstant()
方法将日期转换为Instant
:
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZonedDateTime;
// testing in the same timezone
ZoneId sp = ZoneId.of("America/Sao_Paulo");
// savedDate: 22/05/2017 10:00 in Sao Paulo timezone
Instant savedDate = ZonedDateTime.of(2017, 5, 22, 10, 0, 0, 0, sp).toInstant();
// 1 nanosecond before expires (returns false - not expired)
System.out.println(hasDateExpired(3, savedDate, ZonedDateTime.of(2017, 5, 25, 9, 59, 59, 999999999, sp).toInstant()));
// exactly 3 days (72 hours) after saved date (returns false - not expired)
System.out.println(hasDateExpired(3, savedDate, ZonedDateTime.of(2017, 5, 25, 10, 0, 0, 0, sp).toInstant()));
// 1 nanosecond after 3 days (72 hours) (returns true - expired)
System.out.println(hasDateExpired(3, savedDate, ZonedDateTime.of(2017, 5, 25, 10, 0, 0, 1, sp).toInstant()));
// testing in different timezones (savedDate in Sao Paulo, currentDate in London)
ZoneId london = ZoneId.of("Europe/London");
// In 22/05/2017, London will be in summer time, so 10h in Sao Paulo = 14h in London
// 1 nanosecond before expires (returns false - not expired)
System.out.println(hasDateExpired(3, savedDate, ZonedDateTime.of(2017, 5, 25, 13, 59, 59, 999999999, london).toInstant()));
// exactly 3 days (72 hours) after saved date (returns false - not expired)
System.out.println(hasDateExpired(3, savedDate, ZonedDateTime.of(2017, 5, 25, 14, 0, 0, 0, london).toInstant()));
// 1 nanosecond after 3 days (72 hours) (returns true - expired)
System.out.println(hasDateExpired(3, savedDate, ZonedDateTime.of(2017, 5, 25, 14, 0, 0, 1, london).toInstant()));
PS:对于案例2 (currentDate
在 savedDate 之后正好 72 小时 -未过期) - 如果您希望它过期,只需将if
上面的内容更改为使用>=
而不是>
:
if (ChronoUnit.NANOS.between(savedDate, currentDate) >= days * ChronoUnit.DAYS.getDuration().toNanos()) {
... // it returns "true" for case 2
}
如果您不想要纳秒级精度而只想比较日期之间的天数,您可以按照@Ole VV 的回答进行操作。我相信我们的答案非常相似(我怀疑代码是等效的,尽管我不确定),但我没有测试足够的案例来检查它们在任何特定情况下是否不同。