calendar start date before end date on same day di

2019-08-16 04:29发布

问题:

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);
}

回答1:

    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.timeto 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.


回答2:

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;
}