# Documentation Django 3.1.9.dev

# Fuseaux horaires

## Aperçu

Lorsque la prise en charge des fuseaux horaires est activée, Django stocke les informations de date/heure en UTC dans la base de données, utilise en interne des objets date/heure conscients de leur fuseau horaire et les convertit dans les gabarits et les formulaires en utilisant le fuseau horaire de l’utilisateur.

C’est très pratique si vos utilisateurs sont répartis sur plus d’un fuseau horaire et que vous vouliez afficher les informations temporelles selon l’heure locale de chacun.

Même si votre site Web n’est utilisé que dans un seul fuseau horaire, stocker les données en UTC dans la base de données fait partie des bonnes pratiques. La raison principale étant l’heure d’été (Daylight Saving Time - DST). Dans beaucoup de pays, l’heure d’été fait avancer d’une heure au printemps et reculer d’une heure en automne. Si vous travaillez en temps local, vous risquez d’obtenir des erreurs deux fois par année, au moment de la transition (la documentation de pytz aborde ces questions plus en détails). ce n’est probablement pas un problème pour votre blog, mais c’en est un si vous surfacturez ou sous-facturez vos clients d’une heure, deux fois par année, chaque année. La solution à ce problème est d’utiliser UTC dans le code, et le temps local uniquement lors des interactions avec les utilisateurs du site.

La prise en charge des fuseaux horaires est désactivée par défaut. Pour l’activer, définissez `USE_TZ = True` dans votre fichier de réglages. La prise en charge des fuseaux horaires utilise pytz qui est installé en même temps que Django.

Note

Le fichier `settings.py` créé par défaut par `django-admin startproject` définit `USE_TZ = True` par commodité.

Note

Il existe également un réglage différent mais lié nommé `USE_L10N` qui contrôle l’activation ou non des formats de régionalisation. Voir Régionalisation des formats pour plus de détails.

Si vous êtes empêtré dans un problème particulier, commencez par lire la FAQ des fuseaux horaires.

## Concepts

### Objets `datetime` naïfs et conscients

Les objets `datetime.datetime` de Python possèdent un attribut `tzinfo` pouvant être utilisé pour stocker le fuseau horaire, représenté par une instance d’une sous-classe de `datetime.tzinfo`. Lorsque cet attribut est défini et qu’il décrit un décalage horaire, l’objet `datetime` est conscient. Dans le cas contraire, il est naïf.

Vous pouvez utiliser `is_aware()` et `is_naive()` pour déterminer si les objets `datetime` sont conscients (aware) ou naïfs.

Lorsque la prise en charge des fuseaux horaires est désactivée, Django utilise des objets `datetime` naïfs en heure locale. C’est suffisant dans de nombreux cas. Dans ce mode, pour obtenir le temps actuel, vous écririez :

    import datetime

    now = datetime.datetime.now()

Lorsque la prise en charge des fuseaux horaires est activée (`USE_TZ=True`), Django utilise des objets `datetime` conscients de leur fuseau horaire. Si vote code crée des objets `datetime`, ils devraient également être conscients. Dans ce mode, l’exemple ci-dessus devient :

    from django.utils import timezone

    now = timezone.now()

Avertissement

La manipulation des objets `datetime` conscients n’est pas toujours intuitive. Par exemple, le paramètre `tzinfo` du constructeur standard de `datetime` ne fonctionne pas de manière fiable pour les fuseaux horaires avec heure d’été. L’utilisation de l’heure UTC est généralement sûre ; si vous utilisez d’autres fuseaux horaires, vous devriez lire attentivement la documentation de pytz.

Note

Les objets `datetime.time` de Python comportent également un attribut `tzinfo`, et PostgreSQL possède un type correspondant `time with time zone` (heure avec fuseau horaire). Cependant, comme l’explique la documentation de PostgreSQL, ce type « prête des propriétés qui font douter de son utilité ».

