fix problem with failing date/time comparison tests
This commit is contained in:
parent
58724b3694
commit
2b53f0368f
|
@ -861,73 +861,32 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
|||
}
|
||||
|
||||
/**
|
||||
* This method implements a datetime equality check using the rules as defined by FHIRPath.
|
||||
* This method implements a datetime equality check using the rules as defined by FHIRPath (R2)
|
||||
*
|
||||
* This method returns:
|
||||
* <ul>
|
||||
* <li>true if the given datetimes represent the exact same instant with the same precision (irrespective of the timezone)</li>
|
||||
* <li>true if the given datetimes represent the exact same instant but one includes milliseconds of <code>.[0]+</code> while the other includes only SECONDS precision (irrespecitve of the timezone)</li>
|
||||
* <li>true if the given datetimes represent the exact same year/year-month/year-month-date (if both operands have the same precision)</li>
|
||||
* <li>false if both datetimes have equal precision of MINUTE or greater, one has no timezone specified but the other does, and could not represent the same instant in any timezone</li>
|
||||
* <li>null if both datetimes have equal precision of MINUTE or greater, one has no timezone specified but the other does, and could potentially represent the same instant in any timezone</li>
|
||||
* <li>false if the given datetimes have the same precision but do not represent the same instant (irrespective of timezone)</li>
|
||||
* <li>null otherwise (since these datetimes are not comparable)</li>
|
||||
* </ul>
|
||||
* Caveat: this implementation assumes local timezone for unspecified timezones
|
||||
*/
|
||||
public Boolean equalsUsingFhirPathRules(BaseDateTimeType theOther) {
|
||||
|
||||
BaseDateTimeType me = this;
|
||||
|
||||
// Per FHIRPath rules, we compare equivalence at the lowest precision of the two values,
|
||||
// so if we need to, we'll clone either side and reduce its precision
|
||||
int lowestPrecision = Math.min(me.getPrecision().ordinal(), theOther.getPrecision().ordinal());
|
||||
TemporalPrecisionEnum lowestPrecisionEnum = TemporalPrecisionEnum.values()[lowestPrecision];
|
||||
if (me.getPrecision() != lowestPrecisionEnum) {
|
||||
me = new DateTimeType(me.getValueAsString());
|
||||
me.setPrecision(lowestPrecisionEnum);
|
||||
}
|
||||
if (theOther.getPrecision() != lowestPrecisionEnum) {
|
||||
theOther = new DateTimeType(theOther.getValueAsString());
|
||||
theOther.setPrecision(lowestPrecisionEnum);
|
||||
}
|
||||
|
||||
if (me.hasTimezoneIfRequired() != theOther.hasTimezoneIfRequired()) {
|
||||
if (me.getPrecision() == theOther.getPrecision()) {
|
||||
if (me.getPrecision().ordinal() >= TemporalPrecisionEnum.MINUTE.ordinal() && theOther.getPrecision().ordinal() >= TemporalPrecisionEnum.MINUTE.ordinal()) {
|
||||
boolean couldBeTheSameTime = couldBeTheSameTime(me, theOther) || couldBeTheSameTime(theOther, me);
|
||||
if (!couldBeTheSameTime) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
TemporalPrecisionEnum mp = this.myPrecision == TemporalPrecisionEnum.MILLI ? TemporalPrecisionEnum.SECOND : this.myPrecision;
|
||||
TemporalPrecisionEnum op = theOther.myPrecision == TemporalPrecisionEnum.MILLI ? TemporalPrecisionEnum.SECOND : theOther.myPrecision;
|
||||
TemporalPrecisionEnum cp = (mp.compareTo(op) < 0) ? mp : op;
|
||||
FastDateFormat df = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSS");
|
||||
String ms = df.format(this.getValue());
|
||||
String os = df.format(theOther.getValue());
|
||||
if (!sub(ms, cp.stringLength()).equals(sub(os, cp.stringLength())))
|
||||
return false;
|
||||
if (mp != op)
|
||||
return null;
|
||||
if (this.myPrecision == TemporalPrecisionEnum.MILLI || theOther.myPrecision == TemporalPrecisionEnum.MILLI) {
|
||||
float mf = Float.parseFloat(ms.substring(17));
|
||||
float of = Float.parseFloat(os.substring(17));
|
||||
if (mf != of)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Same precision
|
||||
if (me.getPrecision() == theOther.getPrecision()) {
|
||||
if (me.getPrecision().ordinal() >= TemporalPrecisionEnum.MINUTE.ordinal()) {
|
||||
long leftTime = me.getValue().getTime();
|
||||
long rightTime = theOther.getValue().getTime();
|
||||
return leftTime == rightTime;
|
||||
} else {
|
||||
String leftTime = me.getValueAsString();
|
||||
String rightTime = theOther.getValueAsString();
|
||||
return leftTime.equals(rightTime);
|
||||
}
|
||||
}
|
||||
|
||||
// Both represent 0 millis but the millis are optional
|
||||
if (((Integer)0).equals(me.getMillis())) {
|
||||
if (((Integer)0).equals(theOther.getMillis())) {
|
||||
if (me.getPrecision().ordinal() >= TemporalPrecisionEnum.SECOND.ordinal()) {
|
||||
if (theOther.getPrecision().ordinal() >= TemporalPrecisionEnum.SECOND.ordinal()) {
|
||||
return me.getValue().getTime() == theOther.getValue().getTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
private String sub(String ms, int i) {
|
||||
return ms.length() < i ? ms : ms.substring(0, i);
|
||||
}
|
||||
|
||||
private boolean couldBeTheSameTime(BaseDateTimeType theArg1, BaseDateTimeType theArg2) {
|
||||
|
@ -944,9 +903,13 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
|||
}
|
||||
|
||||
boolean hasTimezoneIfRequired() {
|
||||
return getPrecision().ordinal() <= TemporalPrecisionEnum.DAY.ordinal() ||
|
||||
getTimeZone() != null;
|
||||
}
|
||||
return getPrecision().ordinal() <= TemporalPrecisionEnum.DAY.ordinal() ||
|
||||
getTimeZone() != null;
|
||||
}
|
||||
|
||||
|
||||
boolean hasTimezone() {
|
||||
return getTimeZone() != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -79,4 +79,20 @@ public enum TemporalPrecisionEnum {
|
|||
return myCalendarConstant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the standard string representation - YYYY-DD-MMTHH:NN:SS.SSS - how long is the string for the stated precision?
|
||||
* @return
|
||||
*/
|
||||
public int stringLength() {
|
||||
switch (this) {
|
||||
case YEAR: return 4;
|
||||
case MONTH: return 7;
|
||||
case DAY: return 10;
|
||||
case MINUTE: return 16;
|
||||
case SECOND: return 19;
|
||||
case MILLI: return 23;
|
||||
}
|
||||
return 0; // ??
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -232,8 +232,8 @@
|
|||
<test name="testLiteralDate" inputfile="patient-example.xml"><expression>Patient.birthDate = @1974-12-25</expression><output type="boolean">true</output></test>
|
||||
<test name="testLiteralDate" inputfile="patient-example.xml"><expression>Patient.birthDate != @1974-12-25T12:34:00</expression></test>
|
||||
<test name="testLiteralDate" inputfile="patient-example.xml"><expression>Patient.birthDate != @1974-12-25T12:34:00-10:00</expression><output type="boolean">true</output></test>
|
||||
<test name="testLiteralDate" inputfile="patient-example.xml"><expression>Patient.birthDate != @1974-12-25T12:34:00+10:00</expression><output type="boolean">true</output></test>
|
||||
<test name="testLiteralDate" inputfile="patient-example.xml"><expression>Patient.birthDate != @1974-12-25T12:34:00Z</expression><output type="boolean">true</output></test>
|
||||
<test name="testLiteralDate" inputfile="patient-example.xml"><expression>Patient.birthDate != @1974-12-25T12:34:00+10:00</expression></test>
|
||||
<test name="testLiteralDate" inputfile="patient-example.xml"><expression>Patient.birthDate != @1974-12-25T12:34:00Z</expression></test>
|
||||
<test name="testLiteralDate" inputfile="patient-example.xml"><expression>Patient.birthDate != @T12:14:15</expression><output type="boolean">true</output></test>
|
||||
<test name="testLiteralDate" inputfile="patient-example.xml"><expression>Patient.birthDate != @T12:14</expression><output type="boolean">true</output></test>
|
||||
<test name="testLiteralDate" inputfile="patient-example.xml"><expression>Patient.birthDate < today()</expression><output type="boolean">true</output></test>
|
||||
|
@ -618,7 +618,7 @@
|
|||
<test inputfile="patient-example.xml"><expression>@2012-04-15 = @2012-04-16</expression><output type="boolean">false</output></test>
|
||||
<test inputfile="patient-example.xml"><expression>@2012-04-15 = @2012-04-15T10:00:00</expression></test>
|
||||
<test inputfile="patient-example.xml"><expression>@2012-04-15T15:00:00 = @2012-04-15T10:00:00</expression><output type="boolean">false</output></test>
|
||||
<test inputfile="patient-example.xml"><expression>@2012-04-15T15:00:00Z = @2012-04-15T10:00:00</expression></test>
|
||||
<test inputfile="patient-example.xml"><expression>@2012-04-15T15:00:00Z = @2012-04-15T10:00:00</expression><output type="boolean">false</output></test>
|
||||
<test inputfile="patient-example.xml"><expression>@2012-04-15T15:00:00+02:00 = @2012-04-15T16:00:00+03:00</expression><output type="boolean">true</output></test>
|
||||
<test inputfile="patient-example.xml"><expression>name = name</expression><output type="boolean">true</output></test>
|
||||
<test inputfile="patient-example.xml"><expression>name.take(2) = name.take(2).first() | name.take(2).last()</expression><output type="boolean">true</output></test>
|
||||
|
@ -641,7 +641,7 @@
|
|||
<test inputfile="patient-example.xml"><expression>@2012-04-15 != @2012-04-16</expression><output type="boolean">true</output></test>
|
||||
<test inputfile="patient-example.xml"><expression>@2012-04-15 != @2012-04-15T10:00:00</expression></test>
|
||||
<test inputfile="patient-example.xml"><expression>@2012-04-15T15:00:00 != @2012-04-15T10:00:00</expression><output type="boolean">true</output></test>
|
||||
<test inputfile="patient-example.xml"><expression>@2012-04-15T15:00:00Z != @2012-04-15T10:00:00</expression></test>
|
||||
<test inputfile="patient-example.xml"><expression>@2012-04-15T15:00:00Z != @2012-04-15T10:00:00</expression><output type="boolean">true</output></test>
|
||||
<test inputfile="patient-example.xml"><expression>@2012-04-15T15:00:00+02:00 != @2012-04-15T16:00:00+03:00</expression><output type="boolean">false</output></test>
|
||||
<test inputfile="patient-example.xml"><expression>name != name</expression><output type="boolean">false</output></test>
|
||||
<test inputfile="patient-example.xml"><expression>name.take(2) != name.take(2).first() | name.take(2).last()</expression><output type="boolean">false</output></test>
|
||||
|
|
|
@ -16,15 +16,31 @@ public class BaseDateTimeTypeTest {
|
|||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
public void equalsUsingFhirPathRules() {
|
||||
public void equalsUsingFhirPathRulesInSpec() {
|
||||
|
||||
// from the spec
|
||||
assertTrue( compareDateTimes("2012", "2012"));
|
||||
assertFalse(compareDateTimes("2012", "2013"));
|
||||
assertNull( compareDateTimes("2012-01", "2012"));
|
||||
assertNull( compareDateTimes("2012-01-01", "2012-01-01T00:00:00"));
|
||||
assertTrue( compareDateTimes("2012-01-01T10:30:00", "2012-01-01T10:30:00"));
|
||||
assertFalse(compareDateTimes("2012-01-01T10:30:00", "2012-01-01T10:31:00"));
|
||||
assertTrue( compareDateTimes("2012-01-01T10:30:31.0", "2012-01-01T10:30:31"));
|
||||
assertFalse(compareDateTimes("2012-01-01T10:30:31.1", "2012-01-01T10:30:31"));
|
||||
assertFalse(compareDateTimes("2017-11-05T01:30:00.0-04:00", "2017-11-05T01:15:00.0-05:00"));
|
||||
assertTrue(compareDateTimes("2017-11-05T01:30:00.0-04:00", "2017-11-05T00:30:00.0-05:00"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalsUsingFhirPathRulesOther() {
|
||||
// Exact same - Same timezone
|
||||
assertTrue(compareDateTimes("2001-01-02T11:22:33.444Z", "2001-01-02T11:22:33.444Z"));
|
||||
assertTrue( compareDateTimes("2001-01-02T11:22:33.444Z", "2001-01-02T11:22:33.444Z"));
|
||||
// Exact same - Different timezone
|
||||
assertTrue(compareDateTimes("2001-01-02T11:22:33.444-03:00", "2001-01-02T10:22:33.444-04:00"));
|
||||
assertTrue( compareDateTimes("2001-01-02T11:22:33.444-03:00", "2001-01-02T10:22:33.444-04:00"));
|
||||
// Exact same - Dates
|
||||
assertTrue(compareDateTimes("2001", "2001"));
|
||||
assertTrue(compareDateTimes("2001-01", "2001-01"));
|
||||
assertTrue(compareDateTimes("2001-01-02", "2001-01-02"));
|
||||
assertTrue( compareDateTimes("2001", "2001"));
|
||||
assertTrue( compareDateTimes("2001-01", "2001-01"));
|
||||
assertTrue( compareDateTimes("2001-01-02", "2001-01-02"));
|
||||
// Same precision but different values - Dates
|
||||
assertFalse(compareDateTimes("2001", "2002"));
|
||||
assertFalse(compareDateTimes("2001-01", "2001-02"));
|
||||
|
@ -34,12 +50,12 @@ public class BaseDateTimeTypeTest {
|
|||
assertFalse(compareDateTimes("2001-01-02T11:22:33.445Z", "2001-01-02T11:22:33.444Z"));
|
||||
|
||||
// FHIRPath tests:
|
||||
assertFalse(compareDateTimes("1974-12-25", "1974-12-25T12:34:00+10:00"));
|
||||
assertFalse(compareDateTimes("1974-12-25T12:34:00+10:00", "1974-12-25"));
|
||||
assertNull( compareDateTimes("1974-12-25", "1974-12-25T12:34:00+10:00"));
|
||||
assertNull( compareDateTimes("1974-12-25T12:34:00+10:00", "1974-12-25"));
|
||||
assertFalse(compareDateTimes("1974-12-25", "1974-12-25T12:34:00-10:00"));
|
||||
assertFalse(compareDateTimes("1974-12-25T12:34:00-10:00", "1974-12-25"));
|
||||
assertFalse(compareDateTimes("1974-12-25", "1974-12-25T12:34:00Z"));
|
||||
assertFalse(compareDateTimes("1974-12-25T12:34:00Z", "1974-12-25"));
|
||||
assertNull( compareDateTimes("1974-12-25", "1974-12-25T12:34:00Z"));
|
||||
assertNull( compareDateTimes("1974-12-25T12:34:00Z", "1974-12-25"));
|
||||
assertFalse(compareDateTimes("2012-04-15", "2012-04-16"));
|
||||
assertFalse(compareDateTimes("2012-04-16", "2012-04-15"));
|
||||
assertFalse(compareDateTimes("2012-04-15T15:00:00", "2012-04-15T10:00:00"));
|
||||
|
@ -49,8 +65,8 @@ public class BaseDateTimeTypeTest {
|
|||
assertNull(compareDateTimes("1974-12-25", "1974-12-25T12:34:00"));
|
||||
assertNull(compareDateTimes("1974-12-25T12:34:00", "1974-12-25"));
|
||||
assertNull(compareDateTimes("2012-04-15T10:00:00", "2012-04-15"));
|
||||
assertNull(compareDateTimes("2012-04-15T15:00:00Z", "2012-04-15T10:00:00"));
|
||||
assertNull(compareDateTimes("2012-04-15T10:00:00", "2012-04-15T15:00:00Z"));
|
||||
assertFalse(compareDateTimes("2012-04-15T15:00:00Z", "2012-04-15T10:00:00"));
|
||||
assertFalse(compareDateTimes("2012-04-15T10:00:00", "2012-04-15T15:00:00Z"));
|
||||
assertTrue(compareDateTimes("1974-12-25", "1974-12-25"));
|
||||
assertTrue(compareDateTimes("2012-04-15", "2012-04-15"));
|
||||
assertTrue(compareDateTimes("2012-04-15T15:00:00+02:00", "2012-04-15T16:00:00+03:00"));
|
||||
|
@ -59,7 +75,7 @@ public class BaseDateTimeTypeTest {
|
|||
assertTrue(compareDateTimes("2017-11-05T00:30:00.0-05:00", "2017-11-05T01:30:00.0-04:00"));
|
||||
|
||||
assertFalse(compareDateTimes("2016-12-02T13:00:00Z", "2016-11-02T10:00:00")); // no timezone, but cannot be the same time
|
||||
assertNull(compareDateTimes("2016-12-02T13:00:00Z", "2016-12-02T10:00:00")); // no timezone, might be the same time
|
||||
assertFalse(compareDateTimes("2016-12-02T13:00:00Z", "2016-12-02T10:00:00")); // no timezone, might be the same time
|
||||
}
|
||||
|
||||
private Boolean compareDateTimes(String theLeft, String theRight) {
|
||||
|
|
Loading…
Reference in New Issue