Reputation: 527
In my Python script, I pass a commandline option --before
with a date
argument, i.e.
myscript.py --before 2014-Aug-02
I then need to read it into my variable. I want to support several possible date formats, i.e. 2014-Aug-02
, 2014-08-02
, 2014-08
, ...
In my script, I have following construct to try to match the provided date format, but it looks to me very ugly. Is there a better, more elegant way to do it?
if args.before:
try:
BEFORE = datetime.datetime.strptime(args.before[0], "%Y-%b-%d")
except ValueError:
try:
BEFORE = datetime.datetime.strptime(args.before[0], "%Y-%b")
except ValueError:
try:
BEFORE = datetime.datetime.strptime(args.before[0], "%Y-%m-%d")
except ValueError:
try:
BEFORE = datetime.datetime.strptime(args.before[0], "%Y-%m")
except ValueError:
try:
BEFORE = datetime.datetime.strptime(args.before[0], "%Y")
except ValueError:
print 'time data %s does not match format' % args.before[0]
exit(1)
Upvotes: 0
Views: 352
Reputation: 121976
I would do something like:
def validate_date(datestr):
for format in ("%Y-%b-%d", "%Y-%b", ...):
try:
return datetime.datetime.strptime(datestr, format)
except ValueError:
pass
else:
print 'time data %s does not match format' % datestr
exit(1)
Then:
BEFORE = validate_date(args.before[0])
The else
block on a for
loop runs if the loop reaches an end without break
or return
, which in this case only happens if no format
ever successfully parses the datestr
.
If, like @poke, you prefer to have the function not exit
the whole script (as may not always be appropriate), you can remove exit(1)
from the function entirely (which will therefore implicitly return None
if no format
matches) and do something like:
BEFORE = validate_date(args.before[0])
if BEFORE is None:
exit(1)
You could alternatively move the whole else
block outside the function, as you might not always want it to print
anything, either.
Upvotes: 1
Reputation: 1121524
I'd personally use the dateutil
package to parse arbitrary dates:
from dateutil.parser import parse as date_parse
try:
BEFORE = date_parse(args.before[0])
except (TypeError, ValueError):
print 'time data %s does not match format' % args.before[0]
exit(1)
The dateutil
parser can handle all formats you want to support plus more.
But if you don't want to install an external dependency, then create a list of supported formats, and use a loop:
formats = ('%Y-%b-%d', '%Y-%b', '%Y-%m-%d', '%Y-%m', '%Y')
for format in formats:
try:
BEFORE = datetime.datetime.strptime(args.before[0], format)
break
except ValueError:
pass
else:
print 'time data %s does not match format' % args.before[0]
exit(1)
As soon as a working format is found, the loop is ended with a break
, otherwise the else:
suite of the for
loop is reached, and an error message is printed. Note that an else:
suite of a loop is not executed when you break out early.
Upvotes: 4
Reputation: 387557
acceptedFormats = ("%Y-%b-%d", "%Y-%b", "%Y-%m-%d", "%Y-%m", "%Y")
if args.before:
for format in acceptedFormats:
try:
before = datetime.datetime.strptime(args.before[0], format)
break
except ValueError:
pass
else:
print 'time data %s does not match format' % args.before[0]
exit(1)
Upvotes: 2