Fix #57: Date/Time types should not throw exceptions for bad precision on setValue(String) but should for constructors

This commit is contained in:
jamesagnew 2014-11-25 09:14:11 +01:00
parent f9e19f759f
commit 383d4929c8
6 changed files with 294 additions and 116 deletions

View File

@ -42,16 +42,11 @@ import ca.uhn.fhir.parser.DataFormatException;
public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
/**
* For unit tests only
*/
static List<FastDateFormat> getFormatters() {
return ourFormatters;
}
/*
* Add any new formatters to the static block below!!
*/
private static final List<FastDateFormat> ourFormatters;
private static final Pattern ourYearDashMonthDashDayPattern = Pattern.compile("[0-9]{4}-[0-9]{2}-[0-9]{2}");
private static final Pattern ourYearDashMonthPattern = Pattern.compile("[0-9]{4}-[0-9]{2}");
private static final FastDateFormat ourYearFormat = FastDateFormat.getInstance("yyyy");
@ -67,8 +62,8 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
private static final FastDateFormat ourYearMonthFormat = FastDateFormat.getInstance("yyyy-MM");
private static final FastDateFormat ourYearMonthNoDashesFormat = FastDateFormat.getInstance("yyyyMM");
private static final Pattern ourYearMonthPattern = Pattern.compile("[0-9]{4}[0-9]{2}");
private static final Pattern ourYearPattern = Pattern.compile("[0-9]{4}");
static {
ArrayList<FastDateFormat> formatters = new ArrayList<FastDateFormat>();
formatters.add(ourYearFormat);
@ -86,9 +81,51 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
}
private TemporalPrecisionEnum myPrecision = TemporalPrecisionEnum.SECOND;
private TimeZone myTimeZone;
private TimeZone myTimeZone;
private boolean myTimeZoneZulu = false;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseDateTimeDt.class);
/**
* Constructor
*/
public BaseDateTimeDt() {
// nothing
}
/**
* Constructor
*
* @throws DataFormatException
* If the specified precision is not allowed for this type
*/
public BaseDateTimeDt(Date theDate, TemporalPrecisionEnum thePrecision) {
setValue(theDate, thePrecision);
if (isPrecisionAllowed(thePrecision) == false) {
throw new DataFormatException("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support " + thePrecision + " precision): " + theDate);
}
}
/**
* Constructor
*
* @throws DataFormatException
* If the specified precision is not allowed for this type
*/
public BaseDateTimeDt(String theString) {
setValueAsString(theString);
if (isPrecisionAllowed(getPrecision()) == false) {
throw new DataFormatException("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support " + getPrecision() + " precision): " + theString);
}
}
/**
* Constructor
*/
public BaseDateTimeDt(Date theDate, TemporalPrecisionEnum thePrecision, TimeZone theTimeZone) {
this(theDate, thePrecision);
setTimeZone(theTimeZone);
}
private void clearTimeZone() {
myTimeZone = null;
@ -136,6 +173,10 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
}
}
/**
* Returns the default precision for the given datatype
*/
protected abstract TemporalPrecisionEnum getDefaultPrecisionForDatatype();
/**
* Gets the precision for this datatype (using the default for the given type if not set)
@ -150,13 +191,8 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
}
/**
* Returns the default precision for the given datatype
*/
protected abstract TemporalPrecisionEnum getDefaultPrecisionForDatatype();
/**
* Returns the TimeZone associated with this dateTime's value. May return
* <code>null</code> if no timezone was supplied.
* Returns the TimeZone associated with this dateTime's value. May return <code>null</code> if no timezone was
* supplied.
*/
public TimeZone getTimeZone() {
return myTimeZone;
@ -204,57 +240,52 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
protected Date parse(String theValue) throws DataFormatException {
try {
if (theValue.length() == 4 && ourYearPattern.matcher(theValue).matches()) {
if (isPrecisionAllowed(YEAR)) {
setPrecision(YEAR);
clearTimeZone();
return ((ourYearFormat).parse(theValue));
} else {
throw new DataFormatException("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support YEAR precision): " + theValue);
if (!isPrecisionAllowed(YEAR)) {
ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support YEAR precision): " + theValue);
}
setPrecision(YEAR);
clearTimeZone();
return ((ourYearFormat).parse(theValue));
} else if (theValue.length() == 6 && ourYearMonthPattern.matcher(theValue).matches()) {
// Eg. 198401 (allow this just to be lenient)
if (isPrecisionAllowed(MONTH)) {
setPrecision(MONTH);
clearTimeZone();
return ((ourYearMonthNoDashesFormat).parse(theValue));
} else {
throw new DataFormatException("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support DAY precision): " + theValue);
if (!isPrecisionAllowed(MONTH)) {
ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support DAY precision): " + theValue);
}
setPrecision(MONTH);
clearTimeZone();
return ((ourYearMonthNoDashesFormat).parse(theValue));
} else if (theValue.length() == 7 && ourYearDashMonthPattern.matcher(theValue).matches()) {
// E.g. 1984-01 (this is valid according to the spec)
if (isPrecisionAllowed(MONTH)) {
setPrecision(MONTH);
clearTimeZone();
return ((ourYearMonthFormat).parse(theValue));
} else {
throw new DataFormatException("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support MONTH precision): " + theValue);
if (!isPrecisionAllowed(MONTH)) {
ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support MONTH precision): " + theValue);
}
setPrecision(MONTH);
clearTimeZone();
return ((ourYearMonthFormat).parse(theValue));
} else if (theValue.length() == 8 && ourYearMonthDayPattern.matcher(theValue).matches()) {
// Eg. 19840101 (allow this just to be lenient)
if (isPrecisionAllowed(DAY)) {
setPrecision(DAY);
clearTimeZone();
return ((ourYearMonthDayNoDashesFormat).parse(theValue));
} else {
throw new DataFormatException("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support DAY precision): " + theValue);
if (!isPrecisionAllowed(DAY)) {
ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support DAY precision): " + theValue);
}
setPrecision(DAY);
clearTimeZone();
return ((ourYearMonthDayNoDashesFormat).parse(theValue));
} else if (theValue.length() == 10 && ourYearDashMonthDashDayPattern.matcher(theValue).matches()) {
// E.g. 1984-01-01 (this is valid according to the spec)
if (isPrecisionAllowed(DAY)) {
setPrecision(DAY);
clearTimeZone();
return ((ourYearMonthDayFormat).parse(theValue));
} else {
throw new DataFormatException("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support DAY precision): " + theValue);
if (!isPrecisionAllowed(DAY)) {
ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support DAY precision): " + theValue);
}
setPrecision(DAY);
clearTimeZone();
return ((ourYearMonthDayFormat).parse(theValue));
} else if (theValue.length() >= 18) { // date and time with possible time zone
int dotIndex = theValue.indexOf('.', 18);
boolean hasMillis = dotIndex > -1;
if (!hasMillis && !isPrecisionAllowed(SECOND)) {
throw new DataFormatException("Invalid date/time string (data type does not support SECONDS precision): " + theValue);
ourLog.debug("Invalid date/time string (data type does not support SECONDS precision): " + theValue);
} else if (hasMillis && !isPrecisionAllowed(MILLI)) {
throw new DataFormatException("Invalid date/time string (data type " + getClass().getSimpleName() + " does not support MILLIS precision):" + theValue);
ourLog.debug("Invalid date/time string (data type " + getClass().getSimpleName() + " does not support MILLIS precision):" + theValue);
}
Date retVal;
@ -262,10 +293,11 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
try {
if (hasOffset(theValue)) {
retVal = ourYearMonthDayTimeMilliZoneFormat.parse(theValue);
} else if (theValue.endsWith("Z"))
} else if (theValue.endsWith("Z")) {
retVal = ourYearMonthDayTimeMilliUTCZFormat.parse(theValue);
else
} else {
retVal = ourYearMonthDayTimeMilliFormat.parse(theValue);
}
} catch (ParseException p2) {
throw new DataFormatException("Invalid data/time string (" + p2.getMessage() + "): " + theValue);
}
@ -316,8 +348,6 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
updateStringValue();
}
private void setTimeZone(String theValueString, boolean hasMillis) {
clearTimeZone();
int timeZoneStart = 19;
@ -332,13 +362,11 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
}
}
public void setTimeZone(TimeZone theTimeZone) {
myTimeZone = theTimeZone;
updateStringValue();
}
public void setTimeZoneZulu(boolean theTimeZoneZulu) {
myTimeZoneZulu = theTimeZoneZulu;
updateStringValue();
@ -353,9 +381,11 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
/**
* Sets the value of this date/time using the specified level of precision
*
* @param theValue The date value
* @param thePrecision The precision
* @throws DataFormatException
* @param theValue
* The date value
* @param thePrecision
* The precision
* @throws DataFormatException
*/
public void setValue(Date theValue, TemporalPrecisionEnum thePrecision) throws DataFormatException {
clearTimeZone();
@ -369,4 +399,11 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
super.setValueAsString(theValue);
}
/**
* For unit tests only
*/
static List<FastDateFormat> getFormatters() {
return ourFormatters;
}
}

View File

@ -25,7 +25,16 @@ import java.util.Date;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.api.annotation.SimpleSetter;
import ca.uhn.fhir.parser.DataFormatException;
/**
* Represents a FHIR date datatype. Valid precisions values for this type are:
* <ul>
* <li>{@link TemporalPrecisionEnum#YEAR}
* <li>{@link TemporalPrecisionEnum#MONTH}
* <li>{@link TemporalPrecisionEnum#DAY}
* </ul>
*/
@DatatypeDef(name = "date")
public class DateDt extends BaseDateTimeDt {
@ -44,10 +53,9 @@ public class DateDt extends BaseDateTimeDt {
/**
* Constructor which accepts a date value and uses the {@link #DEFAULT_PRECISION} for this type
*/
@SimpleSetter(suffix="WithDayPrecision")
@SimpleSetter(suffix = "WithDayPrecision")
public DateDt(@SimpleSetter.Parameter(name = "theDate") Date theDate) {
setValue(theDate);
setPrecision(DEFAULT_PRECISION);
super(theDate, DEFAULT_PRECISION);
}
/**
@ -57,11 +65,23 @@ public class DateDt extends BaseDateTimeDt {
* <li>{@link TemporalPrecisionEnum#MONTH}
* <li>{@link TemporalPrecisionEnum#DAY}
* </ul>
*
* @throws DataFormatException
* If the specified precision is not allowed for this type
*/
@SimpleSetter
public DateDt(@SimpleSetter.Parameter(name = "theDate") Date theDate, @SimpleSetter.Parameter(name = "thePrecision") TemporalPrecisionEnum thePrecision) {
setValue(theDate);
setPrecision(thePrecision);
super(theDate, thePrecision);
}
/**
* Constructor which accepts a date as a string in FHIR format
*
* @throws DataFormatException
* If the precision in the date string is not allowed for this type
*/
public DateDt(String theDate) {
super(theDate);
}
@Override

View File

@ -26,7 +26,18 @@ import java.util.TimeZone;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.api.annotation.SimpleSetter;
import ca.uhn.fhir.parser.DataFormatException;
/**
* Represents a FHIR dateTime datatype. Valid precisions values for this type are:
* <ul>
* <li>{@link TemporalPrecisionEnum#YEAR}
* <li>{@link TemporalPrecisionEnum#MONTH}
* <li>{@link TemporalPrecisionEnum#DAY}
* <li>{@link TemporalPrecisionEnum#SECOND}
* <li>{@link TemporalPrecisionEnum#MILLI}
* </ul>
*/
@DatatypeDef(name = "dateTime")
public class DateTimeDt extends BaseDateTimeDt {
@ -43,18 +54,44 @@ public class DateTimeDt extends BaseDateTimeDt {
}
/**
* Create a new DateTimeDt
* Create a new DateTimeDt with seconds precision and the local time zone
*/
@SimpleSetter(suffix = "WithSecondsPrecision")
public DateTimeDt(@SimpleSetter.Parameter(name = "theDate") Date theDate) {
setValue(theDate);
setPrecision(DEFAULT_PRECISION);
setTimeZone(TimeZone.getDefault());
super(theDate, DEFAULT_PRECISION, TimeZone.getDefault());
}
/**
* Constructor which accepts a date value and a precision value. Valid
* precisions values for this type are:
* Constructor which accepts a date value and a precision value. Valid precisions values for this type are:
* <ul>
* <li>{@link TemporalPrecisionEnum#YEAR}
* <li>{@link TemporalPrecisionEnum#MONTH}
* <li>{@link TemporalPrecisionEnum#DAY}
* <li>{@link TemporalPrecisionEnum#SECOND}
* <li>{@link TemporalPrecisionEnum#MILLI}
* </ul>
*
* @throws DataFormatException
* If the specified precision is not allowed for this type
*/
@SimpleSetter
public DateTimeDt(@SimpleSetter.Parameter(name = "theDate") Date theDate, @SimpleSetter.Parameter(name = "thePrecision") TemporalPrecisionEnum thePrecision) {
super(theDate, thePrecision, TimeZone.getDefault());
}
/**
* Create a new instance using a string date/time
*
* @throws DataFormatException
* If the specified precision is not allowed for this type
*/
public DateTimeDt(String theValue) {
super(theValue);
}
/**
* Constructor which accepts a date value, precision value, and time zone. Valid precisions values for this type
* are:
* <ul>
* <li>{@link TemporalPrecisionEnum#YEAR}
* <li>{@link TemporalPrecisionEnum#MONTH}
@ -63,18 +100,8 @@ public class DateTimeDt extends BaseDateTimeDt {
* <li>{@link TemporalPrecisionEnum#MILLI}
* </ul>
*/
@SimpleSetter
public DateTimeDt(@SimpleSetter.Parameter(name = "theDate") Date theDate, @SimpleSetter.Parameter(name = "thePrecision") TemporalPrecisionEnum thePrecision) {
setValue(theDate);
setPrecision(thePrecision);
setTimeZone(TimeZone.getDefault());
}
/**
* Create a new instance using a string date/time
*/
public DateTimeDt(String theValue) {
setValueAsString(theValue);
public DateTimeDt(Date theDate, TemporalPrecisionEnum thePrecision, TimeZone theTimezone) {
super(theDate, thePrecision, theTimezone);
}
@Override
@ -92,10 +119,11 @@ public class DateTimeDt extends BaseDateTimeDt {
}
/**
* Returns a new instance of DateTimeDt with the current system time and SECOND precision
* Returns a new instance of DateTimeDt with the current system time and SECOND precision and the system local time
* zone
*/
public static DateTimeDt withCurrentTime() {
return new DateTimeDt(new Date(), TemporalPrecisionEnum.SECOND);
return new DateTimeDt(new Date(), TemporalPrecisionEnum.SECOND, TimeZone.getDefault());
}
/**
@ -108,5 +136,4 @@ public class DateTimeDt extends BaseDateTimeDt {
return DEFAULT_PRECISION;
}
}

View File

@ -29,6 +29,13 @@ import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.api.annotation.SimpleSetter;
import ca.uhn.fhir.parser.DataFormatException;
/**
* Represents a FHIR instant datatype. Valid precisions values for this type are:
* <ul>
* <li>{@link TemporalPrecisionEnum#SECOND}
* <li>{@link TemporalPrecisionEnum#MILLI}
* </ul>
*/
@DatatypeDef(name = "instant")
public class InstantDt extends BaseDateTimeDt {
@ -54,31 +61,39 @@ public class InstantDt extends BaseDateTimeDt {
* Create a new DateTimeDt
*/
public InstantDt(Calendar theCalendar) {
setValue(theCalendar.getTime());
setPrecision(DEFAULT_PRECISION);
setTimeZone(theCalendar.getTimeZone());
super(theCalendar.getTime(), DEFAULT_PRECISION, theCalendar.getTimeZone());
}
/**
* Create a new instance using the given date, precision level, and time zone
*
* @throws DataFormatException
* If the specified precision is not allowed for this type
*/
public InstantDt(Date theDate, TemporalPrecisionEnum thePrecision, TimeZone theTimezone) {
super(theDate, thePrecision, theTimezone);
}
/**
* Create a new DateTimeDt using an existing value. <b>Use this constructor with caution</b>,
* as it may create more precision than warranted (since for example it is possible to pass in
* a DateTime with only a year, and this constructor will convert to an InstantDt with
* milliseconds precision).
* milliseconds precision).
*/
public InstantDt(BaseDateTimeDt theDateTime) {
// Do not call super(foo) here, we don't want to trigger a DataFormatException
setValue(theDateTime.getValue());
setPrecision(DEFAULT_PRECISION);
setTimeZone(theDateTime.getTimeZone());
}
/**
* Create a new DateTimeDt
* Create a new DateTimeDt with the given date/time and {@link TemporalPrecisionEnum#MILLI} precision
*/
@SimpleSetter(suffix = "WithMillisPrecision")
public InstantDt(@SimpleSetter.Parameter(name = "theDate") Date theDate) {
setValue(theDate);
setPrecision(DEFAULT_PRECISION);
setTimeZone(TimeZone.getDefault());
super(theDate, DEFAULT_PRECISION, TimeZone.getDefault());
}
/**
@ -105,7 +120,7 @@ public class InstantDt extends BaseDateTimeDt {
* @throws DataFormatException
*/
public InstantDt(String theString) {
setValueAsString(theString);
super(theString);
}
/**
@ -154,10 +169,10 @@ public class InstantDt extends BaseDateTimeDt {
/**
* Factory method which creates a new InstantDt with millisecond precision and initializes it with the
* current time.
* current time and the system local timezone.
*/
public static InstantDt withCurrentTime() {
return new InstantDt(new Date(), TemporalPrecisionEnum.MILLI);
return new InstantDt(new Date(), TemporalPrecisionEnum.MILLI, TimeZone.getDefault());
}
/**

View File

@ -1,58 +1,128 @@
package ca.uhn.fhir.model.primitive;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.parser.DataFormatException;
import org.apache.commons.lang3.time.FastDateFormat;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import org.apache.commons.lang3.time.FastDateFormat;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.dstu.resource.Condition;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.validation.ValidationResult;
public class BaseDateTimeDtTest {
private SimpleDateFormat myDateInstantParser;
private FastDateFormat myDateInstantZoneParser;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseDateTimeDtTest.class);
private static FhirContext ourCtx = new FhirContext();
@Before
public void before() {
myDateInstantParser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
myDateInstantZoneParser = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSSZ", TimeZone.getTimeZone("GMT-02:00"));
}
@Test
public void setTimezoneToZulu() {
DateTimeDt dt = new DateTimeDt(new Date(816411488000L));
// assertEquals("1995-11-14T23:58:08", dt.getValueAsString());
// assertEquals("1995-11-14T23:58:08", dt.getValueAsString());
dt.setTimeZoneZulu(true);
assertEquals("1995-11-15T04:58:08Z", dt.getValueAsString());
}
@Test
public void testDateTimeInLocalTimezone() {
DateTimeDt dt = DateTimeDt.withCurrentTime();
String str = dt.getValueAsString();
char offset = str.charAt(19);
if (offset != '+' && offset != '-') {
fail("No timezone provided: " + str);
}
}
@Test
public void testInstantInLocalTimezone() {
InstantDt dt = InstantDt.withCurrentTime();
String str = dt.getValueAsString();
char offset = str.charAt(23);
if (offset != '+' && offset != '-') {
fail("No timezone provided: " + str);
}
}
/**
* Test for #57
*/
@Test
public void testDateParsesWithInvalidPrecision() {
Condition c = new Condition();
c.setDateAsserted(new DateDt());
c.getDateAsserted().setValueAsString("2001-01-02T11:13:33");
assertEquals(TemporalPrecisionEnum.SECOND, c.getDateAsserted().getPrecision());
String encoded = ourCtx.newXmlParser().encodeResourceToString(c);
Assert.assertThat(encoded, Matchers.containsString("value=\"2001-01-02T11:13:33\""));
c = ourCtx.newXmlParser().parseResource(Condition.class, encoded);
assertEquals("2001-01-02T11:13:33", c.getDateAsserted().getValueAsString());
assertEquals(TemporalPrecisionEnum.SECOND, c.getDateAsserted().getPrecision());
ValidationResult outcome = ourCtx.newValidator().validateWithResult(c);
String outcomeStr = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getOperationOutcome());
ourLog.info(outcomeStr);
assertThat(outcomeStr, containsString("date-primitive"));
}
/**
* Test for #57
*/
@Test
public void testConstructorRejectsInvalidPrecision() {
try {
new DateDt("2001-01-02T11:13:33");
fail();
} catch (DataFormatException e) {
assertThat(e.getMessage(), containsString("precision"));
}
try {
new InstantDt("2001-01-02");
fail();
} catch (DataFormatException e) {
assertThat(e.getMessage(), containsString("precision"));
}
}
@Test
public void testFormats() throws Exception {
Date instant = myDateInstantParser.parse("2001-02-03 13:01:02.555");
for (FastDateFormat next : BaseDateTimeDt.getFormatters()) {
Calendar cal = Calendar.getInstance();
cal.setTime(instant);
String value = next.format(cal);
ourLog.info("String: {}", value);
DateTimeDt dt = new DateTimeDt(value);
String reEncoded = next.format(dt.getValue());
assertEquals(value, reEncoded);
}
}
@Test
public void testParseDay() throws DataFormatException {
DateTimeDt dt = new DateTimeDt();
@ -64,8 +134,7 @@ public class BaseDateTimeDtTest {
assertNull(dt.getTimeZone());
assertEquals(TemporalPrecisionEnum.DAY, dt.getPrecision());
}
@Test()
public void testParseMalformatted() throws DataFormatException {
DateTimeDt dt = new DateTimeDt("20120102");
@ -83,8 +152,8 @@ public class BaseDateTimeDtTest {
assertEquals(false, dt.isTimeZoneZulu());
assertNull(dt.getTimeZone());
assertEquals(TemporalPrecisionEnum.MILLI, dt.getPrecision());
}
}
@Test
public void testParseMilliZone() throws DataFormatException {
InstantDt dt = new InstantDt();
@ -183,11 +252,12 @@ public class BaseDateTimeDtTest {
public void testSetValueByString() {
InstantDt i = new InstantDt();
i.setValueAsString("2014-06-20T20:22:09Z");
assertNotNull(i.getValue());
assertNotNull(i.getValueAsString());
assertEquals(1403295729000L, i.getValue().getTime());
assertEquals("2014-06-20T20:22:09Z",i.getValueAsString());
assertEquals("2014-06-20T20:22:09Z", i.getValueAsString());
}
}

View File

@ -156,6 +156,15 @@
were applied to other client instances for the same client interface as well. (Issue
did not affect generic/fluent clients)
</action>
<action type="fix" issue="57">
DateDt, DateTimeDt and types InstantDt types now do not throw an exception
if they are used to parse a value with the wrong level of precision for
the given type but do throw an exception if the wrong level of precision
is passed into their constructors.<![CDATA[<br/><br/>]]>
This means that HAPI FHIR can now successfully parse resources from external
sources that have the wrong level of precision, but will generate a validation
error if the resource is validated. Thanks to Alexander Kley for the suggestion!
</action>
</release>
<release version="0.7" date="2014-Oct-23">
<action type="add" issue="30">