1

I am trying to display a custom text result between two dates. Here is the code in my Fragment, which return two dates:

public class HomeFragment extends BaseFragment {

  ...

  dashboardViewModel.productCategory.observe(this, data - > {
    if (data != null && data.getData() != null) {
      int totalLos = Integer.parseInt(data.getData().getLos());
      Log.e("totalLOS", String.valueOf(totalLos));
      explainDays(totalLos);
      mBinding.los.setText("");
    }
  });

}

And here the code in BaseFragment which generate two dates:

public abstract class BaseFragment extends Fragment {

  ...
  public void explainDays(int totalDays) {

    Calendar calendar = Calendar.getInstance();
    Date start = calendar.getTime();

    calendar.add(Calendar.DATE, -totalDays);
    Date end = calendar.getTime();

    Log.e("startDate", String.valueOf(start));
    Log.e("endDate", String.valueOf(end));

  }

}

From the code above, I am getting these three logs:

E/totalLOS: 1233
E/startDate: Mon Jun 08 19:45:08 GMT+07:00 2020
E/endDate: Sun Jan 22 19:45:08 GMT+07:00 2017

How do I generate a response like for example 1 Year and 5 Months since 2007 between these two date results? the since 2007 needs to be extracted from endDate from Log above.

Any help will be much appreciated.

Thank you.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
M Ansyori
  • 429
  • 6
  • 21
  • 2
    Seriously, avoid the use of `java.util` whenever possible... What is the minimum API level you are supporting in this app? If you can use `java.time`, then do that. It's a lot better... – deHaar Jun 08 '20 at 12:48
  • A division by 365 and 12 comes mind. – blackapps Jun 08 '20 at 12:48
  • @deHaar Hi, any reason why **java.time** is better? the current min api is 19 by the way – M Ansyori Jun 08 '20 at 12:51
  • @blackapps Hello, can you please elaborate? do you mind giving an answer below? – M Ansyori Jun 08 '20 at 12:53
  • 2
    There are several reasons, e.g. consideration of daylight saving times and the possibility of using objects with or without respect to time zones or offsets. However, it's natively supported from Android 26, but there is a [backport](https://github.com/JakeWharton/ThreeTenABP) recommended to be used in lower API versions. – deHaar Jun 08 '20 at 12:58
  • You learned in primary school to determine amount of months from amount of days. So what are you asking for? I forgot 31. – blackapps Jun 08 '20 at 12:58
  • @deHaar Okay, thanks for your explanation. I'll write it down and try to migrate to java.time. – M Ansyori Jun 08 '20 at 13:01
  • 1
    Good... use one or both of the classes `Period` and `Duration` if you want to calculate elapsed temporal amounts. – deHaar Jun 08 '20 at 13:03
  • By the way... What is *since 2007* supposed to mean exactly? Since 2007-01-01 or since 2007-12-31? Is this all about the date part or do you want a difference in hours, minutes, seconds a.s.o., too? – deHaar Jun 08 '20 at 13:05
  • @blackapps well I apologize if I wrote something ain't right. what I am asking for is that how do I get a result like for example, **1 Year and 5 Months since 2007** between *startDate* and *endDate* in BaseFragment. I was able to subtract the current date with days in integer passed to the function. – M Ansyori Jun 08 '20 at 13:07
  • @deHaar *since 2007* supposed to be extracted from endDate *2007* is just an example from the endDate. – M Ansyori Jun 08 '20 at 13:09
  • 1
    Well, 2007 is an incomplete because it has no day of year and no month of year, which seem to be mandatory for a calculation having a desired result like *13 years and 5 months*... But ok, I get you are receiving some kind of datetime object. – deHaar Jun 08 '20 at 13:12
  • @deHaar I think from the generated Log above, the endDate result is Sun Jan 22 19:45:08 GMT+07:00 2017. It has a complete all-time requirement for a Date variable. – M Ansyori Jun 08 '20 at 13:15

3 Answers3

4

java.time

You can do it as follows:

import java.time.OffsetDateTime;
import java.time.Period;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        // Define format
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss O yyyy");

        // Date/time strings
        String strEndDate = "Mon Jun 08 19:45:08 GMT+07:00 2020";
        String strStartDate = "Sun Jan 22 19:45:08 GMT+07:00 2017";

        // Define ZoneOffset
        ZoneOffset zoneOffset = ZoneOffset.ofHours(6);

        // Parse date/time strings into OffsetDateTime
        OffsetDateTime startDate = OffsetDateTime.parse(strStartDate, formatter).withOffsetSameLocal(zoneOffset);
        OffsetDateTime endDate = OffsetDateTime.parse(strEndDate, formatter).withOffsetSameLocal(zoneOffset);

        // Calculate period between `startDate` and `endDate`
        Period period = Period.between(startDate.toLocalDate(), endDate.toLocalDate());

        // Display result
        System.out.println(
                period.getYears() + " years and " + period.getMonths() + " months since " + startDate.getYear());
    }
}

