# Shifting Clinical Dates

Apply consistent per-patient date shifting in OpenMed that preserves intervals between...

- Repository: https://github.com/maziyarpanahi/openmed (5755 stars)
- Category: Writing
- License: Apache-2.0
- Last updated: 2026-10-31
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add maziyarpanahi/openmed --skill shifting-clinical-dates -g -a claude-code -y`
Codex: `npx skills add maziyarpanahi/openmed --skill shifting-clinical-dates -g -a codex -y`
Cursor: `npx skills add maziyarpanahi/openmed --skill shifting-clinical-dates -g -a cursor -y`
Gemini CLI: `npx skills add maziyarpanahi/openmed --skill shifting-clinical-dates -g -a gemini-cli -y`
Claude Code plugin marketplace: `/plugin marketplace add maziyarpanahi/openmed`

## Description

Apply consistent per-patient date shifting in OpenMed that preserves intervals between events while satisfying HIPAA Safe Harbor's date rule. Use when the user needs to de-identify dates but keep temporal structure for research, shift all dates by the same offset per patient, preserve days-between-events for survival or longitudinal analysis, cap ages over 89, or strip everything but the year. Covers deidentify(method=\"shift_dates\", date_shift_days=..., keep_year=...) and per-patient reproducible offsets via consistent=True, seed=.... Pairs with OpenMed deidentifying-clinical-text and auditing-safe-harbor-checklist.

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# Shifting clinical dates

HIPAA Safe Harbor forbids keeping dates more specific than the year. But naively
deleting dates destroys the temporal structure research depends on, time to
event, length of stay, intervals between visits. **Date shifting** is the
compromise: move every date by a single random offset so the *absolute* dates
become meaningless while the *intervals* between them are preserved exactly.
OpenMed does this on-device with `deidentify(method="shift_dates", ...)`.

## When to use this skill

Use it when downstream analysis needs temporal relationships (survival curves,
sepsis-to-antibiotic time, readmission gaps) but the calendar dates must be
de-identified. If you can throw dates away entirely, plain `method="mask"` is
simpler, reach for shifting only when intervals matter.

## Quick start

```python
import openmed

note = (
    "Admitted 2024-03-02, started antibiotics 2024-03-04, discharged 2024-03-09. "
    "Follow-up scheduled 2024-04-02."
)

# Shift every date by the SAME offset -> intervals preserved, dates obscured.
result = openmed.deidentify(
    note,
    method="shift_dates",
    consistent=True,        # one stable offset for this run
    seed=20240519,          # reproducible per-patient offset (use a per-patient key)
    keep_year=False,        # do NOT retain the year (Safe Harbor: year-only is the max)
)
print(result.deidentified_text)
# Admit -> antibiotics is still 2 days; admit -> discharge still 7 days; etc.
```

## How interval preservation works

All dates in the document are moved by **one** offset (auto-selected as a random
non-zero value in roughly ±1 year, or fixed with `date_shift_days=`). Because
the offset is identical for every date, the difference between any two dates is
unchanged:

```
real:    Mar 2  ──2d──▶ Mar 4  ──5d──▶ Mar 9
shifted: Jul 18 ──2d──▶ Jul 20 ──5d──▶ Jul 25     (offset = +138 days, intervals intact)
```

The rest: https://github.com/maziyarpanahi/openmed/blob/HEAD/skills/shifting-clinical-dates/SKILL.md
