File: README.md

package info (click to toggle)
python-django-timezone-field 7.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 292 kB
  • sloc: python: 1,047; sh: 6; makefile: 3
file content (279 lines) | stat: -rw-r--r-- 11,768 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# django-timezone-field

[![CI](https://github.com/mfogel/django-timezone-field/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mfogel/django-timezone-field/actions)
[![codecov](https://codecov.io/gh/mfogel/django-timezone-field/branch/main/graph/badge.svg?token=Rwekzmim3l)](https://codecov.io/gh/mfogel/django-timezone-field)
[![pypi downloads](https://img.shields.io/pypi/dm/django-timezone-field.svg)](https://pypi.python.org/pypi/django-timezone-field/)
[![pypi python support](https://img.shields.io/pypi/pyversions/django-timezone-field.svg)](https://pypi.python.org/pypi/django-timezone-field/)
[![pypi django support](https://img.shields.io/pypi/djversions/django-timezone-field.svg)](https://pypi.python.org/pypi/django-timezone-field/)

A Django app providing DB, form, and REST framework fields for
[`zoneinfo`](https://docs.python.org/3/library/zoneinfo.html) and [`pytz`](http://pypi.python.org/pypi/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:

- Django <= 3.X: `use_pytz` defaults to `True`
- Django == 4.X: `use_pytz` defaults to the value of
  [`django.conf.settings.USE_DEPRECATED_PYTZ`](https://docs.djangoproject.com/en/4.0/ref/settings/#use-deprecated-pytz),
  which itself defaults to `False`
- Django >= 5.X: 
  [drops support for `pytz` altogether](https://docs.djangoproject.com/en/5.0/releases/5.0/#features-removed-in-5-0),
  and this app has done 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.

### 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](https://www.iana.org/time-zones)
- `zoneinfo` first searches the local system's timezone DB for a match. If no match is found, it then searches within
  the [`tzdata`](https://pypi.org/project/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](https://docs.djangoproject.com/en/4.0/topics/migrations/#data-migrations) should be necessary when
switching from `pytz` to `zoneinfo`.

## Examples

### Database Field

```python
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

```python
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

```python
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`](https://pypi.org/project/django-timezone-field/) and can be installed using various
python packaging tools.

```bash
# with poetry
poetry add django-timezone-field

# with pip
pip install django-timezone-field
```

## Running the tests

From the repository root, with [`poetry`](https://python-poetry.org/):

```bash
poetry install
poetry run pytest
```

## Changelog

#### 7.1 (2025-01-11)

- Add support for python 3.13

#### 7.0 (2024-07-07)

- Better default sorting of `choices` ([#116](https://github.com/mfogel/django-timezone-field/issues/116)), ([#123](https://github.com/mfogel/django-timezone-field/issues/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](https://github.com/mfogel/django-timezone-field/issues/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](https://github.com/mfogel/django-timezone-field/issues/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](https://github.com/mfogel/django-timezone-field/issues/114))

#### 6.0.1 (2023-09-07)

- Use correct default backend when running with django 3.X ([#109](https://github.com/mfogel/django-timezone-field/issues/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](https://github.com/mfogel/django-timezone-field/issues/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](https://github.com/mfogel/django-timezone-field/issues/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](https://github.com/mfogel/django-timezone-field/issues/78))
- Officially support python 3.10

#### 4.2.1 (2021-07-07)

- Reinstate `TimeZoneField.default_choices` ([#76](https://github.com/mfogel/django-timezone-field/issues/76))

#### 4.2 (2021-07-07)

- Officially support django 3.2, python 3.9
- Fix bug with field deconstruction ([#74](https://github.com/mfogel/django-timezone-field/issues/74))
- Housekeeping: use poetry, github actions, pytest

#### 4.1.2 (2021-03-17)

- Avoid `NonExistentTimeError` during DST transition ([#70](https://github.com/mfogel/django-timezone-field/issues/70))

#### 4.1.1 (2020-11-28)

- Don't import `rest_framework` from package root ([#67](https://github.com/mfogel/django-timezone-field/issues/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](https://github.com/mfogel/django-timezone-field/issues/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](https://github.com/mfogel/django-timezone-field/issues/32) &
  [#37](https://github.com/mfogel/django-timezone-field/issues/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](https://github.com/mfogel/django-timezone-field/issues/38) &
  [#39](https://github.com/mfogel/django-timezone-field/issues/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](https://github.com/mfogel/django-timezone-field/issues?q=milestone%3A1.3)

#### 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](https://github.com/brosner/django-timezones).

Made possible thanks to the work of the
[contributors](https://github.com/mfogel/django-timezone-field/graphs/contributors).