While I read just about every post related to timezone conversions I'm still having some issues and my converted time is incorrect
settings.py
TIME_ZONE = 'UTC'
USE_TZ = True
views.py
utc = datetime.utcnow()
instance_time_zone = pytz.timezone(instance.timezone) # 'US/Pacific'
start_date = instance_time_zone.localize(datetime.utcnow(), is_dst=None)
template.html
utc: Oct. 2, 2015, 5:32 p.m. #correct time
start_date: Oct. 3, 2015, 1:32 a.m. #incorrect time
For some reason, the converted time is wrong and 15 hours ahead of the Pacific Time and 8 hours ahead of the UTC time.
timezone.localize()
should be used for naive datetime
objects (objects with no timezone of their own). The timezone is attached to that datetime
as if the date and time are correct for that timezone. So in your case you 'localised' UTC as if it is your local time without DST, shifting it 8 hours in the wrong direction.
You used a UTC timestamp however, so you need to attach the UTC timezone to that, then move the timestamp to the desired timezone:
utc = pytz.utc.localize(datetime.utcnow())
instance_time_zone = pytz.timezone(instance.timezone) # 'US/Pacific'
start_date = utc.astimezone(instance_time_zone)
Note that the utc
value is now a datetime
object with timezone, so you can then use the datetime.astimezone()
method to produce a value in the desired target timezone from it.
Demo:
>>> from datetime import datetime
>>> utc = pytz.utc.localize(datetime.utcnow())
>>> utc
datetime.datetime(2015, 10, 2, 17, 58, 10, 168575, tzinfo=<UTC>)
>>> instance_time_zone = pytz.timezone('US/Pacific')
>>> utc.astimezone(instance_time_zone)
datetime.datetime(2015, 10, 2, 10, 58, 10, 168575, tzinfo=<DstTzInfo 'US/Pacific' PDT-1 day, 17:00:00 DST>)
Now the produced datetime
is properly 5 hours removed from UTC.
If you are outputting these values into a Django template, however, note that Django will also transform the timezone. See the Django timezone documentation, specifically the section on using aware datetime objects in templates:
When you enable time zone support, Django converts aware datetime objects to the current time zone when they’re rendered in templates. This behaves very much like format localization.
and from the current time zone section:
You should set the current time zone to the end user’s actual time zone with
activate()
. Otherwise, the default time zone is used.
It then doesn't matter what timezone you moved the datetime
object to; it'll use whatever is the current timezone to display the value. You generally want to use aware datetime
objects in the UTC timezone, then use activate()
to switch what timezone everything is displayed in.
So in Django, just use timezone.now()
everywhere, and let the templating system worry about converting that to a given timezone.