Speeding up datetime.strptime
datetime, profiling, python, python-2.7, strptime
Solution
Yes, there are faster methods to parse a date than `datetime.strptime()`, if you forgo a lot of flexibility and validation. `strptime()` allows both numbers with and without zero-padding, and it only matches strings that use the right separators, whilst your 'ugly' version doesn't.
You should always use the `timeit` module for time trials, it is far more accurate than `cProfile` here.
Indeed, your 'ugly' approach is twice as fast as `strptime()`:
>>> from datetime import date, datetime
>>> import timeit
>>> def ugly(input_date):
... a= 1000 * int(input_date[0])
... b= 100 * int(input_date[1])
... c= 10 * int(input_date[2])
... d= 1 * int(input_date[3])
... year = a+b+c+d
... c= 10 * int(input_date[5])
... d= 1 * int(input_date[6])
... month = c+d
... c= 10 * int(input_date[8])
... d= 1 * int(input_date[9])
... day = c+d
... try:
... my_date = date(year, month, day)
... except ValueError:
... my_date = None
...
>>> def strptime(input_date):
... try:
... my_date = datetime.strptime(input_date, "%Y-%m-%d").date()
... except ValueError:
... my_date = None
...
>>> timeit.timeit('f("2014-07-08")', 'from __main__ import ugly as f')
4.21576189994812
>>> timeit.timeit('f("2014-07-08")', 'from __main__ import strptime as f')
9.873773097991943
Your approach can be improved upon though; you could use slicing:
>>> def slicing(input_date):
... try:
... year = int(input_date[:4])
... month = int(input_date[5:7])
... day = int(input_date[8:])
... my_date = date(year, month, day)
... except ValueError:
... my_date = None
...
>>> timeit.timeit('f("2014-07-08")', 'from __main__ import slicing as f')
1.7224829196929932
Now it is almost 6 times faster. I also moved the `int()` calls into the `try` - `except` to handle invalid input when converting strings to integers.
You could also use `str.split()` to get the parts, but that makes it slightly slower again:
>>> def split(input_date):
... try:
... my_date = date(*map(int, input_date.split('-')))
... except ValueError:
... my_date = None
...
>>> timeit.timeit('f("2014-07-08")', 'from __main__ import split as f')
2.294667959213257
Problem
I am using the following piece of code to extract a date from a string: ``` try: my_date = datetime.strptime(input_date, "%Y-%m-%d").date() except ValueError: my_date = None ``` If I run this 750,000 times, it takes 19.144 seconds (determined with cProfile). Now I replace this with the following (ugly) code: ``` a= 1000 * int(input_date[0]) b= 100 * int(input_date[1]) c= 10 * int(input_date[2]) d= 1 * int(input_date[3]) year = a+b+c+d c= 10 * int(input_date[5]) d= 1 * int(input_date[6]) month = c+d c= 10 * int(input_date[8]) d= 1 * int(input_date[9]) day = c+d try: my_date = date(year, month, day) except ValueError: my_date = None ``` If I run this 750,000 times, it only takes 5.946 seconds. However, I find the code really ugly. Is there another fast way to extract a date from a string, without using strptime?