Update chapters

Updated chapters 2, 6, 8, 9 and 11.
This commit is contained in:
2025-07-11 21:36:41 +02:00
parent 77aa231f5b
commit 086da10d79
5 changed files with 182 additions and 192 deletions

View File

@ -7,189 +7,213 @@ author: Steve Kossouho
----
## Un type pour les dates et heures
## `datetime` : Des moments dans le temps
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}.
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, un type pour stocker des moments dans le temps, nommé `datetime`,
est fourni.
```python {.numberLines}
from datetime import datetime
timestamp = 1577836800
as_datetime = datetime.fromtimestamp(timestamp)
print(as_datetime)
now = datetime.now() # l'instant actuel
midnight = datetime(2021, 1, 31) # 31 janvier 2021 à minuit
noon = datetime(2021, 1, 31, hour=12) # 31 janvier 2021 à 12h00
print(now)
print(midnight)
print(noon)
```
----
Les objets de type `datetime`{.python} sont exploitables grâce à plusieurs
méthodes et attributs :
## Convertir une date en chaîne
```python {.numberLines}
from datetime import datetime
Pour convertir une date vers une chaîne, ou convertir une chaîne vers un objet de date, consultez toujours la même ressource :
now = datetime.now()
print(now.year) # Année
print(now.month) # Mois (int)
print(now.day) # Jour (int)
print(now.hour) # Heure (int)
print(now.weekday()) # Jour de la semaine (int)
print(now.date()) # objet qui représente une journée
print(now.timestamp()) # Timestamp Unix (float)
```
[Table de référence pour le format de dates](https://docs.python.org/fr/3/library/datetime.html#strftime-and-strptime-format-codes)
----
## `date` : Une journée
Le type `date` du module `datetime` permet de représenter des jours,
sans notion d'heure.
```python {.numberLines}
from datetime import date
event_1 = date(1944, 6, 6) # 6 juin 1944
event_2 = date(1986, 4, 26) # 26 avril 1986
print(event_1.year)
print(event_1.month)
print(event_1.day)
```
----
## `timedelta` : Intervalles de temps
Un troisième type de données, `timedelta`, permet de représenter des durées.
Vous pouvez obtenir des objets de ce type de deux façons :
- Soit en calculant la différence entre deux `datetime` ou `date`;
- Soit en créant explicitement un objet de ce type;
- Soit en ajoutant des objets de ce type.
```python {.numberLines}
from datetime import timedelta, datetime, date
event_1 = date(2003, 6, 11) # 11 juin 2003
event_2 = date(2003, 9, 27) # 27 septembre 2003
elapsed = event_2 - event_1 # 108 jours
custom_duration = timedelta(weeks=4, days=2, hours=5, minutes=10)
double_duration = custom_duration * 2.0
event_end = event_1 + custom_duration
```
----
Les objets `timedelta` possèdent peu d'attributs et de méthodes.
Nous pouvons récupérer d'un tel objet les informations suivantes :
- `timedelta.days`
- `timedelta.seconds`
- `timedelta.microseconds`.
Ces informations additionnées donnent la durée complète.
Cette dernière peut être obtenue en secondes grâce à la méthode `total_seconds()` :
```python {.numberLines}
from datetime import timedelta
interval = timedelta(weeks=4.3, hours=14, minutes=31, seconds=53.234_567)
print(f"Nombre de jours : {interval.days}")
print(f"Secondes restantes : {interval.seconds}")
print(f"Microsecondes restantes : {interval.microseconds}")
print(f"Durée totale (s) : {interval.total_seconds():.3f}")
```
----
## Récupérer un `datetime` depuis un [timestamp]{.naming}
Un [timestamp]{.naming} est un instant exprimé sous la forme d'un nombre entier (ou flottant).
Dans la plupart des environnements de programmation, un timestamp s'exprime en nombre de secondes
écoulées depuis le `1er janvier 1970 à 00:00:00 UTC`. On appelle ce moment l'[epoch Unix]{.naming}.
On peut calculer un objet `datetime`{.python} depuis un timestamp, ou inversément, un timestamp depuis un objet `datetime`{.python}.
```python {.numberLines}
from datetime import datetime
stamp_1 = 1577836800.24 # 1 janvier 2020 à 01h00
event_1 = datetime.fromtimestamp(stamp_1) # 1 janvier 2020 à 01h00
event_2 = datetime(1996, 4, 1) # I Got the Vibration
stamp_2 = event_2.timestamp() # 828309600
print(f"La date du timestamp 1 est : {event_1}")
print(f"Le timestamp de la date 2 est : {stamp_2}")
```
----
## Générer une chaîne depuis une date
Pour convertir des informations d'un objet `date` ou `datetime` et générer une chaîne (ou vice-versa)
vous devez vous référer en premier lieu à une ressource de référence :
[Table de référence pour le formatage de dates](https://docs.python.org/fr/3/library/datetime.html#strftime-and-strptime-format-codes)
Ce tableau de référence reprend les spécifications des mêmes fonctionnalités telles que fournies par la
bibliothèque standard du C.
```python {.numberLines}
from datetime import datetime
event = datetime.now()
print(event.strftime("%d/%m/%Y %H:%M et %S secondes."))
print(f"{event:%d/%m/%Y %H:%M et %S secondes}") # via des f-strings
```
----
### É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.
Par défaut, Python n'utilise pas la langue configurée sur votre système d'exploitation,
mais l'anglais pour générer des chaînes de caractères depuis vos objets `datetime`;
Pour demander à Python d'utiliser votre configuration système, utilisez une chaîne vide
pour définir le code de langue à utiliser.
```{.python .numberLines}
```python {.numberLines}
from datetime import datetime
import locale
locale.setlocale(locale.LC_ALL, "") # utilise les paramètres de langue de l'utilisateur
event_1 = datetime.now()
print(f"{event_1:%A %d %B %Y}")
```
[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 :
## Obtenir un objet `datetime` depuis une chaîne
```{.python .numberLines}
Ici, il s'agit de comprendre la structure d'une chaîne de caractères contenant
une date et en déduire un objet `datetime`.
```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")
text = "31/10/1991 15:17"
# La méthode `strptime` est utilisée (string parse time)
moment = datetime.strptime(text, "%d/%m/%Y %H:%M")
print(moment)
```
----
## Bonus : Fuseaux horaires
## Extra : 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())
```
Par défaut, les objets de date que vous confectionnez sont dits [naïfs]{.naming}, 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.
----
### 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)
Depuis la version 3.9, Python propose un module `zoneinfo`, qui offre un type `ZoneInfo`
applicable à des objets `datetime` :
```{.python .numberLines}
from datetime import datetime
```python {.numberLines}
from datetime import datetime, UTC
from zoneinfo import ZoneInfo
moment = datetime(1975, 3, 1, hour=13, tzinfo=ZoneInfo("Europe/Madrid"))
moment_madrid = datetime(1975, 3, 1, hour=13, tzinfo=ZoneInfo("Europe/Madrid"))
moment_utc = datetime(1966, 10, 5, tzinfo=UTC)
```
----
## 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 :
L'écosystème Python propose des bibliothèques simplifiant l'usage des dates :
- [Arrow](https://arrow.readthedocs.io/en/latest/) : Better dates and times for Python
- [Pendulum](https://pendulum.eustace.io/) : Python datetimes made easy