date_shift
date_shift moves every shiftable calendar date by the same configured number of days. Full dates (March 14, 2026), timestamps (2026-03-14T09:30:00Z), and yearless month-day dates (July 12, 07/12) all shift. Because every shifted date uses the same offset, intervals between shifted calendar dates are preserved when the source text contains real calendar days. A note that says a procedure occurred 30 days after admission still has that 30-day spacing after replacement, while the original date values are no longer shown.
This is the operator for clinical notes, longitudinal corpora, claims, timelines, and any dataset where date spacing matters.
Anything that is not at least a month+day calendar value passes through unchanged: relative phrases (in two weeks, tomorrow), durations (30 days, post-op day 30), times of day (3pm), bare years (2026), and month-year values (March 2026). Those values may matter to the text, but shifting them would either be ambiguous or would destroy useful meaning.
Parameters
Section titled “Parameters”| Parameter | Required | Description |
|---|---|---|
offset_days | yes | Integer days to shift every absolute date. Positive or negative, non-zero, within ±3650. Keep it constant for a whole corpus so dates stay consistent across requests. |
dayfirst | no | Boolean, default false (month-first, US convention). Set true for day-first corpora so an ambiguous 03/04/2026 parses as 3 April. Self-disambiguating numeric dates infer from the value itself (07/15 is July 15, 15/07 is 15 July). Declaring the right convention still matters for ambiguous dates: with the wrong policy, ambiguous dates shift consistently but their real intervals are destroyed. |
Example
Section titled “Example”SELECT app_public.mask( 'Admitted 03/14/2026. Surgery on March 20, 2026. Follow-up in two weeks.', OBJECT_CONSTRUCT( 'entity_config', OBJECT_CONSTRUCT( 'DATE_TIME', OBJECT_CONSTRUCT('operator', 'date_shift', 'operator_params', OBJECT_CONSTRUCT('offset_days', 137)) ) ));Output:
{ "columns": [{ "deidentified_text": "Admitted 07/29/2026. Surgery on August 4, 2026. Follow-up in two weeks." }], "entity_ledger": [ {"entity_type": "DATE_TIME", "original": "03/14/2026", "placeholder": "[REDACTED_DATE_TIME_1]", "replacement": "07/29/2026"}, {"entity_type": "DATE_TIME", "original": "March 20, 2026", "placeholder": "[REDACTED_DATE_TIME_2]", "replacement": "August 4, 2026"} ]}Both full dates moved by exactly 137 days — the 6-day surgery interval is intact. “in two weeks” passed through unchanged and produces no ledger entry (pass-through entries are omitted from the ledger; the text is identical and there is nothing to look up).
date_shift leaves relative temporal phrases unchanged. To exclude those
phrases before any operator runs, or to transform only concrete dates with a
different DATE_TIME operator, add value_filter: 'absolute_date' to the
DATE_TIME config.
Format handling
Section titled “Format handling”The shifted value is emitted in the input’s original date format when that format can be preserved:
| Input | With offset_days = 10 |
|---|---|
2026-03-14 | 2026-03-24 |
March 14, 2026 | March 24, 2026 |
14-Mar-2026 | 24-Mar-2026 |
July 12 | July 22 |
12 July | 22 July |
07/12 | 07/22 |
Feb 29 | Mar 10 |
2026-03-14T09:30:00.123Z | 2026-03-24T09:30:00.123Z |
Yearless dates stay yearless. Date-times keep their clock time, timezone text,
and fractional-second precision where possible. When a full-date format cannot
be preserved, the replacement falls back to ISO-8601 with the input’s time
components preserved when present. Format preservation is best-effort.
Treat date_shift as replacing detected absolute dates with deterministic
shifted dates while preserving the spacing between shifted date values. It does
not remove relative timing language, bare years, or month-year references.
Rehydration
Section titled “Rehydration”Each shifted date is an ordinary ledger entry, so rehydration uses the same
replacement → original lookup as every other entity. Because the shift is
deterministic and the offset is constant, the same original date maps to the
same shifted date across a corpus when you keep the same operator configuration
and ledger_seed.
Limitations and guidance
Section titled “Limitations and guidance”The offset is constant per corpus. If someone knows one original date and its shifted value, they can infer the offset and apply it to other shifted dates created with the same configuration. Date spacing is also intentionally preserved, so records with matching timelines may remain comparable after shifting.
Choose date_shift when timeline fidelity is required. Choose
faker or mask for
DATE_TIME when you do not need to preserve date intervals.