114

How do I sort a list of date and/or datetime objects? The accepted answer here isn't working for me:

from datetime import datetime,date,timedelta

a=[date.today(), date.today() + timedelta(days=1), date.today() - timedelta(days=1)]
print(a) # [datetime.date(2013, 1, 22), datetime.date(2013, 1, 23), datetime.date(2013, 1, 21)]
a = a.sort()
print(a) # prints 'None'....what???
cottontail
  • 10,268
  • 18
  • 50
  • 51
user_78361084
  • 3,538
  • 22
  • 85
  • 147
  • 1
    lst.sort() is an inplace operation –  Jan 23 '13 at 05:06
  • 1
    Did you read *inplace* operation? Why would the method return something that is performed on the existing datastructure? No new list is created and the existing list is not returned. This is completely intentional and documented behavior, brother. –  Jan 23 '13 at 05:10
  • 1
    I used `sorted()` operating on a list comprehension as follows: `sorted([datetime.strptime(dt, "%Y-%m-%d %H:%M:%S") for dt in dateList])` . My dates were strings that looked like: '2018-09-07 19:00:46' – Grant Shannon Oct 21 '18 at 16:00

2 Answers2

180

You're getting None because list.sort() it operates in-place, meaning that it doesn't return anything, but modifies the list itself. You only need to call a.sort() without assigning it to a again.

There is a built in function sorted(), which returns a sorted version of the list - a = sorted(a) will do what you want as well.

Volatility
  • 31,232
  • 10
  • 80
  • 89
  • 5
    which way is best? do they do same things under the covers? – radtek Mar 06 '14 at 22:51
  • 6
    @radtek `list.sort()` changes the object from which it is invoked (which is always a list). `sorted()` works on any iterable, not only list. `list.sort()` might be a little faster if you have a very large list because `sorted()` creates a new list and needs to copy the elements to it. – flyman Feb 06 '15 at 22:50
2

If your list contains a list of strings that look like datetime, you can sort them using a datetime parser as key.

For example, to sort lst, you can pass a lambda that parses each string into datetime as key (for a full list of possible formats, see https://strftime.org/).

from datetime import datetime, date
lst = ['02/01/2023 12:25 PM', '01/22/2023 11:00 PM', '12/01/2022 02:23 AM']
sorted_lst = sorted(lst, key=lambda x: datetime.strptime(x, '%m/%d/%Y %I:%M %p'))
# ['12/01/2022 02:23 AM', '01/22/2023 11:00 PM', '02/01/2023 12:25 PM']

# in-place sorting is also possible
lst.sort(key=lambda x: datetime.strptime(x, '%m/%d/%Y %I:%M %p'))

Of course, you can parse them into datetime first and then sort but that would change the type of the items in the list from

new_lst = sorted(datetime.strptime(x, '%m/%d/%Y %I:%M %p') for x in lst)
# [datetime.datetime(2022, 12, 1, 2, 23), datetime.datetime(2023, 1, 22, 23, 0), datetime.datetime(2023, 2, 1, 12, 25)]

If your list is a mixture of date and datetimes, you can normalize them all into datetime objects, and then sort; again, as a key so that the type of the items in the original list doesn't change.

lst = [datetime(2013, 1, 21, 6, 14, 47), date(2013, 1, 22), date(2013, 1, 21)]
new_lst = sorted(lst, key=lambda x: x if isinstance(x, datetime) else datetime(x.year, x.month, x.day))
# [datetime.date(2013, 1, 21), datetime.datetime(2013, 1, 21, 6, 14, 47), datetime.date(2013, 1, 22)]
cottontail
  • 10,268
  • 18
  • 50
  • 51