Reputation: 13
I have model:
class Account(models.Model):
contract_date = models.DateTimeField()
Field contract_date stored in db in UTC timezone. I need select all accounts where contract_date__date == date. But date stored in MSK timezone (+3). For example:
Account.objects.create(contract_date='2010-01-01 21:00:00')
Account.objects.filter(contract_date__date=date(2010, 1, 2)).all()
The query return a empty list.
Upvotes: 1
Views: 558
Reputation: 20672
If you enabled timezones (USE_TZ = True
in your settings), then django will make sure that all datetimes are saved in the UTC timezone and retrieved in the UTC timezone.
When displaying them, it will use the current timezone (settings.TIME_ZONE
or another one if you activate it) to display them in the appropriate timezone. When receiving input from forms, it will convert them to UTC.
Also note that a date
(2019-01-02) cannot be timezone aware, only a datetime
can, since without the time, time zones don't make sense.
So in your case, you need to tell Django that you want to filter with the date in MKS timezone. You can use Trunc
for that:
from django.db.models.functions import Trunc
from django.db.models import DateTimeField
import pytz
from datetime import datetime
mks_filter_day = pytz.timezone("Europe/Moscow").localize(datetime(2010, 1, 2))
Account.objects.exclude(contract_date__isnull=True).annotate(
mks_day=Trunc('contract_date', 'day', output_field=DateTimeField(), tzinfo=pytz.timezone("Europe/Moscow")))\
.filter(mks_day=mks_filter_day)
# or in Django 1.11 the above doesn't work due to a bug
Account.objects.exclude(contract_date__isnull=True).annotate(
mks_day=Trunc('contract_date', 'day', output_field=DateTimeField(), tzinfo=pytz.timezone("Europe/Moscow")))\
.filter(mks_day__contains=datetime.date(2010, 1, 2))
This tells the database to convert the datetime to MKS and truncates the day before comparing to the reference date. I make sure contract_date
isn't null otherwise you get an error.
Upvotes: 1
Reputation: 2568
You are querying using a date without time... use datetime instead:
datetime(2010,1,2,21,0,0)
Upvotes: 0