I have two calendar dates where i am getting the difference between in days, hours, and minutes.
This works perfectly if the end date is greater than the start date.
What doesnt work is if the start date is the same day of week as the end date, but an earlier time than the end date.
For example: end date 2:20 pm Saturday, and start date is 7:20 pm on saturday.
It calculates it at like 0days, and 5 hours. But, it should be more like 7 days.
Here is the code
long t1 = curCal.getTimeInMillis();
long t2 = setCal.getTimeInMillis();
if(t2 < t1){
days = t1-t2;
}else{
days = t2-t1;
}
long toDays = TimeUnit.MILLISECONDS.toDays(days);
long toHours = TimeUnit.MILLISECONDS.toHours(days) % 24;
long toMinutes = TimeUnit.MILLISECONDS.toMinutes(days) % 60;
String toastMessage = String.format(" %d Days %d Hours %d Minutes", toDays, toHours, toMinutes);
Toast.makeText(context, "ALARM in" + " " + toastMessage , Toast.LENGTH_LONG).show();
How can i handle the case where the end date is the same day as the start date, but the end date is a time before the start date?
Thanks
EDIT
I think i solved my problem. I am adding it for anyone else having the same issue. if end date = startdate(same day) add 7 to the calendar object for enddate. psuedocode
if (enddate == startdate)) {
enddate.add(Calendar.DAY_OF_YEAR, 7);
}
ZoneId zone = ZoneId.of("Europe/Busingen");
DayOfWeek alarmDay = DayOfWeek.SUNDAY;
LocalTime alarmTime = LocalTime.of(14, 20);
ZonedDateTime now = ZonedDateTime.now(zone);
ZonedDateTime alarmDateTime = now.with(alarmDay).with(alarmTime);
if (alarmDateTime.isBefore(now)) {
alarmDateTime = alarmDateTime.plusWeeks(1);
}
Duration difference = Duration.between(now, alarmDateTime);
String toastMessage = String.format(" %d Days %d Hours %d Minutes",
difference.toDaysPart(), difference.toHoursPart(), difference.toMinutesPart());
System.out.println(toastMessage);
Running just now (Sunday 22:03:17 in Büsingen) I got:
6 Days 16 Hours 16 Minutes
I believe that I am contributing the answer that is not only the modern one but also the more robust one.
- Modern: The
Calendar
class is long outdated and by today’s standards poorly designed. Instead I use and recommend java.time
, the modern Java date and time API.
- Robust: As far as I can tell your code doesn’t only have an issue when today and alarm date are the same day of week, but also if the alarm falls on an earlier day of week. I take that into account.
- Furthermore accurate: In cases where you cross transitions to and from summer time (DST), you may get the wrong number of hours when you use the millisecond values in your calculation. Using two
ZonedDateTime
objects minimizes surprises here. It does require you to fill in your desired time zone where I put Europe/Busingen since summer time transitions are time zone specific.
- Furthermore more precisely modelled: Using a
Calendar
, a date and time, for a weekly recurring alarm seems a bit funny. What you need is a day-of-week and a time of day, so I use that. java.time
offers the classes needed, the DayOfWeek
enum and the LocalTime
class.
I am in fact so modern that I am using the toXxxPart
methods of the Duration
class that were introduced in Java 9. For formatting the Duration
if you are not yet using Java 9 you will need to subtract first the days from the duration to get the hours: use the minusDays
method. Then do similarly with minusHours
to get the minutes.
long toDays = difference.toDays();
difference = difference.minusDays(toDays);
long toHours = difference.toHours();
difference = difference.minusHours(toHours);
long toMinutes = difference.toMinutes();
Question: Can I use java.time on Android?
Yes, java.time
works nicely on older and newer Android devices. It just requires at least Java 6.
- In Java 8 and later and on newer Android devices (from API level 26, I’m told) the modern API comes built-in.
- In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
- On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from
org.threeten.bp
with subpackages.
Links
- Oracle tutorial: Date Time explaining how to use
java.time
.
- Java Specification Request (JSR) 310, where
java.time
was first described.
- ThreeTen Backport project, the backport of
java.time
to Java 6 and 7 (ThreeTen for JSR-310).
- ThreeTenABP, Android edition of ThreeTen Backport
- Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Reading your question another way, if t1
is the start date and t2
is the end date, your logic does not include the case where t1 < t2
and t2 - t1
< 1. In this case, you need to add 7 to the number of days. Something like:
long t1 = curCal.getTimeInMillis();
long t2 = setCal.getTimeInMillis();
if(t2 < t1){
days = t1-t2;
}else{
days = t2-t1;
if (days < 1) {
days += 7;
}
}
All of this can be simplified to
days = Math.abs(t1 - t2);
if (days < 1 && t1 < t2) {
days += 7;
}