Skip to main content

django-timezone-field

CI codecov pypi downloads pypi python support pypi django support

A Django app providing DB, form, and REST framework fields for zoneinfo and pytz timezone objects.

The transition from 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:

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.

Differences in recognized timezones between pytz and zoneinfo

pytz and zoneinfo search for timezone data differently.

  • pytz bundles and searches within its own copy of the IANA timezone DB
  • zoneinfo 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.

Examples

Database Field

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')

my_model.tz1 = "UTC"  # assignment of a string, immediately converted to timezone object
my_model.tz1          # zoneinfo.ZoneInfo(key='UTC') or pytz.utc, depending on use_pytz default
my_model.tz2 = "Invalid/Not_A_Zone"  # immediately raises ValidationError

Form Field

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')

REST Framework Serializer Field

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')

Installation

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

Running the tests

From the repository root, with poetry:

poetry install
poetry run pytest

Changelog

7.2.2 (2026-06-05)

  • Test aginst django 6.1 pre-release

7.2.1 (2025-12-06)

  • Add missing python classifier to package metadata

7.2 (2025-12-06)

  • Add support for django 6,0, 5.2
  • Add support for python 3.14

7.1 (2025-01-11)

  • Add support for python 3.13

7.0 (2024-07-07)

  • Better default sorting of choices (#116), (#123)
  • Convert string value to timezone object immediately on creation/assignment. Accessing a TimeZoneField will always return a timezone or None (never a string). (Potentially BREAKING: Unknown timezone names now raise ValidationError at time of assignment. Previously, conversion was delayed until model full_clean or save.) (#57)
  • Add support for django 5.1
  • Drop support for django 3.2, 4.0, 4.1
  • Change base class of TimeZoneSerializerField from DJRF's Field to CharField (#137)

6.1.0 (2023-11-25)

  • Add support for django 5.0
  • Add support for python 3.12
  • Fix issue with Factory timezone on some BSD systems (#114)

6.0.1 (2023-09-07)

  • Use correct default backend when running with django 3.X (#109)

6.0 (2023-08-20)

  • BREAKING: pytz removed from dependencies. If you use this package with use_pytz=True, you'll need to install pytz yourself.
  • Drop support for django 2.2
  • Drop support for python 3.7

5.1 (2023-06-18)

  • Add django as a dependency of this package, with correct version constraints (#90)
  • Add support for django 4.1, 4.2
  • Add support for python 3.11

5.0 (2022-02-08)

  • Add support for zoneinfo objects (#79)
  • Add support for django 4.0
  • Remove timezone_field.utils.add_gmt_offset_to_choices, display_GMT_offset kwarg (use choices_display instead)
  • Drop support for django 3.0, 3.1
  • Drop support for python 3.5, 3.6

4.2.3 (2022-01-13)

  • Fix sdist installs (#78)
  • Officially support python 3.10

4.2.1 (2021-07-07)

  • Reinstate TimeZoneField.default_choices (#76)

4.2 (2021-07-07)

  • Officially support django 3.2, python 3.9
  • Fix bug with field deconstruction (#74)
  • Housekeeping: use poetry, github actions, pytest

4.1.2 (2021-03-17)

  • Avoid NonExistentTimeError during DST transition (#70)

4.1.1 (2020-11-28)

  • Don't import rest_framework from package root (#67)

4.1 (2020-11-28)

  • Add Django REST Framework serializer field
  • Add new choices_display kwarg with supported values WITH_GMT_OFFSET and STANDARD
  • Deprecate display_GMT_offset kwarg

4.0 (2019-12-03)

  • Add support for django 3.0, python 3.8
  • Drop support for django 1.11, 2.0, 2.1, python 2.7, 3.4

3.1 (2019-10-02)

  • Officially support django 2.2 (already worked)
  • Add option to display TZ offsets in form field (#46)

3.0 (2018-09-15)

  • Support django 1.11, 2.0, 2.1
  • Add support for python 3.7
  • Change default human-readable timezone names to exclude underscores (#32 & #37)

2.1 (2018-03-01)

  • Add support for django 1.10, 1.11
  • Add support for python 3.6
  • Add wheel support
  • Support bytes in DB fields (#38 & #39)

2.0 (2016-01-31)

  • Drop support for django 1.7, add support for django 1.9
  • Drop support for python 3.2, 3.3, add support for python 3.5
  • Remove tests from source distribution

1.3 (2015-10-12)

  • Drop support for django 1.6, add support for django 1.8
  • Various bug fixes

1.2 (2015-02-05)

  • For form field, changed default list of accepted timezones from pytz.all_timezones to pytz.common_timezones, to match DB field behavior.

1.1 (2014-10-05)

  • Django 1.7 compatibility
  • Added support for formatting choices kwarg as [[<str>, <str>], ...], in addition to previous format of [[<pytz.timezone>, <str>], ...].
  • Changed default list of accepted timezones from 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.

1.0 (2013-08-04)

  • Initial release as timezone_field.

Credits

Originally adapted from Brian Rosner's django-timezones.

Made possible thanks to the work of the contributors.

Metadata

Release files for django-timezone-field 7.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-timezone-field 7.2.2
File Size Uploaded
django_timezone_field-7.2.2.tar.gz 13.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-timezone-field 7.2.2
File Interpreter ABI Platform
django_timezone_field-7.2.2-py3-none-any.whl Python 3 none any Details

Total release size: 26.5 kB

Release files / django_timezone_field-7.2.2.tar.gz

Download URL django_timezone_field-7.2.2.tar.gz
Size 13.2 kB
Tags Source
SHA-256 checksum
How to use checksums
a004d0b19fe10bf5964cb21a65b36324b16a61879e4711c0dafdf8d6253e8ebc
BLAKE2b-256 checksum
How to use checksums
120b22654abc2355f3b84e3e5b9d26569639c15d04b96d7186f3a477ec45c1ef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.2.1 CPython/3.12.12 Darwin/25.5.0

Release files / django_timezone_field-7.2.2-py3-none-any.whl

Download URL django_timezone_field-7.2.2-py3-none-any.whl
Size 13.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
30354d0f37462a0b9b5c289e271580a6be9b58dea30e7bf88435372882c8fa7a
BLAKE2b-256 checksum
How to use checksums
2b5fc8dfb67105c4ef391a3e9d0bcd35b7eae4c4c9d023d612c3999ae1cb32ef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.2.1 CPython/3.12.12 Darwin/25.5.0

Release history Release notifications | RSS feed

This release

7.2.2 This release

2 release files

7.2.1

2 release files

7.2

2 release files

7.1

2 release files

7.0

2 release files

6.1.0

2 release files

6.0.1

2 release files

6.0

2 release files

5.1

2 release files

5.0

2 release files

4.2.3

2 release files

4.2.2

2 release files

4.2.1

2 release files

4.2

2 release files

4.1.2

2 release files

4.1.1

2 release files

4.1

2 release files

4.0

2 release files

3.1

2 release files

3.0

2 release files

2.1

2 release files

2.0

1 release file

1.3

1 release file

1.2

1 release file

1.1

1 release file

1.0

1 release file

0.4

1 release file

0.3.2

1 release file

0.3.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page