Django ne prend en charge que des objets `time` naïfs et génère une exception si vous essayez d’enregistrer un objet `time` conscient, dans la mesure où un fuseau horaire n’a pas de sens pour un objet `time` sans date associée.

### Interprétation des objets `datetime` naïfs

Lorsque `USE_TZ` vaut `True`, Django accepte encore les objets `datetime` naïfs, afin de préserver la rétrocompatibilité. Lorsque la couche base de données en reçoit un, elle essaie de le rendre conscient en l’interprétant dans le fuseau horaire par défaut et génère un avertissement.

Malheureusement, durant les transitions d’heure d’été, certains objets `datetime` n’existent pas ou sont ambigus. Dans de telles situations, pytz génère une exception. C’est pourquoi vous devriez toujours créer des objets `datetime` conscients lorsque la prise en charge des fuseaux horaires est activée.

En pratique, c’est rarement un problème. Django produit des objets `datetime` conscients dans les modèles et les formulaires, et la plupart du temps, les nouveaux objets `datetime` sont créés à partir d’objets existants par des opérations `timedelta`. Le seul objet `datetime` qui est souvent créé dans du code applicatif est l’heure actuelle et `timezone.now()` fait automatiquement ce qu’il faut.

### Fuseau horaire par défaut et fuseau horaire actuel

Le fuseau horaire par défaut est le fuseau horaire défini par le réglage `TIME_ZONE`.

Le fuseau horaire actuel est le fuseau horaire utilisé pour l’affichage.

Vous devriez définir le fuseau horaire actuel au fuseau horaire réel de l’utilisateur avec `activate()`. Sinon, c’est le fuseau horaire par défaut qui est utilisé.

Note

Comme expliqué dans la documentation de `TIME_ZONE`, Django définit des variables d’environnement afin que son processus tourne dans le fuseau horaire par défaut. Ce comportement est indépendant de la valeur de `USE_TZ` et du fuseau horaire actuel.

Lorsque `USE_TZ` vaut `True`, ceci est utile pour préserver la rétrocompatibilité avec les applications qui se basent encore sur le temps local. Cepedant, comme expliqué ci-dessus, ce n’est pas totalement fiable et vous devriez toujours travailler avec des objets `datetime` conscients en UTC dans votre propre code. Par exemple, utilisez `fromtimestamp()` et définissez le paramètre `tz` à `utc`.

### Sélection du fuseau horaire actuel

Le fuseau horaire actuel est l’équivalent de la langue actuelle pour les traductions. Cependant, il n’y a pas d’équivalent à l’en-tête HTTP `Accept-Language` que Django pourrait utiliser pour déterminer automatiquement le fuseau horaire de l’utilisateur. Au lieu de cela, Django fournit des fonctions de sélection du fuseau horaire. Utilisez-les pour bâtir une logique de sélection du fuseau horaire qui a du sens dans votre situation.

La plupart des sites Web se préoccupant des fuseaux horaires demandent aux utilisateurs leur fuseau horaire de domicile et stockent cette information dans le profil des utilisateurs. Pour les utilisateurs anonymes, ils utilisent le fuseau horaire de la majorité de leur public ou l’heure UTC. pytz propose des utilitaires, comme une liste de fuseaux horaires par pays, qu’il est possible d’exploiter pour faire une présélection des choix les plus probables.

Voici un exemple qui stocke le fuseau horaire actuel dans la session (la gestion d’erreur est totalement absente par simplicité).

Ajoutez l’intergiciel suivant à `MIDDLEWARE`:

    import pytz

    from django.utils import timezone

    class TimezoneMiddleware:
        def __init__(self, get_response):
            self.get_response = get_response

        def __call__(self, request):
            tzname = request.session.get('django_timezone')
            if tzname:
                timezone.activate(pytz.timezone(tzname))
            else:
                timezone.deactivate()
            return self.get_response(request)

Créez une vue capable de définir le fuseau horaire actuel :

    from django.shortcuts import redirect, render

    def set_timezone(request):
        if request.method == 'POST':
            request.session['django_timezone'] = request.POST['timezone']
            return redirect('/')
        else:
            return render(request, 'template.html', {'timezones': pytz.common_timezones})

