Comment parser efficacement les dates et heures en Python ?

Parser les dates et heures en Python peut vite devenir un cauchemar à cause des formats variés et des données réelles souvent chaotiques. Découvrez cinq fonctions DIY essentielles pour manipuler ces données sans perdre la tête ni votre temps.

3 principaux points à retenir.

  • Maîtriser les formats relatifs avec des regex adaptées pour convertir « il y a 2 heures » en datetime.
  • Extraire les dates naturelles dans du texte grâce à des patterns ciblés et une gestion intelligente des années.
  • Gérer les formats flexibles via une approche multiple et pragmatique pour ne jamais rater une date.

Comment convertir des temps relatifs en objets datetime ?

Convertir des expressions comme « 5 minutes ago » en objets datetime est crucial pour traiter des données issues des réseaux sociaux ou des logs. Ces formats de temps relatifs rendent souvent la manipulation des données plus complexe, car ils ne correspondent pas à des formats de date et d’heure standardisés. Heureusement, Python offre des outils puissants pour simplifier cette tâche grâce à une combinaison de regex et de la bibliothèque datetime.

Voici une fonction Python qui gère l’extraction des données temporelles à partir de ces expressions relatives. Cette fonction commence par normaliser la chaîne de caractères pour s’assurer qu’elle est en minuscules et bien formatée. Ensuite, elle utilise une expression régulière pour capturer le nombre et l’unité de temps :

from datetime import datetime, timedelta
import re

def parse_relative_time(time_string, reference_time=None):
    """
    Convertit les chaînes de temps relatifs en objets datetime.
    
    Exemples : "2 heures ago", "3 jours ago", "1 semaine ago"
    """
    if reference_time is None:
        reference_time = datetime.now()
    
    # Normalisation de la chaîne
    time_string = time_string.lower().strip()
    
    # Modèle : nombre + unité de temps + "ago"
    pattern = r'(\d+)\s*(second|minute|heure|jour|semaine|mois|an)s?\s*ago'
    match = re.match(pattern, time_string)
    
    if not match:
        raise ValueError(f"Impossible de parser : {time_string}")
    
    amount = int(match.group(1))
    unit = match.group(2)
    
    # Mapping des unités vers les arguments de timedelta
    unit_mapping = {
        'second': 'seconds',
        'minute': 'minutes',
        'heure': 'hours',
        'jour': 'days',
        'semaine': 'weeks',
    }
    
    if unit in unit_mapping:
        delta_kwargs = {unit_mapping[unit]: amount}
        return reference_time - timedelta(**delta_kwargs)
    elif unit == 'mois':
        # Approximation : 30 jours par mois
        return reference_time - timedelta(days=amount * 30)
    elif unit == 'an':
        # Approximation : 365 jours par an
        return reference_time - timedelta(days=amount * 365)

Cette fonction utilise une expression régulière pour extraire le nombre et l’unité de temps de la chaîne d’entrée. Pour les unités directement supportées par timedelta (secondes à semaines), on crée un objet timedelta et on le soustrait du temps de référence. Pour les mois et les années, on fait des approximations en considérant respectivement 30 jours et 365 jours, ce qui est suffisant pour la plupart des cas d’utilisation.

Entre nous, vous avez de la data partout, mais rien de vraiment clair ? Un expert data analytics engineering comme moi peut tout connecter. On attaque quand ?

Voici quelques tests pour voir cette fonction en action :

result1 = parse_relative_time("2 heures ago")
result2 = parse_relative_time("3 jours ago")
result3 = parse_relative_time("1 semaine ago")

print(f"2 heures ago: {result1}")
print(f"3 jours ago: {result2}")
print(f"1 semaine ago: {result3}")

Avec ces tests, vous devriez obtenir des objets datetime qui représentent les dates et heures correspondantes. L’importance de la flexibilité du paramètre reference_time permet également de simuler des dates passées ou de traiter des données historiques sans avoir à modifier la logique de votre code.

Pour aller plus loin dans la gestion des dates et heures en Python, vous pouvez consulter cet article qui explore d’autres techniques et astuces sur le sujet.

Comment extraire des dates dans un texte naturel ?

Extraire des dates dans du texte non structuré est un défi courant, surtout quand il s’agit de traiter des données réelles. Qui n’a jamais eu à faire face à des phrases comme « La réunion est prévue pour le 15 janvier 2026 » ou « Répondez d’ici le 3 mars » ? Pour extraire ces informations, il est essentiel de construire un dictionnaire de mois et un pattern regex capable de capturer ces dates, y compris celles avec des suffixes (st, nd, rd, th) et des années optionnelles.

