A Django app providing DB, form, and REST framework fields for zoneinfo and pytz timezone objects.
A Django app providing DB, form, and REST framework fields for
zoneinfo
and pytz
timezone
objects.
pytz
to zoneinfo
Like Django, this app supports both pytz
and zoneinfo
objects while the community transitions away from pytz
to
zoneinfo
. All exposed fields and functions that return a timezone object accept an optional boolean kwarg use_pytz
.
If not explicitly specified, the default value used for use_pytz
matches Django's behavior:
use_pytz
defaults to True
use_pytz
defaults to the value of
django.conf.settings.USE_DEPRECATED_PYTZ
,
which itself defaults to False
pytz
altogether,
and this app will likely do the same.Note that this app does not declare pytz
to be a dependency, so if you're using this app with use_pytz=True
, you'll need
to ensure pytz
is included in the environment yourself.
pytz
and zoneinfo
pytz
and zoneinfo
search for timezone data differently.
pytz
bundles and searches within its own copy of the IANA timezone DBzoneinfo
first searches the local system's timezone DB for a match. If no match is found, it then searches within
the tzdata
package if it is installed. The tzdata
package contains a copy of
the IANA timezone DB.If the local system's timezone DB doesn't cover the entire IANA timezone DB and the tzdata
package is not installed,
you may run across errors like ZoneInfoNotFoundError: 'No time zone found with key Pacific/Kanton'
for seemingly valid
timezones when transitioning from pytz
to zoneinfo
. The easy fix is to add tzdata
to your project with
poetry add tzdata
or pip install tzdata
.
Assuming you have the tzdata
package installed if needed, no
data migration should be necessary when
switching from pytz
to zoneinfo
.
import zoneinfo
import pytz
from django.db import models
from timezone_field import TimeZoneField
class MyModel(models.Model):
tz1 = TimeZoneField(default="Asia/Dubai") # defaults supported, in ModelForm renders like "Asia/Dubai"
tz2 = TimeZoneField(choices_display="WITH_GMT_OFFSET") # in ModelForm renders like "GMT+04:00 Asia/Dubai"
tz3 = TimeZoneField(use_pytz=True) # returns pytz timezone objects
tz4 = TimeZoneField(use_pytz=False) # returns zoneinfo objects
my_model = MyModel(
tz2="America/Vancouver", # assignment of a string
tz3=pytz.timezone("America/Vancouver"), # assignment of a pytz timezone
tz4=zoneinfo.ZoneInfo("America/Vancouver"), # assignment of a zoneinfo
)
my_model.full_clean() # validates against pytz.common_timezones by default
my_model.save() # values stored in DB as strings
my_model.tz3 # value returned as pytz timezone: <DstTzInfo 'America/Vancouver' LMT-1 day, 15:48:00 STD>
my_model.tz4 # value returned as zoneinfo: zoneinfo.ZoneInfo(key='America/Vancouver')
from django import forms
from timezone_field import TimeZoneFormField
class MyForm(forms.Form):
tz1 = TimeZoneFormField() # renders like "Asia/Dubai"
tz2 = TimeZoneFormField(choices_display="WITH_GMT_OFFSET") # renders like "GMT+04:00 Asia/Dubai"
tz3 = TimeZoneFormField(use_pytz=True) # returns pytz timezone objects
tz4 = TimeZoneFormField(use_pytz=False) # returns zoneinfo objects
my_form = MyForm({"tz3": "Europe/Berlin", "tz4": "Europe/Berlin"})
my_form.full_clean() # validates against pytz.common_timezones by default
my_form.cleaned_data["tz3"] # value returned as pytz timezone: <DstTzInfo 'Europe/Berlin' LMT+0:53:00 STD>
my_form.cleaned_data["tz4"] # value returned as zoneinfo: zoneinfo.ZoneInfo(key='Europe/Berlin')
from rest_framework import serializers
from timezone_field.rest_framework import TimeZoneSerializerField
class MySerializer(serializers.Serializer):
tz1 = TimeZoneSerializerField(use_pytz=True)
tz2 = TimeZoneSerializerField(use_pytz=False)
my_serializer = MySerializer(data={
"tz1": "America/Argentina/Buenos_Aires",
"tz2": "America/Argentina/Buenos_Aires",
})
my_serializer.is_valid()
my_serializer.validated_data["tz1"] # <DstTzInfo 'America/Argentina/Buenos_Aires' LMT-1 day, 20:06:00 STD>
my_serializer.validated_data["tz2"] # zoneinfo.ZoneInfo(key='America/Argentina/Buenos_Aires')
Releases are hosted on pypi
and can be installed using various
python packaging tools.
# with poetry
poetry add django-timezone-field
# with pip
pip install django-timezone-field
From the repository root, with poetry
:
poetry install
poetry run pytest
Factory
timezone on some BSD systems (#114)pytz
removed from dependencies. If you use this package with use_pytz=True
, you'll need to install
pytz
yourself.zoneinfo
objects (#79)timezone_field.utils.add_gmt_offset_to_choices
, display_GMT_offset
kwarg (use choices_display
instead)TimeZoneField.default_choices
(#76)NonExistentTimeError
during DST transition (#70)rest_framework
from package root (#67)choices_display
kwarg with supported values WITH_GMT_OFFSET
and STANDARD
display_GMT_offset
kwargpytz.all_timezones
to pytz.common_timezones
, to
match DB field behavior.choices
kwarg as [[<str>, <str>], ...]
, in addition to previous format of
[[<pytz.timezone>, <str>], ...]
.pytz.all_timezones
to pytz.common_timezones
. If you have timezones
in your DB that are in pytz.all_timezones
but not in pytz.common_timezones
, this is a backward-incompatible
change. Old behavior can be restored by specifying choices=[(tz, tz) for tz in pytz.all_timezones]
in your model
definition.timezone_field
.Originally adapted from Brian Rosner's django-timezones.
Made possible thanks to the work of the contributors.