Not able to change TImezone in Trunc functions. It always take timezone from settings.py
import pytz
ind = pytz.timezone('Asia/Calcutta')
Query:
queryset = Order.objects.annotate(date=TruncDate('created_at', tzinfo=ind)).values('date')
While inspecting sql query by queryset.query
SELECT DATE(CONVERT_TZ(`nm_order`.`created_at`, 'UTC', UTC)) AS `date` FROM `nm_order`
Reference: Trunc in Django
But for Extract, it's get working
ORM:
queryset = Order.objects.annotate(date=ExtractDay('created_at',tzinfo=ind)).values('date')
Query:
SELECT EXTRACT(DAY FROM CONVERT_TZ(`nm_order`.`created_at`, 'UTC', Asia/Calcutta)) AS `date` FROM `nm_order`
Am I miss something in Trunc ?
TimeZone Settings in my settings.py
IME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
You need to use TruncDay() instead of TruncDate. In the usage example just below that section of the documentation you'll see the difference between the two.
TruncDate does not take a timezone option - it uses the current timezone and gives you the date in that timezone.
I think the distinction between the two is that TruncDate returns a DateField which by definition cannot be timezone-aware. TruncDay on the other hand returns a DateTimeField(with time portion set to 00:00:00), which can be timezone aware.
From django 3.2, TruncDate now accepts tzinfo parameter. https://docs.djangoproject.com/en/dev/ref/models/database-functions/#django.db.models.functions.TruncDate
After Inspecting TruncDate Class looks like it doesn't have timezone option
class TruncDate(TruncBase):
kind = 'date'
lookup_name = 'date'
#cached_property
def output_field(self):
return DateField()
def as_sql(self, compiler, connection):
# Cast to date rather than truncate to date.
lhs, lhs_params = compiler.compile(self.lhs)
tzname = timezone.get_current_timezone_name() if settings.USE_TZ else None
sql, tz_params = connection.ops.datetime_cast_date_sql(lhs, tzname)
lhs_params.extend(tz_params)
return sql, lhs_params
Related
I try to make a query to select all the object that where modified since a specified time
This time is now - max_schedule_delay where max_schedule_delay is a data from the object (see code sample below).
I try multiple thing .. but here I am. Maybe you will be able to help me find a way.
Environment
python 2.7
django 1.11
database : Posgresql
Sample code
from django.db import models
class MyObject(models.Model):
# last modification date
mtime = models.DateTimeField(auto_now=True, db_index=True)
# maximum delay before rescheduling in seconds
max_schedule_delay = models.IntegerField()
What I want to achieve
select * from MyObject where (mtime + max_schedule_delay > now)
My tests
from django.db.models import F, ExpressionWrapper,, TimeField, DateTimeField
from django.db.models.functions import Cast
import datetime
now = datetime.datetime.now()
MyObject.objects.filter(max_schedule_delay__lte=now - F("mtime")) # here max_schedule_delay is a integer, so this query is not possible
# I try to split this query in two, but still not wotking
MyObject.objects.annotate(threshold=ExpressionWrapper(now - F("max_schedule_delay"), output_field=DateTimeField())).filter(mtime__gte=F("threshold"))
MyObject.objects.annotate(threshold=ExpressionWrapper(F("mtime") + F("max_schedule_delay"), output_field=DateTimeField())).filter(threshold__gte=now)
MyObject.objects.annotate(as_date=Cast("max_schedule_delay", TimeField()))
Any help is welcome,
Thanks !
After some more research, and based on the post Using dateadd in django filter I was able to do something, but only for posgresql
from django.db.models import Func, DateTimeField
import datetime
class DateAdd(Func):
"""
Custom Func expression to add date and int fields as day addition
Usage:
Model.objects.annotate(annotation=DateAdd('field_date','field_seconds'))
"""
arg_joiner = " + CAST("
template = "%(expressions)s || ' seconds' as INTERVAL)"
output_field = DateTimeField()
MyModel.objects.annotate(
threshold=DateAdd("mtime", "max_schedule_delay")
).filter(
max_schedule_delay__isnull=False,
state=botSession.STATE.DONE,
threshold__lte=datetime.datetime.now()
)
I have a test where I create a few objects:
def test_get_courier_task_returns_couriers_tasks(self):
with patch('django.utils.timezone.now', return_value=make_aware(datetime(2018, 1, 24, 11, 57))):
task1 = TaskFactory()
response = json.loads(MyAPI.get_tasks_list(self.user.username))
print('[*] Response timestamp: {}'.format(response['content'][0]['timestamp']))
The Task has created_timestamp field with auto_add_now set to True and to_json() method which is used in get_tasks_list() above:
class Task(models.Model):
created_timestamp = models.DateTimeField(auto_now_add=True)
def to_json(self):
to_return = {
'timestamp': self.created_timestamp.strftime('%d-%m-%Y %H:%M')
}
return to_return
Unfortunately tests give this output:
[*] Response timestamp: 24-01-2018 10:57
I have checked that this is timezone aware, but instead of giving me UTC+1 it gives UTC+0 on saving. What do I have to do? I have USE_TZ = True in my settings and I have applied migrations. This question did not help with my problem.
It turned out that giving timezone explicityl helped:
with patch('django.utils.timezone.now', return_value=datetime(2018, 1, 24, 11, tzinfo=pytz.timezone('utc'))):
Try providing make_aware with the timezone you want.
Also checking for a specific time in the test is a bit circular, probably don't need to check for it and just make sure it runs and produces a timestamp.
The time that is being inserted in database is default UTC, not the timezone based time..I do not understand why is this happening, even though I am particularly specifying, in the query, the time that I want to be inserted.
In my Model I have
class leave(models.Model):
date_created = models.DateTimeField(auto_now_add=True)
In my settings I have
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
In my views i am setting timezone based on employee country
if employees.objects.get(emp_id=request.user.username).emp_loc == 'IND':
tzone=pytz.timezone('Asia/Calcutta')
elif employees.objects.get(emp_id=request.user.username).emp_loc == 'MLA':
tzone=pytz.timezone('Asia/Manila')
elif employees.objects.get(emp_id=request.user.username).emp_loc == 'MPLS':
tzone=pytz.timezone('CST6CDT')
And then I am creating leave and updating timezone based on country
new_leave = leave.objects.create(employee=employees.objects.get(emp_id = userid.emp_id), start_date=sdt, end_date=edt, ltype=ltyp, message=des,date_created=datetime.now(tzone))
new_leave.save()
Thanks in Advance.
You can create a middleware that handles the conversion of date and time,
import pytz
from django.utils import timezone
from django.utils.deprecation import MiddlewareMixin
class TimezoneMiddleware(MiddlewareMixin):
def process_request(self, request):
tzname = request.session.get('django_timezone')
if tzname:
timezone.activate(pytz.timezone(tzname))
else:
timezone.deactivate()
and then you can as easily create the view with the conditions that you indicated earlier.
Best if you read the documentation as Kevin suggested.
I want to disable django fields for 6 months after the date of update. I have saved update_time to a table.
updated_time = a.update_time
disabled_time = a.update_time + timedelta(180)
I want to diable field that updated:
self.fields['first_name'].widget.attrs['readonly'] = True
How can I disable self.fields['first_name'].widget.attrs['readonly'] = True for disabled_time?
Thanks in advance
You can compare, and substract basic datetime objects and make some check at form initialization time:
from datetime import timedelta, datetime
...
class FooForm(ModelForm):
def __init__(self, *args, **kwargs):
super(FooForm, self).__init__(*args, **kwargs)
# check if we already have a saved object and it's not older than 180 days
if self.instance.pk and
(datetime.now() - self.instance.update_time) < timedelta(180):
self.fields['first_name'].widget.attrs['readonly'] = True
class Meta:
model = Foo
(Not really tested but should work as it is.)
Also note, that it is often convenient to keep update_time with auto_now set to True.
I need to use SHORT_DATETIME_FORMAT in view.
def manage_list(request):
user = User.objects.filter().order_by('date_joined')
usrs = []
for usr in user:
usrs.append({
_('First name'): usr.first_name,
_('Last name'): usr.last_name,
_('Email'): usr.email,
_('Active'): usr.is_active,
_('Superuser'): usr.is_superuser,
_('Staff'): usr.is_staff,
_('Joined date'): usr.date_joined.strftime(SHORT_DATETIME_FORMAT),
})
data = simplejson.dumps(usrs, indent=4)
return HttpResponse(data, mimetype='application/json')
usr.date_joined has a type of "date field" I think. I want to format this data according to django locale. so this string probably should help. I know that there's a template filter which does that I wan, but I want to format usr.date_joined in view only - saving django choosen locale.
If there's any other methods to do this please provide examples. in the end I just wanna have a formated date according to django locale which shows only date and time, I think this constant should do what the name says..
The django.utils.formats module is what you're looking for. The only reference I could find in the docs was in the Django 1.2 release notes.
Remember that the localisation will only work if the USE_L10N setting is True. You can use the date_format as follows.
from datetime import datetime
from django.utils import formats
date_joined = datetime.now()
formatted_datetime = formats.date_format(date_joined, "SHORT_DATETIME_FORMAT")
You might want to try using django.utils.dateformat.DateFormat
>>> from datetime import datetime
>>> dt = datetime.now()
>>> from django.utils.dateformat import DateFormat
>>> from django.utils.formats import get_format
>>> df = DateFormat(dt)
>>> df.format(get_format('DATE_FORMAT'))
u'April 23, 2013'
>>> df.format('Y-m-d')
u'2013-04-23'
More information using Python:
import django
help(django.utils.dateformat)
To use the Django date filter in a view use defaultfilters, e.g.:
from django.template import defaultfilters
formatted_date = defaultfilters.date(usr.date_joined, "SHORT_DATETIME_FORMAT")
Use localize shortcut.
>>> from django.utils.formats import localize
>>> from datetime import datetime
>>>
>>> print(datetime.now())
2016-12-18 19:30:35.786818
>>> print(localize(datetime.now()))
18 декабря 2016 г. 19:30
from django.utils.formats import date_format
date_format(usr.date_joined)
As of today what worked for me was setting USE_L10N to True.
Then import some utils :
from django.utils import (dateformat, formats)
Which can be used as such :
dateformat.format(my_date_object, formats.get_format('DATE_FORMAT'))
Note thate my_date_object should be a datetime object.
And there is a list of available formats :
DECIMAL_SEPARATOR
THOUSAND_SEPARATOR
NUMBER_GROUPING
FIRST_DAY_OF_WEEK
MONTH_DAY_FORMAT
TIME_FORMAT
DATE_FORMAT
DATETIME_FORMAT
SHORT_DATE_FORMAT
SHORT_DATETIME_FORMAT
YEAR_MONTH_FORMAT
DATE_INPUT_FORMATS
TIME_INPUT_FORMATS
DATETIME_INPUT_FORMATS
The name is pretty self explanatory...
see : https://github.com/django/django/blob/main/django/utils/formats.py