87

Im trying to write a python program that I will run at the command line. I'd like the program to take a single input variable. Specifically, I would use a date in the form of 2014-01-28 (yyyy-mm-dd):

e.g. python my_script.py 2014-01-28

It seems argparse might be able to help me but I have found very little documentation regarding the module. Does anyone have experience with something like this?

Stevoisiak
  • 23,794
  • 27
  • 122
  • 225
Chase CB
  • 1,561
  • 1
  • 13
  • 20

2 Answers2

121

There's lots of documentation in the standard library, but generally, something like:

import argparse
import datetime

parser = argparse.ArgumentParser()
parser.add_argument(
        'date',
        type=lambda s: datetime.datetime.strptime(s, '%Y-%m-%d'),
)

# For testing.  Pass no arguments in production
args = parser.parse_args(['2012-01-12'])
print(args.date) # prints datetime.datetime object
Jason
  • 9,408
  • 5
  • 36
  • 36
mgilson
  • 300,191
  • 65
  • 633
  • 696
  • basically i could replace args with sys.argv[1]? – Chase CB Jan 29 '14 at 17:00
  • 1
    @ChaseCB -- If you pass a list to `parse_args`, it will be used as if those arguments were passed on the command line. Under normal circumstances (if you don't pass anything) `argparse` uses `sys.argv[1:]`. See http://docs.python.org/dev/library/argparse.html#argparse.ArgumentParser.parse_args – mgilson Jan 29 '14 at 17:01
  • `parser.parse_args('this is a test string'.split())` is another test option. It's equivalent to `parse_args(['this','is',...])`, and in a few edge conditions better. – hpaulj Jan 29 '14 at 18:37
  • @hpaulj -- better? I can't think of any way that it's better unless your argument is "it saves you some typing"... – mgilson Jan 29 '14 at 20:37
  • I must have been mis-remembering how `choices` are best defined. The real reason I favor `split` is it can save typing. `shlex.split` would be a better choice if I wanted to simulate how the shell creates `sys.argv` – hpaulj Jan 29 '14 at 22:44
  • One way in which `split` is more like `sys.argv` is in string identity. `['test','string'][0] is 'test'` is `True`. `'test string'.split()[0] is 'test'` is `False`. Fortunately `argparse` only uses the `is` test once, and it probably shouldn't do so even there. http://bugs.python.org/issue18943 – hpaulj Feb 11 '14 at 19:48
  • That's strangely interesting... Thanks for pointing that out (although I still don't think I'll be writing my tests with `str.split` ;-) – mgilson Feb 11 '14 at 20:07
98

As of Python 3.7, a (marginally) more convenient option is fromisoformat: https://docs.python.org/3/library/datetime.html#datetime.date.fromisoformat

Using it, you can replace the relevant line in mgilson's code with this:

parser.add_argument('date', type=datetime.date.fromisoformat)

(I would also add a help argument to this invocation of add_argument, and mention that the input should be in ISO format.)

rescdsk
  • 8,739
  • 4
  • 36
  • 32
Damien
  • 1,155
  • 7
  • 7
  • 1
    To get both date and time use `parser.add_argument('date', type=datetime.datetime.fromisoformat, help='ISOformat - YYYY-MM-DD:HH:mm:ss')` – ImranRazaKhan May 10 '23 at 15:43