Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python, date validation

I'm trying to think of a way to accomplish this in the best pythonic way possible. Right now the only method I can think of is to brute force it.

User inputs a date (via command line) in one of the following manners (ex. ./mypy.py date='20110909.00 23' )

date='20110909'
date='20110909.00 23'
date='20110909.00 20110909.23'

All three examples should have the same result, it doesn't matter if it populates a list (which I can sort) such as

['20110909.00', '20110909.23]

or even two sorted separate variables, but in all cases it's YYYYMMDD.HH, and needs to make sure it is indeed a date and not text.

Any ideas?

Thank you.

+++++ EDIT +++++ After plugging away at this, I'm thinking I needed to do a lot of date checking/manipulating first. Which all seems to be working just great. Except at the very end I run the list through the date validation and it fails every time - even when it should be passing.

(I launch it with) ./test.py date='20110909.00 23'

(or any variation of date - i.e. date='20 22' or date='20110909' or date='20110909.00 23' etc.)

import sys, re, time, datetime

now = datetime.datetime.now()
tempdate=[]
strfirstdate=None
strtempdate=None

temparg2 = sys.argv
del temparg2[0]
tempdate = temparg2[0].replace('date=','')
date = tempdate.split(' ');

tempdate=[]
date.sort(key=len, reverse=True)
result = None

# If no date is passed then create list according to [YYMMDD.HH, YYMMDD.HH]
if date[0] == 'None':
    tempdate.extend([now.strftime('%Y%m%d.00'), now.strftime('%Y%m%d.%H')])


# If length of date list is 1 than see if it is YYMMDD only or HH only, and create list according to [YYMMDD.HH, YYMMDD.HH]
elif len(date) == 1:
    if len(date[0]) == 8:
        tempdate.extend([ date[0] + '.00', date[0] + '.23'])
    elif len(date[0]) == 2:
        tempdate.extend([now.strftime('%Y%m%d') + '.' + date[0], now.strftime('%Y%m%d') + '.' + date[0]])
    else:
        tempdate.extend([date[0], date[0]])


# iterate through list, see if value is YYMMDD only or HH only or YYYYMMDD.HH, and create list accoring to [YYYYMMDD.HH, YYYYMMDD.HH] - maximum of 2 values
else:
    for _ in range(2):
        if len(date[_]) == 8:
            strfirstdate = date[0]
            tempdate.append([ date[_] + '.00'])
        elif len(date[_]) == 2:
            if _ == 0:  # both values passed could be hours only
                tempdate.append(now.strftime('%Y%m%d') + '.' + date[_])
            else:  # we must be at the 2nd value passed.
                if strfirstdate == None:
                    tempdate.append(now.strftime('%Y%m%d') + '.' + date[_])
                else:
                    tempdate.append(strfirstdate + '.' + date [_])
        else:
            strfirstdate = date[0][:8]
            tempdate.append(date[_])

tempdate.sort()


for s in tempdate:
    try:
        result = datetime.datetime.strptime(s, '%Y%m%d.%H')
    except:
        pass

if result is None:
    print 'Malformed date.'
else:
    print 'Date is fine.'

print tempdate

++++ Edit 2 ++++ If I remove the bottom part (after tempdate.sort()) and replace it with this.

strfirstdate = re.compile(r'([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]+\.[0-9][0-9])')
for s in tempdate:
    if re.match(strfirstdate, s):
        result = "validated"
    else:
        print "#####################"
        print "#####################"
        print "##  error in date  ##"
        print "#####################"
        print "#####################"
        exit

It will validate appropriately.

This entire method just doesn't seem to be very pythonic.

like image 233
Chasester Avatar asked Feb 24 '23 00:02

Chasester


2 Answers

You can create a mask and parse it, using try...except to determine whether the date string matches one of the many masks. I had this code for a project, so I've slightly modified it:

from time import mktime, strptime
from datetime import datetime

date = '20110909.00 20110909.23'.split(' ')[0]
result = None

for format in ['%Y%m%d', '%Y%m%d.%H']:
  try:
    result = datetime.strptime(date, format)
  except:
    pass

if result is None:
  print 'Malformed date.'
else:
  print 'Date is fine.'
like image 136
Blender Avatar answered Feb 25 '23 14:02

Blender


I found some problems when I attempted to use the try..except code example in my own parsing so here's a version with the fixes I added, and I also addressed the question of handling only the hour part:

from datetime import datetime

dates = ['20110909.00','20110909.23','13','20111212','20113131']

def dateTest(date):
  dateOk = False
  for format in ['%Y%m%d', '%Y%m%d.%H', '%H']:
    try:
      result = datetime.strptime(date, format)
      dateOk = (date == result.strftime(format)) # this makes sure the parsed date matches the original string
      if format == '%H': # this handles the hour only case
        date = '%s.%s' % (datetime.now().strftime('%Y%m%d'), date)
    except:
      pass

  if dateOk:
    print 'Date is fine.'
  else:
    print 'Malformed date.'
  return date

for date in dates:
  print date
  print dateTest(date)
  print ''
like image 30
TheDavidFactor Avatar answered Feb 25 '23 15:02

TheDavidFactor