Isn't django now() supposed to be in the default time zone? - django

This might be a bit of a trivial question, but can't I get django now() to be in the time zone defined in settings.TIME_ZONE?
This is what is actually happening:
>>> from django.utils import timezone
>>> timezone.now()
datetime.datetime(2012, 5, 30, 16, 30, 0, 782087, tzinfo=<UTC>)
>>> timezone.get_default_timezone()
<DstTzInfo 'Asia/Singapore' SMT+6:55:00 STD>

Django's source code (as displayed in the chosen answer) explains the concept of timezone.now():
datetime.now() yields the current time (in your active timezone!) without timezone information ("naive datetime"), whereas ...
timezone.now() always yields the current time in UTC (!) with timezone information.
This is irritating at first sight, yes. They could have decided to yield the current time of the active timezone, but they didn't. You can still use timezone.localtime(timezone.now()) to get what you want:
from django.utils import timezone
from datetime import datetime
timezone.get_current_timezone()
# <DstTzInfo 'Antarctica/McMurdo' LMT+11:39:00 STD>
datetime.now()
# datetime.datetime(2014, 8, 19, 20, 8, 8, 440959)
timezone.localtime(timezone.now())
# datetime.datetime(2014, 8, 19, 20, 8, 14, 889429, tzinfo=<DstTzInfo 'Antarctica/McMurdo' NZST+12:00:00 STD>)
timezone.now()
# datetime.datetime(2014, 8, 19, 8, 8, 22, 273529, tzinfo=<UTC>)
datetime.utcnow()
# datetime.datetime(2014, 8, 19, 8, 8, 29, 769312)
For newcomers and ordinary users timezone.localtime(timezone.now()) is probably the most intuitive. A local time which still retains timezone information.
EDIT: The standard library equivalent for a timezone-aware local time is datetime.now().astimezone(). astimezone applies the system local timezone by default, which allows you to correctly convert any timezone-aware datetime to your local time. To set an arbitrary timezone using timezone names you need the pytz package.
from datetime import datetime, timezone
import pytz
datetime.now()
# datetime.datetime(2022, 9, 14, 5, 26, 35, 146551)
datetime.now().astimezone()
# datetime.datetime(2022, 9, 14, 5, 26, 44, 19645, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200), 'CEST'))
datetime.now(tz=timezone.utc)
# datetime.datetime(2022, 9, 14, 3, 26, 51, 203917, tzinfo=datetime.timezone.utc)
datetime.now(tz=timezone.utc).astimezone()
# datetime.datetime(2022, 9, 14, 5, 26, 58, 546724, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200), 'CEST'))
datetime.now(tz=pytz.timezone('Europe/Kiev'))
# datetime.datetime(2022, 9, 14, 6, 27, 38, 714633, tzinfo=<DstTzInfo 'Europe/Kiev' EEST+3:00:00 DST>)

Or I could just read the source:
def now():
"""
Returns an aware or naive datetime.datetime, depending on settings.USE_TZ.
"""
if settings.USE_TZ:
# timeit shows that datetime.now(tz=utc) is 24% slower
return datetime.utcnow().replace(tzinfo=utc)
else:
return datetime.now()
Answer is nope, I have to adjust it myself.

It depends
now()
Returns an aware or naive datetime that represents the current point in time when USE_TZ is True or False respectively.
https://docs.djangoproject.com/en/dev/ref/utils/#django-utils-timezone
So all would indicate that USE_TZ is false in your case, and it's not taking the TZ in consideration.

Related

Django Infinity as datetime default

I'm struggling to see how I can add a datetime field with an infinity end date.
Setting the default to 'infinity' results in a Django.core exception
django.core.exceptions.ValidationError: ["'infinity' value has an invalid format. It must be in YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."]
NB: This is not the same as defining it Null (None). It's specially supported in postgres as just a string condition check for example
SELECT * FROM table WHERE dt = 'infinity'; // or
SELECT * FROM table WHERE NOT isfinite(dt);
Nulls won't show in this, nor can you do a between condition on a Null value unless you COALESCE it, but that will result in a sequential scan.
Any ideas?
Django ORM converts infinity to datetime.max, so consider using datetime.max instead:
$ psql -d yourdb
yourdb=# UPDATE app_yourmodel SET last_login = 'infinity' WHERE id = 1;
$ python3 manage.py shell
>>> from app.models import YourModel
>>> from datetime import datetime
>>>
>>> YourModel.objects.get(id=1).last_login
datetime.datetime(9999, 12, 31, 23, 59, 59, 999999, tzinfo=<UTC>)
>>>
>>> datetime.max
datetime.datetime(9999, 12, 31, 23, 59, 59, 999999)

