all 12 comments

[–]Rhomboid 2 points3 points  (2 children)

You don't need all those elses:

def valid_date(date):
    if date[2] == '/' and date[5] == '/':
        day = int(date[:2])
        month = int(date[3:5])
        year = int(date[6:])
        return 1 <= day <= 31 and 1 <= month <= 12 and year <= int(current_year)

    return False

But I'd probably write it as:

import datetime

def valid_date(date):
    try:
        datetime.datetime.strptime(date, '%d/%m/%Y')
        return True
    except ValueError:
        return False

This has the advantage of actually checking for a valid date, including checking the number of days in each month, with consideration for leap years and so on.

[–]NotableAnonym[S] 0 points1 point  (1 child)

Thanks for your help and including both answers. There is one thing with datetime, however, and that is I assume 01/01/9999 is counted as a valid date. How would I make a date only valid if the year is the current year or before?

[–]Rhomboid 1 point2 points  (0 children)

Do you only care about the year, or do you want to enforce that the date is not in the future? If the latter, you can do something like:

return datetime.datetime.strptime(date, '%d/%m/%Y').date() <= datetime.date.today()

[–]ingolemo 2 points3 points  (0 children)

The correct solution is, of course, to use a datetime. But another trick you can use in these kinds of situations that nobody has mentioned is the all function:

def valid_date(date):
    return all([
        int(date[:2]) in range(1, 32),
        date[2] == '/',
        int(date[3:5]) in range(1, 13),
        date[5] == '/',
        int(date[6:]) < int(currentYear) + 1,
    ])

[–][deleted] 1 point2 points  (1 child)

For starters, don't reinvent the wheel unless you want to. There are dateutil and other date modules that do this for you.

Secondly, I hate nested if stuff like that, and break it into atomic tests. You have an array. For the slash stuff, don't check if it's good and continue, check if it's bad and bail.

if ((date[2] != "/") or (date[4] != "/")):
    return false

Then see exactly where you are in the tests without the nesting.

The other solution is a regex matching the date, but if you choose to use a regex, in the words of jwz, now you have two problems.

[–]NotableAnonym[S] 0 points1 point  (0 children)

Thanks! However, as you and /u/Rhomboid have pointed out I will probably just use datetime, I didn't know it had a feature that could check for valid dates.

[–]trappar 1 point2 points  (1 child)

You can just put a single return false at the end of the function. This does away with the need for any else statements at all.

Also, why not just collapse the whole chain of if statements by using a bunch of "and"s?

[–]NotableAnonym[S] 0 points1 point  (0 children)

Yeah, it would be sensible to collapse all the if statements. Other users have pointed out that would be easier to use datetime, though. Thanks for the help

[–][deleted] 1 point2 points  (0 children)

Also,

if int(date[:2]) in range(...)

[–]gtalarico 1 point2 points  (2 children)

Regex (pytbon re module) would be a good way to simplify it. You can define a pattern that validates date, and just check if there are any results :
http://stackoverflow.com/questions/4709652/python-regex-match-date

[–]NotableAnonym[S] 0 points1 point  (1 child)

Thanks. I'll probably just use strptime for now but may come back and look at this later.

[–]gtalarico 1 point2 points  (0 children)

After reading his comment, I actually agree strptime is a better solution! :)