1
0
Files
md-dump/howto-fhir-date-parameter.md
T

12 KiB
Raw Blame History

HowTo: Der FHIR date-Suchparameter Präfixe, Intervalle und Kombinationen richtig verstehen

Wer FHIR-Server baut oder abfragt, stolpert früher oder später über den date-Suchparameter. Auf den ersten Blick sieht er simpel aus ?date=2023-06-15 aber sobald Präfixe wie ge, sa oder ap ins Spiel kommen und mehrere date-Parameter kombiniert werden, wird es schnell unübersichtlich. Dieser Artikel bringt Ordnung rein: Schritt für Schritt, mit Zeitleisten-Grafiken zu jedem Fall.


1. Das Grundprinzip: FHIR vergleicht Intervalle, keine Zeitpunkte

Der wichtigste gedankliche Reset zuerst: FHIR behandelt Datumswerte nie als exakten Zeitpunkt, sondern immer als Intervall. Wie breit dieses Intervall ist, hängt von der Precision des angegebenen Werts ab:

  • 2023 → das ganze Jahr 2023
  • 2023-06 → der ganze Juni 2023
  • 2023-06-15 → der ganze 15. Juni 2023 (00:0024:00 Uhr)
  • 2023-06-15T10:00:00 → (fast) ein exakter Zeitpunkt

Jeder Vergleichsoperator vergleicht anschließend zwei Intervalle miteinander: das Such-Intervall aus deinem Query-Parameter und das Resource-Intervall aus dem Feld der Ressource (z. B. Patient.birthDate oder Encounter.period).

Ohne Präfix = eq, aber die Precision entscheidet mit

Gibst du kein Präfix an, nimmt der Server eq an. Das Resource-Datum muss dann vollständig innerhalb deines Such-Intervalls liegen. Je gröber die Precision, desto breiter das Intervall und desto mehr Resource-Werte passen hinein:

Datum ohne Präfix

date=2023-06-15 matched nur diesen einen Tag. date=2023-06 matched dagegen jeden Tag im Juni auch den 15. Das ist der häufigste Stolperstein für Einsteiger: eine „ungenaue" Suchanfrage ist nicht strenger, sondern lockerer.


2. Die neun Präfixe im Überblick

FHIR definiert insgesamt neun Präfixe für date. Jeder davon beschreibt eine andere Beziehung zwischen Such-Intervall (rot gestrichelt in der Grafik) und Treffer-Bereich (grün/farbig schattiert):

Alle Präfixe

Präfix Name Bedeutung
eq gleich Resource-Intervall liegt vollständig im Such-Intervall
ne ungleich Komplement von eq
gt größer als Resource-Intervall ragt über das Ende des Such-Intervalls hinaus
lt kleiner als Resource-Intervall beginnt vor dem Anfang des Such-Intervalls
ge größer/gleich gt oder vollständig im Such-Intervall enthalten (eq)
le kleiner/gleich lt oder vollständig im Such-Intervall enthalten (eq)
sa starts after Beginnt vollständig nach dem Ende des Such-Intervalls, keine Überlappung
eb ends before Endet vollständig vor dem Beginn des Such-Intervalls, keine Überlappung
ap approximately Überlappung, plus ähnliche Größenordnung der Intervalle

Wichtig — Containment vs. Overlap: Nur eq (und implizit sa/eb) verlangen, dass das Resource-Intervall vollständig innerhalb bzw. vollständig getrennt vom Such-Intervall liegt. Bei gt, lt, ge und le reicht dagegen eine Überlappung — das Resource-Intervall muss nicht komplett außerhalb des Suchbereichs liegen, es genügt, dass es über die jeweilige Grenze hinausragt. Details dazu im nächsten Abschnitt.


3. Sonderfall: Matching gegen Period und Range

Die Grafiken oben zeigen das Resource-Datum als schmalen roten Marker das passt für einfache date/dateTime-Felder wie Patient.birthDate. Sobald das Zielfeld selbst ein Intervall ist (Period, z. B. Encounter.period, Condition.onsetPeriod, oder Range), wird die Unterscheidung zwischen Containment (vollständiges Enthaltensein) und Overlap (bloße Überlappung) entscheidend:

  • eq verlangt Containment: das gesamte Resource-Intervall muss im Such-Intervall liegen.
  • gt / lt / ge / le verlangen nur Overlap: es reicht, wenn das Resource-Intervall über die jeweilige Grenze hinausragt auch wenn ein Teil davon auf der "falschen" Seite liegt.
  • sa / eb verlangen das Gegenteil von Overlap: das Resource-Intervall muss vollständig und ohne jede Überlappung auf der jeweiligen Seite liegen.

