Reputation: 321
I am trying to create a time limit for objects in a list. This could mean that the objects shelf life could be 23, 24 or 25 hours. Are there any Java libraries that could be useful? This is what I have so far.
My problem is that when I create a record at 9:30 am for example, it must be removed at 9:30 am on the following day. I get discrepancies when it is during the days which DST takes effect. The record is is either deleted at 8:30 or 10:30 depending if I spring forward or backward.
//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);
}
Upvotes: 2
Views: 1517
Reputation:
The old classes (Date
, Calendar
and SimpleDateFormat
) have lots of problems and design issues, including difficulty to deal with DST changes, and they're being replaced by the new APIs.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time
and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp
), but the classes and methods names are the same.
To take care of DST changes, the ideal class is ZonedDateTime
, which represents a date and time in a specific timezone. I also use the ZoneId
class, which represents the timezone itself.
I'm using my timezone (America/Sao_Paulo
), because here we have DST as well, but you can replace with yours (more on that below):
// 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);
The output is:
2017-10-14T09:00-03:00[America/Sao_Paulo]
2017-10-15T09:00-02:00[America/Sao_Paulo]
Note that the offset changed from -03:00
to -02:00
- it's due to DST starting in São Paulo timezone (clocks move forward 1 hour). But also note that the time (9 AM) was preserved correctly.
If we take the difference in hours, we can see that it's correct:
System.out.println(ChronoUnit.HOURS.between(z, nextDay));
The output is:
23
Which correctly means that 23 hours has passed between those 2 dates (because of clocks shifting 1 hour forward, so 1 hour is "lost").
In your case, you need to know if 1 day has already passed, so you just call:
long days = ChronoUnit.DAYS.between(z, nextDay);
In this case, days
will be 1 (even if the difference in hours calculated above is 23, because the API is smart enough to consider DST effects).
So in your case, you just need to check if the difference in days is 1 (or greater than 1, I don't know) and do all that it needs to be done.
If you need to get the current date/time, you can call ZonedDateTime.now(zone)
.
To use your timezone instead of mine, first note that the API uses IANA timezones names (always in the format Continent/City
, like America/Sao_Paulo
or Europe/Berlin
).
Avoid using the 3-letter abbreviations (like CST
or PST
) because they are ambiguous and not standard.
You can get a list of timezones names with ZoneId.getAvailableZoneIds()
- then choose the one that fits best to your case.
You can also use ZoneId.systemDefault()
- it returns the system's default timezone. But this can be changed without notice - even at runtime - so it's recommended to use an explicit timezone.
Upvotes: 5