1

I have an array of datetime objects, and I would like to find which element in the array is the closest previous a given date (e.g datetime.datetime(2020,11,1))

This post shows how to find the nearest absolute date. How can I alter this code so that it returns only dates that are before a given date?

For example, if the array housed elements datetime.datetime(2020,10,10), datetime.datetime(2020,10,25) and datetime.datetime(2020,11,2), the second item should be returned because it is closest previous date to datetime.datetime(2020,11,1). Is it possible to make something like this with lambda or is it too elaborated for that?

schlumpfpirat
  • 195
  • 2
  • 12

2 Answers2

1

Since datetime.datetime objects are can be compared to one another, you can use max:

import datetime

dates = (
    datetime.datetime(2020,10,10),
    datetime.datetime(2020,10,25),
    datetime.datetime(2020,11,2)
)

date = datetime.datetime(2020,11,1)

print(max(d for d in dates if d < date))

Output:

2020-10-25 00:00:00
>>> 
Paul M.
  • 10,481
  • 2
  • 9
  • 15
1

You just need to filter the dates before your target date, and take the max:

import datetime

dates = [datetime.datetime(2020,10,10), datetime.datetime(2020,10,25), datetime.datetime(2020,11,2)]

target = datetime.datetime(2020,11,1)

res = max(date for date in dates if date < target)

print(res)
#2020-10-25 00:00:00

To answer the question in your comment: you can simply extract the dates from your data:

data = [{'start': datetime.datetime(2020,10,10)}, {'start': datetime.datetime(2020,10,25)}, {'start': datetime.datetime(2020,11,2)}]

dates = [d['start'] for d in data]

and continue the same way, or do it all in one line:

import datetime

data = [{'start': datetime.datetime(2020,10,10)}, {'start': datetime.datetime(2020,10,25)}, {'start': datetime.datetime(2020,11,2)}]
target = datetime.datetime(2020,11,1)

res = max(d['start'] for d in data if d['start'] < target)

print(res)
#2020-10-25 00:00:00

or, using an assignment expression (for Python >= 3.8) to avoid accessing the dict twice:

res = max(date for d in data if (date := d['start']) < target)

And to address your last comment, if you want to return the dict, you can use the same principle and give max a custom key, a function that will return the value associated to 'start':

from operator import itemgetter

res = max((d for d in data if d['start'] < target), key=itemgetter('start'))

or equivalently, without importing itemgetter, by using a lambda for the key:

res = max((d for d in data if d['start'] < target), key=lambda d: d['start'])
Thierry Lathuille
  • 23,663
  • 10
  • 44
  • 50
  • Awesome! How would I use `max` if I had a list of dicts, e.g. `[{'start': datetime.datetime(2020,10,10)}, {'start': datetime.datetime(2020,10,25)}, {'start': datetime.datetime(2020,11,2)}]`? – schlumpfpirat Nov 02 '20 at 13:33
  • Sorry for causing confusion – I actually meant in regards to extracting the full dict then, instead of just the date. E.g. to return `{'start': datetime.datetime(2020,10,25)}` – schlumpfpirat Nov 02 '20 at 13:46