La première étape consiste à établir un dictionnaire qui associe les noms des mois (en version complète et abrégée) à leurs valeurs numériques. Voici un exemple de ce que cela pourrait donner :


months = {
    'janvier': 1, 'jan': 1,
    'février': 2, 'févr': 2,
    'mars': 3, 'mar': 3,
    'avril': 4, 'avr': 4,
    'mai': 5,
    'juin': 6, 'jun': 6,
    'juillet': 7, 'juil': 7,
    'août': 8, 'aou': 8,
    'septembre': 9, 'sep': 9,
    'octobre': 10, 'oct': 10,
    'novembre': 11, 'nov': 11,
    'décembre': 12, 'dec': 12
}

Une fois que le dictionnaire est en place, on peut construire un pattern regex pour extraire les dates. L’idée est de capturer les mois suivis d’un jour, avec des suffixes optionnels et une année facultative. Un pattern efficace pourrait ressembler à ceci :


pattern = r'(janvier|jan|février|févr|mars|mar|avril|avr|mai|juin|jun|juillet|juil|août|aou|septembre|sep|octobre|oct|novembre|nov|décembre|dec)\s+(\d{1,2})(?:st|nd|rd|th)?(?:,?\s+(\d{4}))?'

Ce pattern permet de capturer les noms de mois, le jour et l’année si elle est présente. Si l’année n’est pas spécifiée, la logique consiste à utiliser l’année courante. Cela évite des erreurs fréquentes, notamment lorsque l’on traite des données qui pourraient faire référence à des événements futurs ou passés.

Pour illustrer, prenons quelques exemples de phrases et les résultats qu’on pourrait obtenir :


text1 = "La réunion est prévue pour le 15 janvier 2026"
text2 = "Répondez d'ici le 3 mars"
text3 = "Deadline : 25 déc."

date1 = extract_date_from_text(text1)
date2 = extract_date_from_text(text2)
date3 = extract_date_from_text(text3)

print(date1)  # 2026-01-15
print(date2)  # 2026-03-03
print(date3)  # 2023-12-25

Cette méthode d’extraction permet de rendre le processus de récupération de dates beaucoup plus robuste, en évitant les erreurs fréquentes que l’on pourrait rencontrer avec des approches de traitement de langage naturel basiques. Pour aller plus loin, vous pouvez découvrir d’autres techniques sur ce sujet dans cette vidéo.

Comment gérer les formats de date multiples sans se prendre la tête ?

Quand on parle de dates, on ne peut pas faire l’impasse sur la variété des formats. Que ce soit « 15/01/2026 », « 2026-01-15 » ou « Jan 15, 2026 », chaque système a ses petites manies. La diversité des formats de date impose donc une solution robuste pour éviter de perdre du temps à jongler avec des conversions manuelles à chaque fois. La méthode brute-force se présente alors comme une alliée de choix.

Cette approche consiste à essayer plusieurs formats standards jusqu’à ce qu’un d’entre eux fonctionne. C’est simple, efficace et surtout, ça ne nécessite pas d’installer des dépendances externes lourdes. Voici quelques formats de date courants que vous pourriez rencontrer :

  • %Y-%m-%d (2026-01-15)
  • %d-%m-%Y (15-01-2026)
  • %m/%d/%Y (01/15/2026)
  • %B %d, %Y (January 15, 2026)
  • %d %B %Y (15 January 2026)

L’ordre dans lequel vous essayez ces formats est crucial pour éviter les ambiguïtés. Par exemple, si vous testez d’abord un format qui pourrait correspondre à plusieurs interprétations comme %d/%m/%Y, cela peut mener à des erreurs. Priorisez les formats que vous savez être les plus probables pour votre jeu de données.

Voici un exemple de code qui met en œuvre cette méthode :

from datetime import datetime

def parse_flexible_date(date_string):
    formats = [
        '%Y-%m-%d',
        '%d-%m-%Y',
        '%m/%d/%Y',
        '%B %d, %Y',
        '%d %B %Y',
    ]
    
    for fmt in formats:
        try:
            return datetime.strptime(date_string, fmt)
        except ValueError:
            continue
            
    raise ValueError(f"Unable to parse date: {date_string}")

# Test
dates = ["2026-01-15", "15-01-2026", "01/15/2026", "January 15, 2026", "15 January 2026"]
for date_str in dates:
    print(f"{date_str} -> {parse_flexible_date(date_str)}")

