I'm using openjdk version 1.8.0_112-release for development but will need to support previous JDK versions too (pre-Java-8) - so can't use java.time.
I am writing a utitily class to calculate the date to see if a saved date is before the current date which means its expired.
However, I am not sure I have done this the correct way. I am using LocalDate class to calculate the days. The expiration is counted starting from the date and time the user clicked save. That date will be saved and a check will be done against this saved date and time and the current date and time i.e. when the user logs in.
Is this the best way to do it? I would like to keep to the LocalDate class.
import org.threeten.bp.LocalDate;
public final class Utilities {
private Utilities() {}
public static boolean hasDateExpired(int days, LocalDate savedDate, LocalDate currentDate) {
boolean hasExpired = false;
if(savedDate != null && currentDate != null) {
/* has expired if the saved date plus the specified days is still before the current date (today) */
if(savedDate.plusDays(days).isBefore(currentDate)) {
hasExpired = true;
}
}
return hasExpired;
}
}
I'm using the class like this:
private void showDialogToIndicateLicenseHasExpired() {
final LocalDate currentDate = LocalDate.now();
final int DAYS_TO_EXPIRE = 3;
final LocalDate savedDate = user.getSavedDate();
if(hasDateExpired(DAYS_TO_EXPIRE, savedDate, currentDate)) {
/* License has expired, warn the user */
}
}
I am looking a solution that will take in account time zones. If a license was set to expire in 3 days, and the user was to travel to a different time zone. i.e. they could be ahead or behind based on hours. The license should still expire.
You can use
ChronoUnit.DAYS(inorg.threeten.bp.temporalpackage, or injava.time.temporalif you use java 8 native classes) to calculate the number of days between the 2LocalDateobjects: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
Instantclass. 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
Instantis 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
savedDateandcurrentDatemust beInstant'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:
The second assumption is important for the way I implemented the solution. I'm considering the following cases:
currentDateis less than 72 hours aftersavedDate- not expiredcurrentDateis exactly 72 hours aftersavedDate- not expired (or expired? see comments below)currentDateis more than 72 hours aftersavedDate(even by a fraction of a second) - expiredThe
Instantclass has nanosecond precision, so in case 3 I'm considering that it's expired even if it's 1 nanosecond after 72 hours: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 toInstant:PS: for case 2 (
currentDateis exactly 72 hours after savedDate - not expired) - if you want this to be expired, just change theifabove to use>=instead of>: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.