If you’ve ever had to sift through a pile of text—like log files, user comments, or documents—and pull out dates and times, you know it can be a real hassle. Copying them one by one? Not efficient. Manually writing code to check every possible format? Way too time-consuming. That’s where Python’s regular expressions (regex) come in handy. They let you automatically find and extract dates and times, no matter how they’re written—well, almost. Let’s break down how to do it, step by step.
Why Regex for Dates and Times?
Dates and times show up in text in all sorts of ways. Think about it: someone might write "7/10/2017", another "October 7, 2017", and someone else "2017-10-07". Times aren’t simpler either—"5:45 pm", "17:30", "3:15"—the list goes on.
Regex is like a pattern-matching superpower. It lets you define what a "date" or "time" looks like to your program, so it can scan through text and pick out exactly what you need. No more manual hunting.
Let’s Start with a Basic Example
Let’s look at a simple regex pattern that finds common date and time formats. Here’s a Python snippet to get us going:
import re
# Define our regex pattern
pattern = re.compile(r'\b\d{1,2}/\d{1,2}/\d{4}\b|\b\d{1,2}:\d{2}\b')
# The text we want to scan
text = 'The Yellow Door is open today for your convenience from 10 am till 5:45 pm. 7/10/2017'
# Find all matches
matches = re.findall(pattern, text)
print(matches) Code result as follows

What’s Happening Here?
Let’s break down the regex pattern r'\b\d{1,2}/\d{1,2}/\d{4}\b|\b\d{1,2}:\d{2}\b':
\b: This is a word boundary. It makes sure we’re matching whole "words" (so we don’t accidentally pick up dates inside longer numbers).\d{1,2}/\d{1,2}/\d{4}: This part matches dates in the format "day/month/year" (like 7/10/2017).\d{1,2}: Matches 1 or 2 digits (for days or months, since they can be 1-31 or 1-12)./: The slash separates day, month, and year.\d{4}: Matches 4 digits (for the year, like 2017).
|: This is like an "or"—it lets us add another pattern.\d{1,2}:\d{2}: This matches times like "5:45" or "10:30".\d{1,2}: 1 or 2 digits for the hour (1-12 or 0-23, depending on the format).:: The colon separates hours and minutes.\d{2}: Exactly 2 digits for minutes (00-59).
Expanding to More Formats
The basic example works for simple cases, but what if you need to catch more date and time formats? Let’s expand our regex to handle common variations.
1. Matching "Month/Day/Year" and "Year-Month-Day"
Some countries use "month/day/year" (like 10/7/2017 instead of 7/10/2017), and many systems use "year-month-day" (2017-10-07). Let’s adjust our pattern:
import re
# Pattern now includes month/day/year, year-month-day, and times
pattern = re.compile(r'''
\b\d{1,2}/\d{1,2}/\d{4}\b # day/month/year (e.g., 7/10/2017)
|\b\d{1,2}/\d{4}/\d{1,2}\b # month/day/year (e.g., 10/7/2017)
|\b\d{4}-\d{1,2}-\d{1,2}\b # year-month-day (e.g., 2017-10-07)
|\b\d{1,2}:\d{2}\b # times like 5:45 or 10:30
''', re.VERBOSE) # re.VERBOSE lets us add comments to the pattern
text = 'Meeting on 10/7/2017 (US date) or 2017-10-07 (ISO). Starts at 9:30, ends at 14:45.'
matches = re.findall(pattern, text)
print(matches)
# Output: ['10/7/2017', '2017-10-07', '9:30', '14:45'] The execution result of the code is as follows

2. Including AM/PM in Times
Lots of texts specify morning or evening with "am" or "pm" (like "9:30 am" or "2:15 PM"). Let’s tweak our time pattern to include these:
import re
pattern = re.compile(r'''
\b\d{1,2}/\d{1,2}/\d{4}\b # day/month/year
|\b\d{4}-\d{1,2}-\d{1,2}\b # year-month-day
|\b\d{1,2}:\d{2}\s?[apAP][mM]\b # times with am/pm (e.g., 9:30 am, 2:15 PM)
|\b\d{1,2}:\d{2}\b # times without am/pm
''', re.VERBOSE)
text = 'Breakfast at 7:00 am, lunch at 12:30 PM, dinner at 6:45. Date: 5/3/2023.'
matches = re.findall(pattern, text)
print(matches) Output

