-1

i am pretty new to coding, so this might be a stupid question, but I can't find any solution. I want to calculate the difference (in days) between to dates. It works most of the time, but when the month changes, I get weird solutions.
First example:
today - 30 September 2018 = 78 Days,
today - 31 September 2018 = 79 Days (??),
today - 1 October 2018 = 80 Days
Second example:
today - 31 August 2018 = 49 Days,
today - 1 September 2018 = 49 Days

The code

private static int[] abstandTage(GregorianCalendar date1, ArrayList<GregorianCalendar> csvDate)
{
    int[] abstand = new int[csvDate.size()];
    int i = 0;
    while ( i < csvDate.size() )
    {
        long diffInMillis = csvDate.get(i).getTimeInMillis() - date1.getTimeInMillis();
        long tage = diffInMillis / 1000 / 60 / 60 / 24;
        abstand[i] = (int) tage;
        i++ ;
    }

    return abstand;
}

date1 is a predefined Date, csvDate is a list with dates. Can anybody help me?

Thanks in advance Alex

ɐlǝx
  • 1,384
  • 2
  • 17
  • 22
  • Better not to use the long outdated and poorly designed `GregorianCalendar` class and better to let a library method do the calculation for you. For example `ChronoUnit.DAYS.between()`, passing two `LocalDate` instances. Those classes are in [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Jul 13 '18 at 11:02
  • I would recommend to program against an interface by changing the signature to `int[] abstandTage(GregorianCalendar date1, List csvDate)`, more information about this [here](https://stackoverflow.com/questions/383947/what-does-it-mean-to-program-to-an-interface). – Glains Jul 13 '18 at 11:05
  • You results are unexpected, I agree. From today (13 July) to 30 September should be 79 days. To 1 September should be 50 days. Sounds like the days in September are wrong? How are you creating the `GregorianCalendar` objects? Could you [create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve), please? – Ole V.V. Jul 13 '18 at 11:06
  • Possible duplicate of [Difference in days between two dates in Java?](https://stackoverflow.com/questions/3299972/difference-in-days-between-two-dates-in-java) – Peter Walser Jul 13 '18 at 15:10
  • Possible near-duplicate of [Creating java date object from year,month,day](https://stackoverflow.com/questions/16499228/creating-java-date-object-from-year-month-day) – Ole V.V. Jul 14 '18 at 09:36

3 Answers3

1

The array of differences can be calculated using ChronoUnit. You can also use a stream to further simplify your implementation:

private static int[] abstandTage(GregorianCalendar date1,
          ArrayList<GregorianCalendar> csvDate) {

    return csvDate.stream()
            .mapToInt(csvdate -> (int) 
               ChronoUnit.DAYS.between(date1.toZonedDateTime(), csvdate.toZonedDateTime()))
            .toArray();
}
ernest_k
  • 44,416
  • 5
  • 53
  • 99
  • 1
    If we cannot avoid the `GregorianCalendar` class, this is the way to go. Still better if the caller would pass `LocalDate` or another modern date and time class in. – Ole V.V. Jul 13 '18 at 11:03
1

This happens if you create your GregorianCalendar objects as for example new GregorianCalendar(2018, 7, 13) for July 13. GregorianCalendar uses a weird month numbering, so you are not getting July 13.

The solution is to throw that long outdated and poorly designed class away and create your dates using for example LocalDate.of(2018, 7, 13) or even better, LocalDate.of(2018, Month.JULY, 13). Then use ChronoUnit.DAYS.between for finding the number of days between the dates.

Link: Oracle tutorial: Date Time explaining how to use java.time, the modern Java date and time API.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Thanks to your comment (weird numbering), I found a solution. Nevertheless, I am going to try the way you suggested here with Chronounit. Thanks for your efforts! Really appreciated. – dribble290 Jul 13 '18 at 11:51
  • 1
    @dribble290 The old legacy date-time classes really are a bloody awful mess. Sun, Oracle, and the JCP all agreed to replace them with *java.time* for a reason. Actually, for *many* reasons. You won't regret adopting *java.time*. – Basil Bourque Jul 14 '18 at 04:34
0

As mentioned above, you will have to use LocalDate here :

SimpleDateformat sdf = new SimpleDateFormat("yyyyMMdd");
Date date1 = sdf.parse("20180713);
Date date2 = sdf.parse("20180930");
LocalDate startDate = 
date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate endDate = 
date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
long days = ChronoUnit.DAYS.between(startDate, endDate);
return days;

Conversion from Gregorian to Date is done via :

Date newDate = new Date(date1.getTime());
luthrap
  • 1
  • 1
  • Thanks for wanting to contribute. Yes to `LocalDate´, but when you can use `LocalDate` from `java.time`, is see no reason whatsoever to use the old-fashioned `Date` nor the notoriously troublesome `SimpleDateFormat`. Use `java.time` exclusively. It’s also simpler. – Ole V.V. Jul 13 '18 at 16:58
  • As Ole V.V. commented, the terribly troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html) and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). Do not mix the legacy classes were entirely supplanted by *java.time*, so no need to ever mix. – Basil Bourque Jul 14 '18 at 04:29