Pour parser efficacement dates et heures en Python, il faut maîtriser regex et datetime. Ces 5 fonctions DIY traitent les formats relatifs, naturels, flexibles, durées et ISO. Vous gagnez en robustesse sans dépendances lourdes, idéal pour scripts et prototypes.
3 principaux points à retenir.
- Maîtrisez les expressions régulières pour extraire les informations clés dans les formats variés.
- Utilisez datetime et timedelta pour manipuler et convertir les dates et durées de façon fiable.
- Privilégiez la flexibilité en testant plusieurs formats et en adaptant vos parsers aux données réelles et imprévues.
Comment convertir des temps relatifs en dates précises ?
La conversion des temps relatifs, comme « 5 minutes ago », en dates précises est un exercice délicat mais tout à fait réalisable. Cela passe par l’utilisation d’expressions régulières pour extraire le nombre et l’unité de temps, puis en soustrayant ce délai à une date de référence à l’aide de timedelta. Cela devient particulièrement utile lorsque vous traitez des données issues de réseaux sociaux ou d’applications de messagerie où les timestamps sont souvent exprimés de cette manière.
Voici comment fonctionne la fonction parse_relative_time :
from datetime import datetime, timedelta
import re
def parse_relative_time(time_string, reference_time=None):
"""
Convertit des chaînes de temps relatives en objets datetime.
Exemples : "2 hours ago", "3 days ago", "1 week ago"
"""
if reference_time is None:
reference_time = datetime.now()
# Normaliser la chaîne
time_string = time_string.lower().strip()
# Modèle : nombre + unité de temps + "ago"
pattern = r'(\d+)\s*(second|minute|hour|day|week|month|year)s?\s*ago'
match = re.match(pattern, time_string)
if not match:
raise ValueError(f"Cannot parse: {time_string}")
amount = int(match.group(1))
unit = match.group(2)
# Mapper les unités aux kwargs de timedelta
unit_mapping = {
'second': 'seconds',
'minute': 'minutes',
'hour': 'hours',
'day': 'days',
'week': 'weeks',
}
if unit in unit_mapping:
delta_kwargs = {unit_mapping[unit]: amount}
return reference_time - timedelta(**delta_kwargs)
elif unit == 'month':
# Approximatif : 30 jours par mois
return reference_time - timedelta(days=amount * 30)
elif unit == 'year':
# Approximatif : 365 jours par an
return reference_time - timedelta(days=amount * 365)
Dans cette fonction, nous commençons par vérifier si une reference_time est fournie. Si ce n’est pas le cas, nous utilisons l’heure actuelle. Ensuite, nous normalisons la chaîne de temps et utilisons une expression régulière pour extraire le nombre et l’unité. Les unités sont ensuite mappées à des arguments que timedelta peut comprendre. Pour les mois et les années, nous faisons une approximation, car ces unités ne sont pas directement gérées par timedelta.
Voici un exemple de test :
result1 = parse_relative_time("2 hours ago")
result2 = parse_relative_time("3 days ago")
result3 = parse_relative_time("1 week ago")
print(f"2 hours ago: {result1}")
print(f"3 days ago: {result2}")
print(f"1 week ago: {result3}")
Ce code renvoie des objets datetime précis correspondant aux temps relatifs donnés. Cela vous permet de travailler efficacement avec des données temporelles issues de sources variées, rendant votre code plus robuste et adaptable. Pour plus de détails sur les objets datetime, vous pouvez consulter la documentation officielle ici.
Comment extraire des dates dans un texte naturel ?
Pour extraire une date d’un texte naturel, la clé réside dans la détection des noms de mois, des jours et éventuellement de l’année, à l’aide d’une expression régulière bien conçue. Cela permet de cibler précisément les informations sans avoir à analyser l’ensemble du texte, ce qui est crucial dans des contextes comme les emails, les messages ou les documents divers.
Voici la fonction extract_date_from_text qui illustre cette méthode :
import re
from datetime import datetime
def extract_date_from_text(text, current_year=None):
"""
Extract dates from natural language text.
Handles formats like:
- "January 15th, 2024"
- "March 3rd"
- "Dec 25th, 2023"
"""
if current_year is None:
current_year = datetime.now().year
# Month names (full and abbreviated)
months = {
'january': 1, 'jan': 1,
'february': 2, 'feb': 2,
'march': 3, 'mar': 3,
'april': 4, 'apr': 4,
'may': 5,
'june': 6, 'jun': 6,
'july': 7, 'jul': 7,
'august': 8, 'aug': 8,
'september': 9, 'sep': 9, 'sept': 9,
'october': 10, 'oct': 10,
'november': 11, 'nov': 11,
'december': 12, 'dec': 12
}
# Pattern: Month Day(st/nd/rd/th), Year (year optional)
pattern = r'(january|jan|february|feb|march|mar|april|apr|may|june|jun|july|jul|august|aug|september|sep|sept|october|oct|november|nov|december|dec)\s+(\d{1,2})(?:st|nd|rd|th)?(?:,?\s+(\d{4}))?'
matches = re.findall(pattern, text.lower())
if not matches:
return None
# Take the first match
month_str, day_str, year_str = matches[0]
month = months[month_str]
day = int(day_str)
year = int(year_str) if year_str else current_year
return datetime(year, month, day)
Cette fonction commence par établir un dictionnaire qui associe les noms des mois (complets et abrégés) à leurs valeurs numériques respectives. Ensuite, elle utilise une expression régulière pour identifier les motifs correspondants à un mois, un jour et éventuellement une année. Les suffixes de jours tels que st, nd, rd et th sont pris en compte, mais ne sont pas nécessaires pour l’extraction.
Voici quelques exemples de tests avec des phrases variées :
text1 = "The meeting is scheduled for January 15th, 2026 at 3pm"
text2 = "Please respond by March 3rd"
text3 = "Deadline: Dec 25th, 2026"
date1 = extract_date_from_text(text1)
date2 = extract_date_from_text(text2)
date3 = extract_date_from_text(text3)
print(f"From '{text1}': {date1}")
print(f"From '{text2}': {date2}")
print(f"From '{text3}': {date3}")
Avec cette approche, vous simplifiez considérablement l’extraction ciblée des dates dans un texte, ce qui peut s’avérer très utile dans de nombreux scénarios. Si vous souhaitez approfondir les meilleures pratiques pour obtenir et utiliser les dates en Python, vous pouvez consulter cet article ici.
Comment gérer plusieurs formats de dates sans se compliquer ?
Face à la diversité des formats de dates, il est souvent tentant de se perdre dans des solutions complexes. Pourtant, une méthode simple et efficace consiste à tester une liste de formats courants avec datetime.strptime jusqu’à trouver un match. Cela permet de gérer la variété des formats sans se compliquer la vie.
Voici une fonction appelée parse_flexible_date qui illustre cette approche. Elle essaie plusieurs formats de date, en commençant par les plus standards, comme l’ISO, pour finir par des formats plus ambigus. Voici le code :
from datetime import datetime
def parse_flexible_date(date_string):
"""
Parse dates in multiple common formats.
Tries various formats and returns the first match.
"""
date_string = date_string.strip()
# List of common date formats
formats = [
'%Y-%m-%d',
'%Y/%m/%d',
'%d-%m-%Y',
'%d/%m/%Y',
'%m/%d/%Y',
'%d.%m.%Y',
'%Y%m%d',
'%B %d, %Y',
'%b %d, %Y',
'%d %B %Y',
'%d %b %Y',
]
# Try each format
for fmt in formats:
try:
return datetime.strptime(date_string, fmt)
except ValueError:
continue
# If nothing worked, raise an error
raise ValueError(f"Unable to parse date: {date_string}")
Dans cette fonction, nous avons une liste de formats de date dans un ordre logique. L’ISO (%Y-%m-%d) est priorisé car il est le plus courant dans les contextes techniques. Les formats ambigus, comme %d/%m/%Y et %m/%d/%Y, viennent plus tard dans la liste pour éviter toute confusion.
La gestion des erreurs est aussi cruciale ici. Si un format ne correspond pas, nous attrapons l’exception ValueError et continuons avec le suivant. Cela permet à la fonction de rester fluide et réactive, sans bloquer le processus.
Pour illustrer son efficacité, testons la fonction avec plusieurs formats :
# Test different formats
dates = [
"2026-01-15",
"15/01/2026",
"01/15/2026",
"January 15, 2026",
]
for date_str in dates:
parsed = parse_flexible_date(date_str)
print(f"{date_str:20} -> {parsed}")
Cette approche brute-force est pragmatique pour des projets où la simplicité prime. Vous n’avez pas besoin d’une bibliothèque externe complexe, juste d’un peu de logique et de regex. Pour plus d’informations sur la gestion des différentes chaînes de format de date, vous pouvez consulter cet article ici.
Comment convertir des durées en objets temporels exploitables ?
Pour manipuler des durées exprimées dans des formats variés, comme « 1h 30m 45s » ou « 2:45:30 », il est crucial de parser ces chaînes de caractères. Cela signifie extraire les heures, minutes et secondes, puis les convertir en objets timedelta exploitables. Ces conversions sont essentielles dans des applications vidéo, sportives ou de suivi temporel, où chaque seconde compte.
Voici une fonction, parse_duration, qui gère ces formats. Elle prend en charge à la fois les formats avec des deux-points (H:M:S ou M:S) et ceux basés sur des unités avec des regex. Cette approche permet de traiter des entrées variées et de renvoyer un objet timedelta qui peut être utilisé directement dans des calculs temporels.
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}")
# Test the function with various duration formats
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}")
Cette fonction est robuste et peut gérer des formats divers, en s’adaptant aux différentes manières dont les utilisateurs pourraient entrer des durées. En fin de compte, comprendre et manipuler ces durées est fondamental pour toute application nécessitant une gestion du temps. Pour plus de détails sur le traitement du temps en Python, consultez la documentation officielle.
Comment interpréter les dates au format ISO semaine ?
Le format ISO semaine, comme « 2026-W03-2 », est un système qui encode une semaine et un jour spécifiques d’une année. Ce format est particulièrement prisé dans le milieu professionnel, où la planification hebdomadaire est cruciale. Il permet de référencer des dates de manière standardisée, ce qui évite les ambiguïtés souvent rencontrées avec les formats de date traditionnels.
Pour gérer ce type de date, nous avons développé une fonction efficace : parse_iso_week_date. Cette fonction commence par découper la chaîne d’entrée pour en extraire l’année, le numéro de semaine et le jour. Elle effectue ensuite des validations sur les valeurs obtenues, s’assurant que la semaine est comprise entre 1 et 53, et que le jour est un chiffre valide entre 1 et 7.
La logique de calcul repose sur une règle clé : la première semaine de l’année est définie comme celle qui contient le 4 janvier. Pour déterminer la date correspondante, nous localisons le lundi de cette première semaine, puis nous ajoutons le nombre de semaines et de jours nécessaires pour atteindre la date cible.
from datetime import datetime, timedelta
def parse_iso_week_date(iso_week_string):
parts = iso_week_string.split('-')
if len(parts) != 3 or not parts[1].startswith('W'):
raise ValueError(f"Invalid ISO week format: {iso_week_string}")
year = int(parts[0])
week = int(parts[1][1:]) # Remove 'W' prefix
day = int(parts[2])
if not (1
Pour illustrer son utilisation, considérons quelques exemples de tests :
# Test ISO week dates
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)')}")
Ce code va afficher les dates correspondantes sous le format standard, par exemple, "2024-W01-1" donnera "2024-01-01 (Lundi)". Ce format, bien que moins courant que les dates traditionnelles, mérite d'avoir un parser dédié pour éviter des erreurs de conversion et gagner un temps précieux lors de la manipulation de données professionnelles. Pour plus de détails sur la gestion des dates en Python, vous pouvez consulter la documentation officielle ici.
Prêt à maîtriser le parsing des dates et heures en Python ?
Ces cinq fonctions DIY vous donnent les clés pour dompter les dates et heures en Python, même dans leur forme la plus chaotique. Vous gagnez en autonomie, sans dépendre d’outils lourds, et améliorez la robustesse de vos scripts ou prototypes. Maîtriser ces techniques, c’est s’assurer que vos données temporelles ne vous planteront plus jamais un projet. En prime, vous comprenez mieux les rouages du parsing, un savoir indispensable pour tout développeur ou data scientist.
FAQ
Comment gérer les formats de date inconnus en Python ?
Peut-on parser des durées exprimées en texte libre ?
Quelle précision attendre des conversions relatives comme "2 months ago" ?
Pourquoi utiliser un parseur ISO semaine ?
Ces fonctions remplacent-elles les bibliothèques spécialisées ?
A propos de l'auteur
Franck Scandolera est consultant et formateur expert en Analytics, Data, Automatisation IA et développement d’applications intégrant l’intelligence artificielle. Avec une expérience solide dans la manipulation avancée de données et le développement Python, il accompagne les entreprises dans la mise en place de workflows intelligents et performants. Basé à Brive‑la‑Gaillarde, il intervient partout en France, Suisse et Belgique, partageant son savoir au service de l’efficacité métier.
⭐ Expert et formateur en Tracking avancé, Analytics Engineering et Automatisation IA (n8n, Make) ⭐
Ref clients : Logis Hôtel, Yelloh Village, BazarChic, Fédération Football Français, Texdecor…
Mon terrain de jeu :
Data & Analytics engineering : tracking propre RGPD, entrepôt de données (GTM server, BigQuery…), modèles (dbt/Dataform), dashboards décisionnels (Looker, SQL, Python).
Automatisation IA des taches Data, Marketing, RH, compta etc : conception de workflows intelligents robustes (n8n, Make, App Script, scraping) connectés aux API de vos outils et LLM (OpenAI, Mistral, Claude…).
Engineering IA pour créer des applications et agent IA sur mesure : intégration de LLM (OpenAI, Mistral…), RAG, assistants métier, génération de documents complexes, APIs, backends Node.js/Python.