_AppCtxGlobals' object has no attribute 'p1' SocketIO with Flask

I am using Flask to render graph from bokeh-server
from flask import Flask, render_template
from flask.ext.socketio import SocketIO, emit
import flask
from bokeh.plotting import figure, push
from bokeh.models import Range1d
from bokeh.embed import components
from bokeh.embed import autoload_server
from bokeh.session import Session
from bokeh.document import Document
from bokeh.models.renderers import GlyphRenderer
from flask.globals import current_app
app = Flask("Graph Realtime",static_url_path='/static')
app.config['SECRET_KEY'] = 'secret!'
app.debug = True
socketio = SocketIO(app)
#app.route('/')
def index():
x1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y1 = [0, 8, 2, 4, 6, 9, 5, 6, 25, 28, 4, 7]
# select the tools we want
TOOLS="pan,wheel_zoom,box_zoom,reset,save"
# the red and blue graphs will share this data range
xr1 = Range1d(start=0, end=30)
yr1 = Range1d(start=0, end=30)
# build our figures
p1 = figure(x_range=xr1, y_range=yr1, tools=TOOLS, plot_width=300, plot_height=300)
p1.scatter(x1, y1, size=12, color="red", alpha=0.5)
document = Document()
session = Session(root_url='http://localhost:5006/', load_from_config=False)
session.use_doc('graph')
session.load_document(document)
document.clear() # Semi-optional - see below
document.add(p1) # Put it on the server
session.store_document(document)
app_con = current_app._get_current_object().app_context()
app_con.g.p1 = p1.select(dict(type=GlyphRenderer))[0].data_source
script = autoload_server(p1, session)
return render_template('index.html', script=script)
I am saving the data source to g variable so that I can update it.
#socketio.on('my event', namespace='/test')
def test_message(message):
app = current_app._get_current_object()
with app.app_context():
print flask.g.p1
emit('my response', {'data': 'data'})
I am trying to update p1 if 'my event' happens.
But trying to access g variable raises error AttributeError: "'_AppCtxGlobals' object has no attribute 'p1'" error.
What am I doing wrong? Really appreciate the help.

Django sometimes fetching datetimes in native form from PostgreSQL even though USE_TZ = True

I'm using Django 1.4 and PostgreSQL.
In settings.py I have:
USE_TZ = True
Creation of dates always makes offset-aware timezones:
>>> from django.utils import timezone
>>> timezone.now()
datetime.datetime(2014, 9, 1, 7, 48, 12, 636318, tzinfo=<UTC>)
Models from my own app return timezone aware dates.
>>> from fundedbyme.campaign.models import *
>>> e = EquityCampaign.objects.all()[0].created
datetime.datetime(2013, 9, 19, 11, 29, 57, 844642, tzinfo=<UTC>)
From some other third party apps I return offset aware dates.
>>> from paypaladaptive.models import Payment
>>> Payment.objects.all()[0].created_date
datetime.datetime(2013, 5, 14, 11, 58, 47, 713878, tzinfo=<UTC>)
However the User model does not have a timezone aware date.
>>> u = User.objects.all()[0]
>>> u.date_joined
datetime.datetime(2014, 5, 13, 16, 20, 37, 709550)
Why would only the django user model not return offset aware datetimes? This is causing me a serious bug when I use django-registration. In the line linked to below, a native and aware date get compared.
https://bitbucket.org/ubernostrum/django-registration/src/8f242e35ef7c004e035e54b4bb093c32bf77c29f/registration/models.py?at=default#cl-218 it
I've looked in the auth_user table in postgres and the date_joined field is a "timestamp with time zone" field.
Why would I get native dates returned only on the User model?

RuntimeWarning: DateTimeField received a naive datetime

