Day Validation returning an error

Day Validation is always returning the illegal argument exception and never setting the day as inputed especially when trying to input 29 for february in a leap year. i've been trying to find the error for a long time now and just gave up. thanks for your help in advance.

import java.util.Calendar;

public class DateOfBirth
{
    private int day;
    private int month;
    private int year;

    private Calendar cld = Calendar.getInstance();

    public DateOfBirth()
    {
        this(0,0,0);
    } 
    public DateOfBirth(int a,int b,int c)
    {
        setDay(c);
        setMonth(a);
        setYear(b);
    }
    public void setDay(int a)
    {
        if( getMonth()==2 && (getYear() % 4 == 0 && (getYear() % 100 != 0 || getYear() % 400 == 0))&& a == 29)
             day = a;
        else if(getMonth() == 2 && a <= 28)
            day = a;
        else if(getMonth() == 1 || getMonth() == 3 || getMonth() == 5 || getMonth() ==  7 || getMonth() ==  8 || getMonth() ==  10 || getMonth() == 12 && a < 31)
            day = a;
        else if(getMonth() == 4 || getMonth() == 6 || getMonth() == 9 || getMonth() == 11 && a < 30)
            day = a;
        else
            throw new IllegalArgumentException("Day Out Of Bounds.");
    }
    public void setMonth(int b)
    {
        if( b > 0 && b <= 12)
            month = b;
        else
            throw new IllegalArgumentException("Month Out of Bounds.");
    }
    public void setYear(int c)
    {
        if( c > (cld.get(Calendar.YEAR) - 150) && c < cld.get(Calendar.YEAR))
            year = c;
        else
            throw new IllegalArgumentException("Year Out of Bounds.");
    }
    public int getDay()
    {
        return day;
    }
    public int getMonth()
    {
        return month;
    }
    public int getYear()
    {
        return year;
    }
    @Override
    public String toString()
    {
        return String.format("Date Of Birth: %02d/%02d/%d",getDay(),getMonth(),getYear());
    }
}
Jon Skeet
people
quotationmark

You're calling setDay first, before you call setMonth or setYear... which means setDay doesn't know which month and year you're talking about. It can't possibly validate that the day is correct without that information.

You could just switch the order of the setter calls:

setYear(b);
setMonth(a);
setDay(c);

However:

  • Your parameterless constructor tries to set an invalid value (day=0, month=0 - what?) so what's the point of having it?
  • You should definitely rename your constructor parameters to be meaningful (how is anyone meant to know that b represents the year, for example?)
  • Being able to set each property individually makes this fragile... for example, you could set the month to January, the day to 30, then the month to February... all without any validation errors, leaving you with February 30th. That's basically what's happening at the moment in your constructor, but you could do that from outside, too.

I would suggest that you make your class immutable if at all possible. Then you just need to validate in the constructor. Consider refactoring it to:

// TODO: Think of a decent name. Not DateOfBirth because it's just representing
// a date, and not Date as that conflicts with java.util.Date.
public final class GregorianDate {
    private final int year, month day;

    public GregorianDate(int year, int month, int day) {
        validate(year, month, day);
        this.year = year;
        this.month = month;
        this.day = day;
    }

    private static void validate(int year, int month, int day) {
        // TODO: The validation
    }

    // getters, toString, hashCode, equals, and possibly implement
    // Comparable<GregorianDate> too.
}

Of course, this is assuming this is just an exercise - normally you'd use appropriate date/time APIs that are already provided to you - ideally avoiding java.util.Date/Calendar and using Joda Time or the Java 8 java.time API.

people

See more on this question at Stackoverflow