Filter queryset with same DateTime fields

Question:

I’m trying to filter a queryset with the same DateTime fields:

objects = Obj.objects.filter(start_date_time=F('end_date_time'))
objects
<QuerySet []>

models.py:

start_date_time = models.DateTimeField(default=now, blank=True)
end_date_time = models.DateTimeField(default=now, blank=True)

If I remove microseconds, then the fields are equal:

obj = Obj.objects.filter(id='id').first()
obj.start_date_time
datetime.datetime(2023, 3, 10, 9, 24, 29, 326238, tzinfo=<UTC>)
obj.end_date_time
datetime.datetime(2023, 3, 10, 9, 24, 29, 326241, tzinfo=<UTC>)
obj.start_date_time == obj.end_date_time
False
obj.start_date_time.replace(microsecond=0) == obj.end_date_time.replace(microsecond=0)
True

How to make a request to the database correctly?

Asked By: user13824551

||

Answers:

You can use Trunc function to truncate the milisecond information and filter like this:

objects = Obj.objects.annotate(truc_start_date_time=Trunc('start_datetime', 'second', output_field=DateTimeField()), trunc_end_date_time==Trunc('endt_datetime', 'second', output_field=DateTimeField())).filter(trunc_start_date=F('trunc_end_date'))

Another alternative is to filter using all segments of the date time object (ie date, hour, minute, second)

objects = Obj.objects.filter(start_date_time_day__date = F('end_datetime__date'), start_date_time_day__hour =  F('end_datetime__hour'), start_date_time_day__minute =  F('end_datetime__minute'), start_date_time_day__second =  F('end_datetime__second'))
Answered By: ruddra

A slightly more efficient way is to truncate with .alias(…) [Django-doc] and then filter directly, this will prevent that the values end up in the SELECT clause. We can also work with TruncSecond [Django-doc]

from django.db.models.functions import TruncSecond

Obj.objects.alias(trunc_start_date_time=TruncSecond('start_date_time')).filter(
    trunc_start_date_time=TruncSecond('end_date_time')
)
Answered By: Willem Van Onsem