Output:

3 years and 4 months since 2017

Note: Instead of using the outdated java.util.Date and SimpleDateFormat, use the modern date/time API. Check this to learn more about it.


Note: The following content has been copied from How to get start time and end time of a day in another timezone in Android

Question: Doesn’t java.time require Android API level 26?

java.time works nicely on both 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) the modern API comes built-in.
  • In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern 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.

But don't we have any other option apart from switching to ThreeTenBP Library?

If you insisted, I suppose that a way through using Calendar, Date and SimpleDateFormat could be found. Those classes are poorly designed and long outdated, so with what I know and don’t know I would prefer ThreeTenABP.

Links


Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • I am unable to try your solution, these OffsetDateTime.parse(), withOffsetSameLocal() and Period.between() requires API level 26 but the current min api is 19. – M Ansyori Jun 08 '20 at 13:40
  • 3
    @MAnsyori - Please check [ThreeTenABP](https://github.com/JakeWharton/ThreeTenABP) – Arvind Kumar Avinash Jun 08 '20 at 13:46
  • 1
    @MAnsyori See: [*How to use ThreeTenABP in Android Project*](https://stackoverflow.com/q/38922754/642706). And see [my graphic table](https://i.stack.imgur.com/7BcmB.png). – Basil Bourque Jun 09 '20 at 01:10
  • @ArvindKumarAvinash interesting, everything's work. so firstly, I tried your code and added if the build version is or greater than 26 conditions, everything goes well. After that, I tried to run in API 22, it crashes. I use ThreeTenABP as you suggested, no need to change the code, just the imports, then it works well in API 22. I'm not sure about API 19 since too much error happens when testing the app I'm working on in API 19. I thank you so much for your answer. – M Ansyori Jun 09 '20 at 01:44
  • @BasilBourque thanks for the extra how-to pal. appreciate it. – M Ansyori Jun 09 '20 at 01:45
  • @MAnsyori - You are most welcome. It is Basil Bourque whose posts inspired me to learn the modern date/time API. Later on, Ole V.V. too supported me a lot in this process. I do not have enough words to thank both of them. – Arvind Kumar Avinash Jun 09 '20 at 08:47
0

If you can extract the month,day and year from both dates you can use following solution to calculate the exact difference between two dates.

            int sday=22 //int day of month here
            int smonth=1 //int month here
            int syear=2017 //int year here

            int eday=5 //int day of month here
            int emonth=6 //int month here
            int eyear=2020 //int year here

                resyear = eyear - syear;
                if (emonth >= smonth) {
                    resmonth = emonth - smonth;
                } else {
                    resmonth = emonth - smonth;
                    resmonth = 12 + resmonth;
                    resyear--;
                }
                if (eday >= sday) {
                    resday = eday - sday;
                } else {
                    resday = eday - sday;
                    resday = 31 + resday;
                    if (resmonth == 0) {
                        resmonth = 11;
                        resyear--;
                    } else {
                        resmonth--;
                    }
                }
                if (resday <0 || resmonth<0 || resyear<0) {
                    Toast.makeText(getApplicationContext(), "starting date must greater than ending date", Toast.LENGTH_LONG).show();

                }
                else {

Toast.makeText(getApplicationContext(), "difference: " + resyear + " years /" + resmonth + " months/" + resday + " days", Toast.LENGTH_LONG).show();

                }
            }
Prathamesh
  • 1,064
  • 1
  • 6
  • 16
0
// in kotlin 
fun getDateAndYearsDifference(startDate: Date?, endDate: Date? = null): String {
    val startCalendar: Calendar = GregorianCalendar()
    startCalendar.time = startDate
    val endCalendar: Calendar = GregorianCalendar()
    endCalendar.time = endDate ?: Calendar.getInstance().time
    val period = Period(startCalendar.time.time, endCalendar.time.time, PeriodType.standard())
    val yearsAndMonths = PeriodFormatterBuilder()
        .printZeroNever()
        .appendYears()
        .appendSuffix(" yrs", " yrs")
        .appendSeparator(Constants.COMMA)
        .printZeroRarelyLast()
        .appendMonths()
        .appendSuffix(" mos", " mos")
        .toFormatter()
    return period.toString(yearsAndMonths)
}
Abhay Pratap
  • 1,886
  • 11
  • 15
  • 1
    I strongly recommend that no one uses the old `Date`, `Calendar` and `GregorianCalendar` classes anymore. They were poorly designed and cumbersome to work with. Your alswer seriously lacks some explanation. First of all, are the `Period`and `PeriodFormatterBuilder` from Joda-Time? If so, please state so. As long as we don’t know, we can’t really use your answer. – Ole V.V. Aug 04 '23 at 05:57