Beispiel: Ein Encounter läuft vom 10. bis 20. Juni. Die Suche date=gt2023-06-15 soll ihn finden, obwohl der Encounter vor dem 15. begonnen hat — entscheidend ist nur, dass er über den 15. hinausreicht (Overlap mit dem Bereich "nach dem 15."). Bei date=sa2023-06-15 würde derselbe Encounter dagegen nicht matchen, weil er nicht vollständig nach dem 15. liegt — genau das ist der praktische Unterschied zwischen gt und sa.

Die folgende Grafik macht das für alle vier "einseitigen" Präfixe (gt, sa, lt, eb) an denselben drei Beispiel-Periods sichtbar — einer Period komplett davor, einer, die die Suchgrenze überlappt, und einer komplett danach:

Period/Range Matching

Man sieht deutlich: gt und lt (blau schattierter Bereich, durchgezogene Grenzlinie) lassen die überlappende Period B als Treffer durch, während sa und eb (gestrichelte Grenzlinie) sie ablehnen — nur eine Period, die komplett auf der richtigen Seite liegt, zählt dort.

Encounter-Zeitraum date=gt2023-06-15 date=sa2023-06-15
10.20. Juni (überlappt die Grenze) Treffer (Overlap) kein Treffer (nicht vollständig danach)
16.20. Juni (komplett danach) Treffer Treffer
01.10. Juni (komplett davor) kein Treffer kein Treffer

Offene (unvollständige) Periods

In der Praxis sind Periods oft nicht abgeschlossen — z. B. ein laufender Encounter ohne end, oder ein importierter Datensatz mit unbekanntem start. Der FHIR-Standard regelt das eindeutig:

Ein fehlender unterer Rand (start) gilt implizit als kleiner als jedes reale Datum (also -∞). Ein fehlender oberer Rand (end) gilt implizit als größer als jedes reale Datum (also +∞).

Das hat spürbare Konsequenzen, gerade für sa und eb:

  • Ein laufender Encounter (start gesetzt, end fehlt → end = +∞) kann niemals eb (ends before) matchen — sein Ende liegt ja nie vor irgendeinem endlichen Datum. Er matcht aber sehr wohl gt, weil sein (unendliches) Ende immer über jede Suchgrenze hinausragt.
  • Ein Encounter mit unbekanntem Start (start fehlt → start = -∞) kann niemals sa (starts after) matchen — sein Beginn liegt ja nie nach irgendeinem endlichen Datum. Er matcht aber lt, weil sein (unendlicher) Anfang immer vor jede Suchgrenze hineinreicht.
  • Eine Period ganz ohne start und end überlappt praktisch jeden overlap-basierten Filter (gt, lt, ge, le) — sie „reicht" ja per Definition über jede Grenze hinaus.

Dieselben vier Präfixe wie oben, jetzt mit offenen statt geschlossenen Periods:

Offene Periods Matching

Praktische Konsequenz: Wenn du „laufende" Ressourcen (z. B. aktive Encounter, offene Verordnungen) gezielt aus einer Zeitraumsuche ausschließen willst, reicht eb/sa allein nicht — du musst zusätzlich nach dem Status oder explizit nach end:missing=true/start:missing=true filtern, je nachdem, was dein Server unterstützt.

Bei einem einfachen Zeitpunkt-Feld (kein Period) fällt dieser Unterschied praktisch nicht auf, da Resource-Start und -Ende (fast) identisch sind — dort verhalten sich gt und sa de facto gleich. Der Unterschied wird erst bei echten Zeitspannen relevant. Das ist auch der Grund, warum sa/eb laut Spezifikation in erster Linie für Period/Range-Werte gedacht sind.


4. Mehrere date-Parameter kombinieren

In der Praxis reicht ein einzelner Präfix selten meist willst du einen Bereich definieren. FHIR-Server verknüpfen mehrere date-Parameter in derselben Query immer per UND. Vier typische Muster:

Kombinationen

Kombination Beispiel Charakter
ge + le ge2023-01-01&le2023-12-31 Geschlossenes Intervall (beide Grenzen inklusive)
gt + lt gt2023-01-01&lt2023-12-31 Offenes Intervall (beide Grenzen exklusive)
sa + eb sa2023-01-01&eb2023-12-31 Strikt getrennter Bereich, primär für Period-Werte
ge + lt ge2023-06-01&lt2023-07-01 Halboffenes Intervall [start, ende) Standardmuster für „genau ein Monat"

