diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/BaseDateTimeDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/BaseDateTimeDt.java index 4e099e94d62..97e5e23cd9b 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/BaseDateTimeDt.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/primitive/BaseDateTimeDt.java @@ -1,7 +1,6 @@ package ca.uhn.fhir.model.primitive; import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.apache.commons.lang3.StringUtils.length; import java.util.Calendar; import java.util.Date; @@ -21,7 +20,7 @@ public abstract class BaseDateTimeDt extends BasePrimitive { private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM); private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM); - private int myFractionalSeconds; + private String myFractionalSeconds; private TemporalPrecisionEnum myPrecision = TemporalPrecisionEnum.SECOND; private TimeZone myTimeZone; @@ -106,7 +105,10 @@ public abstract class BaseDateTimeDt extends BasePrimitive { leftPadWithZeros(cal.get(Calendar.SECOND), 2, b); if (myPrecision.ordinal() > TemporalPrecisionEnum.SECOND.ordinal()) { b.append('.'); - leftPadWithZeros(myFractionalSeconds, 3, b); + for (int i = myFractionalSeconds.length(); i < 3; i++) { + b.append('0'); + } + b.append(myFractionalSeconds); } } @@ -149,8 +151,7 @@ public abstract class BaseDateTimeDt extends BasePrimitive { return -1; } if ((retVal - 2) != (plusIndex + minusIndex + zIndex)) { - // This means we have more than one separator - throw new DataFormatException("Invalid FHIR date/time string: " + theValueString); + throwBadDateFormat(theValueString); } return retVal; } @@ -178,24 +179,6 @@ public abstract class BaseDateTimeDt extends BasePrimitive { return myTimeZone; } - private boolean hasOffset(String theValue) { - boolean inTime = false; - for (int i = 0; i < theValue.length(); i++) { - switch (theValue.charAt(i)) { - case 'T': - inTime = true; - break; - case '+': - case '-': - if (inTime) { - return true; - } - break; - } - } - return false; - } - /** * To be implemented by subclasses to indicate whether the given precision is allowed by this type */ @@ -223,7 +206,7 @@ public abstract class BaseDateTimeDt extends BasePrimitive { } theTarget.append(string); } - + @Override protected Date parse(String theValue) throws DataFormatException { Calendar cal = new GregorianCalendar(0, 0, 0); @@ -293,15 +276,21 @@ public abstract class BaseDateTimeDt extends BasePrimitive { endIndex = value.length(); } int millis; + String millisString; if (endIndex > 23) { - myFractionalSeconds = parseInt(value, value.substring(20, endIndex), 0, Integer.MAX_VALUE); + myFractionalSeconds = value.substring(20, endIndex); endIndex = 23; - String millisString = value.substring(20, endIndex); + millisString = value.substring(20, endIndex); millis = parseInt(value, millisString, 0, 999); } else { - String millisString = value.substring(20, endIndex); + millisString = value.substring(20, endIndex); millis = parseInt(value, millisString, 0, 999); - myFractionalSeconds = millis; + myFractionalSeconds = millisString; + } + if (millisString.length() == 1) { + millis = millis * 100; + } else if (millisString.length() == 2) { + millis = millis * 10; } cal.set(Calendar.MILLISECOND, millis); precision = TemporalPrecisionEnum.MILLI; @@ -407,9 +396,9 @@ public abstract class BaseDateTimeDt extends BasePrimitive { setTimeZone(TimeZone.getDefault()); myPrecision = thePrecision; super.setValue(theValue); - myFractionalSeconds = 0; + myFractionalSeconds = ""; if (theValue != null) { - myFractionalSeconds = (int) (theValue.getTime() % 1000); + myFractionalSeconds = Integer.toString((int) (theValue.getTime() % 1000)); } } diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/model/primitive/BaseDateTimeDtDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/model/primitive/BaseDateTimeDtDstu2Test.java index dc65c67f3c5..5581df1c115 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/model/primitive/BaseDateTimeDtDstu2Test.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/model/primitive/BaseDateTimeDtDstu2Test.java @@ -216,6 +216,37 @@ public class BaseDateTimeDtDstu2Test { assertEquals("2015-06-22T19:44:32.831Z", string); } + @Test + public void testParseHandlesMillisPartial() { + // .12 should be 120ms + validateMillisPartial("2015-06-22T00:00:00.1Z", 100); + validateMillisPartial("2015-06-22T00:00:00.12Z", 120); + validateMillisPartial("2015-06-22T00:00:00.123Z", 123); + validateMillisPartial("2015-06-22T00:00:00.1234Z", 123); + validateMillisPartial("2015-06-22T00:00:00.01Z", 10); + validateMillisPartial("2015-06-22T00:00:00.012Z", 12); + validateMillisPartial("2015-06-22T00:00:00.0123Z", 12); + validateMillisPartial("2015-06-22T00:00:00.001Z", 1); + validateMillisPartial("2015-06-22T00:00:00.0012Z", 1); + validateMillisPartial("2015-06-22T00:00:00.00123Z", 1); + } + + private void validateMillisPartial(String input, int expected) { + InstantDt dt = new InstantDt(); + dt.setValueAsString(input); + Date date = dt.getValue(); + + assertEquals(expected, date.getTime() % 1000); + } + + @Test + public void testDateTimeFormatsInvalidMillis() { + verifyFails("1974-12-01T00:00:00.AZ"); + verifyFails("1974-12-01T00:00:00.-Z"); + verifyFails("1974-12-01T00:00:00.-1Z"); + verifyFails("1974-12-01T00:00:00..1111Z"); + } + @Test public void testDateTimeFormatsInvalid() { // Bad timezone