-1

I am trying to calculate the age of the person based on the date of birth and doing some logic if its over 18 years. I had my code written and it was working fine, but I stumbled upon a code I found online and I am not getting one condition in that. The code is:

public class AgeValidation {
public static void main(String[] args) {
    getAge("29-12-1999");
}

private static void getAge(String dob1) {
    SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
    Date dob;
    try {
        dob = format.parse(dob1);
        Calendar dob2 = Calendar.getInstance();
        dob2.setTime(dob);
        Calendar today = Calendar.getInstance();
        int age = today.get(Calendar.YEAR) - dob2.get(Calendar.YEAR);

        if(dob2.after(today)) {
            System.out.println("Future date not allowed");
            System.exit(0);
        }

        if (today.get(Calendar.MONTH) < dob2.get(Calendar.MONTH)) {
            System.out.println("First if condition");
            age--;
        } else if (today.get(Calendar.MONTH) == dob2.get(Calendar.MONTH)
                && today.get(Calendar.DAY_OF_MONTH) < dob2.get(Calendar.DAY_OF_MONTH)) {
            System.out.println("else if condition");
            age--;
        }

        if (age < 18) {
            System.out.println(age);
            System.out.println("Underage");
        } else {
            System.out.println(age);
            System.out.println("18 years");
            //Some logic
        }
    } catch (ParseException e) {

        e.printStackTrace();
    }
}
}

Need addressing on below points:

  1. I have added a condition if DOB year is after Current year it should not proceed.

    if(dob2.after(today)) {
        System.out.println("Future date not allowed");
        System.exit(0);
    }
    

Is it correct to use System.exit(0); or is there some better approach to stop further execution.

  1. In the code that I found online I saw a condition as

    ` if (today.get(Calendar.MONTH) < dob2.get(Calendar.MONTH))`
    

    I am not getting in which scenario will this be executed.

  2. Is there any use case in which this code will not work (I cannot think of any)

halfer
  • 19,824
  • 17
  • 99
  • 186
  • Beware of code you "stumbled on" on the Internet. It may or may not be any good. However, explaining random code from the internet to you is not within this site's purpose and guidelines. This is, in fact, a really good opportunity for you to educate yourself by stepping through the code one line at a time in your IDE debugger to see if it makes sense. Remember, the code you found may be poorly written (as this code is) so don't assume it must be right. – Jim Garrison Dec 07 '17 at 05:13
  • Hint: The code you posted is much more complex and convoluted than any competent programmer would write, _especially_ with the `java.time.*` classes available since Java 8. – Jim Garrison Dec 07 '17 at 05:15
  • *“Is it correct to use System.exit”* - IMHO, no, you should either return a `null` or "invalid value" (ie `-1`) or throw an `Exception` of some kind – MadProgrammer Dec 07 '17 at 05:41
  • 1
    `if (today.get(Calendar.MONTH) < dob2.get(Calendar.MONTH))` - it's possible that the difference between the years is `18`, but because the current month is before the `dob` month, then person won't actually, technically, be `18` years of age – MadProgrammer Dec 07 '17 at 05:44

2 Answers2

2

java.time

You should not (as in not) want to use the long outdated classes SimpleDateFormat, Date and Calendar. Especially the first is notoriously troublesome, but we have better replacements for all of them in java.time, the modern Java date and time API also known as JSR-310.

And even more so because the modern API has a method for counting years between two dates built-in. Not only is it easier to write the code, more importantly it is easier to read and understand, and you can be more sure of the correctness.

private static final DateTimeFormatter dateFormatter 
        = DateTimeFormatter.ofPattern("dd-MM-uuuu");

private static void getAge(String dob1) {
    LocalDate dob = LocalDate.parse(dob1, dateFormatter);
    LocalDate today = LocalDate.now(ZoneId.of("Asia/Dushanbe"));
    if (dob.isAfter(today)) {
        System.out.println("Future date not allowed");
    } else {
        int age = (int) ChronoUnit.YEARS.between(dob, today);

        if (age < 18) {
            System.out.println(age);
            System.out.println("Underage");
        } else {
            System.out.println(age);
            System.out.println("18 years");
            //Some logic
        }
    }
}

With your example date of "29-12-1999" the above method prints:

17
Underage

Since it is never the same date in all time zones, please substitute your desired time zone instead of Asia/Dushanbe.

between() returns a long. In this case we can safely cast it to an int because LocalDate only handles years in the range -999 999 999 through 999 999 999, so the difference in years will never exceed the capacity of int.

Your questions

  1. Use of System.exit(0); is generally questionable, though at times necessary. In my code I have avoided it using an if-else construct. Another option would be return;. I guess this would more give you what you wanted in case there were two calls to getAge() after each other. Yet another option is throwing an IllegalArgumentException, that would leave for the caller to decide to catch it or not.
  2. The line you are quoting will not be executed when running your code here in December. Imagine running your code next January, then today’s month will be January and dob2’s month will still be December, so since January is before December, the code will be executed. Which will also be necessary for your method to calculate the correct age.
  3. The code seems convoluted, as Jim Garrison said, but appears to be correct (not even with the outdated API needed it be this complex). I have not spotted a case that would not be handled correctly.

Question: Can I use the modern API with my Java version?

If using at least Java 6, you can.

For learning to use java.time, see the Oracle tutorial or find other resoureces on the net.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

I am giving you a solution which doesn't take care of leap year logic. But you can build upon this approach.

public static void main(String[] args) throws Exception{
    String date ="11_10_1991";

    SimpleDateFormat sdf = new SimpleDateFormat("dd_MM_yyyy");
    Date birthDate = sdf.parse(date);

    long ageInMillis = System.currentTimeMillis() - birthDate.getTime();

    long years = ageInMillis /(365 * 24*60*60*1000l);

    long leftover = ageInMillis %(365 * 24*60*60*1000l);
    long days = leftover/(24*60*60*1000l);

    System.out.println(years);
    System.out.println(days);

}
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Srijan Mehrotra
  • 222
  • 2
  • 10
  • 2
    Because of edged cases like leap years, leap seconds, century and millennium boundaries, it is ill advised to attempt to perform date/time calculations in this way, especially when other apis exist - hint, a year is not 365 days long and a day isn’t always 24 hours long – MadProgrammer Dec 07 '17 at 05:39
  • 1
    I read the lowercase letter `l` (ell) in `1000l` as digit 1 (one) at first. Always use uppercase `L` for long constants to avoid such confusion. – Ole V.V. Dec 07 '17 at 08:50
  • 1
    It is far from trivial to adapt your code to take care of leap years. – Ole V.V. Dec 07 '17 at 08:51
  • (A) Whipping up your own date-time handling code is a fool’s errand. Use a proven library for such work. (B) You are using troublesome old date-time classes long ago supplanted by the java.time classes. See the [correct, modern Answer](https://stackoverflow.com/a/47688553/642706) by Ole V.V. instead of this Answer. – Basil Bourque Dec 09 '17 at 08:58