Wenn du in Timestamp-lastigen ETL-Pipelines mit [start, ende) arbeitest, kommt dir ge + lt bekannt vor es ist exakt dasselbe Muster wie bei klassischen Zeitfenster-Queries in SQL.


5. Die vollständige 3×3-Matrix aller Bereichs-Kombinationen

Die vier Muster oben sind nur die gebräuchlichsten. Tatsächlich lässt sich jede Untergrenze mit jeder Obergrenze kombinieren:

  • Untergrenzen: ge, gt, sa
  • Obergrenzen: le, lt, eb

Das ergibt 3 × 3 = 9 mögliche Kombinationen, alle spec-konform:

3x3 Matrix

Sie unterscheiden sich nur darin, ob die jeweilige Grenze inklusiv (durchgezogene Linie) oder exklusiv (gestrichelte Linie) ist, und ob es sich um einen einfachen Werte-Vergleich (ge/gt/le/lt) oder einen strengen Period-Vergleich (sa/eb) handelt. Es gibt keine explizite Ausschluss-Regel im FHIR-Standard jede Zelle dieser Matrix ist eine gültige, funktionierende Query.


6. Sonderfälle: Wenn Kombinationen redundant oder widersprüchlich werden

Nicht jede syntaktisch gültige Kombination ist auch praktisch sinnvoll. Drei Kategorien solltest du kennen, bevor du sie versehentlich in einer generierten Query landen lässt:

Sonderfälle

a) Redundante Kombinationen

Ändern nichts am Ergebnis, sind aber technisch kein Fehler:

  • eq + eine Grenze, die vom eq-Intervall ohnehin erfüllt wird (eq2023-06-15&ge2020-01-01) die Zusatzbedingung ist überflüssig.
  • Zwei Bedingungen desselben Richtungstyps (ge2020-01-01&ge2023-01-01) nur die strengere (spätere) Untergrenze wirkt effektiv.

b) Kombinationen mit garantiert leerem Ergebnis

Strukturell unmöglich zu erfüllen:

  • eq + ne auf denselben Wert (eq2023-06-15&ne2023-06-15) sich gegenseitig ausschließende Bedingungen.
  • Untergrenze liegt zeitlich nach der Obergrenze (ge2023-06-01&le2023-01-01) kein Datum erfüllt beides gleichzeitig.

Der Server wird solche Queries syntaktisch akzeptieren und einfach eine leere Ergebnismenge zurückgeben kein Fehler, aber auch keine hilfreiche Rückmeldung. Es lohnt sich, so etwas clientseitig vorab zu validieren.

c) Ungewöhnliche, aber gültige Sonderfälle

  • Drei oder mehr date-Parameter, z. B. ein Jahresbereich mit ausgeschlossenem Einzeltag: ge2023-01-01&le2023-12-31&ne2023-06-15.
  • ap kombiniert mit einer Grenze, z. B. ap2023-06-15&ge2023-01-01 selten genutzt, da ap selbst schon unscharf ist und die Toleranzberechnung serverabhängig bleibt.

7. Praxis-Empfehlungen zum Schluss

  • Für einfache Bereichsfilter ist ge + lt (halboffenes Intervall) meist das robusteste Muster es vermeidet Rundungsprobleme an der Precision-Grenze (kein Off-by-one bei „bis einschließlich 31.12.").
  • sa/eb bewusst einsetzen, wenn du bei Period/Range-Feldern eine vollständige Trennung brauchst (siehe Abschnitt 3) z. B. „Encounter vollständig nach Entlassung X". Für einen simplen „ab Datum X"-Filter ist meist ge/gt gemeint, nicht sa.
  • Vor dem Absetzen einer Multi-Parameter-Query lohnt sich ein kurzer Check auf logische Konsistenz zwischen Unter- und Obergrenze, um leere Ergebnisse durch Konfigurationsfehler in der eigenen Pipeline zu vermeiden.

Mit diesen fünf Grafiken im Hinterkopf ohne Präfix, alle neun Präfixe einzeln, typische Kombinationen, die volle 3×3-Matrix und die Sonderfälle und dem Wissen um den Unterschied zwischen Containment und Overlap bei Period/Range-Feldern sollte die nächste date-Query im FHIR-Suchparameter kein Rätsel mehr sein.