---
title: Types supplémentaires
author: Steve Kossouho
---

# Types supplémentaires

----

## Un type pour les dates et heures

La bibliothèque standard nous offre plusieurs types de données pour gérer des moments dans le temps, avec le module `datetime`. Dans ce module, le type pour les dates avec heure s'appelle aussi `datetime`.

```{.python .numberLines}
from datetime import datetime

now = datetime.now()
then = datetime(2021, 1, 31)  # arguments positionnels
then2 = datetime(2021, 1, 31, hour=12)  # arguments par défaut
```

----

Les objets de ce type offrent un accès à plusieurs attributs, pour récupérer le jour, le mois, l'heure etc.

```{.python .numberLines}
from datetime import datetime

now = datetime.now()
print(now.day, now.date())  # affiche le jour du mois, et la date sans l'heure
```

----

## Opérations arithmétiques entre dates et intervalles de temps

Le module `datetime` propose un type qui représente un intervalle de temps, nommé `timedelta`. 
C'est ce que l'on obtient quand on soustrait deux dates (le temps écoulé entre les deux). 
Mais on peut aussi créer des objets `timedelta`{.python} et les ajouter (ou soustraire) à des dates.

```{.python .numberLines}
from datetime import timedelta, datetime

interval = timedelta(hours=15)
now = datetime.now()
then = datetime(2000, 1, 1)
interval2 = now - then
the_future = now + interval  # dans 15 heures
print(interval2, the_future)
```

----

Les objets d'intervalle de temps donnent accès à peu d'attributs. Nous avons uniquement accès aux jours, secondes et microsecondes.
On préférera utiliser le résultats renvoyés par la méthode `total_seconds()` comme base pour nos propres conversions d'ordres de grandeur.

```{.python .numberLines}
from datetime import timedelta

interval = timedelta(hours=14, minutes=31, seconds=53)
print(interval.days, interval.seconds, interval.microseconds)
print(interval.total_seconds())
```

----

## Récupérer une date depuis un timestamp

Un [timestamp]{.naming} est une date exprimée sous la forme d'un nombre entier (ou flottant). 
En général, un timestamp en programmation est le nombre de secondes depuis le
1er janvier 1970 à 00:00:00 UTC. On appelle ce moment l'epoch Unix.

On peut calculer un objet `datetime`{.python} depuis un timestamp, ou un timestamp depuis un objet `datetime`{.python}.

```python {.numberLines}
from datetime import datetime

timestamp = 1577836800
as_datetime = datetime.fromtimestamp(timestamp)
print(as_datetime)
```

----


## Convertir une date en chaîne

Pour convertir une date vers une chaîne, ou convertir une chaîne vers un objet de date, consultez toujours la même ressource :

[Table de référence pour le format de dates](https://docs.python.org/fr/3/library/datetime.html#strftime-and-strptime-format-codes)

----

### Éléments de date localisés dans la langue système

Pour une raison inconnue, probablement un bug sous certaines distributions Linux, Python n'utilise pas la langue configurée sur votre système, 
et vous voyez un formatage tel que `Sunday` s'afficher au lieu de `Dimanche`.
Pas de panique, il existe une solution pour forcer Python à utiliser la langue que vous désirez.


```{.python .numberLines}
import locale

locale.setlocale(locale.LC_ALL, "")  # utilise les paramètres de langue de l'utilisateur
```

[Documentation sur setlocale](https://docs.python.org/fr/3/library/locale.html)

----

Pour convertir un objet `datetime` vers une chaîne, grâce à la table de référence, c'est simple :

```{.python .numberLines}
from datetime import datetime

now = datetime.now()
text = now.strftime("%d/%m/%Y %H:%M et %S secondes.")
other = f"{now:%d/%m/%Y %H:%M et %S secondes}"  # via des f-strings
print(text, other)
```

----

## Convertir une chaîne en date

Dans l'autre sens, c'est à peine plus compliqué :

```{.python .numberLines}
from datetime import datetime

text = "24 12 2003 15:17"
moment = datetime.strptime(text, "%d %m %Y %H:%M")
print(moment)
```

----

## Bonus : Fuseaux horaires

Par défaut, les objets de date que vous confectionnez sont dits naïfs, car ils ne contiennent pas d'information de fuseau
horaire. Vous pouvez créer ou modifier des objets pour porter ces informations si vous en avez besoin.

La façon de s'en servir changera selon que vous utilisez Python 3.9 ou une version antérieure.

----

### Fuseaux horaires avant Python 3.9

Avant Python 3.9, il est conseillé d'installer `pytz` et `tzlocal` avec `pip`, puis de définir vos dates ainsi :

```{.python .numberLines}
import pytz
from datetime import datetime

moment = datetime(2013, 4, 16, tzinfo=pytz.timezone("Europe/Paris"))
moment2 = datetime(2010, 1, 1)
moment2 = moment2.replace(tzinfo=pytz.UTC)
```

----

Vous pouvez convertir votre date de façon à la représenter dans un autre fuseau horaire :

```{.python .numberLines}
import pytz, tzlocal
from datetime import datetime

moment = datetime(2013, 4, 16, tzinfo=pytz.timezone("America/Chihuahua"))
moment2 = moment.astimezone(tzlocal.get_localzone())
```

----

### Fuseaux horaires avec Python 3.9+

Python 3.9 ajoute enfin `zoneinfo`, qui couvre presque totalement les larges lacunes de `tzinfo`. (il demeure impossible
de connaître le fuseau horaire local)

```{.python .numberLines}
from datetime import datetime
from zoneinfo import ZoneInfo

moment = datetime(1975, 3, 1, hour=13, tzinfo=ZoneInfo("Europe/Madrid"))
```

----

## Bonus : Bibliothèques tierces pour les dates

L'écosystème Python propose de temps en temps des alternatives plus abordables que les
outils présents dans la bibliothèque standard. La gestion de dates n'y échappe pas et je peux proposer
deux bibliothèques élégantes et simples à comprendre pour Python :

- [Arrow](https://arrow.readthedocs.io/en/latest/) : Better dates and times for Python
- [Pendulum](https://pendulum.eustace.io/) : Python datetimes made easy
