#10587 closed (duplicate)
Store datetime as UTC and change how Django handles datetime objects
Reported by: | George Song | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.0 |
Severity: | Keywords: | ||
Cc: | django@… | Triage Stage: | Unreviewed |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Problem
The way Django handles datetime right now makes developing time zone aware applications unnecessarily hard.
I've been doing some research and some thinking about this issue, mainly from these two tickets:
How it is right now
As I understand it right now, this is how datetime works in Django:
- For anything that implements
time.tzset()
, Django sets the timezone for the entire runtime tosettings.TIME_ZONE
. This means on Windows the setting is ignored. Django on Windows will operate in whatever timezone is specified on the OS.
- EXCEPT in the case of PostgreSQL backend, where the db connection initializes with
cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE])
. Sincetimestamp
andtime
fields are createdwith time zone
, this means PostgreSQL will return datetime values typecasted tosettings.TIME_ZONE
first.
- Django typecasts everything to naive Python
datetime
objects (notzinfo
attached).
Proposed solution
This blog post is a good overview of how Rails handles time zone support: http://mad.ly/2008/04/09/rails-21-time-zone-support-an-overview/
- PostgreSQL should not have time zone set, or have time zone set to 'UTC'.
- Django should store all datetime on DB backends as naive UTC datetime.
settings.TIME_ZONE
becomes a site-wide runtime typecast directive. This waysettings.TIME_ZONE
can be optional if someone doesn't care about time zones in their application. In that case it feels more natural to operate in the timezone of the server hosting Django. The default return frommodel.some_datetime_field
could be:
from django.conf import settings from django.db.backends.util import typecast_timestamp from dateutil.tz import tzutc, tzstr, tzlocal utc = tzutc() server_tz = tzlocal() settings_tz = None if settings.TIME_ZONE: settings_tz = tzstr(settings.TIME_ZONE) utc_dt = typecast_timestamp(db_value).replace(tzinfo=utc) if settings_tz == utc: dt = utc_dt elif settings_tz: # Cast it to the specified timezone dt = utc_dt.astimezone(settings_tz) else: # Cast to server local time then make it naive dt = utc_dt.astimezone(server_tz).replace(tzinfo=None) return dt
- On the way back into the database, Django can do something like:
from django.conf import settings from dateutil.tz import tzutc, tzstr utc = tzutc() server_tz = tzlocal() settings_tz = None if settings.TIME_ZONE: settings_tz = tzstr(settings.TIME_ZONE) dt = dt_value_from_model_save if dt.tzinfo: pass # It's a smart date, do nothing. elif settings_tz: dt = dt.replace(tzinfo=settings_tz) else: # Default to server time zone dt = dt.replace(tzinfo=server_tz) dt = dt.astimezone(utc).replace(tzinfo=None) # Now save dt into the database
- I think the following convenience
DateTimeField
instance methods or attributes might be nice:
naive_utc
: returnsdatetime.datetime
object in UTC, notzinfo
utc
: returnsdatetime.datetime
object in UTC, withtzinfo
posix_timestamp
: returns the POSIX timestamp as float, such as is returned bytime.time()
, with the exception that microsecond precision should be retainedastimezone(tzinfo)
: might be convenient for those who operate in naive datetime mode most of the time, but have specific places where time zones are important
Benefits
- Django doesn't have to change the entire runtime with
os.environ['TZ']
ortime.tzset()
.
- Windows servers acts just like Unix servers.
- I don't think this will break standard application code, since
settings.TIME_ZONE
essentially functions the same way as before, except yourdatetime
objects will havetzinfo
attached.
- For those dealing with time zones, UTC underneath the hood!
- If you want UTC everything while working inside Django,
settings.TIME_ZONE='UTC'
.
- If you don't care about time zones,
settings.TIME_ZONE=None
.
Change History (3)
comment:1 by , 16 years ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
comment:3 by , 15 years ago
Cc: | added |
---|
Note:
See TracTickets
for help on using tickets.
Duplicate of #2626