You can use ChronoUnit.DAYS
(in org.threeten.bp.temporal
package, or in java.time.temporal
if you use java 8 native classes) to calculate the number of days between the 2 LocalDate
objects:
if (savedDate != null && currentDate != null) {
if (ChronoUnit.DAYS.between(savedDate, currentDate) > days) {
hasExpired = true;
}
}
Edit (after bounty explanation)
For this test, I'm using threetenbp version 1.3.4
As you want a solution that works even if the user is in a different timezone, you shouldn't use LocalDate
, because this class doesn't handle timezone issues.
I think the best solution is to use the Instant
class. It represents a single point in time, no matter in what timezone you are (at this moment, everybody in the world are in the same instant, although the local date and time might be different depending on where you are).
Actually Instant
is always in UTC Time - a standard indepedent of timezone, so very suitable to your case (as you want a calculation independent of what timezone the user is in).
So both your savedDate
and currentDate
must be Instant
's, and you should calculate the difference between them.
Now, a subtle detail. You want the expiration to happen after 3 days. For the code I did, I'm making the following assumptions:
- 3 days = 72 hours
- 1 fraction of a second after 72 hours, it's expired
The second assumption is important for the way I implemented the solution. I'm considering the following cases:
currentDate
is less than 72 hours after savedDate
- not expired
currentDate
is exactly 72 hours after savedDate
- not expired (or expired? see comments below)
currentDate
is more than 72 hours after savedDate
(even by a fraction of a second) - expired
The Instant
class has nanosecond precision, so in case 3 I'm considering that it's expired even if it's 1 nanosecond after 72 hours:
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;
}
Note that I used ChronoUnit.DAYS.getDuration().toNanos()
to get the number of nanoseconds in a day. It's better to rely on the API instead of having hardcoded big error-prone numbers.
I've made some tests, using dates in the same timezone and in different ones.
I used ZonedDateTime.toInstant()
method to convert the dates to 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: for case 2 (currentDate
is exactly 72 hours after savedDate - not expired) - if you want this to be expired, just change the if
above to use >=
instead of >
:
if (ChronoUnit.NANOS.between(savedDate, currentDate) >= days * ChronoUnit.DAYS.getDuration().toNanos()) {
... // it returns "true" for case 2
}
If you don't want nanosecond precision and just want to compare the days between the dates, you can do as in @Ole V.V's answer. I believe our answers are very similar (and I suspect that the codes are equivalent, although I'm not sure), but I haven't tested enough cases to check if they differ in any particular situation.