Given:
from datetime import datetime
date = datetime.strptime('Wed 12 Nov', '%a %d %b')
It returns datetime.datetime(1900, 11, 12, 0, 0). What might be the best way to get the greatest past year?, in this case should 2014 instead of 1900.
Any help will be appreciate.
You can get the year from datetime.now() and subtract 1:
from datetime import datetime
date = datetime.strptime('Wed 12 Nov {}'.format(datetime.now().year-1), '%a %d %b %Y')
This will not work for feb 29.
Actually a bug in the first implementation, it was starting on a monday because 12 November 1900 was a Monday:
dte = 'Wed 12 Nov'
start = datetime.strptime('Wed 12 Nov', "%a %d %b")
greatest = None
while start <= datetime.now():
start += timedelta(days=1)
if start.strftime("%a %d %b") == dte:
greatest = start
print(greatest)
2014-11-12 00:00:00
There is also a monthdelta package that you can use to increment by month:
from datetime import datetime
from monthdelta import monthdelta
dte = 'Wed 12 Nov'
start = datetime.strptime('Wed 12 Nov', "%a %d %b")
greatest = None
while start <= datetime.now():
start += monthdelta(1)
if start.strftime("%a %d %b") == dte:
greatest = start
print(greatest)
You can see incrementing by months is much more efficient:
In [1]: from datetime import datetime, timedelta
In [2]: %%timeit
...: dte = 'Wed 12 Nov'
...: start = datetime.strptime('Wed 12 Nov', "%a %d %b")
...: greatest = None
...: while start <= datetime.now():
...: start += timedelta(days=1)
...: if start.strftime("%a %d %b") == dte:
...: greatest = start
...:
1 loops, best of 3: 382 ms per loop
In [3]: from datetime import datetime
In [4]: from monthdelta import monthdelta
In [5]: %%timeit
...: dte = 'Wed 12 Nov'
...: start = datetime.strptime('Wed 12 Nov', "%a %d %b")
...: greatest = None
...: while start <= datetime.now():
...: start += monthdelta(1)
...: if start.strftime("%a %d %b") == dte:
...: greatest = start
...:
100 loops, best of 3: 18.7 ms per loop
Both return pretty quick but if you had many calls to the method then the monthly increase is a better option. We could also add 30 days and then set the day to 12, there may be bugs as I have not overly tested it:
def match_date(abb_wk_dy, day_date, abb_mon):
dte = "{} {} {}".format(abb_wk_dy.capitalize(), day_date, abb_mon.capitalize())
start = datetime.strptime(dte, "%a %d %b")
greatest = None
while start <= datetime.now():
start += timedelta(days=30)
start = start.strptime("{} {} {}".format(start.year, start.month, day_date), "%Y %m %d")
if start.strftime("%a %d %b") == dte:
greatest = start
return greatest
The last code runs pretty efficiently:
In [12]: timeit match_date("wed","12","nov")
10 loops, best of 3: 34.7 ms per loop
If you only want the year then return greatest.year.
On testing the above code fails for leap years so we need to catch that, we can also just increase the year by 1 each time:
def match_date(abb_wk_dy, day_date, abb_mon):
wkd, dd, ab = abb_wk_dy.capitalize(), day_date, abb_mon.capitalize()
match = "{} {} {}".format(wkd, dd, ab)
try:
dte = "{} {} {} {}".format(1900, wkd, dd, ab)
start = datetime.strptime(dte, "%Y %a %d %b")
except ValueError:
# first leap year since 1900
dte = "{} {} {} {}".format(1904, wkd, dd, ab)
start = datetime.strptime(dte, "%Y %a %d %b")
day, mon = start.day, start.month
greatest = None
while start <= datetime.now():
try:
start = start.strptime("{} {} {}".format(start.year + 1, mon, day), "%Y %m %d")
except ValueError:
start = start.strptime("{} {} {}".format(start.year + 1, 01, 01), "%Y %m %d")
continue
if start.strftime("%a %d %b") == match:
greatest = start
return greatest.year if greatest else "No match"
Which runs in:
In [27]: timeit match_date("Wed","12","Nov")
100 loops, best of 3: 2.63 ms per loop
You would also need to validate that no day > 31 is ever entered and other months and days match up which could be achieved using a dict or calender.monthrange or a dict mapping max day in month to month name.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With