Learn how to automatically detect and redact dates, birth dates, and temporal information from text and documents. Protect age-related PII while preserving data utility through generalization and shifting techniques.
Dates, particularly dates of birth, are critical personally identifiable information (PII) that can directly identify individuals or significantly narrow down their identity when combined with other data.
Birth dates are used for identity verification, age-based profiling, and when combined with location data, can uniquely identify over 87% of the US population according to research.
Anonymization API uses sophisticated pattern recognition to detect dates in virtually any format with 99.3% accuracy.
Before Anonymization
After Anonymization
Whether you're processing medical records, customer databases, HR files, or research data, our API ensures that date information is properly anonymized while preserving temporal relationships and analytical value. We support multiple techniques from complete redaction to date shifting that maintains relative time intervals.
US, European, ISO, and international date formats
Context-aware birth date identification
Preserve temporal relationships while anonymizing
Dates present unique privacy challenges because they can be highly identifying, especially dates of birth. A birth date combined with just gender and 5-digit zip code can uniquely identify 87% of Americans. Additionally, dates often reveal sensitive information about life events, medical conditions, or activities.
Dates directly related to an individual (birth date, admission date, discharge date, death date) are Protected Health Information. For Safe Harbor de-identification, only year may be retained. For individuals over 89, even the year must be aggregated.
Birth dates are personal data. When combined with other data, even partial dates may require protection. Age-based processing may require explicit consent.
Collection of birth dates from children under 13 requires parental consent. Date information that reveals a child's age triggers COPPA requirements.
Birth dates in credit reports are regulated information with restricted access.
Student birth dates in education records require protection.
Birth dates in employment contexts can create legal liability under ADEA and similar laws.
Get started with date redaction in just a few lines of code. This example demonstrates the simplest way to detect and redact dates from text using our API.
from anonymization import Client client = Client(api_key="your_api_key") result = client.anonymize( text="Patient born 03/15/1985, appointment on 2025-01-20", entity_types=["DATE", "DATE_OF_BIRTH"] ) print(result.anonymized_text) # Output: Patient born [DATE_OF_BIRTH], appointment on [DATE]
const { AnonymizationClient } = require('@anonymization/api'); const client = new AnonymizationClient('your_api_key'); const result = await client.anonymize({ text: "Patient born 03/15/1985, appointment on 2025-01-20", entityTypes: ["DATE", "DATE_OF_BIRTH"] }); console.log(result.anonymizedText); // Output: Patient born [DATE_OF_BIRTH], appointment on [DATE]
curl -X POST https://api.anonymizationapi.com/v2/anonymize \ -H "Authorization: Bearer your_api_key" \ -H "Content-Type: application/json" \ -d '{ "text": "Patient born 03/15/1985, appointment on 2025-01-20", "entity_types": ["DATE", "DATE_OF_BIRTH"] }'
The API response includes parsed date information and classification details:
{
"anonymized_text": "Patient born [DATE_OF_BIRTH], appointment on [DATE]",
"entities": [
{
"type": "DATE_OF_BIRTH",
"text": "03/15/1985",
"start": 13,
"end": 23,
"confidence": 0.98,
"metadata": {
"parsed_date": "1985-03-15",
"format": "MM/DD/YYYY",
"age": 39
}
},
{
"type": "DATE",
"text": "2025-01-20",
"start": 40,
"end": 50,
"confidence": 0.99,
"metadata": {
"parsed_date": "2025-01-20",
"format": "YYYY-MM-DD"
}
}
]
}
Dates appear in countless formats depending on locale, system, and writing style. Our API recognizes and normalizes all common variations.
The API can detect and handle partial dates and individual components:
# Detect full dates (default) result = client.anonymize(text, entity_types=["DATE"]) # Detect specific date types result = client.anonymize(text, entity_types=[ "DATE", # Full dates "DATE_OF_BIRTH", # Birth dates (contextual) "YEAR", # Year only (e.g., "born in 1985") "MONTH_YEAR", # Month and year (e.g., "March 2025") "AGE" # Age mentions (e.g., "45 years old") ]) # Specify expected date format for ambiguous dates result = client.anonymize( text="Date: 03/04/2025", # Is this March 4 or April 3? entity_types=["DATE"], options={"date_format": "MM/DD/YYYY"} # US format )
Choose the appropriate date anonymization technique based on your privacy requirements and analytical needs.
Completely replaces the date with a placeholder. Maximum privacy protection.
Keeps only the year, removing month and day. Meets HIPAA Safe Harbor requirements.
Converts birth dates to ages. Useful when age is needed for analysis but exact birth date is not.
Converts to age ranges for additional protection. Useful for demographic analysis.
Shifts all dates by a random but consistent offset. Preserves temporal relationships between events while hiding actual dates.
Keeps month and year, removes the specific day. Balances privacy with temporal precision.
# Full redaction (default) result = client.anonymize(text, entity_types=["DATE"], mode="redact") # Year-only generalization (HIPAA compliant) result = client.anonymize(text, entity_types=["DATE"], mode="generalize", options={"date_keep": "year"}) # Convert DOB to age result = client.anonymize(text, entity_types=["DATE_OF_BIRTH"], mode="generalize", options={"dob_to_age": True}) # Convert to age ranges (10-year buckets) result = client.anonymize(text, entity_types=["DATE_OF_BIRTH"], mode="generalize", options={"dob_to_age_range": 10}) # Date shifting with consistent offset per session result = client.anonymize(text, entity_types=["DATE"], mode="shift", options={"date_shift_range": 365}, # Max shift of 1 year session_id="patient-123") # Same shift for same patient # Keep month and year result = client.anonymize(text, entity_types=["DATE"], mode="generalize", options={"date_keep": "month_year"})
Research shows that date of birth is one of the most powerful quasi-identifiers. When building anonymized datasets, consider that even approximate dates can enable re-identification attacks when combined with other fields.
Process medical records with Safe Harbor compliant date handling:
medical_record = """ Patient: John Smith DOB: March 15, 1985 Admission Date: January 20, 2025 Procedure Date: January 22, 2025 Discharge Date: January 25, 2025 Next Appointment: February 15, 2025 """ # HIPAA Safe Harbor: Keep only year, aggregate ages over 89 result = client.anonymize( text=medical_record, entity_types=["PERSON", "DATE", "DATE_OF_BIRTH"], mode="generalize", options={ "date_keep": "year", "hipaa_age_90": True # Aggregate ages 90+ as "90+" } ) print(result.anonymized_text)
Maintain temporal relationships while anonymizing dates:
# Process multiple records for the same patient with consistent shift patient_records = [ "Visit 1: 2025-01-15, BP 120/80", "Visit 2: 2025-02-20, BP 118/78", "Visit 3: 2025-04-10, BP 122/82" ] # Same session_id ensures consistent date shift across records results = client.batch_anonymize( items=[{"text": r, "session_id": "patient-001"} for r in patient_records], entity_types=["DATE"], mode="shift", options={"date_shift_range": 180} # +/- 6 months ) # Time intervals between visits are preserved! # e.g., 36 days between visit 1 and 2 remains 36 days
Convert birth dates to ages or age ranges for demographic analysis:
customer_data = [
"Customer A, DOB: 1985-03-15",
"Customer B, born January 2, 1970",
"Customer C, birthdate 06/20/1992"
]
# Convert to age ranges for demographic analysis
results = client.batch_anonymize(
items=[{"text": c} for c in customer_data],
entity_types=["DATE_OF_BIRTH"],
mode="generalize",
options={"dob_to_age_range": 10} # 10-year buckets
)
for r in results:
print(r.anonymized_text)
# Customer A, Age: 35-44
# Customer B, Age: 55-64
# Customer C, Age: 25-34
Redact some dates while preserving others:
# Only redact birth dates, keep other dates result = client.anonymize( text="DOB: 03/15/1985, hired on 01/10/2020, contract ends 12/31/2025", entity_types=["DATE_OF_BIRTH"] # Only birth dates ) # Output: DOB: [DATE_OF_BIRTH], hired on 01/10/2020, contract ends 12/31/2025 # Redact dates within a specific range result = client.anonymize( text=text, entity_types=["DATE"], options={ "date_before": "2020-01-01", # Only dates before 2020 } )
Birth dates are more identifying than general dates and require stricter handling:
# Apply stricter rules to DOB than general dates result = client.anonymize( text=text, entity_types=["DATE", "DATE_OF_BIRTH"], options={ "date_keep": "month_year", # General dates: keep month/year "dob_mode": "year_only" # DOB: keep year only } )
HIPAA requires special handling for ages over 89:
# HIPAA compliant: aggregate 90+ ages result = client.anonymize( text="Patient born 1930, admitted today", entity_types=["DATE_OF_BIRTH"], mode="generalize", options={ "dob_to_age": True, "hipaa_age_90": True # Show as "90+" for 90+ years } ) # Output: Patient age 90+, admitted today
When analyzing data over time, date shifting preserves patterns while hiding actual dates:
# Date shifting maintains: # - Days between events # - Weekday patterns (optional) # - Seasonal patterns (with small shift range) result = client.anonymize( text=text, entity_types=["DATE"], mode="shift", options={ "date_shift_range": 30, # +/- 30 days "preserve_weekday": True, # Keep same day of week "preserve_month": True # Keep within same month }, session_id="study-participant-001" )
Enable context analysis to properly classify date types:
# Context helps distinguish: # - "DOB: 03/15/1985" -> DATE_OF_BIRTH # - "Report date: 03/15/1985" -> DATE # - "Invoice #03151985" -> Not a date result = client.anonymize( text=text, entity_types=["DATE", "DATE_OF_BIRTH"], options={"use_context": True} )
Specify the expected date format when processing data from known sources:
Caution: The date "03/04/2025" is March 4th in US format but April 3rd in European format. Always specify the expected format when processing data from a known source to avoid misinterpretation.
Our date detection achieves 99.3% accuracy on benchmark datasets covering 40+ formats. Accuracy is highest for standard numeric formats (99.7%) and slightly lower for written dates and relative expressions. Context analysis significantly improves birth date classification.
The API supports date detection in multiple languages including month names in Spanish, French, German, and more. Specify the language for better accuracy: options={"language": "es"}. Written dates like "quince de marzo" are properly detected.
The API attempts to parse and validate dates. Invalid dates (like February 30th) are flagged with lower confidence. Partial dates (just month/year or just year) are detected with the appropriate entity type (MONTH_YEAR, YEAR).
Yes, use entity_types=["AGE"] to detect age mentions like "45 years old", "a 30-year-old patient", or "aged 65". These can be generalized to age ranges just like birth dates.
Date shifting operates on dates without time zone consideration by default. For timestamps with time zones, the shift is applied consistently. You can specify options={"preserve_timezone": True} to maintain original time zone information.
Relative dates like "yesterday" or "last week" can be optionally preserved since they don't identify specific dates. Use options={"preserve_relative_dates": True}. Note that relative dates may become identifying when combined with document timestamps.
Full timestamps (date + time) are detected and handled. You can redact only the date portion, only the time portion, or both. Use entity_types=["DATE", "TIME", "DATETIME"] for granular control.
Protect date information with 99.3% accuracy. Support for 40+ formats, date shifting, and HIPAA-compliant options.
Get Started Free