Reputation: 1395
I'm looking to compare a list of dates with todays date and would like to return the closest one. Ive had various ideas on it but they are seem very convoluted and involve scoring based on how many days diff and taking the smallest diff. But I have no clue how to do this simply any pointers would be appreciated.
import datetime
import re
date_list = ['2019-02-10', '2018-01-13', '2019-02-8',]
now = datetime.date.today()
for date_ in date_list:
match = re.match('.*(\d{4})-(\d{2})-(\d{2}).*', date_)
if match:
year = match.group(1)
month = match.group(2)
day = match.group(3)
delta = now - datetime.date(int(year), int(month), int(day))
print(delta)
As I was Waiting EDIT
So I solved this using the below
import datetime
import re
date_list = ['2019-02-10', '2018-01-13', '2019-02-8',]
now = datetime.date.today()
for date_ in date_list:
match = re.match('.*(\d{4})-(\d{2})-(\d{2}).*', date_)
if match:
year = match.group(1)
month = match.group(2)
day = match.group(3)
delta = now - datetime.date(int(year), int(month), int(day))
dates_range.append(int(delta.days))
days = min(s for s in dates_range)
Upvotes: 1
Views: 2703
Reputation: 17322
one fast and simple way will be to use bisect algorithm, especially if your date_list is significantly big :
import datetime
from bisect import bisect_left
FMT = '%Y-%m-%d'
date_list = ['2019-02-10', '2018-01-13', '2019-02-8', '2019-02-12']
date_list.sort()
def closest_day_to_now(days):
"""
Return the closest day form an ordered list of days
"""
now = datetime.datetime.now()
left_closest_day_index = bisect_left(days, now.strftime(FMT))
# check if there is one greater value
if len(days) - 1 > left_closest_day_index:
right_closest_day_index = left_closest_day_index + 1
right_day = datetime.datetime.strptime(days[right_closest_day_index], FMT)
left_day = datetime.datetime.strptime(days[left_closest_day_index], FMT)
closest_day_index = right_closest_day_index if abs(right_day - now) < abs(left_day - now) \
else left_closest_day_index
else:
closest_day_index = left_closest_day_index
return days[closest_day_index]
print(closest_day_to_now(date_list))
Upvotes: 0
Reputation: 5686
Python's inbuilt datetime module has the functionality to do what you desire.
Let's first take your list of dates and convert it into a list of datetime objects:
from datetime import datetime
date_list = ['2019-02-10', '2018-01-13', '2019-02-8']
datetime_list = [datetime.strptime(date, "%Y-%m-%d") for date in date_list]
Once we have this we can find the difference between those dates and today's date.
today = datetime.today()
date_diffs = [abs(date - today) for date in datetime_list]
Excellent, date_diffs
is now a list of datetime.timedelta
objects. All that is left is to find the minimum and find which date this represents.
To find the minimum difference it is simple enough to use min(date_diffs)
, however, we then want to use this minimum to extract the corresponding closest date. This can be achieved as:
closest_date = date_list[date_diffs.index(min(date_diffs))]
If performance is an issue, it may be worth investigating a pandas implementation. Using pandas we can convert your dates to a pandas dataframe:
from datetime import datetime
import pandas as pd
date_list = ['2019-02-10', '2018-01-13', '2019-02-8']
date_df = pd.to_datetime(date_list)
Finally, as in the method using inbuilts we find the differences in the dates and use it to extract the closest date to today.
today = datetime.today()
date_diffs = abs(today - date_df)
closest_date = date_list[date_diffs.argmin()]
The advantage of this method is that we've removed the for loops and so I'd expect this method to be more efficient for large numbers of dates
Upvotes: 1
Reputation: 171
This converts the strings to a datetime object, then subracts the current date from that and returns the date with the corresponding lowest absolute difference:
import datetime
import re
date_list = ['2019-02-10', '2018-01-13', '2019-02-8',]
numPattern = re.compile("[0-9]+")
def getclosest(dates):
global numPattern
now = datetime.date.today()
diffs = []
for day in date_list:
year, month, day = [int(i) for i in re.findall(numPattern, day)]
currcheck = datetime.date(year, month, day)
diffs.append(abs(now - currcheck))
return dates[diffs.index(min(diffs))]
It's by no means the most efficient, but it's semi-elegant and works.
Upvotes: 1
Reputation: 633
convert each string into a datetime.date object, then just subtract and get the smallest difference
import datetime
import re
date_list = ['2019-02-10', '2018-01-13', '2019-02-8',]
now = datetime.date.today()
date_list_converted = [datetime.datetime.strptime(each_date, "%Y-%m-%d").date() for each_date in date_list]
differences = [abs(now - each_date) for each_date in date_list_converted]
minimum = min(differences)
closest_date = date_list[differences.index(minimum)]
Upvotes: 2