In my models, I have a DateTimeField say
class ReturnEvent(models.Model):
book_title = models.CharField()
return_time = models.DateTimeField()
When I retrieve the return_time to be printed, for example:
return_event = ReturnEvent.objects.get(id=1)
print(return_event.return_time.strftime("%H:%M"))
I am seeing the datetime unaware time like:
2016-06-18 08:18:00+00:00
However, I like to see the local time using strftime.
2016-06-18 10:18:00+02:00
Is there a quick solution for this?
If you have USE_TZ = True in your settings, Django stores all the datetime objects in the database as UTC and convert them to your TIME_ZONE=XYZ from settings.py on the fly when rendering in the templates.
That is why, when retrieved from the database, datetime object is timezone aware but it has UTC as its timezone (hence +00:00 in 2016-06-18 08:18:00+00:00). As, you are converting the time to str yourself (and not rendering in the template) so Django does not convert it to your TIME_ZONE setting. You need to convert it yourself to your desired TimeZone.
If you want to convert it to the TimeZone from your TIME_ZONE setting, you can do
from django.utils import timezone
to_tz = timezone.get_default_timezone()
print return_event.return_time.astimezone(to_tz).strftime("%H:%M")
Related
I am trying to fetch data based on DateTime Field! I wrote the following script for the same:
import datetime as dt
from dasboard.models import Visionsystem
from django.utils.timezone import make_aware
min_dt = dt.datetime.combine(dt.date.today(), dt.time(7, 15))
max_dt = dt.datetime.combine(dt.date.today(), dt.time(15, 44))
# Changing format for Django
min_dt_aware = make_aware(min_dt)
max_dt_aware = make_aware(max_dt)
# Fetching all the data between 7:15:00 to 15:44:00 for current day
l1 = Visionsystem.objects.filter(start_datetime__range=(min_dt_aware, max_dt_aware))
print(l1) yields empty list and Checking str(l1.query) gives:
'SELECT `visionsystem`.`id`, `visionsystem`.`Start_Datetime` ... FROM `visionsystem` WHERE
`visionsystem`.`Start_Datetime` BETWEEN 2019-10-16 01:45:00 AND 2019-10-16 10:14:00'
Desired query would be:
'SELECT `visionsystem`.`id`, `visionsystem`.`Start_Datetime` ... FROM `visionsystem` WHERE
`visionsystem`.`Start_Datetime` BETWEEN 2019-10-16 07:15:00 AND 2019-10-16 15:44:00'
I don't understand why Django-ORM is querying with a different time then what's specified ?
My timezone settings ( in settings.py ):
TIME_ZONE = 'Asia/Kolkata'
USE_I18N = True
USE_L10N = True
USE_TZ = True
How do I resolve this, to fetch the required data from 7:15:00 to 15:44:00, for current day ? NOTE: I am using MySQL Database!!
models.py file:
from django.db import models
class Visionsystem(models.Model):
start_datetime = models.DateTimeField(db_column='Start_Datetime', blank=True, null=True)
class Meta:
managed = False
db_table = 'visionsystem'
MySql doesn't supports timezones, It stores datetime in UTC, while your django
application timezone is Asia/Kolkata (UTC +5:30).
Here django automatically converts your application timezone to UTC before querying to MySQL database. This makes sense as when you save data using django application, it converts datetime to UTC time, so 07:15:00 Kolkata time would be stored as 01:45:00 in UTC.
Solution:
You can store MySql data in UTC timezone, If existing data is in Kolkata timezone, run update query by subtracting -5:30 and save all new data in UTC timezone.
OR
If your application doesn't need to support multiple timezone, you can change application timezone to UTC. This is quick solution but not a good idea as timezone information is truncated.
In short
Django saves store UTC in database.
If you don't mention a timezone, the timezone you mentioned in settings.py is taken (in your case, Asia/Kolkata is taken, so make_aware function assumes, you are entering a datetime with timezone Asia/Kolkata. But as mentioned in step 1., it is saved as UTC. Both time points to same time - that is, time described by both UTC and Asia/Kolkata is same).
In addition to both 1 and 2, django convert your timezone_aware datetime (ie. min_dt_aware and max_dt_aware) to UTC, to make the correctness of your query during query execution.
Here is the detailed explanation.
Time zones overview
When support for time zones is enabled, Django stores date-time information in UTC in the database, uses time-zone-aware date-time objects internally, and translates them to the end user’s time zone in templates and forms.
Value is shown as UTC, which is printed in SQL query:
import pytz
utc = pytz.UTC
# Print the utc value of min_dt_aware and max_dt_aware
print(min_dt_aware.astimezone(utc), max_dt_aware.astimezone(utc))
# So, as you can see, these utc values are which you see in SQL queries.
You can use timezone.now(), it worked for me. For this first you need to import timezone,from django.utils import timezone https://docs.djangoproject.com/en/3.1/topics/i18n/timezones/
I'm querying a Django model connected to a table in my Postgres database that contains a datetime stored in UTC.
My query code looks something like this:
query_set = table_object.objects.values()
One of the columns in the query set is the datetime value in UTC.
The model looks like this:
class ops_inbox_view(models.Model):
requested_date = models.DateTimeField()
other_item = models.CharField(max_length=20)
other_item2 = models.CharField(max_length=40)
other_item3 = models.CharField(primary_key=True, max_length=10)
other_item4 = models.CharField(max_length=50)
other_item5 = models.CharField(max_length=50)
other_item6 = models.CharField(max_length=50)
I want to convert this into PST or robustly in the enduser's local time zone. My current solution is to use pandas with dt.tz_localize and dt.tz_convert after loading the query set into a dataframe but I'm trying to find a solution that is easily manageable in one location of the project file structure of the app. In my settings.py, I have TIME_ZONE set to 'US/Pacific' but because I'm using Pandas, the conversion to PST is not automatically done and will have to change many lines of code in my views.py to make the conversion with pandas.
Is there a way to not use Pandas and instead either make the field timezone aware or make the explicit conversion in the query code? Also looking for any other best practices in timezone management and display. Serving this datetimefield into an html file...
You can use F() with annotate
from datetime import timedelta
from django.db.models import DateTimeField, ExpressionWrapper, F
table_object.objects.annotate(modified_date=ExpressionWrapper(F('requested_date')+timedelta(minutes=960), output_field=DateTimeField())).filter(modified_date='2019-11-30')
Here you need to +/- minutes to convert utc datetime to your(PST) timezone and it will store converted dates into modofied_date, after that we can filter it.
Note:
You don't need to use pandas to convert timezones. Django good built-in timezone management tools.
Their timezone docs are quite good as well, so I'd suggest reading it all the way through.
The problem you're having seems very similar to one described in their docs
so I have model with a DateTimeField. Now when I store it in the database it gives me the correct time. However, when I print out the time, the time is ahead by 4 hours. This is probably due to some timezone issue. So I did some research and in my settings.py I have set a timezone:
TIME_ZONE = 'Canada/Eastern'
But it still doesn't work. Any ideas on how to solve this issue?
EDIT: How I define the field: Date = models.DateTimeField(auto_now_add=True)
If you're using Mysql/SQLite, as database doesn't store timezone info, so, after you defined timezone in settings.py, Django will convert your local time to UTC time each time before insert into the database. Don't worry, each time before you use this DateTime filed,Django would convert it back to local time automatically.
I don't know if this explanation can solve your problem.Also,remember define USE_TZ =True in settings.py.
I have a timezone aware object:
date = timezone.now()
and then I am getting the user's timezone using some middleware, so I have it as a string, like:
tz = "America/New_York"
This is probably a really simple question but I have not been able to find the answer anywhere: How do I change the timezone of the date object to the user's timezone? I tried date.localize(tz) but that gave me an error. What am I doing wrong.
You need to convert the string to a timezone object, then use astimezone()
import pytz
timezone = pytz.timezone(tz)
your_date_with_usertimezone = date.astimezone(timezone)
I suppose time zone management was added to Django 1.4, so the problem is quite new.
I used a simple model
class Sample(models.Model):
...
date_generated = models.DateTimeField(auto_now_add = True)
When I try to retrieve a newly created record its fails.
min_datetime = datetime.now() - timedelta(seconds = 300)
sample = Sample.objects.get(date_generated__gte = min_datetime)
and the server issues a warning.
DateTimeField received a naive DateTime (2012-06-29 15:02:15.074000) while time zone support is active.
I figured out two solutions to that problem.
Disable time zone management in settings.py
USE_TZ = False
but this is not always desirable.
2. changing
date_generated = models.DateTimeField(auto_now_add = True)
to
date_generated = models.DateTimeField(default=datetime.now())
is the solution that keeps time zone management working
Use timezone utils of django
from django.utils import timezone
date_generated = models.DateTimeField(default=timezone.now)
The problem is on your end: datetime.now() is not TZ aware, so you're the one feeding in a naive TZ. See the Django docs on this issue. The reason it works when setting default=datetime.now is that you're forcing the value to a naive datetime, so when you later compare it with another naive datetime, there's no problem.
You need to get "now" the following way:
import datetime
from django.utils.timezone import utc
now = datetime.datetime.utcnow().replace(tzinfo=utc)
Be careful setting a DateTimeField default value of datetime.now(), as that will compute a single value when Apache/nginx loads Django (or when you start the development server), and all subsequent records will receive that value.
Always use auto_now_add for that reason.