74

I am trying to determine an age in years from a certain date. Does anyone know a clean way to do this in Android? I have the Java api available obviously, but the straight-up java api is pretty weak, and I was hoping that Android has something to help me out.

EDIT: The multiple recommendations to use Joda time in Android worries me a bit due to Android Java - Joda Date is slow and related concerns. Also, pulling in a library not shipped with the platform for something this size is probably overkill.

m0skit0
  • 25,268
  • 11
  • 79
  • 127
Micah Hainline
  • 14,367
  • 9
  • 52
  • 85
  • A similar question: http://stackoverflow.com/questions/1116123/how-do-i-calculate-someones-age-in-java – jeha Oct 26 '11 at 17:23
  • 1
    Both the legacy `Date`/`Calendar` classes and *Joda-Time* have been supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes. Most of the *java.time* functionality is back-ported to Java 6 & Java 7 in the [***ThreeTen-Backport***](http://www.threeten.org/threetenbp/) project. Further adapted for earlier Android in the [***ThreeTenABP***](https://github.com/JakeWharton/ThreeTenABP) project. See [*How to use ThreeTenABP…*](http://stackoverflow.com/q/38922754/642706). – Basil Bourque Oct 01 '18 at 00:40

12 Answers12

128
import java.util.Calendar;
import java.util.Locale;
import static java.util.Calendar.*;
import java.util.Date;

public static int getDiffYears(Date first, Date last) {
    Calendar a = getCalendar(first);
    Calendar b = getCalendar(last);
    int diff = b.get(YEAR) - a.get(YEAR);
    if (a.get(MONTH) > b.get(MONTH) || 
        (a.get(MONTH) == b.get(MONTH) && a.get(DATE) > b.get(DATE))) {
        diff--;
    }
    return diff;
}

public static Calendar getCalendar(Date date) {
    Calendar cal = Calendar.getInstance(Locale.US);
    cal.setTime(date);
    return cal;
}

Note: as Ole V.V. noticed, this won't work with dates before Christ due how Calendar works.

sinuhepop
  • 20,010
  • 17
  • 72
  • 107
  • 4
    What are the constants MONTH, YEAR and DATE ?? – Chris Sim Jul 16 '13 at 09:57
  • 4
    @ChrisSim: They are static imports of Calendar.MONTH and so on. – sinuhepop Jul 16 '13 at 10:54
  • 2
    I think instead of DATE it should be DAY_OF_MONTH. – jiahao May 19 '14 at 10:37
  • 2
    @jiahao: they're synonyms – sinuhepop May 19 '14 at 12:49
  • 1
    .get(YEAR) and .get(MONTH) are now deprecated I believe. Possibly edit? –  Aug 07 '15 at 09:32
  • @Iridann: where do you see that? There's nothing deprecated: http://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html – sinuhepop Aug 07 '15 at 10:33
  • @sinuhepop My bad, that's Calendar.getYear() I read as being deprecated! –  Aug 07 '15 at 10:39
  • @sinuhepop Although saying that I thought that the convention was to use the form Calendar.get(Calendar.YEAR);? –  Aug 07 '15 at 10:39
  • 1
    FYI, the troublesome old date-time classes such as `java.util.Date`, `java.util.Calendar`, and `java.text.SimpleDateFormat` are now legacy, supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes. Most of the *java.time* functionality is back-ported to Java 6 & Java 7 in the [***ThreeTen-Backport***](http://www.threeten.org/threetenbp/) project. Further adapted for earlier Android in the [***ThreeTenABP***](https://github.com/JakeWharton/ThreeTenABP) project. See [*How to use ThreeTenABP…*](http://stackoverflow.com/q/38922754/642706). – Basil Bourque Oct 01 '18 at 00:39
  • Keep in mind to add +1 to Calendar.MONTH if comparing Calendar.getInstance() with your set date! – Androidz Jun 08 '20 at 08:30
  • int diff = b.get(Calendar.YEAR) - a.get(Calendar.YEAR); if (a.get(Calendar.MONTH) > b.get(Calendar.MONTH) || (a.get(Calendar.MONTH) == b.get(Calendar.MONTH) && a.get(Calendar.DATE) > b.get(Calendar.DATE))) { diff--; } – selwyn Oct 28 '20 at 08:38
  • How long did Roman emperor Augustus live? According to [Wikipedia](https://en.wikipedia.org/wiki/List_of_Roman_emperors#27_BC%E2%80%9368_AD:_Julio-Claudian_dynasty) 75 years. Feeding the dates from there into your code gave: -50 (minus fifty). – Ole V.V. May 27 '21 at 18:32
  • @OleV.V.: Good find! I'll update my answer. – sinuhepop Jun 16 '21 at 17:38
  • `if (a.get(MONTH) > b.get(MONTH) || (a.get(MONTH) == b.get(MONTH) && a.get(DATE) > b.get(DATE))) { diff--; }` why did you use this condition? – Sanatbek_Matlatipov Jun 26 '22 at 06:09
  • @mr.sanatbek: it tells if **a** is after **b** (excluding years) – sinuhepop Jun 27 '22 at 13:33
  • if (a.get(MONTH) < b.get(MONTH) || (a.get(MONTH) == b.get(MONTH) && a.get(DATE) < b.get(DATE))) { diff++; // for comparison purpose } – Smart Coder Oct 19 '22 at 17:38
  • use import static java.util.Calendar.*; in your code. – Shiv Buyya Feb 13 '23 at 11:06
  • @ShivBuyya: Third line in my code is exactly that. – sinuhepop Feb 13 '23 at 14:47
46

tl;dr

ChronoUnit.YEARS.between( 
    LocalDate.of( 2010 , 1 , 1 ) , 
    LocalDate.now( ZoneId.of( "America/Montreal" ) ) 
)

Test for zero years elapsed, and one year elapsed.

ChronoUnit.YEARS.between( 
    LocalDate.of( 2010 , 1 , 1 )  , 
    LocalDate.of( 2010 , 6 , 1 ) 
)

0

ChronoUnit.YEARS.between( 
    LocalDate.of( 2010 , 1 , 1 )  , 
    LocalDate.of( 2011 , 1 , 1 ) 
)

1

See this code run at Ideone.com.

java.time

The old date-time classes really are bad, so bad that both Sun & Oracle agreed to supplant them with the java.time classes. If you do any significant work at all with date-time values, adding a library to your project is worthwhile. The Joda-Time library was highly successful and recommended, but is now in maintenance mode. The team advises migration to the java.time classes.

Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).

LocalDate start = LocalDate.of( 2010 , 1 , 1 ) ;
LocalDate stop = LocalDate.now( ZoneId.of( "America/Montreal" ) );
long years = java.time.temporal.ChronoUnit.YEARS.between( start , stop );

Dump to console.

System.out.println( "start: " + start + " | stop: " + stop + " | years: " + years ) ;

start: 2010-01-01 | stop: 2016-09-06 | years: 6


Table of all date-time types in Java, both modern and legacy


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

Table of which java.time library to use with which version of Java or Android

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • This does the diff of actual year number only but not the calculated year based on actual full date. – Smart Coder Oct 19 '22 at 19:32
  • @SmartCoder I do not understand your Comment. I read the Question as asking for age, number of years reached on an anniversary date. The code shown does so. See [this demo](https://ideone.com/3aVjsg) on Ideone.com. – Basil Bourque Oct 19 '22 at 21:21
  • I used the code to calculate year based on actual date and it just gives the difference of year number. It'd actually calculate based on date difference. The date '09/12/2022' an '11/23/2020' should give diff of just one year and not two. – Smart Coder Oct 19 '22 at 21:38
  • @SmartCoder Indeed, yes. `ChronoUnit.YEARS.between( LocalDate.of( 2020 , 11 , 23 ) , LocalDate.of( 2022 , 9 , 12 ) )` returns `1`. See [demo](https://ideone.com/3aVjsg). – Basil Bourque Oct 19 '22 at 21:47
  • 1
    @SmartCoder If I have missed your point, please explain. I do not see how you got a result of two years when comparing those two dates. – Basil Bourque Oct 19 '22 at 21:56
19

I would recommend using the great Joda-Time library for everything date related in Java.

For your needs you can use the Years.yearsBetween() method.

Marcelo
  • 11,218
  • 1
  • 37
  • 51
  • I've used Joda a lot this last project. It is really over kill in terms of setting up... – StarWind0 Sep 26 '15 at 09:00
  • 2
    Just to elaborate: `public int getYears(org.java.util.Date time) { org.joda.time.DateTime now = org.joda.time.DateTime.now(); org.joda.time.DateTime then = new org.joda.time.DateTime(time.getTime()); return org.joda.time.Years.yearsBetween(now, then).getYears(); }` – Nielsvh Oct 06 '15 at 16:05
  • An update, a decade later… The *Joda-Time* framework has been supplanted by the *java.time* classes built into Java 8+, defined in [JSR 310](https://jcp.org/en/jsr/detail?id=310). *Joda-Time* is now in [maintenance-mode](https://en.wikipedia.org/wiki/Maintenance_mode). Both *Joda-Time* and *java.time* are led by the same man, [Stephen Colebourne](https://stackoverflow.com/users/38896/jodastephen). – Basil Bourque Oct 19 '22 at 21:52
5

I apparently can't comment yet, but I think you can just use the DAY_OF_YEAR to workout if you should adjust the years down one (copied and modified from current best answer)

public static int getDiffYears(Date first, Date last) {
    Calendar a = getCalendar(first);
    Calendar b = getCalendar(last);
    int diff = b.get(Calendar.YEAR) - a.get(Calendar.YEAR);
    if (a.get(Calendar.DAY_OF_YEAR) > b.get(Calendar.DAY_OF_YEAR)) {
        diff--;
    }
    return diff;
}

public static Calendar getCalendar(Date date) {
    Calendar cal = Calendar.getInstance(Locale.US);
    cal.setTime(date);
    return cal;
}

Similarly you could probably just diff the ms representations of the time and divide by the number of ms in a year. Just keep everything in longs and that should be good enough most of the time (leap years, ouch) but it depends on your application for the number of years and how performant that function has to be weather it would be worth that kind of hack.

sagechufi
  • 67
  • 1
  • 1
1

Here's what I think is a better method:

public int getYearsBetweenDates(Date first, Date second) {
    Calendar firstCal = GregorianCalendar.getInstance();
    Calendar secondCal = GregorianCalendar.getInstance();

    firstCal.setTime(first);
    secondCal.setTime(second);

    secondCal.add(Calendar.DAY_OF_YEAR, 1 - firstCal.get(Calendar.DAY_OF_YEAR));

    return secondCal.get(Calendar.YEAR) - firstCal.get(Calendar.YEAR);
}

EDIT

Apart from a bug which I fixed, this method does not work well with leap years. Here's a complete test suite. I guess you're better off using the accepted answer.

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

class YearsBetweenDates {
    public static int getYearsBetweenDates(Date first, Date second) {
        Calendar firstCal = GregorianCalendar.getInstance();
        Calendar secondCal = GregorianCalendar.getInstance();

        firstCal.setTime(first);
        secondCal.setTime(second);

        secondCal.add(Calendar.DAY_OF_YEAR, 1 - firstCal.get(Calendar.DAY_OF_YEAR));

        return secondCal.get(Calendar.YEAR) - firstCal.get(Calendar.YEAR);
    }

    private static class TestCase {
        public Calendar date1;
        public Calendar date2;
        public int expectedYearDiff;
        public String comment;

        public TestCase(Calendar date1, Calendar date2, int expectedYearDiff, String comment) {
            this.date1 = date1;
            this.date2 = date2;
            this.expectedYearDiff = expectedYearDiff;
            this.comment = comment;
        }
    }

    private static TestCase[] tests = {
        new TestCase(
                new GregorianCalendar(2014, Calendar.JULY, 15),
                new GregorianCalendar(2015, Calendar.JULY, 15),
                1,
                "exactly one year"),
        new TestCase(
                new GregorianCalendar(2014, Calendar.JULY, 15),
                new GregorianCalendar(2017, Calendar.JULY, 14),
                2,
                "one day less than 3 years"),
        new TestCase(
                new GregorianCalendar(2015, Calendar.NOVEMBER, 3),
                new GregorianCalendar(2017, Calendar.MAY, 3),
                1,
                "a year and a half"),
        new TestCase(
                new GregorianCalendar(2016, Calendar.JULY, 15),
                new GregorianCalendar(2017, Calendar.JULY, 15),
                1,
                "leap years do not compare correctly"),
    };

    public static void main(String[] args) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        for (TestCase t : tests) {
            int diff = getYearsBetweenDates(t.date1.getTime(), t.date2.getTime());
            String result = diff == t.expectedYearDiff ? "PASS" : "FAIL";
            System.out.println(t.comment + ": " +
                    df.format(t.date1.getTime()) + " -> " +
                    df.format(t.date2.getTime()) + " = " +
                    diff + ": " + result);
        }
    }
}
SnakE
  • 2,355
  • 23
  • 31
  • There was a bug related to days being one-based. But this also doesn't work well with leap years. Please see my edit. – SnakE Aug 25 '17 at 18:24
1

a handy one if you don't want to border Calendar, Locale, or external library:

private static SimpleDateFormat YYYYMMDD = new SimpleDateFormat("yyyyMMdd");
public static Integer toDate8d(Date date) {
    String s;
    synchronized (YYYYMMDD) { s = YYYYMMDD.format(date); }  // SimpleDateFormat thread safety
    return Integer.valueOf(s);
}
public static Integer yearDiff(Date pEarlier, Date pLater) {
    return (toDate8d(pLater) - toDate8d(pEarlier)) / 10000;
}
Bee Chow
  • 508
  • 1
  • 4
  • 15
  • Any advantage over the one-liner by Basil Bourque? I recommend staying away form `SImpleDateFormat`, it’s a notorious troublemaker of a class. And converting to an `int` the numerical value if which makes no sense? Me don’t like. – Ole V.V. May 27 '21 at 17:52
  • comparing to Basil's is mainly the learning curve of java.time cos not everyone would have much time to spend on studying; SimpleDateFormat is only by design to be minimal and not for multithreading so many people may hit issues if they are not aware. This can be easily resolved by a simple synchironized block; this int solution move the logic computation from partially-library to simple maths computation wich is in fact not complex. This is of least use of library it don't even need to involve Calendar class; this is intuitive and easy to understand. – Bee Chow Sep 12 '21 at 12:23
1

I know you have asked for a clean solution, but here are two dirty once:

        static void diffYears1()
{
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
    Calendar calendar1 = Calendar.getInstance(); // now
    String toDate = dateFormat.format(calendar1.getTime());

    Calendar calendar2 = Calendar.getInstance();
    calendar2.add(Calendar.DAY_OF_YEAR, -7000); // some date in the past
    String fromDate = dateFormat.format(calendar2.getTime());

    // just simply add one year at a time to the earlier date until it becomes later then the other one 
    int years = 0;
    while(true)
    {
        calendar2.add(Calendar.YEAR, 1);
        if(calendar2.getTimeInMillis() < calendar1.getTimeInMillis())
            years++;
        else
            break;
    }

    System.out.println(years + " years between " + fromDate + " and " + toDate);
}

static void diffYears2()
{
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
    Calendar calendar1 = Calendar.getInstance(); // now
    String toDate = dateFormat.format(calendar1.getTime());

    Calendar calendar2 = Calendar.getInstance();
    calendar2.add(Calendar.DAY_OF_YEAR, -7000); // some date in the past
    String fromDate = dateFormat.format(calendar2.getTime());

    // first get the years difference from the dates themselves
    int years = calendar1.get(Calendar.YEAR) - calendar2.get(Calendar.YEAR);
    // now make the earlier date the same year as the later
    calendar2.set(Calendar.YEAR, calendar1.get(Calendar.YEAR));
    // and see if new date become later, if so then one year was not whole, so subtract 1 
    if(calendar2.getTimeInMillis() > calendar1.getTimeInMillis())
        years--;

    System.out.println(years + " years between " + fromDate + " and " + toDate);
}
Ma99uS
  • 10,605
  • 8
  • 32
  • 42
0
// int year =2000;  int month =9 ;    int day=30;

    public int getAge (int year, int month, int day) {

            GregorianCalendar cal = new GregorianCalendar();
            int y, m, d, noofyears;         

            y = cal.get(Calendar.YEAR);// current year ,
            m = cal.get(Calendar.MONTH);// current month 
            d = cal.get(Calendar.DAY_OF_MONTH);//current day
            cal.set(year, month, day);// here ur date 
            noofyears = y - cal.get(Calendar.YEAR);
            if ((m < cal.get(Calendar.MONTH))
                            || ((m == cal.get(Calendar.MONTH)) && (d < cal
                                            .get(Calendar.DAY_OF_MONTH)))) {
                    --noofyears;
            }
            if(noofyears < 0)
                    throw new IllegalArgumentException("age < 0");
             System.out.println(noofyears);
            return noofyears;
Rishi Gautam
  • 1,948
  • 3
  • 21
  • 31
0

This will work and if you want the number of years replace 12 to 1

    String date1 = "07-01-2015";
    String date2 = "07-11-2015";
    int i = Integer.parseInt(date1.substring(6));
    int j = Integer.parseInt(date2.substring(6));
    int p = Integer.parseInt(date1.substring(3,5));
    int q = Integer.parseInt(date2.substring(3,5));


    int z;
    if(q>=p){
        z=q-p + (j-i)*12;
    }else{
        z=p-q + (j-i)*12;
    }
    System.out.println("The Total Months difference between two dates is --> "+z+" Months");
keyRen
  • 37
  • 1
  • 5
  • 1
    Thanks for wanting to contribute. I tried your code with `date1 = "07-11-2015"`and `date2 = "07-01-2016"`. Expected result was 2 months, Instead I got `The Total Months difference between two dates is --> 22 Months`. It’s easier than you think to get date math wrong, and even more so when you choose poor variable names. There is a reason why people prefer and advocate the library classes. – Ole V.V. Jun 20 '18 at 12:27
0

Thanks @Ole V.v for reviewing it: i have found some inbuilt library classes which does the same

    int noOfMonths = 0;
    org.joda.time.format.DateTimeFormatter formatter = DateTimeFormat
            .forPattern("yyyy-MM-dd");
    DateTime dt = formatter.parseDateTime(startDate);

    DateTime endDate11 = new DateTime();
    Months m = Months.monthsBetween(dt, endDate11);
    noOfMonths = m.getMonths();
    System.out.println(noOfMonths);
keyRen
  • 37
  • 1
  • 5
0

If you don't want to calculate it using java's Calendar you can use Androids Time class It is supposed to be faster but I didn't notice much difference when i switched.

I could not find any pre-defined functions to determine time between 2 dates for an age in Android. There are some nice helper functions to get formatted time between dates in the DateUtils but that's probably not what you want.

dweebo
  • 3,222
  • 1
  • 17
  • 19
-2

Try this:

int getYear(Date date1,Date date2){ 
      SimpleDateFormat simpleDateformat=new SimpleDateFormat("yyyy");
      Integer.parseInt(simpleDateformat.format(date1));

      return Integer.parseInt(simpleDateformat.format(date2))- Integer.parseInt(simpleDateformat.format(date1));

    }
Benoit Garret
  • 14,027
  • 4
  • 59
  • 64