'Comparing two date objects in Python: TypeError: '<' not supported between instances of 'datetime.date' and 'method'

This shouldn't be too difficult but I can't seem to get it to work. I want to compare two datetime.date types in Python but I keep getting a Type Error:

from datetime import date  

class Vacancy(object):
    def __init__(self, date): #date is a datetime string of format 2017-13-03T00.00.000Z
        self.date = datetime.strptime(date[:-1], '%Y-%m-%dT%H:%M:%S.%f').date()

    def getDate(self):
         return self.date


all_objects = [o1, o2, o3, o4, ...] #contains objects of type Vacancy
for o in all_objects:
    earliestDate = date(2020, 1, 1) 
    if o.getDate() < earliestDate:
        earliestDate = o.getDate()

print(earliestDate)

TypeError: '<' not supported between instances of 'datetime.date' and 'method'

Which doesn't make sense to me because: print(type(earliestDate)) and print(type(o.getDate())) both give <class 'datetime.date'>

What could I be doing wrong?

EDIT: added class sample code for the objects in all_objects

EDIT2: As many of you pointed out it is indeed a missing '()'. In my actual code I was assigning the method instad of the value by doing earliestDate = o.getDate. Next time I'll try to be more truthful to my code. Thank you all for the insight you provided as I indeed come from Java and I don't fully comprehend Python yet.



Solution 1:[1]

The TypeError should give you all information you need to solve this problem. Here's how to interpret it:

TypeError: '<' not supported between instances of 'datetime.date' and 'method'
  • The '<' not supported means that you got the error when using the < operator, as you already know.
  • The comparison doesn't work because one of the things you are comparing is not a datetime.date instance. You already got this, too.
  • The method type is what you get if you would use o.getDate instead of o.getDate(). In Python you can pass around methods as values if you like, just like lambdas or functions. This is not what you want in this case however, so make sure you use () everywhere you want to call a method, even if it doesn't take any arguments.
  • The order of the types in the error message is also interesting. That datetime.date comes before method mean that the date was on the left side and the problematic value was on the right side. In your case, the earliestDate is holding a method instead of a datetime.date.
  • Now that we know that earliestDate is the problem, where is it updated? earliestDate = date(2020, 1, 1) is clearly a date, but how about earliestDate = o.getDate()? It's using parentheses, so o.getDate() must be returning a method.
  • Given your code, the Vacancy will always have self.date set to a date, or an exception will be thrown (something like ValueError: time data 'xxx' does not match format '%Y-%m-%dT%H:%M:%S.%f'). I'm guessing your code looks different and the initialization for Vacancy is wrong somehow. This is the benefit of providing a MCVE :)

Solution 2:[2]

You overwritten the definition of date, try this (maintaining the datetime namespace with an alias: dt). A good practice would be to not name local or member variables with the same name of functions and objects of the libraries you import (you imported date from datetime and then use date as the argument of the init).

import datetime as dt   

class Vacancy(object):
    def __init__(self, date):
        self.date = date

    def getDate(self):
         return self.date


all_objects = [o1, o2, o3, o4, ...] #contains objects of type Vacancy
for o in all_objects:
    earliestDate = dt.date(2020, 1, 1) 
    if o.getDate() < earliestDate:
        earliestDate = o.getDate()

print(earliestDate)

An extra observation is that in python there is no need of defining getters and setters, since the variables are public. It is better if you just:

import datetime as dt   

class Vacancy(object):
    def __init__(self, date):
        self.date = date

all_objects = [o1, o2, o3, o4, ...] #contains objects of type Vacancy
for o in all_objects:
    earliestDate = dt.date(2020, 1, 1) 
    if o.date < earliestDate:
        earliestDate = o.date

And if you want to be sure the date member variable is not modified, you can do something like this:

class Vacancy(object):
    def __init__(self, date):
        self.date = date

    def getMinDate(self, other_date):
        if self.date < other_date:
            return dt.date(self.date)
        else:
            return other_date

all_objects = [o1, o2, o3, o4, ...] #contains objects of type Vacancy
earliestDate = dt.date(2020, 1, 1) 
for o in all_objects:
    earliestDate = o.getMinDate(earliestDate)

Solution 3:[3]

This error is also thrown when trying to apply the condition to NULL values in the column.

To solve this:

  • Add a condition to only perform the condition when the values are NOT null.
  • Remove the null values
from datetime import date  

class Vacancy(object):
    def __init__(self, date): #date is a datetime string of format 2017-13-03T00.00.000Z
        self.date = datetime.strptime(date[:-1], '%Y-%m-%dT%H:%M:%S.%f').date()

    def getDate(self):
         return self.date


all_objects = [o1, o2, o3, o4, ...] #contains objects of type Vacancy
for o in all_objects:
    earliestDate = date(2020, 1, 1) 
    
    # NOT Null condition 
    if (o != None) and (earliestDate != None):
        if o.getDate() < earliestDate:
            earliestDate = o.getDate()

print(earliestDate)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3