I know that if I want to filter results by date range, I just use something like
Sample.objects.filter(birthday__range=(start_date, end_date))
But how would I filter by a date range that excludes the year?
I know that if I want to filter results by date range, I just use something like
Sample.objects.filter(birthday__range=(start_date, end_date))
But how would I filter by a date range that excludes the year?
You can use both filter and exclude. Filter as you done, and then exclude the year, like 2021
Sample.objects.filter(birthday__range=(start_date, end_date)).exclude(birthday_date__year=2021)
We can work with a range of datetimes with:
from datetime import timedelta
from django.db.models import Q
def filter_query(start_date, end_date):
a = am, ad = start_date.month, start_date.day
b = bm, bd = end_date.month, end_date.day
end_date2 = end_date + timedelta(days=1)
c = end_date2.month, end_date2.day
if c == (2, 29) and a == (3, 1):
return ~Q(birthday__month=2, birthday__day__gt=28)
if a == c:
return Q()
if a <= b:
if am == bm:
return Q(birthday__month=am, birthday__day__range=(ad, bd))
else:
return (Q(birthday__month=am, birthday__day__gte=ad) |
Q(month__range=(am+1, bm-1)) |
Q(birthday__month=bm, birthday__day__lte=bd))
else:
return ~filter_query(end_date+timedelta(days=1), start_date-timedelta(days=1))
This will return a Q object that then can be used by filtering the queryset, for example:
Sample.objects.filter(filter_query(date(2020, 12, 15), date(2021, 1, 16)))
There are basically five cases:
end_date is February 28th, and the start date is March 1st, then we exclude February 29th.end_date plus one day is the same as the start date, then we do not have to filter;start_date is less than the end_date and the months match, then we filter on that month, and a range check on the days;start_date is less than the end_date and the months do not match, then we look for the ranges:
start_date and with a day greater than the month of the start_date;start_date and less than the previous month of the end_date; andend_date and a day less than or equal to the day of the end_date.end_date plus one day, and the start_date minus one day.