Here, \s? matches an optional space (so "9:30am" and "9:30 am" both work), and [apAP][mM] catches "am", "pm", "AM", or "PM".
3. Full Month Names (e.g., "October 7, 2017")
What if the date uses a full month name, like "October 7, 2017" or "7 October 2017"? We can add patterns for that too:
import re
pattern = re.compile(r'''
\b\d{1,2}/\d{1,2}/\d{4}\b # day/month/year
|\b(January|February|March|April|May|June|
July|August|September|October|November|December)
\s\d{1,2},\s\d{4}\b # Month Day, Year (e.g., October 7, 2017)
|\b\d{1,2}\s(January|February|March|April|May|June|
July|August|September|October|November|December)
\s\d{4}\b # Day Month Year (e.g., 7 October 2017)
|\b\d{1,2}:\d{2}\s?[apAP][mM]\b # times with am/pm
''', re.VERBOSE | re.IGNORECASE) # re.IGNORECASE makes month names case-insensitive
text = 'We met on October 7, 2017, then again on 15 november 2023. Call at 3:15 PM.'
matches = re.findall(pattern, text)
# Clean up matches (since we have groups, we'll filter out empty strings)
clean_matches = [match for group in matches for match in group if match]
print(clean_matches) Code result as follows

Note: When using re.findall with groups (parentheses), it returns tuples of group matches. We added a quick cleanup step to get a simple list of matches.
Common Pitfalls to Avoid
Regex is powerful, but it’s not perfect. Here are a few things to watch out for:
- Invalid dates: Regex can match "13/13/2023" (13th month) or "31/04/2023" (April has 30 days), but that’s not a real date. For validation, use Python’s
datetimemodule after extraction. - Overlapping patterns: If your patterns are too similar (e.g., "mm/dd/yyyy" and "dd/mm/yyyy"), you might get unexpected matches. Test with sample text!
- Case sensitivity: "PM" vs "pm"—use
re.IGNORECASEto avoid missing matches.
Putting It All Together: A Practical Use Case
Let’s say you’re analyzing customer reviews and want to extract when people mentioned visiting a store. Here’s how you might use regex:
import re
from datetime import datetime
def extract_and_validate_dates(text):
# Using non-capturing groups (?:...) to prevent findall from returning only group contents
pattern = re.compile(r'''
\b\d{1,2}/\d{1,2}/\d{4}\b # day/month/year format
|\b\d{4}-\d{1,2}-\d{1,2}\b # year-month-day format
|\b(?:January|February|March|April|May|June|
July|August|September|October|November|December)
\s\d{1,2},\s\d{4}\b # Month Day, Year format
|\b\d{1,2}:\d{2}\s?[apAP][mM]\b # time with am/pm
''', re.VERBOSE | re.IGNORECASE)
# Find all matches
matches = pattern.findall(text)
# Validate dates
valid_dates = []
for match in matches:
# Try parsing common date formats
parsed = False
for fmt in ['%d/%m/%Y', '%m/%d/%Y', '%Y-%m-%d', '%B %d, %Y']:
try:
datetime.strptime(match, fmt)
valid_dates.append(match)
parsed = True
break
except ValueError:
continue
# If it's a time format, add it directly
if not parsed and ':' in match:
# Simple time format validation
time_pattern = re.compile(r'\b\d{1,2}:\d{2}\s?[apAP][mM]\b')
if time_pattern.match(match):
valid_dates.append(match)
return valid_dates
# Example text
review = "Visited on 5/3/2023 at 2:30 pm. Great service! Will come again in June 10, 2024."
print(extract_and_validate_dates(review)) Output:
Wrapping Up
Python’s regex is a fantastic tool for pulling dates and times from text. Start with simple patterns, test them on your actual text, and expand as needed. Remember—regex finds patterns, not validity, so pair it with datetime for checking if those dates and times are real.
Whether you’re cleaning data, analyzing logs, or parsing user input, this skill will save you tons of time. Give it a try with your own text—you’ll be surprised how much easier it makes things!