Ajoutez un formulaire dans `template.html` dont la cible `POST` est cette vue :

    {% load tz %}
    {% get_current_timezone as TIME_ZONE %}
    <form action="{% url 'set_timezone' %}" method="POST">
        {% csrf_token %}
        <label for="timezone">Time zone:</label>
        <select name="timezone">
            {% for tz in timezones %}
            <option value="{{ tz }}"{% if tz == TIME_ZONE %} selected{% endif %}>{{ tz }}</option>
            {% endfor %}
        </select>
        <input type="submit" value="Set">
    </form>

## Saisie de données avec fuseau horaire dans les formulaires

Lorsque vous activez la prise en charge des fuseaux horaires, Django interprète les dates/heures saisies dans les formulaires dans le fuseau horaire actuel et place des objets `datetime` conscients dans `cleaned_data`.

Si le fuseau horaire actuel génère une exception pour les dates/heures qui n’existent pas ou qui sont ambiguës car elles se trouvent dans une transition d’heure d’été (les fuseaux horaires dans pytz le font), ces dates/heures seront signalées comme non valables.

## Affichage de fuseaux horaires conscients dans les gabarits

Lorsque vous activez la prise en charge des fuseaux horaires, Django convertit les objets `datetime` dans le fuseau horaire actuel au moment où ils sont affichés dans un gabarit. Ce comportement est très semblable à la régionalisation des formats.

Avertissement

Django ne convertit pas les objets `datetime` naïfs car ils peuvent être ambigus et parce que votre code ne doit jamais produire de tels objets naïfs lorsque la prise en charge des fuseaux horaires est activée. Cependant, vous pouvez forcer la conversion avec les filtres de gabarit décrits ci-dessous.

La conversion en temps local n’est pas toujours adéquate, par exemple dans le cas où vous générez du contenu à destination d’autres ordinateurs. Les filtres et balises suivants, mis à disposition par la bibliothèque de balises de gabarit `tz`, permettent de contrôler les conversions de fuseaux horaires.

### Balises de gabarit

#### `localtime`

Active ou désactive la conversion d’objets `datetime` conscients dans le fuseau horaire actuel à l’intérieur du bloc contenu.

Cette balise a exactement le même effet que le réglage `USE_TZ` en ce qui concerne le moteur de gabarits. Elle permet un contrôle plus précis des endroits où la conversion se fait.

Pour activer ou désactiver la conversion pour un bloc de gabarit, utilisez :

    {% load tz %}

    {% localtime on %}
        {{ value }}
    {% endlocaltime %}

    {% localtime off %}
        {{ value }}
    {% endlocaltime %}

Note

La valeur de `USE_TZ` n’est pas prise en compte à l’intérieur d’un bloc `{% localtime %}`.

#### `timezone`

Définit ou annule le fuseau horaire actuel dans le bloc contenu. Lorsque le fuseau horaire actuel est annulé, c’est le fuseau horaire par défaut qui s’applique.

    {% load tz %}

    {% timezone "Europe/Paris" %}
        Paris time: {{ value }}
    {% endtimezone %}

    {% timezone None %}
        Server time: {{ value }}
    {% endtimezone %}

#### `get_current_timezone`

Vous pouvez obtenir le nom du fuseau horaire actuel en utilisant la balise `get_current_timezone`:

    {% get_current_timezone as TIME_ZONE %}

Une alternative possible est d’activer le processeur de contexte `tz()` et d’utiliser la variable de contexte `TIME_ZONE`.

### Filtres de gabarit

Ces filtres acceptent aussi bien des objets `datetime` conscients que naïfs. À des fins de conversion, ils partent du principe que les objets naïfs sont dans le fuseau horaire par défaut. Ils renvoient toujours des objets `datetime` conscients.

#### `localtime`

Force la conversion d’une valeur unique dans le fuseau horaire actuel.

