This app is derived from brosner/django-timezones application (http://github.com/brosner/django-timezones). It takes different approach to timezones localization, so I’ve separated those two apps for clarity.
django-tz manages timezones transitions in a manner similar to how django implements language switching. Timezone is stored in global cache and datetime values can be ,,localized’’ according to it in templates with custom template filter or in forms with custom form fields. Because timezone localization works through form fields and template filter you can easily add it to an existing app.
,,What does this application do?’’
- It defines TimeZoneField which is taken from django-timezones.
- It provides global (per thread) timezone cache which can be easily updated by custom middleware.
- It defines LocalizedDateTimeField (+ some additional form fields) – which makes automatically transitions: settings.TIME_ZONE <—> current timezone.
- It implements template filter to localize datetime values according to cache.
- It defines set_timezone view which stores given timezone in session or cookie.
This multivalue form field decompresses given datetime value to datetime and timezone. It contains: DateTimeField and TimezoneField. TimezoneField is set by default to current global timezone (if given value has empty tzinfo) and datetime value is converted from default timezone (settings.TIME_ZONE) to selected timezone. After form submit this process is reversed.
There is also split (similar to SplitDateTimeField) version of this field (SplitLocalizedDateTimeField).
This template filter takes datetime value and assumes that is given in default timezone (settings.TIME_ZONE) and converts it to current global timezone value.
This is simple view which is nearly copy of django.views.i18n.set_language. It caches timezone in session or cookie. Default middleware uses it to determine current timezone.
Assume that we have Profile model which contains ,,timezone’’ field and MeetUp model with ,,start’’ field:
class Profile(models.Model):
user = models.ForeignKey(User)
timezone = models.TimeZoneField()
class MeetUp(models.Model):
start = models.DateTimeField()
user = models.ForeignKey(editable=False)
Now we want to switch timezone according to user settings for every request. This can be done through simple middleware:
from django_tz.middleware import GlobalTimezoneMiddleware, get_tz_from_request
class ProfileTimezoneMiddleware(GlobalTimezoneMiddleware):
def get_tz(self, request):
if hasattr(request, 'user') and request.user.is_authenticated():
profile = request.user.get_profile()
return profile.timezone
return get_tz_from_request(request)
When you want display your meet ups in template you can use to_global_tz filter which converts it to currently used timezone:
{% load django_tz_tags %}
{{ meetup.start|to_global_tz }}
In forms you should use LocalizedDateTimeField (or it’s split version), which is multi value field (datettime + timezone):
class MeetUpForm(forms.ModelForm):
start = LocalizedDateTimeField()
class Model:
model = MeetUp
This form renders as follows:
<p>
<label for="id_start_0">Start:</label>
<input type="text" name="start_0" id="id_start_0" />
<select name="start_1" id="id_start_1">
<option value="Africa/Abidjan">Africa/Abidjan</option>
<option value="Africa/Accra">Africa/Accra</option>
...
</select>
</p>
I think that in most cases you don’t want to show timezone subfield to the user. To hide it use HiddenInput widget:
class MeetUpForm(forms.ModelForm):
start = LocalizedDateTimeField(timezone_widget=widgets.HiddenInput)
...
From pytz docs:
,,UTC is Universal Time, also known as Greenwich Mean Time or GMT in the United Kingdom. All other timezones are given as offsets from UTC. No daylight savings time occurs in UTC, making it a useful timezone to perform date arithmetic without worrying about the confusion and ambiguities caused by daylight savings time transitions, your country changing its timezone, or mobile computers that move roam through multiple timezones.’’
TIME_ZONE='UTC'
I think it’s better to keep all datetime values in UTC in database and convert them to other default timezone (for example with middleware and global cache).
Add django_tz to INSTALLED_APPS and include django_tz.urls your url patterns (there are some tests for views) and run ./manage.py test django_tz.
- DST ambiguity problem – there should be is_dst field (which can be ignored for most cases) in all form fields.