Ce code teste chaque format et renvoie la première date valide trouvée. C’est un moyen rapide et efficace de gérer les formats de date variés. Pour des conseils supplémentaires, vous pouvez consulter cette discussion sur Reddit.

Comment parser des durées exprimées en formats variés ?


Quand il s'agit de parser des durées en Python, vous allez souvent rencontrer des formats variés : des heures, minutes et secondes sous forme de "h:mm:ss", des unités textuelles comme "1h 30m" ou même des décimales comme "1.5 heures". La diversité des formats peut être un vrai casse-tête, mais pas de panique ! Grâce à une fonction bien conçue, vous pouvez gérer toutes ces variations sans trop de tracas.

Voici une fonction qui s'attaque à ce problème en deux étapes. D'abord, elle vérifie si la durée est au format "colon" (h:m:s ou m:s). Ensuite, elle utilise des expressions régulières (regex) pour extraire les heures, minutes et secondes, tout en prenant en charge les décimales. Cela permet de créer des objets timedelta facilement manipulables.


from datetime import timedelta
import re

def parse_duration(duration_string):
    """
    Parse duration strings into timedelta objects.
    
    Handles formats like:
    - "1h 30m 45s"
    - "2:45:30" (H:M:S)
    - "90 minutes"
    - "1.5 hours"
    """
    duration_string = duration_string.strip().lower()
    
    # Try colon format first (H:M:S or M:S)
    if ':' in duration_string:
        parts = duration_string.split(':')
        if len(parts) == 2:
            # M:S format
            minutes, seconds = map(int, parts)
            return timedelta(minutes=minutes, seconds=seconds)
        elif len(parts) == 3:
            # H:M:S format
            hours, minutes, seconds = map(int, parts)
            return timedelta(hours=hours, minutes=minutes, seconds=seconds)
    
    # Try unit-based format (1h 30m 45s)
    total_seconds = 0
    
    # Find hours
    hours_match = re.search(r'(\d+(?:\.\d+)?)\s*h(?:ours?)?', duration_string)
    if hours_match:
        total_seconds += float(hours_match.group(1)) * 3600
    
    # Find minutes
    minutes_match = re.search(r'(\d+(?:\.\d+)?)\s*m(?:in(?:ute)?s?)?', duration_string)
    if minutes_match:
        total_seconds += float(minutes_match.group(1)) * 60
    
    # Find seconds
    seconds_match = re.search(r'(\d+(?:\.\d+)?)\s*s(?:ec(?:ond)?s?)?', duration_string)
    if seconds_match:
        total_seconds += float(seconds_match.group(1))
    
    if total_seconds > 0:
        return timedelta(seconds=total_seconds)
    
    raise ValueError(f"Unable to parse duration: {duration_string}")

Pour voir comment cela fonctionne, testons la fonction avec plusieurs formats de durée :


durations = [
    "1h 30m 45s",
    "2:45:30",
    "90 minutes",
    "1.5 hours",
    "45s",
    "2h 15m"
]

for duration in durations:
    parsed = parse_duration(duration)
    print(f"{duration:15} -> {parsed}")

Les résultats seront les suivants :


1h 30m 45s      -> 1:30:45
2:45:30         -> 2:45:30
90 minutes      -> 1:30:00
1.5 hours       -> 1:30:00
45s             -> 0:00:45
2h 15m          -> 2:15:00

Cette fonction est particulièrement flexible, car elle peut gérer des durées partielles sans obliger l'utilisateur à spécifier chaque unité. Vous pouvez ainsi l'appliquer à une variété de cas d'utilisation, que ce soit pour des applications de suivi de temps ou des analyses de données. Pour plus de détails sur la gestion des dates avec Python, vous pouvez consulter cet article sur la gestion des dates avec Python.

Comment interpréter les dates au format ISO semaine ?

Le format ISO semaine (YYYY-Www-D) est couramment utilisé dans le milieu professionnel, mais avouons-le, il n’est pas des plus intuitifs. Selon la définition officielle, la semaine 1 est celle qui contient le premier jeudi de l’année, et les jours sont numérotés de 1 à 7, où 1 correspond à lundi et 7 à dimanche. Cela peut prêter à confusion, notamment lorsque l’on essaie de planifier des réunions ou des échéances.