Par exemple :

    {% load tz %}

    {{ value|localtime }}

#### `utc`

Force la conversion d’une seule valeur en UTC.

Par exemple :

    {% load tz %}

    {{ value|utc }}

#### `timezone`

Force la conversion d’une seule valeur dans un fuseau horaire arbitraire.

Le paramètre doit être une instance d’une sous-classe de `tzinfo` ou un nom de fuseau horaire.

Par exemple :

    {% load tz %}

    {{ value|timezone:"Europe/Paris" }}

## Guide de migration

Voici comment effectuer la migration d’un projet démarré avant que Django ne prenne en charge les fuseaux horaires.

### Base de données

#### PostgreSQL

Le moteur PostgreSQL stocke les dates/heures comme `timestamp with time zone`. En pratique, cela signifie qu’il convertit les objets `datetime` en UTC à partir du fuseau horaire de la connexion au moment du stockage, et à partir d’UTC vers le fuseau horaire de la connexion lors de la sélection.

En conséquence, si vous utilisez PostgreSQL, vous pouvez librement passer de `USE_TZ = False` à `USE_TZ = True` et inversement. Le fuseau horaire de la connexion de la base de données sera défini respectivement à `TIME_ZONE` et à `UTC`, ce qui fait que Django reçoit des dates/heures correctes dans tous les cas. Vous n’avez pas à convertir les données.

#### Autres bases de données

Les autres moteurs stockent les dates/heures sans information de fuseau horaire. Si vous passez de `USE_TZ = False` à `USE_TZ = True`, vous devez convertir vos données du temps local en UTC, ce qui n’est pas déterministe si votre temps local est sujet à l’heure d’été.

### Code

La première étape est d’ajouter `USE_TZ = True` à votre fichier de réglages. À ce stade, tout devrait fonctionner en principe. Si vous créez des objets `datetime` naïfs dans votre code, Django les rend conscients en cas de besoin.

Cependant, ces conversions peuvent échouer aux alentours des transitions d’heure d’été, ce qui signifie que vous n’obtenez pas encore tous les bénéfices de la prise en charge des fuseaux horaires. Il est également probable que vous rencontriez quelques problèmes car il est impossible de comparer une date/heure naïve avec une date/heure consciente. Comme Django vous donne maintenant des dates/heures conscientes, vous obtiendrez des exceptions chaque fois que vous comparez une date/heure provenant d’un modèle ou d’un formulaire avec une date/heure naïve que vous avez créée dans votre code.

La seconde étape est donc de réviser votre code pour que chaque endroit où vous créer des objets `datetime`, ceux-ci soient conscients. Cela peut se faire progressivement. `django.utils.timezone` définit quelques utilitaires bien pratiques pour du code compatible : `now()`, `is_aware()`, `is_naive()`, `make_aware()` et `make_naive()`.

Finalement, pour vous aider à trouver le code qui a besoin d’être mis à jour, Django émet un avertissement lorsque vous essayez d’enregistrer une date/heure naïve dans la base de données :

    RuntimeWarning: DateTimeField ModelName.field_name received a naive
    datetime (2012-01-01 00:00:00) while time zone support is active.

Durant le développement, vous pouvez transformer ces avertissements en exceptions et obtenir une trace d’appel en ajoutant ce qui suit dans votre fichier de réglages :

    import warnings
    warnings.filterwarnings(
        'error', r"DateTimeField .* received a naive datetime",
        RuntimeWarning, r'django\.db\.models\.fields',
    )

### Instantanés

Lors de la sérialisation d’une date/heure consciente, le décalage UTC est pris en compte, comme ceci :

    "2011-09-01T13:20:30+03:00"

Alors que pour une date/heure naïve, ce n’est pas le cas :

    "2011-09-01T13:20:30"

Pour les modèles comportant des champs `DateTimeField`, cette différence rend impossible l’écriture d’un instantané fonctionnant à la fois avec et sans prise en charge des fuseaux horaires.

