Skip to content

Commit 05fd624

Browse files
authored
Merge pull request #529 from IBM/lee-master-patch1
issue #528 - update Conformance.md and tweak datetime precision
2 parents 08d0ada + 65eff00 commit 05fd624

8 files changed

Lines changed: 992 additions & 396 deletions

File tree

docs/src/pages/Conformance.md

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ FHIR search modifiers are described at https://www.hl7.org/fhir/R4/search.html#m
8585
|Reference |`:[type]`,`:missing` |exact match search|
8686
|URI |`:below`,`:above`,`:missing` |exact match search|
8787
|Token |`:missing` |exact match search|
88-
|Number |`:missing` |exact match search|
89-
|Date |`:missing` |exact match search|
88+
|Number |`:missing` |implicit range search (see http://hl7.org/fhir/R4/search.html#number)|
89+
|Date |`:missing` |implicit range search (see https://www.hl7.org/fhir/search.html#date)|
9090
|Quantity |`:missing` |implicit range search (see http://hl7.org/fhir/R4/search.html#quantity)|
9191
|Composite |`:missing` |processes each parameter component according to its type|
9292
|Special (near) | none |searches a bounding area according to the value of the `fhirServer/search/useBoundingRadius` property|
@@ -124,16 +124,25 @@ The `eb` and `ap` prefixes are not supported for searches which target values of
124124
If not specified on a query string, the default prefix is `eq`.
125125

126126
### Searching on Date
127-
The FHIR server adheres to the specification except in cases where a time is included in the search query value. When a time is specified, the implementation requires an hour, minute, second, and timezone value. Including these values is consistent with the way in which `instant` and `dateTime` data types are defined at https://www.hl7.org/fhir/R4/datatypes.html#primitive. However, the implementation differs from the description at https://www.hl7.org/fhir/R4/search.html#date, which allows clients to include hours and minutes, but to omit values for seconds and time zone.
127+
The IBM FHIR Server adheres to the specification with two minor exceptions:
128+
* The server supports search query values with fractional seconds; any search query value given with fractional seconds is treated as precise value, whereas search query values without fractional seconds are handled as an implicit range (e.g. `2000-04-30T23:59:00` becomes the range `[2000-04-30T23:59:00, 2000-04-30T23:59:01)`).
129+
* Dates and DateTimes (and query parameter values for date search parameters) which are expressed without timezones are handled as UTC values.
130+
* This differs slightly from the specification which indicates that "Where both search parameters and resource element date times do not have time zones, the servers local time zone should be assumed". However, because both the element values AND search query parameters are handled in the same way, this difference matters only when timezones are specified on one side (resource element or search query parameter) but not the other. For example, a query like `Patient?birthdate=2019-01-01` would match a resource with a value of `2019-01-01`, but would *not* match a resource with a value of `2019-01-01T20:00:00-04:00`.
128131

129-
The IBM FHIR Server stores up to 6 fractional seconds (microsecond granularity) for Instant and DateTime values (when present) and allows clients to search with these as well.
132+
The IBM FHIR Server supports up to 6 fractional seconds (microsecond granularity) for Instant and DateTime values and all extracted parameter values are stored in the database in UTC in order to improve data portability.
130133

131-
Query parameter values without fractional seconds will be handled as an implicit range. For example, a search like `Patient?date=2019-01-01T12:00:00Z` would include resources with the following effectiveDateTime values:
134+
Dates and DateTimes which are expressed without timezones are assumed to be in the local timezone of the application server at the time of parameter extraction.
135+
Similarly, query parameter date values with no timezone are assumed to be in the local time of the server at the time the search is invoked.
136+
To ensure consistency of search results, clients are recommended to include the timezone on all search query values that include a time.
137+
138+
Finally, the server extends the specified capabilities with support for "exact match" semantics on fractional seconds.
139+
140+
Query parameter values without fractional seconds is handled as an implicit range. For example, a search like `Observatoin?date=2019-01-01T12:00:00Z` would return resources with the following effectiveDateTime values:
132141
* 2019-01-01T12:00:00Z
133142
* 2019-01-01T12:00:00.1Z
134143
* 2019-01-01T12:00:00.999999Z
135144

136-
Query parameter values with fractional seconds will be handled with exact match semantics (ignoring precision). For example, a search like `Patient?date=2019-01-01T12:00:00.100Z` would include resources with the following effectiveDateTime values:
145+
Query parameter values with fractional seconds is handled with exact match semantics (ignoring precision). For example, a search like `Patient?birthdate=2019-01-01T12:00:00.1Z` would include resources with the following effectiveDateTime values:
137146
* 2019-01-01T12:00:00.1Z
138147
* 2019-01-01T12:00:00.100Z
139148
* 2019-01-01T12:00:00.100000Z

fhir-examples/src/main/resources/json/ibm/basic/BasicDate.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
},
1515
{
1616
"url": "http://example.org/dateTime",
17-
"valueDateTime": "2018-10-29T17:12:00-04:00"
17+
"valueDateTime": "2019-12-31T20:00:00-04:00"
1818
},
1919
{
2020
"url": "http://example.org/time",

fhir-persistence-jdbc/src/main/java/com/ibm/fhir/persistence/jdbc/util/JDBCParameterBuildingVisitor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ private void setDateValues(DateParmVal p, Date date) {
652652
java.time.Instant inst = DateTimeHandler.generateValue(date.getValue());
653653
p.setValueDate(DateTimeHandler.generateTimestamp(inst));
654654
p.setValueDateStart(DateTimeHandler.generateTimestamp(inst));
655-
inst = DateTimeHandler.generateUpperBound(date.getValue());
655+
inst = DateTimeHandler.generateUpperBound(date);
656656
p.setValueDateEnd(DateTimeHandler.generateTimestamp(inst));
657657
}
658658
}
@@ -671,7 +671,7 @@ private void setDateValues(DateParmVal p, DateTime dateTime) {
671671
java.time.Instant inst = DateTimeHandler.generateValue(dateTime.getValue());
672672
p.setValueDate(DateTimeHandler.generateTimestamp(inst));
673673
p.setValueDateStart(DateTimeHandler.generateTimestamp(inst));
674-
inst = DateTimeHandler.generateUpperBound(dateTime.getValue());
674+
inst = DateTimeHandler.generateUpperBound(dateTime);
675675
p.setValueDateEnd(DateTimeHandler.generateTimestamp(inst));
676676
}
677677
}

fhir-persistence-jdbc/src/main/java/com/ibm/fhir/persistence/jdbc/util/type/DateParmBehaviorUtil.java

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.DATE_END;
1212
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.DATE_START;
1313
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.DOT;
14-
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.EQ;
1514
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.GT;
1615
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.GTE;
1716
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.LEFT_PAREN;
@@ -172,25 +171,17 @@ public void buildCommonClause(StringBuilder whereClauseSegment, List<Timestamp>
172171
*/
173172
public void buildEqualsRangeClause(StringBuilder whereClauseSegment, List<Timestamp> bindVariables,
174173
String tableAlias, Instant lowerBound, Instant upperBound) {
175-
bindVariables.add(generateTimestamp(lowerBound));
174+
// @formatter:off
175+
whereClauseSegment
176+
.append(LEFT_PAREN)
177+
.append(tableAlias).append(DOT).append(DATE_START).append(GTE).append(BIND_VAR)
178+
.append(AND)
179+
.append(tableAlias).append(DOT).append(DATE_END).append(LTE).append(BIND_VAR)
180+
.append(RIGHT_PAREN);
181+
// @formatter:on
176182

177-
if (!lowerBound.equals(upperBound)) {
178-
// @formatter:off
179-
whereClauseSegment
180-
.append(LEFT_PAREN)
181-
.append(tableAlias).append(DOT).append(DATE_START).append(GTE).append(BIND_VAR)
182-
.append(AND)
183-
.append(tableAlias).append(DOT).append(DATE_END).append(LTE).append(BIND_VAR)
184-
.append(RIGHT_PAREN);
185-
// @formatter:on
186-
bindVariables.add(generateTimestamp(upperBound));
187-
} else {
188-
// Exact match of an instant.
189-
whereClauseSegment
190-
.append(LEFT_PAREN)
191-
.append(tableAlias).append(DOT).append(DATE_START).append(EQ).append(BIND_VAR)
192-
.append(RIGHT_PAREN);
193-
}
183+
bindVariables.add(generateTimestamp(lowerBound));
184+
bindVariables.add(generateTimestamp(upperBound));
194185
}
195186

196187
/**

0 commit comments

Comments
 (0)