Search code examples
javaexceptiondateintrestrict

Java. Restricting the values for a Date


It might seem like a stupid question to you guys, but I'm a java noob and still trying to grasp the whole concept. So, I basically have a simple theatre management system that allows me to add groups to the database. To each group, you can add students that each have a unique student ID and a name. You can also add rehearsal dates to a group. Both of these are stored in separate linked lists. This is my rehearsal object:

public Rehearsal(int d, int m, int y) {
    day = d;
    month = m;
    year = y;
}

This is the addRehearsal method in the group class:

public void addRehearsal(int d, int m, int y) {
    Rehearsal newrehearsal = new Rehearsal(d, m, y);
    if (!RehearsalDates.contains(newrehearsal)) {
        RehearsalDates.add(newrehearsal);
    }
    else
        JOptionPane.showMessageDialog(null, "Rehearsal already exists for this group!", "Error", JOptionPane.WARNING_MESSAGE);
}

My question is, how and where can I restrict what values can be entered. That means, that the program gives an error in the form of a message dialog if the value entered for int d > 31 or int m > 12. This is not really necessary for the year, as the user is allowed to create rehearsal dates for the past as well as the future.

Thanks for your help guys :)


Solution

  • Validating dates is more complex than checking each parameter. For example, calling it with (29, 2, 2000) would be invalid (recall that 2000 was not a leap year), even though all parameters are "within range".

    The only sane way to check is to attempt to parse a Date from the parameters and catch the exception. There are a couple of ways to do this, but the simplest is this:

    public Rehearsal(int d, int m, int y) {
        try {
            sdf = new SimpleDateFormat("d-M-yyyy");
            sdf.setLenient(false);
            sdf.parse(d + "-" + m + "-" + y);
        } catch (ParseException e) {
            // the parameters are not valid
        }
        // rest of code
    }
    

    Note the call to setLenient(), which is required, otherwise invalid input "rolls over" to the next available valid date - for example 36-12-2012 would be parsed as 05-01-2013.

    The best place to put this code would be in the constructor, throwing an exception:

    public Rehearsal(int d, int m, int y) {
        try {
            sdf = new SimpleDateFormat("d-M-yyyy");
            sdf.setLenient(false);
            sdf.parse(d + "-" + m + "-" + y);
        } catch (ParseException e) {
            // the parameters are not valid
            throw new IllegalArgumentException();
        }
        day = d;
        month = m;
        year = y;
    }
    

    And you would catch this wherever it is called.

    Rehearsal newrehearsal;
    try {
        newrehearsal = new Rehearsal(1, 2, 3);            
    } catch (IllegalArgumentException ex) {
        JOptionPane.showMessageDialog(null, "Invalid date input!", "Error", JOptionPane.WARNING_MESSAGE);
        return;
    }
    // rest of method
    

    An even better design would be to pass a Date object, putting the onus on the caller to validate input, and there would be less throw and catch code.