Maîtriser le temps avec la bibliothèque standard Python : le module datetime en détail

Série 03 – Opérations sur les dates/horaires, fuseaux horaires, conversion de format en un seul passage

Le temps n’est pas qu’une simple chaîne de caractères. Les jours passent, les mois changent, l’heure d’été intervient, et chaque région a ses propres règles. Il est donc crucial de distinguer la représentation textuelle d’une valeur temporelle calculable et d’inclure les fuseaux horaires dans vos traitements.

Un atelier de travail magique pour un horloger

Dans cet article, nous allons explorer le module datetime et aborder les points suivants.

  • Créer la date et l’heure actuelles
  • Calculer des durées (timedelta)
  • Formater et analyser des chaînes (strftime, strptime)
  • Gérer les fuseaux horaires (timezone, zoneinfo)
  • Points d’attention fréquents et modèles fiables

1. Que propose datetime ?



Le module datetime regroupe plusieurs types qui semblent similaires mais ont des rôles distincts.

  • date : uniquement année‑mois‑jour
  • time : uniquement heure‑minute‑seconde
  • datetime : date + heure (le plus utilisé)
  • timedelta : différence de temps (durée)
  • timezone : fuseau horaire à décalage fixe (ex : UTC+9)

Depuis Python 3.9, la bibliothèque standard inclut zoneinfo, qui simplifie la manipulation des fuseaux horaires régionaux (ex : Asia/Tokyo).


2. Obtenir « maintenant » : naive vs aware

2.1 Naïf / conscient

Les objets datetime se divisent en deux catégories.

  • Naïf : sans information de fuseau
  • Conscient : avec tzinfo

Mélanger les deux lors d’opérations ou de comparaisons peut provoquer des erreurs ou des résultats inattendus.

2.2 Valeur par défaut recommandée : commencer en UTC conscient

Uniformiser la base de calcul sur UTC rend souvent les choses plus propres.

from datetime import datetime, timezone

utc_now = datetime.now(timezone.utc)  # conscient (UTC)
print(utc_now)

Si vous avez besoin de l’heure locale, effectuez la conversion lors de l’affichage.

from datetime import datetime, timezone
from zoneinfo import ZoneInfo

utc_now = datetime.now(timezone.utc)
tokyo_now = utc_now.astimezone(ZoneInfo("Asia/Tokyo"))

print(utc_now)
print(tokyo_now)

3. Calculs temporels : le rôle central de timedelta



3.1 Addition / soustraction

from datetime import datetime, timedelta, timezone

now = datetime.now(timezone.utc)
print(now + timedelta(days=3))
print(now - timedelta(hours=2))

3.2 Différence entre deux instants

from datetime import datetime, timezone

a = datetime(2026, 1, 1, tzinfo=timezone.utc)
b = datetime(2026, 1, 10, tzinfo=timezone.utc)

delta = b - a
print(delta.days)            # 9
print(delta.total_seconds()) # 777600.0

3.3 Sens de timedelta pour exprimer une « durée »

timedelta fonctionne en jours, secondes et microsecondes. Une expression comme « un mois plus tard » ne peut pas être modélisée directement ; on peut approximativement utiliser timedelta(days=30), mais pour des calculs précis on recourt souvent à des bibliothèques tierces comme dateutil.


4. Formatage et analyse : strftime / strptime

4.1 datetime → chaîne (strftime)

from datetime import datetime, timezone

dt = datetime(2026, 1, 30, 14, 5, 0, tzinfo=timezone.utc)
print(dt.strftime("%Y-%m-%d %H:%M:%S %z"))

Modèles courants :

  • %Y-%m-%d : 2026-01-30
  • %H:%M:%S : 14:05:00
  • %z : +0000 (décalage UTC)

4.2 Chaîne → datetime (strptime)

from datetime import datetime

s = "2026-01-30 14:05:00"
dt = datetime.strptime(s, "%Y-%m-%d %H:%M:%S")
print(dt)

Le dt obtenu est naïf. Pour préciser le fuseau, ajoutez tzinfo.

from datetime import datetime, timezone

s = "2026-01-30 14:05:00"
dt = datetime.strptime(s, "%Y-%m-%d %H:%M:%S").replace(tzinfo=timezone.utc)
print(dt)

replace(tzinfo=…) ne convertit pas l’heure, il ajoute simplement une étiquette de fuseau. Pour convertir, utilisez astimezone() (voir section suivante).


5. Fuseaux horaires : distinguer timezone et zoneinfo

5.1 Décalage fixe : timezone

Exemple : UTC ou UTC+9.

from datetime import datetime, timezone, timedelta

kst_fixed = timezone(timedelta(hours=9))
dt = datetime(2026, 1, 30, 12, 0, tzinfo=kst_fixed)
print(dt)

5.2 Fuseau régional : zoneinfo

Les fuseaux qui changent (heure d’été) sont mieux gérés par zoneinfo.

from datetime import datetime, timezone
from zoneinfo import ZoneInfo

utc_now = datetime.now(timezone.utc)
ny_now = utc_now.astimezone(ZoneInfo("America/New_York"))
print(ny_now)

5.3 Différence entre replace(tzinfo=…) et astimezone(...)

  • replace(tzinfo=…) : conserve la valeur temporelle, change seulement l’étiquette de fuseau.
  • astimezone(...) : convertit la même instant dans un autre fuseau.

Connaître cette distinction réduit les bugs liés aux fuseaux.


6. Points d’attention fréquents

6.1 Mélange naïf/conscient

  • Utilisez des instants conscients (UTC) pour les calculs internes.
  • Normalisez les entrées externes dès leur arrivée.

6.2 « Heure locale » dépend du contexte

datetime.now() suit la configuration locale de l’environnement d’exécution. Dans des conteneurs ou serveurs, la locale peut être UTC ou autre. Privilégiez datetime.now(timezone.utc) pour éviter les surprises.

6.3 Incohérence de format lors de l’analyse

strptime échoue si le format ne correspond pas exactement. Si vous avez plusieurs formats possibles, pré-traitez ou essayez les formats séquentiellement. Limiter le format d’entrée est souvent la meilleure solution.


7. Trois modèles courants

7.1 Enregistrer en ISO 8601

from datetime import datetime, timezone

dt = datetime.now(timezone.utc)
print(dt.isoformat())  # ex : 2026-01-30T05:12:34.567890+00:00

7.2 Nom de fichier avec la date d’aujourd’hui

from datetime import datetime

stamp = datetime.now().strftime("%Y%m%d")
filename = f"report_{stamp}.json"
print(filename)

7.3 Temps restant jusqu’à une date cible

from datetime import datetime, timezone

target = datetime(2026, 2, 1, 0, 0, tzinfo=timezone.utc)
now = datetime.now(timezone.utc)

remaining = target - now
print(remaining)
print(remaining.total_seconds())

8. Conclusion

datetime dépasse la simple création de chaînes : il permet de manipuler le temps comme une valeur calculable. En y ajoutant les fuseaux horaires (timezone, zoneinfo), vous obtenez un code robuste, indépendant de l’environnement d’exécution.

Dans la prochaine partie, nous aborderons le module random séparément, couvrant génération de nombres aléatoires, échantillonnage, mélange, graines et la génération sécurisée (secrets).


Articles connexes :


Voir la série précédente