### Install project dependencies and run tests with Poetry Source: https://github.com/mfogel/django-timezone-field/blob/main/README.md After cloning the repository, use these commands to install all necessary dependencies and run the test suite. ```bash poetry install poetry run pytest ``` -------------------------------- ### Getting a Timezone Backend Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-backends.md Demonstrates how to retrieve the default, PYTZ, or ZoneInfo backend using `get_tz_backend`. ```APIDOC ## Getting a Timezone Backend ### Description This function retrieves a timezone backend instance. It can be used to get the default backend based on the Django version, or explicitly request the PYTZ or ZoneInfo backend. ### Function Signature `get_tz_backend(use_pytz: Optional[bool]) -> BaseTzBackend` ### Parameters #### Argument `use_pytz` - `None` (Optional): Returns the default backend (ZoneInfoBackend on Django 5.x+, PYTZBackend otherwise). - `True` (Optional): Explicitly returns the PYTZBackend. - `False` (Optional): Explicitly returns the ZoneInfoBackend. ### Example ```python from timezone_field.backends import get_tz_backend # Get the default backend default_backend = get_tz_backend(None) # Get PYTZ backend explicitly pytz_backend = get_tz_backend(True) # Get ZoneInfo backend explicitly zoneinfo_backend = get_tz_backend(False) ``` ``` -------------------------------- ### Install tzdata for Timezone Coverage Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/configuration.md Install the 'tzdata' package to ensure complete timezone coverage, which is particularly important when using the 'zoneinfo' module. ```bash # Install tzdata for complete timezone coverage (especially important for zoneinfo) pip install tzdata ``` ```bash # Or with poetry poetry add tzdata ``` -------------------------------- ### Comprehensive TimeZoneField Example with Type Hints Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/types.md Illustrates a comprehensive example of TimeZoneField usage with type hints, including field definition, default values, and choices display. It highlights that after version 7.0, the `config.timezone` attribute will always be a `zoneinfo.ZoneInfo` object or None, never a string. This snippet also shows how to use the timezone object with standard library functions like `datetime.datetime.now`. ```python from typing import Optional from django.db import models from timezone_field import TimeZoneField class Config(models.Model): # Field type timezone: Optional[TimeZoneField] = TimeZoneField( default="UTC", choices_display="WITH_GMT_OFFSET", use_pytz=False ) # Instance attribute type (what you get when accessing the field) # After v7.0: always zoneinfo.ZoneInfo or None, never str # Usage with type hints config: Config = Config.objects.first() if config and config.timezone: # Type of config.timezone: zoneinfo.ZoneInfo tz_str: str = str(config.timezone) # "America/New_York" # Can use timezone methods now = datetime.datetime.now(tz=config.timezone) ``` -------------------------------- ### Basic Model with Default Configuration Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/configuration.md Define a model with a TimeZoneField using the default UTC setting. This example shows basic model integration. ```python from django.db import models from timezone_field import TimeZoneField class User(models.Model): name = models.CharField(max_length=100) timezone = TimeZoneField(default="UTC") # On Django 5.x: uses zoneinfo # On Django 4.x: uses zoneinfo (if USE_DEPRECATED_PYTZ not set to True) # On Django 3.x: uses pytz ``` -------------------------------- ### Install django-timezone-field with Poetry Source: https://github.com/mfogel/django-timezone-field/blob/main/README.md Use this command to add the package to your project if you are using Poetry for dependency management. ```bash poetry add django-timezone-field ``` -------------------------------- ### Form Processing and Validation Example Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-form-field.md Shows how to process form data with TimeZoneFormField, validating input and accessing cleaned timezone objects. ```python form_data = {'timezone': 'Europe/Berlin'} form = MyForm(data=form_data) if form.is_valid(): # cleaned_data contains timezone objects, not strings cleaned_tz = form.cleaned_data['timezone'] print(type(cleaned_tz)) # print(cleaned_tz) # zoneinfo.ZoneInfo(key='Europe/Berlin') else: # Form validation errors print(form.errors) # Invalid timezone input form_data = {'timezone': 'Invalid/Timezone'} form = MyForm(data=form_data) form.is_valid() # False print(form.errors) # {'timezone': ['Unknown time zone: 'Invalid/Timezone'.']} ``` -------------------------------- ### Get Timezone Backend Instance Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-backends.md Use this factory function to get a timezone backend instance. Instances are cached for performance. It determines the backend based on the `use_pytz` parameter or Django settings. ```python def get_tz_backend(use_pytz: bool | None) -> TimeZoneBackend: # ... implementation details ... pass ``` -------------------------------- ### Install django-timezone-field with Pip Source: https://github.com/mfogel/django-timezone-field/blob/main/README.md Use this command to add the package to your project if you are using pip for dependency management. ```bash pip install django-timezone-field ``` -------------------------------- ### Django Model TimeZoneField Examples Source: https://github.com/mfogel/django-timezone-field/blob/main/README.md Demonstrates defining TimeZoneField in Django models with various configurations for defaults, display formats, and pytz/zoneinfo object handling. Shows assignment and validation. ```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: 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 ``` -------------------------------- ### Django Form TimeZoneFormField Examples Source: https://github.com/mfogel/django-timezone-field/blob/main/README.md Illustrates using TimeZoneFormField in Django forms, showing different display options and how to handle pytz/zoneinfo objects after cleaning. Assumes form data is provided. ```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: my_form.cleaned_data["tz4"] # value returned as zoneinfo: zoneinfo.ZoneInfo(key='Europe/Berlin') ``` -------------------------------- ### Django REST Framework TimeZoneSerializerField Examples Source: https://github.com/mfogel/django-timezone-field/blob/main/README.md Shows how to use TimeZoneSerializerField in DRF serializers for handling timezone data. Demonstrates validation and retrieval of validated data as pytz or zoneinfo objects. ```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"] # my_serializer.validated_data["tz2"] # zoneinfo.ZoneInfo(key='America/Argentina/Buenos_Aires') ``` -------------------------------- ### Get Default Timezone Backend Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-backends.md Retrieve the default timezone backend, which varies based on the Django version. You can also explicitly request the pytz or zoneinfo backends. ```python from timezone_field.backends import get_tz_backend # Get the default backend (depends on Django version) backend = get_tz_backend(None) print(type(backend)) # on Django 5.x # Get PYTZ backend explicitly pytz_backend = get_tz_backend(True) print(type(pytz_backend)) # # Get ZoneInfo backend explicitly zoneinfo_backend = get_tz_backend(False) print(type(zoneinfo_backend)) # ``` -------------------------------- ### Get Coerce Method Signature Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-form-field.md Signature for the get_coerce helper function. It creates a function to convert timezone strings to timezone objects. ```python def get_coerce(tz_backend) -> callable ``` -------------------------------- ### __set__ Method - Automatic Deserialization Example Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/utilities.md Demonstrates how the __set__ method of AutoDeserializedAttribute automatically deserializes a string timezone value to a timezone object immediately upon assignment to a model instance. Invalid values will raise an error. ```python from django.db import models from timezone_field import TimeZoneField class MyModel(models.Model): timezone = TimeZoneField() # When assigning a string, it's immediately converted obj = MyModel() obj.timezone = "America/New_York" # __set__ is called # The attribute now contains a timezone object, not a string print(type(obj.timezone)) # print(obj.timezone) # zoneinfo.ZoneInfo(key='America/New_York') # This happens even before save() or full_clean() # Invalid values raise ValidationError immediately try: obj.timezone = "Invalid/Timezone" except Exception as e: print(f"Error: {e}") ``` -------------------------------- ### Get Python and Database Representations Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-field.md Internal method returning both the Python timezone object and its database string representation. Raises ValidationError for invalid timezone strings. ```python def _get_python_and_db_repr(self, value) -> tuple[object | None, str] ``` -------------------------------- ### Field Assignment Behavior Example Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/utilities.md Demonstrates how assigning a timezone string to a TimeZoneField automatically converts it to a timezone object. Invalid assignments raise a ValidationError immediately. ```python from django.db import models from timezone_field import TimeZoneField class Event(models.Model): event_timezone = TimeZoneField() # Create instance with string event = Event(event_timezone="UTC") # Immediately converted to timezone object print(type(event.event_timezone)) # print(event.event_timezone) # zoneinfo.ZoneInfo(key='UTC') # No conversion happens at save time (already done) event.save() print(event.event_timezone) # Still a zoneinfo.ZoneInfo object # Assignment also triggers conversion event.event_timezone = "America/Los_Angeles" print(event.event_timezone) # zoneinfo.ZoneInfo(key='America/Los_Angeles') # Invalid values raise immediately try: event.event_timezone = "Not/A/Timezone" except ValidationError as e: print(f"Validation failed: {e}") ``` -------------------------------- ### Switch Between pytz and zoneinfo Backends Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-backends.md Demonstrates how to instantiate and use both the pytz and zoneinfo timezone backends, showing that they represent the same timezones despite different underlying implementations. ```python import zoneinfo import pytz from timezone_field.backends import get_tz_backend # Working with pytz pytz_backend = get_tz_backend(True) ny_pytz = pytz_backend.to_tzobj("America/New_York") print(type(ny_pytz)) # # Working with zoneinfo zinfo_backend = get_tz_backend(False) ny_zinfo = zinfo_backend.to_tzobj("America/New_York") print(type(ny_zinfo)) # # Both represent the same timezone, different implementations print(str(ny_pytz) == str(ny_zinfo)) # True ``` -------------------------------- ### ZoneInfoBackend Initialization Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-backends.md Initializes the ZoneInfoBackend using Python's built-in zoneinfo module. This backend provides timezone handling without external dependencies. ```python class ZoneInfoBackend(TimeZoneBackend): utc_tzobj = zoneinfo.ZoneInfo("UTC") all_tzstrs = zoneinfo.available_timezones() base_tzstrs = zoneinfo.available_timezones() ``` -------------------------------- ### PYTZBackend Initialization Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-backends.md Initializes the PYTZBackend with timezone attributes derived from the pytz library. Use this backend for timezone handling when pytz is available. ```python class PYTZBackend(TimeZoneBackend): utc_tzobj = pytz.utc all_tzstrs = pytz.all_timezones base_tzstrs = pytz.common_timezones ``` -------------------------------- ### Module Structure Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/INDEX.md Overview of the project's module structure and documented components. ```tree timezone_field/ ├── __init__.py (exports: TimeZoneField, TimeZoneFormField) ├── fields.py (TimeZoneField) ✅ ├── forms.py (TimeZoneFormField) ✅ ├── rest_framework.py (TimeZoneSerializerField) ✅ ├── choices.py (standard, with_gmt_offset) ✅ ├── utils.py (AutoDeserializedAttribute) ✅ ├── models.py (empty) └── backends/ ├── __init__.py (get_tz_backend) ✅ ├── base.py (TimeZoneBackend, TimeZoneNotFoundError) ✅ ├── pytz.py (PYTZBackend) ✅ └── zoneinfo.py (ZoneInfoBackend) ✅ ``` -------------------------------- ### Get Internal Database Type Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-field.md Returns the Django field type used for storing timezone data in the database. ```python def get_internal_type(self) -> str ``` -------------------------------- ### Using zoneinfo.ZoneInfo with TimeZoneField Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/types.md Demonstrates configuring TimeZoneField to use Python's standard library zoneinfo.ZoneInfo objects. ```python import zoneinfo from timezone_field import TimeZoneField class MyModel(models.Model): tz = TimeZoneField(use_pytz=False) obj = MyModel(tz="America/New_York") # obj.tz is of type ``` -------------------------------- ### Get Default Timezone Value Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-field.md Retrieves the field's default value and converts it to a timezone object, supporting string defaults. ```python def get_default(self) -> object | None ``` -------------------------------- ### Handle TimeZoneNotFoundError Exception Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/types.md Example of how to catch and handle the TimeZoneNotFoundError when converting an invalid timezone string to a timezone object using a backend. ```python from timezone_field.backends import get_tz_backend, TimeZoneNotFoundError backend = get_tz_backend(False) try: tz = backend.to_tzobj("Invalid/Timezone") except TimeZoneNotFoundError: print("Timezone not found") ``` -------------------------------- ### PYTZBackend Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-backends.md Backend implementation using the pytz library for timezone handling. It provides attributes for UTC timezone object, all available timezone strings, and a subset of common timezone strings. ```APIDOC ## PYTZBackend ### Description Backend implementation using the `pytz` library for timezone handling. ### Attributes - `utc_tzobj`: The `pytz.utc` singleton - `all_tzstrs`: All timezones from `pytz.all_timezones` (comprehensive list) - `base_tzstrs`: Common timezones from `pytz.common_timezones` (recommended subset) ``` -------------------------------- ### Create ChoiceTuple with standard timezones Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/types.md Use the `standard` function to create a list of timezone choices. It takes a list of timezone strings and returns a tuple of timezone objects and their display strings. ```python from timezone_field.choices import standard import zoneinfo timezones = ["UTC", "America/New_York"] choices = standard(timezones) # Result: # [ # (zoneinfo.ZoneInfo(key='America/New_York'), 'America/New York'), # (zoneinfo.ZoneInfo(key='UTC'), 'UTC'), # ] ``` -------------------------------- ### Module Organization Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/README.md Illustrates the directory structure and the primary purpose of each file within the timezone_field library. ```tree timezone_field/ ├── __init__.py # Public exports: TimeZoneField, TimeZoneFormField ├── fields.py # TimeZoneField (database field) ├── forms.py # TimeZoneFormField (form field) ├── rest_framework.py # TimeZoneSerializerField (DRF field) ├── choices.py # Choice formatting functions ├── utils.py # AutoDeserializedAttribute descriptor ├── models.py # Empty (intentionally) └── backends/ ├── __init__.py # get_tz_backend() factory function ├── base.py # TimeZoneBackend abstract class ├── pytz.py # PYTZBackend implementation └── zoneinfo.py # ZoneInfoBackend implementation ``` -------------------------------- ### Valid and Invalid Timezone Strings Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/types.md Examples of valid IANA timezone identifiers and invalid strings that would fail validation. These are used when defining timezone fields. ```python valid_tz_strings = [ "UTC", "America/New_York", "Europe/London", "Asia/Tokyo", "GMT" ] invalid_tz_strings = [ "Invalid/Timezone", "Foo/Bar", "Not_A_Tz" ] ``` -------------------------------- ### Standard Format Output Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/choices.md Displays timezone choices in a standard, readable format, replacing underscores and hyphens with spaces. Sorted alphabetically. ```text America/Anchorage America/Chicago America/Denver America/Los Angeles America/New York Asia/Hong Kong Asia/Tokyo Europe/Berlin Europe/London UTC ``` -------------------------------- ### Timezone Backend Implementations Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/README.md Imports the base class and specific implementations for timezone backends used by the library. ```python from timezone_field.backends.base import TimeZoneBackend from timezone_field.backends.pytz import PYTZBackend from timezone_field.backends.zoneinfo import ZoneInfoBackend ``` -------------------------------- ### Work with Timezone Values in Django Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-field.md Demonstrates creating model instances, accessing timezone objects, assigning string or timezone object values, and handling invalid timezones. ```python import zoneinfo import pytz # Creating instances obj = MyModel.objects.create(timezone="America/Los_Angeles") # Accessing the timezone - returns timezone object, not string print(obj.timezone) # zoneinfo.ZoneInfo(key='America/Los_Angeles') print(type(obj.timezone)) # # Assignment with string obj.timezone = "Europe/London" print(obj.timezone) # zoneinfo.ZoneInfo(key='Europe/London') # Assignment with timezone object obj.timezone = zoneinfo.ZoneInfo("Asia/Tokyo") obj.save() # Invalid timezone raises ValidationError immediately on assignment try: obj.timezone = "Invalid/Timezone" except ValidationError as e: print(f"Invalid timezone: {e}") ``` -------------------------------- ### Custom Validation for TimeZoneSerializerField Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-serializer-field.md Demonstrates how to implement custom validation logic for the TimeZoneSerializerField within a Django REST Framework serializer. This example shows how to restrict allowed timezones during validation. ```python class EventSerializer(serializers.Serializer): title = serializers.CharField(max_length=200) event_timezone = TimeZoneSerializerField() def validate_event_timezone(self, value): # Custom validation on timezone field allowed_timezones = { 'America/New_York', 'America/Los_Angeles', 'Europe/London' } if str(value) not in allowed_timezones: raise serializers.ValidationError( f"Event timezone must be one of {allowed_timezones}" ) return value # Usage serializer = EventSerializer(data={ 'title': 'Conference', 'event_timezone': 'Asia/Tokyo' # Not in allowed list }) serializer.is_valid() # False print(serializer.errors) # {'event_timezone': ['Event timezone must be one of ...']} ``` -------------------------------- ### ZoneInfoBackend Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-backends.md Backend implementation using Python's zoneinfo module for timezone handling. It provides attributes for UTC timezone object and available timezone strings. ```APIDOC ## ZoneInfoBackend ### Description Backend implementation using Python's `zoneinfo` module for timezone handling. ### Attributes - `utc_tzobj`: A `zoneinfo.ZoneInfo("UTC")` instance - `all_tzstrs`: Available timezones from `zoneinfo.available_timezones()` - `base_tzstrs`: Same as `all_tzstrs` (no distinction in zoneinfo) - Note: The "Factory" timezone is removed from both `all_tzstrs` and `base_tzstrs` to avoid errors on BSD systems ``` -------------------------------- ### Migrating Code Expecting String Values Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/README.md Shows how to update code that previously handled TimeZoneField values as strings. The v7 approach simplifies this by always returning an object. ```python # Before if isinstance(obj.timezone, str): tz_obj = get_tz_backend().to_tzobj(obj.timezone) else: tz_obj = obj.timezone # After tz_obj = obj.timezone # Always an object ``` -------------------------------- ### Handle TimeZoneNotFoundError with ZoneInfo Backend (Empty/None) Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/errors.md Demonstrates catching TimeZoneNotFoundError with the ZoneInfo backend when an empty or None timezone string is provided. Ensure the ZoneInfo backend is enabled. ```python backend = get_tz_backend(False) try: tz = backend.to_tzobj(None) except TimeZoneNotFoundError: print("Timezone is None") # Triggered here ``` -------------------------------- ### Configure USE_TZ Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/configuration.md Ensure USE_TZ is set to True in your settings.py to enable timezone-aware datetimes, which is recommended for proper interaction with timezone fields. ```python # settings.py USE_TZ = True # Use timezone-aware datetimes ``` -------------------------------- ### Cache Timezone Backend Instances Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/configuration.md Demonstrates how the `get_tz_backend` function caches timezone backend instances globally. Subsequent calls with the same arguments return the cached instance, improving performance. ```python from timezone_field.backends import get_tz_backend # First call: creates and caches PYTZBackend instance backend1 = get_tz_backend(True) # Second call: returns cached instance backend2 = get_tz_backend(True) assert backend1 is backend2 # True ``` -------------------------------- ### Timezone Choice Sorting Behavior Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/choices.md Illustrates the default sorting behavior for `standard` choices (alphabetical by display name) and `with_gmt_offset` choices (by GMT offset). ```python from timezone_field.choices import standard, with_gmt_offset timezones = [ "New_York", # Underscores become spaces "Los_Angeles", "Sydney", "Berlin" ] # Standard format sorts alphabetically by display name standard_choices = standard(timezones) # Display order: Berlin, Los Angeles, New York, Sydney # GMT offset format sorts by offset offset_choices = with_gmt_offset(timezones) # Display order: Sydney (GMT+10), Berlin (GMT+1), New York (GMT-5), Los Angeles (GMT-8) # (Order may vary by DST) ``` -------------------------------- ### Type Hinting with TimeZoneField Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/types.md Demonstrates how to use type hints for TimeZoneField and process timezone objects. The `process_timezone` function accepts either pytz or zoneinfo objects, and `MyModel.timezone` is guaranteed to be one of these types, never a string, after initialization. ```python from typing import Union import pytz import zoneinfo from timezone_field import TimeZoneField class MyModel(models.Model): timezone: TimeZoneField def process_timezone(tz: Union[pytz.tzinfo.BaseTzInfo, zoneinfo.ZoneInfo]) -> str: return str(tz) # In a function accepting TimeZoneField values def handle_model_tz(model: MyModel) -> None: # model.timezone is guaranteed to be either pytz or zoneinfo object, never string result = process_timezone(model.timezone) ``` -------------------------------- ### Using pytz Timezone Objects with TimeZoneField Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/types.md Demonstrates configuring TimeZoneField to use pytz timezone objects, showing the expected type for a timezone with DST. ```python import pytz from timezone_field import TimeZoneField class MyModel(models.Model): tz = TimeZoneField(use_pytz=True) obj = MyModel(tz="America/New_York") # obj.tz is of type ``` -------------------------------- ### Multi-Backend Configuration for TimeZoneField Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/configuration.md Configure different TimeZoneField instances within the same project to use specific backends (pytz or zoneinfo) or rely on Django's auto-detection. This allows for mixed backend usage. ```python # models.py - Some models use pytz, some use zoneinfo from django.db import models from timezone_field import TimeZoneField class LegacySystem(models.Model): # Force pytz for backward compatibility timezone = TimeZoneField(use_pytz=True) class ModernSystem(models.Model): # Use modern zoneinfo timezone = TimeZoneField(use_pytz=False) class AutoDetect(models.Model): # Use whatever Django defaults to timezone = TimeZoneField() ``` -------------------------------- ### TimeZoneSerializerField Constructor Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-serializer-field.md Initializes the TimeZoneSerializerField. It accepts an optional 'use_pytz' argument to control whether to return pytz or zoneinfo.ZoneInfo objects. ```python def __init__(self, *args, **kwargs) ``` -------------------------------- ### Moving Validation Logic Earlier Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/README.md Demonstrates the shift in validation timing from v6 to v7. In v7, validation occurs upon assignment, requiring a try-except block for handling potential errors. ```python # Before obj.timezone = user_input obj.full_clean() # ValidationError here # After try: obj.timezone = user_input # ValidationError here except ValidationError: # Handle invalid input ``` -------------------------------- ### Define Basic Serializer with TimeZoneSerializerField Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-serializer-field.md Shows how to define a basic serializer that includes a TimeZoneSerializerField. ```python from rest_framework import serializers from timezone_field.rest_framework import TimeZoneSerializerField class UserSerializer(serializers.Serializer): username = serializers.CharField(max_length=100) timezone = TimeZoneSerializerField() ``` -------------------------------- ### Deconstruct for Migrations Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-field.md Generates a 4-tuple for migration files, serializing timezone objects to strings for compatibility. ```python def deconstruct(self) -> tuple[str, str, list, dict] ``` -------------------------------- ### standard Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/choices.md Converts an iterable of timezones into a sorted list of choice tuples with human-readable display names. The display format is the timezone name with underscores replaced by spaces. ```APIDOC ## standard ### Description Converts a list of timezone objects or strings into a sorted list of choice tuples with human-readable display names. ### Method ```python def standard(timezones: Iterable) -> list[tuple[object, str]] ``` ### Parameters #### Path Parameters - `timezones` (Iterable) - Required - An iterable of timezone objects or timezone strings ### Returns - `list[tuple[object, str]]` - A list of tuples `(timezone_object, display_name)` sorted alphabetically by display name. ``` -------------------------------- ### Configure TimeZoneField Form Display Options Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-field.md Illustrates how to configure the display format of timezone choices in forms using choices_display. ```python class MyModel(models.Model): tz_standard = TimeZoneField(choices_display="STANDARD") tz_with_offset = TimeZoneField(choices_display="WITH_GMT_OFFSET") tz_default = TimeZoneField() # In ModelForm, the display will show: # tz_standard: "America/Los Angeles" # tz_with_offset: "GMT-07:00 America/Los Angeles" # tz_default: "America/Los_Angeles" ``` -------------------------------- ### Timezone Backend Operations Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-backends.md Illustrates common operations performed using a timezone backend instance, such as converting strings to timezone objects, checking if a value is a timezone object, and accessing UTC or listing timezones. ```APIDOC ## Backend Operations ### Description These operations are available on any timezone backend instance obtained via `get_tz_backend`. ### Methods - `to_tzobj(tz_string: str) -> tzobj` Converts a timezone string (e.g., 'America/New_York') into a timezone object. - `is_tzobj(value: Any) -> bool` Checks if the provided value is a valid timezone object recognized by the backend. - `utc_tzobj` (property) Provides the UTC timezone object. - `base_tzstrs` (property) Returns an iterable of common timezone strings. - `all_tzstrs` (property) Returns an iterable of all available timezone strings. ### Example ```python from timezone_field.backends import get_tz_backend backend = get_tz_backend(False) # Using ZoneInfo backend # Convert string to timezone object tz = backend.to_tzobj("America/New_York") # Check if value is a timezone object print(backend.is_tzobj(tz)) # True print(backend.is_tzobj("America/New_York")) # False # Access UTC timezone print(backend.utc_tzobj) # List common timezones common_timezones = list(backend.base_tzstrs) # List all timezones all_timezones = list(backend.all_tzstrs) ``` ``` -------------------------------- ### TimeZoneBackend Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-backends.md Abstract base class defining the interface for timezone backends. It includes attributes for timezone objects and strings, and abstract methods for validation and conversion. ```APIDOC ## TimeZoneBackend ### Description Abstract base class defining the timezone backend interface. ### Attributes - **utc_tzobj**: The UTC timezone object for this backend (class attribute) - **all_tzstrs**: All available timezone strings (includes uncommon timezones) - **base_tzstrs**: Common timezone strings (subset of `all_tzstrs`) ### Abstract Methods - **is_tzobj(value) -> bool**: Check if a value is a timezone object - **to_tzobj(tzstr: str) -> object**: Convert a timezone string to a timezone object ``` -------------------------------- ### Generate Timezone Choices with Custom Reference Time Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/choices.md Use the `now` parameter in `with_gmt_offset` to specify a reference time for calculating GMT offsets. This is useful for ensuring consistent offsets regardless of the current date. ```python import datetime from timezone_field.choices import with_gmt_offset import zoneinfo # Use a specific time for offset calculation reference_time = datetime.datetime(2026, 1, 15, 12, 0, 0, tzinfo=zoneinfo.ZoneInfo("UTC")) timezones = ["America/New_York", "America/Los_Angeles", "Europe/London"] choices = with_gmt_offset(timezones, now=reference_time) # Output reflects winter time offsets: # [ # (ZoneInfo(key='Europe/London'), 'GMT+00:00 Europe/London'), # (ZoneInfo(key='America/New_York'), 'GMT-05:00 America/New York'), # (ZoneInfo(key='America/Los_Angeles'), 'GMT-08:00 America/Los Angeles'), # ] ``` -------------------------------- ### Model with Custom Choices Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/configuration.md Configure a TimeZoneField with a predefined list of choices for specific regions, like US timezones. This limits user selection to the provided options. ```python USA_TIMEZONES = [ "America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles" ] class USAEvent(models.Model): name = models.CharField(max_length=200) timezone = TimeZoneField( choices=[(tz, tz) for tz in USA_TIMEZONES], default="America/New_York" ) ``` -------------------------------- ### ZoneInfoBackend.to_tzobj Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-backends.md Converts a timezone string into a zoneinfo.ZoneInfo object. ```APIDOC ## ZoneInfoBackend.to_tzobj ### Description Converts a timezone string to a `zoneinfo.ZoneInfo` object. ### Method `to_tzobj(self, tzstr: str) -> object` ### Parameters - `tzstr`: The timezone string ### Returns A `zoneinfo.ZoneInfo` object ### Raises - `TimeZoneNotFoundError` if `tzstr` is `None` or empty string - `TimeZoneNotFoundError` if `zoneinfo.ZoneInfo()` raises `zoneinfo.ZoneInfoNotFoundError` ``` -------------------------------- ### GMT Offset Format Output Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/choices.md Displays timezone choices with their corresponding GMT offset, which is subject to Daylight Saving Time. Sorted numerically by offset. ```text GMT+09:00 Asia/Tokyo GMT+08:00 Asia/Hong Kong GMT+01:00 Europe/Berlin GMT+00:00 Europe/London GMT+00:00 UTC GMT-05:00 America/New York GMT-06:00 America/Chicago GMT-07:00 America/Denver GMT-08:00 America/Los Angeles GMT-09:00 America/Anchorage ``` -------------------------------- ### Handle TimeZoneNotFoundError with PYTZ Backend Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/errors.md Demonstrates catching TimeZoneNotFoundError when using the PYTZ backend with an invalid timezone string. Ensure the PYTZ backend is enabled. ```python from timezone_field.backends import get_tz_backend, TimeZoneNotFoundError backend = get_tz_backend(True) # PYTZ backend try: tz = backend.to_tzobj("Invalid/Timezone") except TimeZoneNotFoundError: print("Timezone not found") # Triggered here ``` -------------------------------- ### Prepare Value for Database Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-field.md Converts a timezone object or string into its database-compatible string representation. ```python def get_prep_value(self, value) -> str | None ``` -------------------------------- ### get_prep_value Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-field.md Converts a timezone object or string into its database-compatible string representation. ```APIDOC ## get_prep_value ### Description Converts a value to its database representation (string). ### Method Signature ```python def get_prep_value(self, value) -> str | None ``` ### Parameters - **value**: A timezone object, string, or None ### Returns - The string representation of the timezone, or empty string for None ``` -------------------------------- ### TimeZone Field Serialization Chain Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/utilities.md Illustrates the data conversion flow for TimeZoneField, from string input to database storage and retrieval, involving to_python, get_prep_value, and from_db_value methods. ```text String Input -> __set__ -> to_python() -> TimeZone Object -> get_prep_value() -> String for DB Storage -> from_db_value() -> TimeZone Object on Retrieval ``` -------------------------------- ### Building Custom Timezone Choice Lists for Models Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/choices.md Demonstrates how to create custom timezone choice lists for specific regions (e.g., USA or Europe) and assign them to `TimeZoneField` in Django models. ```python from timezone_field.choices import standard # USA timezones only usa_timezones = [ "America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Anchorage", "Pacific/Honolulu" ] class TimeZoneModel(models.Model): timezone = TimeZoneField(choices=standard(usa_timezones)) # Europe timezones only europe_timezones = [ "Europe/London", "Europe/Paris", "Europe/Berlin", "Europe/Rome", "Europe/Madrid" ] class EuropeanModel(models.Model): timezone = TimeZoneField(choices=standard(europe_timezones)) ``` -------------------------------- ### Generate Timezone Choices Using pytz Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/choices.md When `use_pytz` is set to `True`, the `with_gmt_offset` function will use `pytz` timezone objects instead of `zoneinfo`. This ensures compatibility with projects already using `pytz`. ```python from timezone_field.choices import with_gmt_offset import pytz timezones = pytz.common_timezones[:5] choices = with_gmt_offset(timezones, use_pytz=True) # Works with pytz timezone objects # Output uses pytz timezone objects instead of zoneinfo ``` -------------------------------- ### TimeZoneField Constructor Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-field.md Details the parameters available when initializing a TimeZoneField in a Django model. ```APIDOC ## TimeZoneField Constructor ### Description Initializes a TimeZoneField for use in Django models. This field stores timezone information as strings and provides timezone objects in Python. ### Method `__init__` ### Parameters #### Constructor Parameters - **use_pytz** (bool | None) - Optional - If `True`, returns `pytz` timezone objects. If `False`, returns `zoneinfo.ZoneInfo` objects. If `None`, uses Django's default behavior. - **choices_display** (str | None) - Optional - Controls how timezone choices are displayed. Valid values: `"STANDARD"`, `"WITH_GMT_OFFSET"`, or `None`. - **choices** (list[tuple] | None) - Optional - Custom list of timezone choices. Can be specified as `[[, ], ...]` or `[[, ], ...]`. - **max_length** (int) - Optional - Maximum length of the stored string. Defaults to 63. - **blank** (bool) - Optional - If `True`, the field is optional in forms. Defaults to `False`. - **null** (bool) - Optional - If `True`, the field can store NULL in the database. Defaults to `False`. - **default** (str | callable) - Optional - Default value for the field, specified as a timezone string or callable. Defaults to `None`. - **`*args`** (tuple) - Positional arguments for `models.Field` (up to 3 allowed). ### Raises - `ValueError`: If more than 3 positional arguments are provided. - `ValueError`: If `choices_display` is not one of `"STANDARD"`, `"WITH_GMT_OFFSET"`, or `None`. ``` -------------------------------- ### Perform Round-trip Serialization with TimeZoneSerializerField Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-serializer-field.md Demonstrates a full round-trip serialization and deserialization cycle, ensuring timezone data integrity. ```python # Original object original = { 'id': 1, 'name': 'Alice', 'timezone': zoneinfo.ZoneInfo('Asia/Tokyo') } # Serialize to JSON serializer = UserProfileSerializer(original) json_data = serializer.data # {'id': 1, 'name': 'Alice', 'timezone': 'Asia/Tokyo'} # Deserialize from JSON deserialized = UserProfileSerializer(data=json_data) if deserialized.is_valid(): print(deserialized.validated_data['timezone']) # zoneinfo.ZoneInfo(key='Asia/Tokyo') ``` -------------------------------- ### Configure USE_DEPRECATED_PYTZ Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/configuration.md Set USE_DEPRECATED_PYTZ to True in your settings.py to force the use of pytz as the default timezone backend. This setting is relevant for Django 4.x. ```python # settings.py USE_DEPRECATED_PYTZ = True # Use pytz globally ``` -------------------------------- ### Handle TimeZoneNotFoundError with ZoneInfo Backend Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/errors.md Demonstrates catching TimeZoneNotFoundError when using the ZoneInfo backend with an invalid timezone string. Ensure the ZoneInfo backend is enabled. ```python from timezone_field.backends import get_tz_backend, TimeZoneNotFoundError backend = get_tz_backend(False) # ZoneInfo backend try: tz = backend.to_tzobj("Not_A_Tz") except TimeZoneNotFoundError: print("Timezone not found") # Triggered here ``` -------------------------------- ### TimeZoneBackend Abstract Base Class Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-backends.md This is the abstract base class for all timezone backends. It defines the interface and common attributes like `utc_tzobj`, `all_tzstrs`, and `base_tzstrs`. ```python class TimeZoneBackend(ABC): utc_tzobj = None all_tzstrs: Iterable[str] = None base_tzstrs: Iterable[str] = None # ... abstract methods ... pass ``` -------------------------------- ### PYTZBackend to_tzobj Method Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-backends.md Converts a timezone string into a pytz timezone object. Raises TimeZoneNotFoundError if the string is invalid or not found by pytz. ```python def to_tzobj(self, tzstr: str) -> object: pass ``` -------------------------------- ### Define Django Models with TimeZoneField Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-field.md Shows how to define model fields using TimeZoneField with default values, optional fields, and explicit pytz usage. ```python from django.db import models from timezone_field import TimeZoneField class MyModel(models.Model): # Default behavior: uses zoneinfo on Django 5.x timezone = TimeZoneField(default="UTC") # Optional timezone field optional_tz = TimeZoneField(blank=True, null=True) # Using pytz explicitly pytz_tz = TimeZoneField(use_pytz=True, default="America/New_York") ``` -------------------------------- ### Control Timezone Backend with TimeZoneField Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/README.md Control the timezone backend used by TimeZoneField using the 'use_pytz' argument. Options include 'zoneinfo' (default on Django 5.x), 'pytz' explicitly, or 'None' to respect Django's default settings. ```python from timezone_field import TimeZoneField class MyModel(models.Model): # Use zoneinfo (default on Django 5.x) tz1 = TimeZoneField(use_pytz=False) # Use pytz explicitly tz2 = TimeZoneField(use_pytz=True) # Use Django's default (respects USE_DEPRECATED_PYTZ setting) tz3 = TimeZoneField(use_pytz=None) ``` -------------------------------- ### Timezone Field Choices Display Options Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/types.md Demonstrates how to configure the `choices_display` argument for `TimeZoneField` to control how timezone choices are presented. This affects the human-readable format of timezone options. ```python class MyModel(models.Model): tz1 = TimeZoneField(choices_display=None) # Default tz2 = TimeZoneField(choices_display="STANDARD") # Spaces instead of underscores tz3 = TimeZoneField(choices_display="WITH_GMT_OFFSET") # With offset ``` -------------------------------- ### TimeZoneFormField Constructor Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-form-field.md Initializes the TimeZoneFormField with various configuration options for timezone selection and display. ```APIDOC ## TimeZoneFormField Constructor ### Description Initializes the TimeZoneFormField with various configuration options for timezone selection and display. ### Signature ```python def __init__(self, *args, **kwargs) ``` ### Parameters #### Constructor Parameters - **use_pytz** (bool | None) - Optional - If `True`, returns `pytz` timezone objects. If `False`, returns `zoneinfo.ZoneInfo` objects. If `None`, uses Django's default behavior. - **choices_display** (str | None) - Optional - Controls timezone display format. Valid values: `"STANDARD"` (timezone name with spaces), `"WITH_GMT_OFFSET"` (e.g., "GMT+04:00 Asia/Dubai"), or `None` for default. - **choices** (list[tuple]) - Optional - Custom timezone choices as `[[, ], ...]` or `[[, ], ...]`. - **coerce** (callable) - Auto-generated - Function to convert form input to Python value. Defaults to a function that converts strings to timezone objects. - **empty_value** (Any) - Optional - Value to return when the form field is empty. Defaults to `None`. - **`*args`** (tuple) - Positional arguments passed to `TypedChoiceField`. - **`**kwargs`** (dict) - Additional keyword arguments passed to `TypedChoiceField`. ``` -------------------------------- ### Set String or Callable Defaults for TimeZoneField Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/configuration.md Demonstrates how to set string-based or callable defaults for the TimeZoneField in a Django model. The migration process will correctly serialize string defaults. ```python class MyModel(models.Model): # This works: string is converted to timezone object tz1 = TimeZoneField(default="America/New_York") # This also works: callable tz2 = TimeZoneField(default=lambda: "UTC") # Migration will serialize the string properly ``` -------------------------------- ### Format Timezones to Standard Names Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/choices.md Converts an iterable of timezone objects or strings into a sorted list of choice tuples with human-readable display names. Use this for simple timezone name displays. ```python def standard(timezones: Iterable) -> list[tuple[object, str]]: """Converts a list of timezone objects or strings into a sorted list of choice tuples with human-readable display names.""" # Implementation details omitted for brevity pass ``` -------------------------------- ### deconstruct Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/api-reference/timezone-field.md Handles the serialization of timezone choices by converting timezone objects to strings, returning a tuple suitable for migration files. ```APIDOC ## deconstruct ### Description Returns a 4-tuple of `(name, path, args, kwargs)` suitable for migration files. Handles serialization of timezone choices by converting timezone objects to strings. ### Method Signature ```python def deconstruct(self) -> tuple[str, str, list, dict] ``` ### Returns - `(name, path, args, kwargs)` for migration serialization ``` -------------------------------- ### Django Settings for Timezone Configuration Source: https://github.com/mfogel/django-timezone-field/blob/main/_autodocs/configuration.md Configure global timezone settings in Django's `settings.py`. Set `USE_DEPRECATED_PYTZ` to `True` for explicit pytz usage on Django 4.x, and `USE_TZ` to `True` for timezone support. ```python # settings.py # For Django 4.x: explicitly use pytz globally USE_DEPRECATED_PYTZ = True # Standard Django timezone settings USE_TZ = True TIME_ZONE = 'UTC' # Default timezone for the project # Optional: configure logging LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'class': 'logging.StreamHandler', }, }, 'loggers': { 'django': { 'handlers': ['console'], 'level': 'INFO', }, }, } ```