简体   繁体   中英

Get correct difference between two selected dates in years, months and days in Android

How can i get difference between two selected dates from calendar in Android in days, months and years? We know all that the months sometimes have 30 days and sometimes 31 days and in February 28 days just every 4 years come 29 days. I want to get the result for example like this: 2 years and 6 months and 24 days. I try to use LocalDate so this is my code:

public void onSelectedDayChange(@NonNull CalendarView view,
        final int year, final int month, final int dayOfMonth) {

    textView.setText(String.valueOf(dateDiff(year,month,dayOfMonth)));
}

public Period dateDiff(int year,int month,int day){
    final int Day = c.get(Calendar.DAY_OF_MONTH);
    final int Month = c.get(Calendar.MONTH);
    final int Year = c.get(Calendar.YEAR);
    LocalDate localDate1 = LocalDate.of(year,month,day);
    LocalDate localDate2 = LocalDate.of(Year,Month,Day);

    Period period = Period.between(localDate2,localDate1);

    return period;
}

I tested the code but i got wrong result. When i test it with days (02/05/2020) i got 8 days but the difference is 7 days because "April" has 30 days and for the selected day (02/07/2020) i got 2 months and 8 days or the correct answer are 2 months and 7 days. I try to get first a correct result, if there is a function or a calculation formula to solve this wrong result, this will help me.

Finally i got in result each time something like (P2M8D) that's meaning 2 months and 8 days, or for example (P7D) that's mean 7 days, so how can i change this text to an understood one like 2 months and 8 days or 7 days like the 2 examples because i found problem in result because we have mixed between numbers and characters.

You're well on the right way.

  1. Follow the Java naming conventions. A variable or parameter name begins with a lower case letter. Always. It's particularly confusing that you've got parameter year and variable Year . This is bound to lead to errors at some point (though this doesn't seem to be the reason at the moment).
  2. Since you can use LocalDate and Period from java.time, the modern Java date and time API, don't mix in the poorly designed and outdated Calendar class too, it just complicates things. Your use of LocalDate and Period is basically correct. For getting the current date as a LocalDate use LocalDate.now(ZoneId.systemDefault()) (and we no longer need the uppercase variables, two problems solved in one shot).
  3. I don't know your date picker, but I suspect that it may use 0-based month numbers: 0 for January through 11 for December. If this is so, you need to add 1 to the month number when creating the LocalDate object.

For a more readable text use the methods of the Period object to get numbers and assemble your own string. A simple example is:

        String periodText = "" + period.getYears() + " years "
                    + period.getMonths() + " months " + period.getDays() + " days";

You will want to modify it to leave out the years if they are 0 and the months if they are 0. Consider what text you want to write if all the numbers are 0. You will want to write something, or the user will be confused. A further possible refinement will be to use singular of the words if there is exactly 1 ( 1 year rather than 1 years , etc.). You may look into using a StringJoiner and into writing an auxiliary method that returns a string with a number and the correct form of a noun, for example 1 month but 2 months .

Edit: Code for formatting the Period

Spelling out my suggestion in code, here's a way to format your Period :

    StringJoiner joiner = new StringJoiner(" ");
    joiner.setEmptyValue("No time at all");
    if (period.getYears() != 0) {
        joiner.add(singularOrPlural(period.getYears(), "year", "years"));
    }
    if (period.getMonths() != 0) {
        joiner.add(singularOrPlural(period.getMonths(), "month", "months"));
    }
    if (period.getDays() != 0) {
        joiner.add(singularOrPlural(period.getDays(), "day", "days"));
    }
    String periodText = joiner.toString();

    System.out.println(periodText);

The code is using this auxiliary method:

private static String singularOrPlural(int count, String singular, String plural) {
    if (count == -1 || count == 1) {
        return "" + count + ' ' + singular;
    } else {
        return "" + count + ' ' + plural;
    }
}

Example outputs:

 No time at all 1 day 2 days 1 month 1 month 1 day 2 months 3 years 4 months 5 days -1 year -1 month -6 days

I can't understand the problem you have with the "wrong result" of the returned period, clarify it better to me if you can.

By the way, you can try this to convert a format like P2M8D to 2 months and 8 days:

public static void main(String[] args) {
    int year = 2020, month = 7, day = 2;
    int yearDiff = dateDiff(year, month, day).getYears();
    int monthDiff = dateDiff(year, month, day).getMonths();
    int dayDiff = dateDiff(year, month, day).getDays();
    System.out.println("Period -> yyyy:" + yearDiff + " mm:" + monthDiff + " dd:" + dayDiff); // OUTPUT: Period -> yyyy:0 mm:3 dd:7
}


static Period dateDiff(int year, int month, int day) {
    Calendar c = Calendar.getInstance();
    final int Day = c.get(Calendar.DAY_OF_MONTH);
    final int Month = c.get(Calendar.MONTH);
    final int Year = c.get(Calendar.YEAR);
    LocalDate localDate1 = LocalDate.of(year, month, day);
    LocalDate localDate2 = LocalDate.of(Year, Month, Day);

    return Period.between(localDate2, localDate1);
}

You have to use getDays , getMonths and getYears methods.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM