iNoob
iNoob

Reputation: 1395

Comparing dates and finding the closest date to the current date

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

Answers (4)

kederrac
kederrac

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

jwalton
jwalton

Reputation: 5686

Using inbuilts

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))]

With pandas

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

Lordfirespeed
Lordfirespeed

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

Zulfiqaar
Zulfiqaar

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

Related Questions