Les instantanés générés avec `USE_TZ = False` ou avant Django 1.4 utilisent le format « naïf ». Si votre projet contient de tels instantanés et que vous activez la prise en charge des fuseaux horaires, vous verrez des exceptions `RuntimeWarning` lorsque vous les chargez. Pour vous débarrasser des ces avertissements, vous devez convertir vos instantanés au format « conscient ».

Vous pouvez régénérer les instantanés avec `loaddata`, puis `dumpdata`. Ou s’ils ne sont pas trop gros, vous pouvez les modifier et ajouter le décalage UTC correspondant à votre `TIME_ZONE` dans chaque objet `datetime` sérialisé.

## FAQ

### Configuration

1. Je n’ai pas besoin de plusieurs fuseaux horaires. Dois-je activer la prise en charge des fuseaux horaires ?

   Oui. Lorsque la prise en charge des fuseaux horaires est activée, Django utilise un modèle plus précis du temps local. Cela vous protège de bogues subtils et non reproductibles lors des transitions d’heure d’été (DST).

   Lorsque vous activez la prise en charge des fuseaux horaires, vous allez rencontrer certaines erreurs parce que vous utilisez des dates/heures naïves là où Django s’attend à des dates/heures conscientes. De telles erreurs apparaissent lors de l’exécution des tests. Vous apprendrez rapidement comment éviter les opérations non valides.

   D’un autre côté, les bogues qui proviennent d’une non prise en charge des fuseaux horaires sont beaucoup plus durs à prévenir, à diagnostiquer et à corriger. Tout ce qui touche aux tâches planifiées ou à l’arithmétique des dates/heures est sujet à de subtils bogues qui ne vous affecteront qu’une ou deux fois par année.

   C’est pour ces raisons que la prise en charge des fuseaux horaires est activée par défaut dans les nouveaux projets, et vous devriez garder ce réglage pour autant que vous n’ayez pas une bonne raison de ne pas le faire.

2. J’ai activé la prise en charge des fuseaux horaires. Suis-je tranquille ?

   Peut-être. Vous êtes mieux protégé des bogues liés à l’heure d’été, mais il est toujours possible que vous vous trompiez en convertissant sans précaution des objets `datetime` naïfs en objets `datetime` conscients et vice-versa.

   Si votre application se connecte à d’autres systèmes, par exemple si elle interroge un service Web, prenez soin de bien définir les dates/heures. Pour les transmettre de manière fiable, leur représentation doit inclure le décalage UTC ou leur valeur doit être en UTC (ou les deux !).

   Finalement, notre système de calendrier contient des cas limites intéressants. Par exemple, il n’est pas toujours possible de soustraire une année directement d’une date donnée

       >>> import datetime
       >>> def one_year_before(value):  # Wrong example.
       ...     return value.replace(year=value.year - 1)
       >>> one_year_before(datetime.datetime(2012, 3, 1, 10, 0))
       datetime.datetime(2011, 3, 1, 10, 0)
       >>> one_year_before(datetime.datetime(2012, 2, 29, 10, 0))
       Traceback (most recent call last):
       ...
       ValueError: day is out of range for month

   Pour implémenter une telle fonction correctement, vous devez décider si 2012-02-29 moins une année est 2011-02-28 ou 2011-03-01, ce qui dépend de vos exigences métier.

3. Comment interagir avec une base de données stockant les dates/heures en temps local ?

   Définissez l’option `TIME_ZONE` au fuseau horaire correspondant à cette base de données dans le réglage `DATABASES`.

   C’est utile pour se connecter à une base de données qui ne gère pas les fuseaux horaires et qui n’est pas gérée par Django lorsque `USE_TZ` vaut `True`.

### Dépannage

1. Mon application plante avec `TypeError: can't compare offset-naive` `and offset-aware datetimes` , qu’est-ce que je fais faux ?

   Reproduisons cette erreur en comparant des objets `datetime` naïf et conscient :

       >>> import datetime
       >>> from django.utils import timezone
       >>> naive = datetime.datetime.utcnow()
       >>> aware = timezone.now()
       >>> naive == aware
       Traceback (most recent call last):
       ...
       TypeError: can't compare offset-naive and offset-aware datetimes

   Si vous rencontrez cette erreur, il est très probable que votre code compare ces deux choses :

   - un objet `datetime` fourni par Django, par exemple une valeur lue à partir d’un champ de formulaire ou d’un champ de modèle. Comme vous avez activé la prise en charge des fuseaux horaires, cet objet est conscient.
   - un objet `datetime` généré dans votre code de manière naïve (sinon vous ne liriez pas ceci).

   Généralement, la solution correcte est de modifier votre code pour qu’il utilise plutôt un objet `datetime` conscient.

   Si vous écrivez une application réutilisable qui doit fonctionner indépendamment de la valeur de `USE_TZ`, il peut être utile d’appeler `django.utils.timezone.now()`. Cette fonction renvoie la date et l’heure actuelle sous forme d’objet `datetime` naïf lorsque `USE_TZ = False` et sous forme d’objet `datetime` conscient lorsque `USE_TZ = True`. Vous pouvez y ajouter ou soustraire une valeur `datetime.timedelta` selon vos besoins.

2. Je vois beaucoup de `RuntimeWarning: DateTimeField received a naive datetime` `(YYYY-MM-DD HH:MM:SS)` `while time zone support is active` , est-ce mauvais signe ?

   Lorsque la prise en charge des fuseaux horaires est activée, la couche de base de données s’attend à ne recevoir que des objets `datetime` conscients de votre code. Cet avertissement se produit lorsqu’elle reçoit un objet `datetime` naïf. Cela indique que vous n’avez pas terminé de transformer votre code pour la prise en charge des fuseaux horaires. Veuillez vous référer au guide de migration pour des indications supplémentaires sur ce processus.

   Dans l’intervalle et par rétrocompatibilité, Django considère l’objet `datetime` comme se trouvant dans le fuseau horaire par défaut, ce qui correspond généralement à la réalité.

3. `now.date()` est hier ! (ou demain)

   Si vous avez toujours utilisé des objets `datetime` naïfs, vous pensez probablement pouvoir convertir un objet `datetime` en objet `date` en appelant sa méthode `date()`. Vous considérez également que `date` est très semblable à `datetime`, avec moins de précision.

   Rien de cela n’est vrai dans un environnement conscient des fuseaux horaires :

       >>> import datetime
       >>> import pytz
       >>> paris_tz = pytz.timezone("Europe/Paris")
       >>> new_york_tz = pytz.timezone("America/New_York")
       >>> paris = paris_tz.localize(datetime.datetime(2012, 3, 3, 1, 30))
       # This is the correct way to convert between time zones with pytz.
       >>> new_york = new_york_tz.normalize(paris.astimezone(new_york_tz))
       >>> paris == new_york, paris.date() == new_york.date()
       (True, False)
       >>> paris - new_york, paris.date() - new_york.date()
       (datetime.timedelta(0), datetime.timedelta(1))
       >>> paris
       datetime.datetime(2012, 3, 3, 1, 30, tzinfo=<DstTzInfo 'Europe/Paris' CET+1:00:00 STD>)
       >>> new_york
       datetime.datetime(2012, 3, 2, 19, 30, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)

   Comme le montre cet exemple, le même objet `datetime` peut représenter une date différente selon le fuseau horaire dans lequel il est représenté. Mais le problème réel est plus fondamental.

   Un objet `datetime` représente un point dans le temps. C’est absolu et cela ne dépend de rien d’autre. Au contraire, une date est un concept calendaire. Il s’agit d’une période de temps dont les limites dépendent du fuseau horaire dans lequel la date est considérée. Comme vous pouvez le voir, ces deux concepts sont fondamentalement différents et la conversion d’un objet `datetime` en un objet `date` n’est pas une opération déterministe.

   Qu’est-ce que cela signifie en pratique ?

   Généralement, vous devriez éviter de convertir un objet `datetime` en `date`. Par exemple, vous pouvez utiliser le filtre de gabarit `date` pour n’afficher que la partie date d’un objet `datetime`. Ce filtre convertit l’objet `datetime` dans le fuseau horaire actuel avant de le mettre en forme, s’assurant ainsi que le résultat produit sera correct.

   Si vous avez réellement besoin d’effectuer vous-même la conversion, vous devez d’abord prendre soin de convertir l’objet `datetime` dans le fuseau horaire approprié. Il s’agit généralement du fuseau horaire actuel :

       >>> from django.utils import timezone
       >>> timezone.activate(pytz.timezone("Asia/Singapore"))
       # For this example, we set the time zone to Singapore, but here's how
       # you would obtain the current time zone in the general case.
       >>> current_tz = timezone.get_current_timezone()
       # Again, this is the correct way to convert between time zones with pytz.
       >>> local = current_tz.normalize(paris.astimezone(current_tz))
       >>> local
       datetime.datetime(2012, 3, 3, 8, 30, tzinfo=<DstTzInfo 'Asia/Singapore' SGT+8:00:00 STD>)
       >>> local.date()
       datetime.date(2012, 3, 3)

