1
0

Update howto-fhir-date-parameter.md

This commit is contained in:
hmk
2026-08-12 12:10:46 +00:00
parent 6c2aed6443
commit 551f945ac6
+110 -21
View File
@@ -52,23 +52,110 @@ Treffer-Bereich (grün/farbig schattiert):
|---|---|---| |---|---|---|
| `eq` | gleich | Resource-Intervall liegt vollständig im Such-Intervall | | `eq` | gleich | Resource-Intervall liegt vollständig im Such-Intervall |
| `ne` | ungleich | Komplement von `eq` | | `ne` | ungleich | Komplement von `eq` |
| `gt` | größer als | Resource-Datum beginnt nach dem Ende des Such-Intervalls | | `gt` | größer als | Resource-Intervall **ragt über** das Ende des Such-Intervalls hinaus |
| `lt` | kleiner als | Resource-Datum endet vor dem Beginn des Such-Intervalls | | `lt` | kleiner als | Resource-Intervall **beginnt vor** dem Anfang des Such-Intervalls |
| `ge` | größer/gleich | Beginnt am oder nach Beginn des Such-Intervalls | | `ge` | größer/gleich | `gt` **oder** vollständig im Such-Intervall enthalten (`eq`) |
| `le` | kleiner/gleich | Endet am oder vor Ende des Such-Intervalls | | `le` | kleiner/gleich | `lt` **oder** vollständig im Such-Intervall enthalten (`eq`) |
| `sa` | starts after | Beginnt vollständig **nach** dem Ende des Such-Intervalls | | `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 | | `eb` | ends before | Endet vollständig **vor** dem Beginn des Such-Intervalls, keine Überlappung |
| `ap` | approximately | Ungefähre Übereinstimmung, Toleranz serverabhängig | | `ap` | approximately | Überlappung, plus ähnliche Größenordnung der Intervalle |
**Praxis-Tipp:** `sa`/`eb` unterscheiden sich von `gt`/`lt` nur spürbar bei **Wichtig — Containment vs. Overlap:** Nur `eq` (und implizit `sa`/`eb`)
Resource-Feldern, die selbst ein **Intervall** sind (`Period`, z. B. verlangen, dass das Resource-Intervall **vollständig** innerhalb bzw.
`Encounter.period`). Bei einem einzelnen Zeitpunkt-Feld ist der Unterschied **vollständig getrennt** vom Such-Intervall liegt. Bei `gt`, `lt`, `ge`
meist nicht beobachtbar `gt` reicht schon, wenn die Period *beginnt* nach und `le` reicht dagegen eine **Überlappung** — das Resource-Intervall muss
dem Suchdatum; `sa` verlangt, dass die *gesamte* Period danach liegt. nicht komplett außerhalb des Suchbereichs liegen, es genügt, dass es über
die jeweilige Grenze hinausragt. Details dazu im nächsten Abschnitt.
--- ---
## 3. Mehrere `date`-Parameter kombinieren ## 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](fhir-date-period-range-matching.svg)
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](fhir-date-offene-periods.svg)
**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 In der Praxis reicht ein einzelner Präfix selten meist willst du einen
**Bereich** definieren. FHIR-Server verknüpfen mehrere `date`-Parameter in **Bereich** definieren. FHIR-Server verknüpfen mehrere `date`-Parameter in
@@ -89,7 +176,7 @@ klassischen Zeitfenster-Queries in SQL.
--- ---
## 4. Die vollständige 3×3-Matrix aller Bereichs-Kombinationen ## 5. Die vollständige 3×3-Matrix aller Bereichs-Kombinationen
Die vier Muster oben sind nur die gebräuchlichsten. Tatsächlich lässt sich Die vier Muster oben sind nur die gebräuchlichsten. Tatsächlich lässt sich
**jede** Untergrenze mit **jeder** Obergrenze kombinieren: **jede** Untergrenze mit **jeder** Obergrenze kombinieren:
@@ -110,7 +197,7 @@ gültige, funktionierende Query.
--- ---
## 5. Sonderfälle: Wenn Kombinationen redundant oder widersprüchlich werden ## 6. Sonderfälle: Wenn Kombinationen redundant oder widersprüchlich werden
Nicht jede syntaktisch gültige Kombination ist auch praktisch sinnvoll. Drei Nicht jede syntaktisch gültige Kombination ist auch praktisch sinnvoll. Drei
Kategorien solltest du kennen, bevor du sie versehentlich in einer Kategorien solltest du kennen, bevor du sie versehentlich in einer
@@ -146,19 +233,21 @@ Rückmeldung. Es lohnt sich, so etwas clientseitig vorab zu validieren.
--- ---
## 6. Praxis-Empfehlungen zum Schluss ## 7. Praxis-Empfehlungen zum Schluss
- Für einfache Bereichsfilter ist **`ge` + `lt`** (halboffenes Intervall) meist - Für einfache Bereichsfilter ist **`ge` + `lt`** (halboffenes Intervall) meist
das robusteste Muster es vermeidet Rundungsprobleme an der das robusteste Muster es vermeidet Rundungsprobleme an der
Precision-Grenze (kein Off-by-one bei „bis einschließlich 31.12."). Precision-Grenze (kein Off-by-one bei „bis einschließlich 31.12.").
- **`sa`/`eb`** nur einsetzen, wenn das Zielfeld tatsächlich ein `Period`- oder - **`sa`/`eb`** bewusst einsetzen, wenn du bei `Period`/`Range`-Feldern eine
`Range`-Element ist. Bei einfachen `date`/`dateTime`-Feldern liefern sie in *vollständige* Trennung brauchst (siehe Abschnitt 3) z. B. „Encounter
der Regel dasselbe Ergebnis wie `gt`/`lt` der zusätzliche Ausdruck bringt vollständig nach Entlassung X". Für einen simplen „ab Datum X"-Filter ist
dann keinen Mehrwert. meist `ge`/`gt` gemeint, nicht `sa`.
- Vor dem Absetzen einer Multi-Parameter-Query lohnt sich ein kurzer Check auf - Vor dem Absetzen einer Multi-Parameter-Query lohnt sich ein kurzer Check auf
logische Konsistenz zwischen Unter- und Obergrenze, um leere Ergebnisse logische Konsistenz zwischen Unter- und Obergrenze, um leere Ergebnisse
durch Konfigurationsfehler in der eigenen Pipeline zu vermeiden. durch Konfigurationsfehler in der eigenen Pipeline zu vermeiden.
Mit diesen fünf Grafiken im Hinterkopf ohne Präfix, alle neun Präfixe 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 einzeln, typische Kombinationen, die volle 3×3-Matrix und die Sonderfälle
sollte die nächste `date`-Query im FHIR-Suchparameter kein Rätsel mehr sein. 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.