I m trying to send a simple mail using IPython. I have not set up any models still getting this error. What can be done?
Error :
/home/sourabh/Django/learn/local/lib/python2.7/site-packages/django/db/models/fields/init.py:827: RuntimeWarning: DateTimeField received a naive datetime (2013-09-04 14:14:13.698105) while time zone support is active.
RuntimeWarning)
Tried : The first step is to add USE_TZ = True to your settings file and install pytz (if possible).
Error changed:
(learn)sourabh#sL:~/Django/learn/event$ python manage.py shell
/home/sourabh/Django/learn/local/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py:53: RuntimeWarning: SQLite received a naive datetime (2013-09-05 00:59:32.181872) while time zone support is active.
RuntimeWarning)
The problem is not in Django settings, but in the date passed to the model. Here's how a timezone-aware object looks like:
>>> from django.utils import timezone
>>> import pytz
>>> timezone.now()
datetime.datetime(2013, 11, 20, 20, 8, 7, 127325, tzinfo=pytz.UTC)
And here's a naive object:
>>> from datetime import datetime
>>> datetime.now()
datetime.datetime(2013, 11, 20, 20, 9, 26, 423063)
So if you are passing email date anywhere (and it eventually gets to some model), just use Django's now(). If not, then it's probably an issue with an existing package that fetches date without timezone and you can patch the package, ignore the warning or set USE_TZ to False.
Use django.utils.timezone.make_aware function to make your naive datetime objects timezone aware and avoid those warnings.
It converts naive datetime object (without timezone info) to the one that has timezone info (using timezone specified in your django settings if you don't specify it explicitly as a second argument):
import datetime
from django.conf import settings
from django.utils.timezone import make_aware
naive_datetime = datetime.datetime.now()
naive_datetime.tzinfo # None
settings.TIME_ZONE # 'UTC'
aware_datetime = make_aware(naive_datetime)
aware_datetime.tzinfo # <UTC>
Just to fix the error to set current time
from django.utils import timezone
import datetime
datetime.datetime.now(tz=timezone.utc) # you can use this value
Quick and dirty - Turn it off:
USE_TZ = False
in your settings.py
make sure settings.py has
USE_TZ = True
In your python file:
from django.utils import timezone
timezone.now() # use its value in model field
One can both fix the warning and use the timezone specified in settings.py, which might be different from UTC.
For example in my settings.py I have:
USE_TZ = True
TIME_ZONE = 'Europe/Paris'
Here is a solution; the advantage is that str(mydate) gives the correct time:
>>> from datetime import datetime
>>> from django.utils.timezone import get_current_timezone
>>> mydate = datetime.now(tz=get_current_timezone())
>>> mydate
datetime.datetime(2019, 3, 10, 11, 16, 9, 184106,
tzinfo=<DstTzInfo 'Europe/Paris' CET+1:00:00 STD>)
>>> str(mydate)
'2019-03-10 11:16:09.184106+01:00'
Another equivalent method is using make_aware, see dmrz post.
If you are trying to transform a naive datetime into a datetime with timezone in django, here is my solution:
>>> import datetime
>>> from django.utils import timezone
>>> t1 = datetime.datetime.strptime("2019-07-16 22:24:00", "%Y-%m-%d %H:%M:%S")
>>> t1
datetime.datetime(2019, 7, 16, 22, 24)
>>> current_tz = timezone.get_current_timezone()
>>> t2 = current_tz.localize(t1)
>>> t2
datetime.datetime(2019, 7, 16, 22, 24, tzinfo=<DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>)
>>>
t1 is a naive datetime and t2 is a datetime with timezone in django's settings.
You can also override settings, particularly useful in tests:
from django.test import override_settings
with override_settings(USE_TZ=False):
# Insert your code that causes the warning here
pass
This will prevent you from seeing the warning, at the same time anything in your code that requires a timezone aware datetime may give you problems. If this is the case, see kravietz answer.
In the model, do not pass the value:
timezone.now()
Rather, remove the parenthesis, and pass:
timezone.now
If you continue to get a runtime error warning, consider changing the model field from DateTimeField to DateField.
If you need to convert the actual date string to date object, I have got rid of the warning by simply using astimezone:
>>> from datetime import datetime, timezone
>>> datetime_str = '2013-09-04 14:14:13.698105'
>>> datetime_object = datetime.strptime(datetime_str, "%Y-%m-%d %H:%M:%S.%f")
>>> datetime_object.astimezone(timezone.utc)
datetime.datetime(2013, 9, 4, 6, 14, 13, 698105, tzinfo=datetime.timezone.utc)
I encountered this warning when using the following model.
from datetime import datetime
class MyObject(models.Model):
my_date = models.DateTimeField(default=datetime.now)
To fix it, I switched to the following default.
from django.utils import timezone
class MyObject(models.Model):
my_date = models.DateTimeField(default=timezone.now)

Unix timestamp to datetime in django with timezone

I have a javascript calendar that is sending me a unixtimestamp. I am in Singapore. I want this timestamp to be interpreted as a Singapore timestamp and then converted to utc for comparisons with the db.
I cant, for the life of myself, figure out how to tell django that this time stamp is from the current timezone, Singapore.
When i do a print statement of the timestamp, it adds 8 hours to the time (which means that django thinks I input the time in utc and is localizing it to the Singaporean context)
Among many other things, I tried:
start=datetime.datetime.fromtimestamp(int(start_date)).replace(tzinfo=get_current_timezone())
The start_date is 1325376000 (which translates to 2012-01-01 00:00:00)
However,when i print the output of this I get 2012-01-01 08:00:00+06:55. I dont even know where +06:55 is coming from when singapore is +08:00. I am SO lost.
Thanks for your help.
settings.py:
TIME_ZONE = 'Asia/Singapore'
USE_TZ = True
all methods above are valide, but not "django like".
Here is a simple example, how a django programmer would do that:
from datetime import datetime
from django.utils.timezone import make_aware
# valid timestamp
value = 1531489250
# you can pass the following obj to a DateTimeField, when your settings.USE_TZ == True
datetime_obj_with_tz = make_aware(datetime.fromtimestamp(value))
See more utilites on the Django github timezone module to get whole overview...
Assuming you've got pytz installed:
from datetime import datetime
import pytz
local_tz = pytz.timezone("Asia/Singapore")
utc_dt = datetime.utcfromtimestamp(timestamp).replace(tzinfo=pytz.utc)
local_dt = local_tz.normalize(utc_dt.astimezone(local_tz))
For example:
>>> from datetime import datetime
>>> import pytz
>>> local_tz = pytz.timezone("Asia/Singapore")
>>> utc_dt = datetime.utcfromtimestamp(1325376000).replace(tzinfo=pytz.utc)
>>> utc_dt
datetime.datetime(2012, 1, 1, 0, 0, tzinfo=<UTC>)
>>> local_dt = local_tz.normalize(utc_dt.astimezone(local_tz))
>>> local_dt
datetime.datetime(2012, 1, 1, 8, 0, tzinfo=<DstTzInfo 'Asia/Singapore' SGT+8:00:00 STD>)
>>> local_dt.replace(tzinfo=None)
datetime.datetime(2012, 1, 1, 8, 0)
Pass the pytz tzinfo object to fromtimestamp() method:
#!/usr/bin/env python
from datetime import datetime
import pytz # $ pip install pytz
tz = pytz.timezone("Asia/Singapore")
print(datetime.fromtimestamp(1325376000, tz))
# -> 2012-01-01 08:00:00+08:00
Note: the result object is timezone-aware: you could compare it with other aware datetime objects i.e., you don't need to convert it to UTC for comparison -- you can use it as is.
I dont even know where +06:55 is coming from when singapore is +08:00.
You see +06:55 due to the invalid .replace() call. get_current_timezone() returns pytz.timezone("Asia/Singapore") that has a variable utc offset (it may have a different utc offset at different dates). When you call .replace() some random (depends on the implementation) tzinfo object is used. The issue is that .replace() method does not allow pytz.timezone("Asia/Singapore") to choose the correct tzinfo for the input date.
>>> list(tz._tzinfos.values())
[<DstTzInfo 'Asia/Singapore' MALT+7:00:00 STD>,
<DstTzInfo 'Asia/Singapore' MALT+7:20:00 STD>,
<DstTzInfo 'Asia/Singapore' JST+9:00:00 STD>,
<DstTzInfo 'Asia/Singapore' SMT+6:55:00 STD>,
<DstTzInfo 'Asia/Singapore' SGT+7:30:00 STD>,
<DstTzInfo 'Asia/Singapore' MALT+7:30:00 STD>,
<DstTzInfo 'Asia/Singapore' MALST+7:20:00 DST>,
<DstTzInfo 'Asia/Singapore' LMT+6:55:00 STD>,
<DstTzInfo 'Asia/Singapore' SGT+8:00:00 STD>]
i.e., both +06:55 and +0800 are valid (at different dates) for Singapore. That is why you should use .replace() only with timezones that have a constant utc offset such as the utc timezone itself (the offset is zero, always for any date).
fromtimestamp(,tz) method calls tz.fromutc() internally that allows tz to choose the correct offset for a given utc time.