Pour déterminer la date précise correspondant à un format ISO semaine, la méthode consiste à identifier le lundi de la semaine 1. Pour ce faire, on commence par trouver le 4 janvier de l’année en question. Ce jour-là, on sait qu’il fait partie de la semaine 1. Ensuite, on recule jusqu’au lundi de cette semaine. Une fois que l’on a ce point de référence, il suffit d’ajouter le nombre de semaines et de jours pour arriver à la date cible.

Voici un exemple de code Python qui illustre cette méthode :

from datetime import datetime, timedelta

def parse_iso_week_date(iso_week_string):
    """
    Parse le format de date ISO semaine : YYYY-Www-D
    Exemple : "2024-W03-2" = Semaine 3 de 2024, mardi
    """
    # Analyser le format : YYYY-Www-D
    parts = iso_week_string.split('-')
    
    if len(parts) != 3 or not parts[1].startswith('W'):
        raise ValueError(f"Format ISO semaine invalide : {iso_week_string}")
    
    year = int(parts[0])
    week = int(parts[1][1:])  # Supprimer le préfixe 'W'
    day = int(parts[2])
    
    if not (1 <= week <= 53):
        raise ValueError(f"La semaine doit être entre 1 et 53 : {week}")
    
    if not (1 <= day <= 7):
        raise ValueError(f"Le jour doit être entre 1 et 7 : {day}")
    
    # Trouver le 4 janvier (toujours dans la semaine 1)
    jan_4 = datetime(year, 1, 4)
    
    # Trouver le lundi de la semaine 1
    week_1_monday = jan_4 - timedelta(days=jan_4.weekday())
    
    # Calculer la date cible
    target_date = week_1_monday + timedelta(weeks=week - 1, days=day - 1)
    
    return target_date

# Test des dates ISO semaine
iso_dates = [
    "2024-W01-1",  # Semaine 1, lundi
    "2024-W03-2",  # Semaine 3, mardi
    "2024-W10-5",  # Semaine 10, vendredi
]

for iso_date in iso_dates:
    parsed = parse_iso_week_date(iso_date)
    print(f"{iso_date} -> {parsed.strftime('%Y-%m-%d (%A)')}")

Lorsque vous exécutez ce code, vous obtiendrez des résultats clairs et précis, vous aidant à éviter des erreurs de planification. Maîtriser ce format est essentiel pour toute personne impliquée dans la gestion de projet ou la planification d’événements. Cela vous permet de naviguer dans les complexités des calendriers d’entreprise sans vous perdre dans les détails.

Prêt à dompter toutes vos dates et heures en Python ?

Ces cinq fonctions DIY vous offrent un arsenal solide pour parser dates et heures dans des contextes réels, souvent chaotiques. En maîtrisant regex, timedelta et les subtilités des formats, vous évitez les pièges classiques, gagnez en robustesse et autonomie. Plus besoin de dépendances lourdes : vous contrôlez vos données temporelles, clé pour tout projet data ou IA. Vous voilà armé pour transformer le chaos temporel en données propres, exploitables et fiables.

FAQ

Comment gérer les formats de date inconnus en Python ?

Utilisez une fonction qui tente plusieurs formats standards avec datetime.strptime. Cette approche brute-force est simple et efficace pour la majorité des cas, même avec des formats variés.

Peut-on parser des durées avec des décimales en Python ?

Oui, en utilisant des expressions régulières adaptées, on peut extraire les heures, minutes ou secondes exprimées en décimales, puis convertir le tout en timedelta.

Comment extraire une date d’un texte naturel ?

Grâce à un dictionnaire des mois et une regex ciblée, on peut identifier et extraire les dates même quand elles sont noyées dans une phrase, avec gestion des suffixes et années optionnelles.

Pourquoi approximons-nous les mois et années en jours pour les temps relatifs ?

Parce que timedelta ne gère pas directement les mois ou années, on utilise 30 jours pour un mois et 365 pour une année, ce qui est suffisant pour la plupart des usages pratiques.

Qu’est-ce que le format ISO semaine et quand l’utiliser ?

Le format ISO semaine (YYYY-Www-D) indique une semaine et un jour spécifiques dans l’année, utilisé en business pour la planification hebdomadaire. Comprendre son calcul évite erreurs dans les calendriers.

 

 

A propos de l’auteur

Franck Scandolera, consultant expert en Analytics, Data et Automatisation IA, cumule des années d’expérience dans le développement d’applications IA et l’intégration de workflows automatisés. Responsable de l’agence webAnalyste et formateur reconnu, il partage ses connaissances pointues en parsing de données et gestion temporelle, aidant les professionnels à maîtriser leurs datas complexes.

Retour en haut