Validating date (both format and value)

Go To StackoverFlow.com

1

I read this and got really interested: Validating date format using regular expression

so I started writing my own version of the date validation function, I think I am close, but not quite, and I would like some suggestion as well as tips. I have spend a lot of time trying to tweak the function.

import re
import datetime

# Return True if the date is in the correct format
def checkDateFormat(myString):
    isDate = re.match('[0-1][0-9]\/[0-3][0-9]\/[1-2][0-9]{3}', myString)
    return isDate

# Return True if the date is real date, by real date it means,
# The date can not be 00/00/(greater than today)
# The date has to be real (13/32) is not acceptable
def checkValidDate(myString):
    # Get today's date
    today = datetime.date.today()
    myMaxYear = int(today.strftime('%Y'))

    if (myString[:2] == '00' or myString[3:5] == '00'):
        return False

    # Check if the month is between 1-12
    if (int(myString[:2]) >= 1 or int(myString[:2]) <=12):
        # Check if the day is between 1-31
        if (int(myString[3:5]) >= 1 or int(myString[3:2]) <= 31):
            # Check if the year is between 1900 to current year
            if (int(myString[-4:]) <= myMaxYear):
                return True
    else:
        return False

testString = input('Enter your date of birth in 00/00/0000 format: ')

# Making sure the values are correct
print('Month:', testString[:2])
print('Date:', testString[3:5])
print('Year:', testString[-4:])

if (checkDateFormat(testString)):
    print('Passed the format test')
    if (checkValidDate(testString)):
        print('Passed the value test too.')
    else:
        print('But you failed the value test.')
else:
    print("Failed. Try again")

Question 1: Is there other way (better) to do int(myString[3:5]) when I want to compare if it is valid? I feel my method is very repetitive, and this function must require 00/00/0000, otherwise it will break. So the function isn't all that useful in that sense. Especially the way I handle my 00/01/1989, it is just simply comparing if they are indeed 00.

Question 2: There are many if statement, I wonder are there better way to write this test?

I would like to learn more about programming in python, any suggestion or advice will be greatly appreciated. Thank you very much.

2012-04-03 22:51
by George


3

Like many things in python there's already underlying capabilities to check dates. Assuming you aren't just doing this as an academic exercise the most straightforward way to validate a date is to try and create it.

import datetime

minyear = 1900
maxyear = datetime.date.today().year

mydate = '12/12/2000'
dateparts = mydate.split('/')
try:
    if len(dateparts) != 3:
       raise ValueError("Invalid date format")
    if int(dateparts[2]) > maxyear or int(dateparts[2]) < minyear:
       raise ValueError("Year out of range")
    dateobj = datetime.date(int(dateparts[2]),int(dateparts[1]),int(dateparts[0]))
except:
    // handle errors

if datetime.date is given an invalid date it will complain, eg:

datetime.date(2000,45,23)

Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    datetime.date(2000,45,23)
ValueError: month must be in 1..12
2012-04-03 23:12
by SpliFF
I am trying to write this as a programming exercise. I think your implementation is cleaner, I like the spiting in list (dateparts), it makes the counting less messy. I will look up the try: except, seems like it is what I should use instead of if statements. Thank you.

And does the datetime.date() do everything I write and then more - George 2012-04-03 23:18

Yes, It's generally considered cleaner in python to handle exceptions rather than try to anticipate them. You should also look at the meaning of except ValueError: which allows you to target certain classes of errors. datetime.date() creates a date object, if you pass it invalid values for year, month or day it will raise an exception - SpliFF 2012-04-03 23:23
I guess I didn't pick the best practice problem, but thank you for teaching me to use the try: and except: ValueError. Thank you - George 2012-04-04 00:05


1

I understand there's some value in academic exercises. I wouldn't discourage them.

I also think a big part of learning Python is discovering which problems have already been solved. There are several reasons I think this way. First, I think it's a waste of time to re-invent the wheel. Also I get a chance to study code and different approaches to solving problems. Finally, I think a long-standing solution is less likely to be naive about quirks in the subject matter.

With that in mind, I recommend the dateutil library.

2013-04-25 13:53
by user1330086
I see, thanks for the suggestion on the dateutil module! I am just trying to practice my python code : - George 2013-04-25 14:11


1

from dateutil.parser import *
parse("1993-09-01")
datetime.datetime(1993, 9, 1, 0, 0)

If the format is not proper, then it will raise a ValueError, you can use try.. catch to catch them so that the application does not close unexpectedly.

2014-07-31 16:22
by Pawan Kumar


1

Based on some answers above I wrote this short piece of code which validates date to in the format: DD/MM/YYYY.

date = "29/02/2016"

min_year = 1900
max_year = min_year + 200

days_31 = ['01', '03', '05', '07', '08', '10', '12']
days_30 = ['04', '06', '10', '11']
days_28 = ['02']

month_dict = {'01':'January',
      '02':'February',
      '03':'March',
      '04':'April',
      '05':'May',
      '06':"June",
      '07':'July',
      '08':'August',
      '09':'September',
      '10':'October',
      '11':'November',
      '12':'December'}

def validate(day, month, leap_year_or_not):
    if leap_year_or_not:
        max_day = 29
    else:
        max_day=28
    if month in days_28:
        if day > max_day:
            print "Invalid day: %s for month %s" %(day, month_dict[month])
            return False
        else:
            return True
    elif month in days_30:
        if day > 30:
            print "Invalid day: %s for month %s" %(day, month_dict[month])
            return False
        else:
            return True
    elif month in days_31:
        if day <= 31:
            return True
        else:
            print "Invalid day: %s for month %s" %(day, month_dict[month])
            return False
    else:
        print "Invalid month:%s, Invalid day:%s" %(month, day)
        return False

if len(date)!= 10:
    print "Invalid Format. Please enter date in DD/MM/YYYY"
else:
    day, month, year = date.split("/")
    if len(day) != 2:
        print "Length of day in not 2. Please enter day as 01 for first!" 
    elif len(month) != 2:
        print "Length of month in not 2. Please enter month as 01 for January!"
    elif len(year) != 4:
        print "Length of year in not 4. Please enter year as 2001!"
    else:
        day=int(day)
        month=int(month)
        year=int(year)
        if day < 1 or day > 31:
            print "Day %s is not in range [1-31]" %str(day)
        else:
            if month < 1 or month > 12:
                print "Month %s is not in range [1-12]" %str(month)
            else:
                if year < min_year or year > max_year:
                    print "Year is not in range [%s-%s]" (str(min_year), str(max_year))
            else:
                if year%4 == 0:
                    leap_year = True
                else:
                    leap_year = False
                valid_day_month = validate(day, str(month).zfill(2), leap_year)
2016-11-02 15:38
by mhdaimi


-1

import time
import datetime
self.date = raw_input('Enter the date to travel in (yyyy-mm-dd) format: ')
try:
    valid_date = time.strptime(self.date, '%Y-%m-%d')
    today_date=str(datetime.date.today())
    if self.date<today_date:
        print "date got over"
    else:
        print " "
except ValueError:
print('Invalid date!')
2015-01-09 03:11
by Ayushraj