I have had the same issue with object-level timezones.
I found this blog entry. It's not perfect but it works! and is not too complex. Plus handling the Admin is dealt with.
Pasting the snippets here:
Making sure the form is processed in the wanted timezone:
def view(request):
if request.method == 'POST':
tz_form = TimeZoneForm(request.POST)
if tz_form.is_valid():
tz = tz_form.cleaned_data['event_time_zone']
timezone.activate(tz)
# Process the full form now
else:
# assuming we have an event object already
timezone.activate(event.event_time_zone)
# Continue to create form for display on the web page
Displaying correctly in the Admin list view
class EventAdmin(admin.ModelAdmin):
list_display = [..., 'event_datetime_in_timezone', ...]
def event_datetime_in_timezone(self, event):
"""Display each event time on the changelist in its own timezone"""
fmt = '%Y-%m-%d %H:%M:%S %Z'
dt = event.event_datetime.astimezone(pytz_timezone(event.event_time_zone))
return dt.strftime(fmt)
event_datetime_in_timezone.short_description = _('Event time')
Interpret correctly the datetimne in Admin Add view
class EventAdmin(admin.ModelAdmin):
# ...
# Override add view so we can peek at the timezone they've entered and
# set the current time zone accordingly before the form is processed
def add_view(self, request, form_url='', extra_context=None):
if request.method == 'POST':
tz_form = TimeZoneForm(request.POST)
if tz_form.is_valid():
timezone.activate(tz_form.cleaned_data['event_time_zone'])
return super(EventAdmin, self).add_view(request, form_url, extra_context)
Handling correctly timezones in the Admin edit view
class EventAdmin(admin.ModelAdmin):
# ...
# Override change view so we can peek at the timezone they've entered and
# set the current time zone accordingly before the form is processed
def change_view(self, request, object_id, form_url='', extra_context=None):
if request.method == 'POST':
tz_form = TimeZoneForm(request.POST)
if tz_form.is_valid():
timezone.activate(tz_form.cleaned_data['event_time_zone'])
else:
obj = self.get_object(request, unquote(object_id))
timezone.activate(obj.event_time_zone)
return super(EventAdmin, self).change_view(request, object_id, form_url, extra_context)