4. J’obtiens une erreur « `Are time zone definitions for your database installed?` »

   Si vous utilisez MySQL, consultez la section Définitions de fuseaux horaires des notes MySQL pour plus d’instructions sur le chargement des définitions de fuseaux horaires.

### Utilisation

1. J’ai une chaîne `"2012-02-21 10:28:45"` et je sais qu’elle est dans le fuseau horaire ** `` »Europe/Helsinki »``. Comment puis-je la transformer en un objet ``datetime`` conscient ?

   C’est exactement le rôle de pytz.

       >>> from django.utils.dateparse import parse_datetime
       >>> naive = parse_datetime("2012-02-21 10:28:45")
       >>> import pytz
       >>> pytz.timezone("Europe/Helsinki").localize(naive, is_dst=None)
       datetime.datetime(2012, 2, 21, 10, 28, 45, tzinfo=<DstTzInfo 'Europe/Helsinki' EET+2:00:00 STD>)

   Notez que `localize` est une extension de pytz à l’API `tzinfo`. Il peut être nécessaire d’intercepter les erreurs `pytz.InvalidTimeError`. La documentation de pytz contient davantage d’exemples. Il est recommandé de la consulter avant d’essayer de manipuler des objets `datetime` conscients.

2. Comment puis-je obtenir le temps local dans le fuseau horaire actuel ?

   Et bien, la première question à se poser est : est-ce réellement nécessaire ?

   Le temps local ne doit être utilisé que lorsque l’on interagit avec des humains, et la couche des gabarits fournit des filtres et des balises pour convertir des objets `datetime` dans le fuseau horaire de votre choix.

   De plus, Python sait comparer des objets `datetime` conscients, en prenant en compte les décalages UTC si nécessaire. C’est beaucoup plus simple (et potentiellement plus rapide) d’écrire tout le code des modèles et des vues en UTC. Ainsi, dans la plupart des cas, l’objet `datetime` en UTC renvoyé par `django.utils.timezone.now()` sera suffisant.

   Par souci d’exhaustivité, si vous devez vraiment obtenir le temps local dans le fuseau horaire actuel, voici comment vous pouvez l’obtenir :

       >>> from django.utils import timezone
       >>> timezone.localtime(timezone.now())
       datetime.datetime(2012, 3, 3, 20, 10, 53, 873365, tzinfo=<DstTzInfo 'Europe/Paris' CET+1:00:00 STD>)

   Dans cet exemple, le fuseau horaire actuel est `"Europe/Paris"`.

3. Comment puis-je voir tous les fuseaux horaires disponibles ?

   pytz fournit des utilitaires, y compris une liste des fuseaux horaires actuels et une liste de tous les fuseaux horaires disponibles, parmi lesquels se trouvent aussi certains qui n’ont qu’un intérêt historique.