Skip to content

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.

ParameterRequiredDescription
offset_daysyesInteger 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.
dayfirstnoBoolean, 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.
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.

The shifted value is emitted in the input’s original date format when that format can be preserved:

InputWith offset_days = 10
2026-03-142026-03-24
March 14, 2026March 24, 2026
14-Mar-202624-Mar-2026
July 12July 22
12 July22 July
07/1207/22
Feb 29Mar 10
2026-03-14T09:30:00.123Z2026-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.

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.

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.

  • faker — realistic fake dates (no interval preservation).
  • keep — detect and catalog without redacting.