invalid values
This commit is contained in:
parent
e1cfc8212e
commit
7588a2ecff
|
@ -84,9 +84,7 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
||||||
*/
|
*/
|
||||||
public BaseDateTimeDt(String theString) {
|
public BaseDateTimeDt(String theString) {
|
||||||
setValueAsString(theString);
|
setValueAsString(theString);
|
||||||
if (isPrecisionAllowed(getPrecision()) == false) {
|
validatePrecisionAndThrowDataFormatException(theString, getPrecision());
|
||||||
throw new DataFormatException("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support " + getPrecision() + " precision): " + theString);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearTimeZone() {
|
private void clearTimeZone() {
|
||||||
|
@ -158,11 +156,74 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the month with 1-index, e.g. 1=the first day of the month
|
||||||
|
*/
|
||||||
|
public Integer getDay() {
|
||||||
|
return getFieldValue(Calendar.DAY_OF_MONTH);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the default precision for the given datatype
|
* Returns the default precision for the given datatype
|
||||||
*/
|
*/
|
||||||
protected abstract TemporalPrecisionEnum getDefaultPrecisionForDatatype();
|
protected abstract TemporalPrecisionEnum getDefaultPrecisionForDatatype();
|
||||||
|
|
||||||
|
private Integer getFieldValue(int theField) {
|
||||||
|
if (getValue() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Calendar cal = getValueAsCalendar();
|
||||||
|
return cal.get(theField);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hour of the day in a 24h clock, e.g. 13=1pm
|
||||||
|
*/
|
||||||
|
public Integer getHour() {
|
||||||
|
return getFieldValue(Calendar.HOUR_OF_DAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the milliseconds within the current second.
|
||||||
|
* <p>
|
||||||
|
* Note that this method returns the
|
||||||
|
* same value as {@link #getNanos()} but with less precision.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public Integer getMillis() {
|
||||||
|
return getFieldValue(Calendar.MILLISECOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the minute of the hour in the range 0-59
|
||||||
|
*/
|
||||||
|
public Integer getMinute() {
|
||||||
|
return getFieldValue(Calendar.MINUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the month with 0-index, e.g. 0=January
|
||||||
|
*/
|
||||||
|
public Integer getMonth() {
|
||||||
|
return getFieldValue(Calendar.MONTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the nanoseconds within the current second
|
||||||
|
* <p>
|
||||||
|
* Note that this method returns the
|
||||||
|
* same value as {@link #getMillis()} but with more precision.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public Long getNanos() {
|
||||||
|
if (isBlank(myFractionalSeconds)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String retVal = StringUtils.rightPad(myFractionalSeconds, 9, '0');
|
||||||
|
retVal = retVal.substring(0, 9);
|
||||||
|
return Long.parseLong(retVal);
|
||||||
|
}
|
||||||
|
|
||||||
private int getOffsetIndex(String theValueString) {
|
private int getOffsetIndex(String theValueString) {
|
||||||
int plusIndex = theValueString.indexOf('+', 16);
|
int plusIndex = theValueString.indexOf('+', 16);
|
||||||
int minusIndex = theValueString.indexOf('-', 16);
|
int minusIndex = theValueString.indexOf('-', 16);
|
||||||
|
@ -189,6 +250,13 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
||||||
return myPrecision;
|
return myPrecision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the second of the minute in the range 0-59
|
||||||
|
*/
|
||||||
|
public Integer getSecond() {
|
||||||
|
return getFieldValue(Calendar.SECOND);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the TimeZone associated with this dateTime's value. May return <code>null</code> if no timezone was
|
* Returns the TimeZone associated with this dateTime's value. May return <code>null</code> if no timezone was
|
||||||
* supplied.
|
* supplied.
|
||||||
|
@ -217,10 +285,17 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
||||||
return cal;
|
return cal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the year, e.g. 2015
|
||||||
|
*/
|
||||||
|
public Integer getYear() {
|
||||||
|
return getFieldValue(Calendar.YEAR);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To be implemented by subclasses to indicate whether the given precision is allowed by this type
|
* To be implemented by subclasses to indicate whether the given precision is allowed by this type
|
||||||
*/
|
*/
|
||||||
abstract boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision);
|
protected abstract boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the timezone is set to GMT-0:00 (Z)
|
* Returns true if the timezone is set to GMT-0:00 (Z)
|
||||||
|
@ -352,6 +427,10 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
||||||
myFractionalSeconds = "";
|
myFractionalSeconds = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (precision == TemporalPrecisionEnum.MINUTE) {
|
||||||
|
validatePrecisionAndThrowDataFormatException(value, precision);
|
||||||
|
}
|
||||||
|
|
||||||
setPrecision(precision);
|
setPrecision(precision);
|
||||||
return cal.getTime();
|
return cal.getTime();
|
||||||
|
|
||||||
|
@ -372,6 +451,92 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the month with 1-index, e.g. 1=the first day of the month
|
||||||
|
*/
|
||||||
|
public BaseDateTimeDt setDay(int theDay) {
|
||||||
|
setFieldValue(Calendar.DAY_OF_MONTH, theDay, null, 0, 31);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setFieldValue(int theField, int theValue, String theFractionalSeconds, int theMinimum, int theMaximum) {
|
||||||
|
validateValueInRange(theValue, theMinimum, theMaximum);
|
||||||
|
Calendar cal;
|
||||||
|
if (getValue() == null) {
|
||||||
|
cal = new GregorianCalendar(0, 0, 0);
|
||||||
|
} else {
|
||||||
|
cal = getValueAsCalendar();
|
||||||
|
}
|
||||||
|
if (theField != -1) {
|
||||||
|
cal.set(theField, theValue);
|
||||||
|
}
|
||||||
|
if (theFractionalSeconds != null) {
|
||||||
|
myFractionalSeconds = theFractionalSeconds;
|
||||||
|
} else if (theField == Calendar.MILLISECOND) {
|
||||||
|
myFractionalSeconds = StringUtils.leftPad(Integer.toString(theValue), 3, '0');
|
||||||
|
}
|
||||||
|
super.setValue(cal.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the hour of the day in a 24h clock, e.g. 13=1pm
|
||||||
|
*/
|
||||||
|
public BaseDateTimeDt setHour(int theHour) {
|
||||||
|
setFieldValue(Calendar.HOUR_OF_DAY, theHour, null, 0, 23);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the milliseconds within the current second.
|
||||||
|
* <p>
|
||||||
|
* Note that this method sets the
|
||||||
|
* same value as {@link #setNanos(long)} but with less precision.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public BaseDateTimeDt setMillis(int theMillis) {
|
||||||
|
setFieldValue(Calendar.MILLISECOND, theMillis, null, 0, 999);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the minute of the hour in the range 0-59
|
||||||
|
*/
|
||||||
|
public BaseDateTimeDt setMinute(int theMinute) {
|
||||||
|
setFieldValue(Calendar.MINUTE, theMinute, null, 0, 59);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the month with 0-index, e.g. 0=January
|
||||||
|
*/
|
||||||
|
public BaseDateTimeDt setMonth(int theMonth) {
|
||||||
|
setFieldValue(Calendar.MONTH, theMonth, null, 0, 11);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the nanoseconds within the current second
|
||||||
|
* <p>
|
||||||
|
* Note that this method sets the
|
||||||
|
* same value as {@link #setMillis(int)} but with more precision.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public BaseDateTimeDt setNanos(long theNanos) {
|
||||||
|
validateValueInRange(theNanos, 0, NANOS_PER_SECOND-1);
|
||||||
|
String fractionalSeconds = StringUtils.leftPad(Long.toString(theNanos), 9, '0');
|
||||||
|
|
||||||
|
// Strip trailing 0s
|
||||||
|
for (int i = fractionalSeconds.length(); i > 0; i--) {
|
||||||
|
if (fractionalSeconds.charAt(i-1) != '0') {
|
||||||
|
fractionalSeconds = fractionalSeconds.substring(0, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int millis = (int)(theNanos / NANOS_PER_MILLIS);
|
||||||
|
setFieldValue(Calendar.MILLISECOND, millis, fractionalSeconds, 0, 999);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the precision for this datatype
|
* Sets the precision for this datatype
|
||||||
*
|
*
|
||||||
|
@ -386,6 +551,14 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the second of the minute in the range 0-59
|
||||||
|
*/
|
||||||
|
public BaseDateTimeDt setSecond(int theSecond) {
|
||||||
|
setFieldValue(Calendar.SECOND, theSecond, null, 0, 59);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
private BaseDateTimeDt setTimeZone(String theWholeValue, String theValue) {
|
private BaseDateTimeDt setTimeZone(String theWholeValue, String theValue) {
|
||||||
|
|
||||||
if (isBlank(theValue)) {
|
if (isBlank(theValue)) {
|
||||||
|
@ -465,6 +638,14 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
||||||
super.setValueAsString(theValue);
|
super.setValueAsString(theValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the year, e.g. 2015
|
||||||
|
*/
|
||||||
|
public BaseDateTimeDt setYear(int theYear) {
|
||||||
|
setFieldValue(Calendar.YEAR, theYear, null, 0, 9999);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
private void throwBadDateFormat(String theValue) {
|
private void throwBadDateFormat(String theValue) {
|
||||||
throw new DataFormatException("Invalid date/time format: \"" + theValue + "\"");
|
throw new DataFormatException("Invalid date/time format: \"" + theValue + "\"");
|
||||||
}
|
}
|
||||||
|
@ -531,189 +712,16 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the year, e.g. 2015
|
|
||||||
*/
|
|
||||||
public Integer getYear() {
|
|
||||||
return getFieldValue(Calendar.YEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the month with 0-index, e.g. 0=January
|
|
||||||
*/
|
|
||||||
public Integer getMonth() {
|
|
||||||
return getFieldValue(Calendar.MONTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the month with 1-index, e.g. 1=the first day of the month
|
|
||||||
*/
|
|
||||||
public Integer getDay() {
|
|
||||||
return getFieldValue(Calendar.DAY_OF_MONTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the hour of the day in a 24h clock, e.g. 13=1pm
|
|
||||||
*/
|
|
||||||
public Integer getHour() {
|
|
||||||
return getFieldValue(Calendar.HOUR_OF_DAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the minute of the hour in the range 0-59
|
|
||||||
*/
|
|
||||||
public Integer getMinute() {
|
|
||||||
return getFieldValue(Calendar.MINUTE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the second of the minute in the range 0-59
|
|
||||||
*/
|
|
||||||
public Integer getSecond() {
|
|
||||||
return getFieldValue(Calendar.SECOND);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the milliseconds within the current second.
|
|
||||||
* <p>
|
|
||||||
* Note that this method returns the
|
|
||||||
* same value as {@link #getNanos()} but with less precision.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public Integer getMillis() {
|
|
||||||
return getFieldValue(Calendar.MILLISECOND);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the nanoseconds within the current second
|
|
||||||
* <p>
|
|
||||||
* Note that this method returns the
|
|
||||||
* same value as {@link #getMillis()} but with more precision.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public Long getNanos() {
|
|
||||||
if (isBlank(myFractionalSeconds)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String retVal = StringUtils.rightPad(myFractionalSeconds, 9, '0');
|
|
||||||
retVal = retVal.substring(0, 9);
|
|
||||||
return Long.parseLong(retVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the year, e.g. 2015
|
|
||||||
*/
|
|
||||||
public BaseDateTimeDt setYear(int theYear) {
|
|
||||||
setFieldValue(Calendar.YEAR, theYear, null, 0, 9999);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the month with 0-index, e.g. 0=January
|
|
||||||
*/
|
|
||||||
public BaseDateTimeDt setMonth(int theMonth) {
|
|
||||||
setFieldValue(Calendar.MONTH, theMonth, null, 0, 11);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the month with 1-index, e.g. 1=the first day of the month
|
|
||||||
*/
|
|
||||||
public BaseDateTimeDt setDay(int theDay) {
|
|
||||||
setFieldValue(Calendar.DAY_OF_MONTH, theDay, null, 0, 31);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the hour of the day in a 24h clock, e.g. 13=1pm
|
|
||||||
*/
|
|
||||||
public BaseDateTimeDt setHour(int theHour) {
|
|
||||||
setFieldValue(Calendar.HOUR_OF_DAY, theHour, null, 0, 23);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the minute of the hour in the range 0-59
|
|
||||||
*/
|
|
||||||
public BaseDateTimeDt setMinute(int theMinute) {
|
|
||||||
setFieldValue(Calendar.MINUTE, theMinute, null, 0, 59);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the second of the minute in the range 0-59
|
|
||||||
*/
|
|
||||||
public BaseDateTimeDt setSecond(int theSecond) {
|
|
||||||
setFieldValue(Calendar.SECOND, theSecond, null, 0, 59);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the milliseconds within the current second.
|
|
||||||
* <p>
|
|
||||||
* Note that this method sets the
|
|
||||||
* same value as {@link #setNanos(long)} but with less precision.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public BaseDateTimeDt setMillis(int theMillis) {
|
|
||||||
setFieldValue(Calendar.MILLISECOND, theMillis, null, 0, 999);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the nanoseconds within the current second
|
|
||||||
* <p>
|
|
||||||
* Note that this method sets the
|
|
||||||
* same value as {@link #setMillis(int)} but with more precision.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public BaseDateTimeDt setNanos(long theNanos) {
|
|
||||||
validateValueInRange(theNanos, 0, NANOS_PER_SECOND-1);
|
|
||||||
String fractionalSeconds = StringUtils.leftPad(Long.toString(theNanos), 9, '0');
|
|
||||||
|
|
||||||
// Strip trailing 0s
|
|
||||||
for (int i = fractionalSeconds.length(); i > 0; i--) {
|
|
||||||
if (fractionalSeconds.charAt(i-1) != '0') {
|
|
||||||
fractionalSeconds = fractionalSeconds.substring(0, i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int millis = (int)(theNanos / NANOS_PER_MILLIS);
|
|
||||||
setFieldValue(Calendar.MILLISECOND, millis, fractionalSeconds, 0, 999);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setFieldValue(int theField, int theValue, String theFractionalSeconds, int theMinimum, int theMaximum) {
|
|
||||||
validateValueInRange(theValue, theMinimum, theMaximum);
|
|
||||||
Calendar cal;
|
|
||||||
if (getValue() == null) {
|
|
||||||
cal = new GregorianCalendar(0, 0, 0);
|
|
||||||
} else {
|
|
||||||
cal = getValueAsCalendar();
|
|
||||||
}
|
|
||||||
if (theField != -1) {
|
|
||||||
cal.set(theField, theValue);
|
|
||||||
}
|
|
||||||
if (theFractionalSeconds != null) {
|
|
||||||
myFractionalSeconds = theFractionalSeconds;
|
|
||||||
} else if (theField == Calendar.MILLISECOND) {
|
|
||||||
myFractionalSeconds = StringUtils.leftPad(Integer.toString(theValue), 3, '0');
|
|
||||||
}
|
|
||||||
super.setValue(cal.getTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateValueInRange(long theValue, long theMinimum, long theMaximum) {
|
private void validateValueInRange(long theValue, long theMinimum, long theMaximum) {
|
||||||
if (theValue < theMinimum || theValue > theMaximum) {
|
if (theValue < theMinimum || theValue > theMaximum) {
|
||||||
throw new IllegalArgumentException("Value " + theValue + " is not between allowable range: " + theMinimum + " - " + theMaximum);
|
throw new IllegalArgumentException("Value " + theValue + " is not between allowable range: " + theMinimum + " - " + theMaximum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Integer getFieldValue(int theField) {
|
private void validatePrecisionAndThrowDataFormatException(String theValue, TemporalPrecisionEnum thePrecision) {
|
||||||
if (getValue() == null) {
|
if (isPrecisionAllowed(thePrecision) == false) {
|
||||||
return null;
|
throw new DataFormatException("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support " + thePrecision + " precision): " + theValue);
|
||||||
}
|
}
|
||||||
Calendar cal = getValueAsCalendar();
|
|
||||||
return cal.get(theField);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,7 @@ public class DateDt extends BaseDateTimeDt {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
|
protected boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
|
||||||
switch (thePrecision) {
|
switch (thePrecision) {
|
||||||
case YEAR:
|
case YEAR:
|
||||||
case MONTH:
|
case MONTH:
|
||||||
|
|
|
@ -105,7 +105,7 @@ public class DateTimeDt extends BaseDateTimeDt {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
|
protected boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
|
||||||
switch (thePrecision) {
|
switch (thePrecision) {
|
||||||
case YEAR:
|
case YEAR:
|
||||||
case MONTH:
|
case MONTH:
|
||||||
|
|
|
@ -157,7 +157,7 @@ public class InstantDt extends BaseDateTimeDt {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
|
protected boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
|
||||||
switch (thePrecision) {
|
switch (thePrecision) {
|
||||||
case SECOND:
|
case SECOND:
|
||||||
case MILLI:
|
case MILLI:
|
||||||
|
|
|
@ -34,17 +34,18 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
||||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
|
||||||
import ca.uhn.fhir.model.primitive.DateDt;
|
import ca.uhn.fhir.model.primitive.*;
|
||||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
|
||||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
|
||||||
import ca.uhn.fhir.rest.method.QualifiedParamList;
|
import ca.uhn.fhir.rest.method.QualifiedParamList;
|
||||||
|
import ca.uhn.fhir.rest.param.DateParam.DateParamDateTimeHolder;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.util.ValidateUtil;
|
import ca.uhn.fhir.util.ValidateUtil;
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public class DateParam extends BaseParamWithPrefix<DateParam> implements /*IQueryParameterType , */IQueryParameterOr<DateParam> {
|
public class DateParam extends BaseParamWithPrefix<DateParam> implements /*IQueryParameterType , */IQueryParameterOr<DateParam> {
|
||||||
|
|
||||||
private final DateTimeDt myValue = new DateTimeDt();
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final DateParamDateTimeHolder myValue = new DateParamDateTimeHolder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -223,6 +224,11 @@ public class DateParam extends BaseParamWithPrefix<DateParam> implements /*IQuer
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DateParam> getValuesAsQueryTokens() {
|
||||||
|
return Collections.singletonList(this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns <code>true</code> if no date/time is specified. Note that this method does not check the comparator, so a
|
* Returns <code>true</code> if no date/time is specified. Note that this method does not check the comparator, so a
|
||||||
* QualifiedDateParam with only a comparator and no date/time is considered empty.
|
* QualifiedDateParam with only a comparator and no date/time is considered empty.
|
||||||
|
@ -267,6 +273,20 @@ public class DateParam extends BaseParamWithPrefix<DateParam> implements /*IQuer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, QualifiedParamList theParameters) {
|
||||||
|
setMissing(null);
|
||||||
|
setPrefix(null);
|
||||||
|
setValueAsString(null);
|
||||||
|
|
||||||
|
if (theParameters.size() == 1) {
|
||||||
|
setValueAsString(theParameters.get(0));
|
||||||
|
} else if (theParameters.size() > 1) {
|
||||||
|
throw new InvalidRequestException("This server does not support multi-valued dates for this paramater: " + theParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private ParamPrefixEnum toPrefix(QuantityCompararatorEnum theComparator) {
|
private ParamPrefixEnum toPrefix(QuantityCompararatorEnum theComparator) {
|
||||||
if (theComparator != null) {
|
if (theComparator != null) {
|
||||||
return ParamPrefixEnum.forDstu1Value(theComparator.getCode());
|
return ParamPrefixEnum.forDstu1Value(theComparator.getCode());
|
||||||
|
@ -282,23 +302,17 @@ public class DateParam extends BaseParamWithPrefix<DateParam> implements /*IQuer
|
||||||
return b.build();
|
return b.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public class DateParamDateTimeHolder extends BaseDateTimeDt {
|
||||||
public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, QualifiedParamList theParameters) {
|
@Override
|
||||||
setMissing(null);
|
protected TemporalPrecisionEnum getDefaultPrecisionForDatatype() {
|
||||||
setPrefix(null);
|
return TemporalPrecisionEnum.SECOND;
|
||||||
setValueAsString(null);
|
}
|
||||||
|
|
||||||
if (theParameters.size() == 1) {
|
@Override
|
||||||
setValueAsString(theParameters.get(0));
|
protected boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
|
||||||
} else if (theParameters.size() > 1) {
|
return true;
|
||||||
throw new InvalidRequestException("This server does not support multi-valued dates for this paramater: " + theParameters);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<DateParam> getValuesAsQueryTokens() {
|
|
||||||
return Collections.singletonList(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -43,13 +43,13 @@ public class BaseDateTimeDtDstu2Test {
|
||||||
Date from = Date.from(ldt.toInstant(ZoneOffset.UTC));
|
Date from = Date.from(ldt.toInstant(ZoneOffset.UTC));
|
||||||
InstantDt type = (InstantDt) new InstantDt(from).setTimeZoneZulu(true);
|
InstantDt type = (InstantDt) new InstantDt(from).setTimeZoneZulu(true);
|
||||||
String encoded = type.getValueAsString();
|
String encoded = type.getValueAsString();
|
||||||
|
|
||||||
ourLog.info("LDT: " + ldt.toString());
|
ourLog.info("LDT: "+ ldt.toString());
|
||||||
ourLog.info("Expected: " + "1960-09-07T00:44:25.012");
|
ourLog.info("Expected: "+"1960-09-07T00:44:25.012");
|
||||||
ourLog.info("Actual: " + encoded);
|
ourLog.info("Actual: "+encoded);
|
||||||
|
|
||||||
assertEquals("1960-09-07T00:44:25.012Z", encoded);
|
assertEquals("1960-09-07T00:44:25.012Z", encoded);
|
||||||
|
|
||||||
type = new InstantDt(encoded);
|
type = new InstantDt(encoded);
|
||||||
assertEquals(1960, type.getYear().intValue());
|
assertEquals(1960, type.getYear().intValue());
|
||||||
assertEquals(8, type.getMonth().intValue()); // 0-indexed unlike LocalDateTime.of
|
assertEquals(8, type.getMonth().intValue()); // 0-indexed unlike LocalDateTime.of
|
||||||
|
@ -65,11 +65,11 @@ public class BaseDateTimeDtDstu2Test {
|
||||||
public void testFromTime() {
|
public void testFromTime() {
|
||||||
long millis;
|
long millis;
|
||||||
InstantDt dt;
|
InstantDt dt;
|
||||||
|
|
||||||
millis = 1466022208001L;
|
millis = 1466022208001L;
|
||||||
String expected = "2016-06-15T20:23:28.001Z";
|
String expected = "2016-06-15T20:23:28.001Z";
|
||||||
validate(millis, expected);
|
validate(millis, expected);
|
||||||
|
|
||||||
millis = 1466022208123L;
|
millis = 1466022208123L;
|
||||||
expected = "2016-06-15T20:23:28.123Z";
|
expected = "2016-06-15T20:23:28.123Z";
|
||||||
validate(millis, expected);
|
validate(millis, expected);
|
||||||
|
@ -77,13 +77,14 @@ public class BaseDateTimeDtDstu2Test {
|
||||||
millis = 1466022208100L;
|
millis = 1466022208100L;
|
||||||
expected = "2016-06-15T20:23:28.100Z";
|
expected = "2016-06-15T20:23:28.100Z";
|
||||||
validate(millis, expected);
|
validate(millis, expected);
|
||||||
|
|
||||||
millis = 1466022208000L;
|
millis = 1466022208000L;
|
||||||
expected = "2016-06-15T20:23:28.000Z";
|
expected = "2016-06-15T20:23:28.000Z";
|
||||||
validate(millis, expected);
|
validate(millis, expected);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void validate(long millis, String expected) {
|
private void validate(long millis, String expected) {
|
||||||
InstantDt dt;
|
InstantDt dt;
|
||||||
dt = new InstantDt(new Date(millis));
|
dt = new InstantDt(new Date(millis));
|
||||||
|
@ -92,12 +93,13 @@ public class BaseDateTimeDtDstu2Test {
|
||||||
|
|
||||||
assertEquals(millis % 1000, dt.getMillis().longValue());
|
assertEquals(millis % 1000, dt.getMillis().longValue());
|
||||||
assertEquals((millis % 1000) * BaseDateTimeDt.NANOS_PER_MILLIS, dt.getNanos().longValue());
|
assertEquals((millis % 1000) * BaseDateTimeDt.NANOS_PER_MILLIS, dt.getNanos().longValue());
|
||||||
|
|
||||||
dt = new InstantDt();
|
dt = new InstantDt();
|
||||||
dt.setTimeZone(TimeZone.getTimeZone("GMT+0:00"));
|
dt.setTimeZone(TimeZone.getTimeZone("GMT+0:00"));
|
||||||
dt.setValue(new Date(millis));
|
dt.setValue(new Date(millis));
|
||||||
assertEquals(expected.replace("Z", "+00:00"), dt.getValueAsString());
|
assertEquals(expected.replace("Z", "+00:00"), dt.getValueAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetPartialsYearFromExisting() {
|
public void testSetPartialsYearFromExisting() {
|
||||||
|
@ -260,6 +262,7 @@ public class BaseDateTimeDtDstu2Test {
|
||||||
verifyFails("1974-A2-25");
|
verifyFails("1974-A2-25");
|
||||||
verifyFails("1974-12-A5");
|
verifyFails("1974-12-A5");
|
||||||
|
|
||||||
|
|
||||||
// Date shouldn't have a time zone
|
// Date shouldn't have a time zone
|
||||||
verifyFails("1974-12-25Z");
|
verifyFails("1974-12-25Z");
|
||||||
verifyFails("1974-12-25+10:00");
|
verifyFails("1974-12-25+10:00");
|
||||||
|
@ -567,26 +570,25 @@ public class BaseDateTimeDtDstu2Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseMinute() throws DataFormatException {
|
public void testParseMinuteShouldFail() throws DataFormatException {
|
||||||
DateTimeDt dt = new DateTimeDt();
|
DateTimeDt dt = new DateTimeDt();
|
||||||
dt.setValueAsString("2013-02-03T11:22");
|
try {
|
||||||
|
dt.setValueAsString("2013-02-03T11:22");
|
||||||
assertEquals("2013-02-03 11:22", myDateInstantParser.format(dt.getValue()).substring(0, 16));
|
fail();
|
||||||
assertEquals("2013-02-03T11:22", dt.getValueAsString());
|
} catch (DataFormatException e) {
|
||||||
assertEquals(false, dt.isTimeZoneZulu());
|
assertEquals(e.getMessage(), "Invalid date/time string (datatype DateTimeDt does not support MINUTE precision): 2013-02-03T11:22");
|
||||||
assertNull(dt.getTimeZone());
|
}
|
||||||
assertEquals(TemporalPrecisionEnum.MINUTE, dt.getPrecision());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseMinuteZulu() throws DataFormatException {
|
public void testParseMinuteZuluShouldFail() throws DataFormatException {
|
||||||
DateTimeDt dt = new DateTimeDt();
|
DateTimeDt dt = new DateTimeDt();
|
||||||
dt.setValueAsString("2013-02-03T11:22Z");
|
try {
|
||||||
|
dt.setValueAsString("2013-02-03T11:22Z");
|
||||||
assertEquals("2013-02-03T11:22Z", dt.getValueAsString());
|
fail();
|
||||||
assertEquals(true, dt.isTimeZoneZulu());
|
} catch (DataFormatException e) {
|
||||||
assertEquals("GMT", dt.getTimeZone().getID());
|
assertEquals(e.getMessage(), "Invalid date/time string (datatype DateTimeDt does not support MINUTE precision): 2013-02-03T11:22Z");
|
||||||
assertEquals(TemporalPrecisionEnum.MINUTE, dt.getPrecision());
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package ca.uhn.fhir.rest.param;
|
package ca.uhn.fhir.rest.param;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.endsWith;
|
||||||
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
@ -19,21 +23,21 @@ public class DateParamTest {
|
||||||
public void testConstructors() {
|
public void testConstructors() {
|
||||||
new DateParam();
|
new DateParam();
|
||||||
new DateParam("2011-01-02");
|
new DateParam("2011-01-02");
|
||||||
new DateParam(ParamPrefixEnum.GREATERTHAN,new Date());
|
new DateParam(ParamPrefixEnum.GREATERTHAN, new Date());
|
||||||
new DateParam(ParamPrefixEnum.GREATERTHAN,new DateTimeDt("2011-01-02"));
|
new DateParam(ParamPrefixEnum.GREATERTHAN, new DateTimeDt("2011-01-02"));
|
||||||
new DateParam(ParamPrefixEnum.GREATERTHAN,InstantDt.withCurrentTime());
|
new DateParam(ParamPrefixEnum.GREATERTHAN, InstantDt.withCurrentTime());
|
||||||
new DateParam(ParamPrefixEnum.GREATERTHAN,"2011-01-02");
|
new DateParam(ParamPrefixEnum.GREATERTHAN, "2011-01-02");
|
||||||
|
|
||||||
new DateParam(QuantityCompararatorEnum.GREATERTHAN,new Date());
|
new DateParam(QuantityCompararatorEnum.GREATERTHAN, new Date());
|
||||||
new DateParam(QuantityCompararatorEnum.GREATERTHAN,new DateTimeDt("2011-01-02"));
|
new DateParam(QuantityCompararatorEnum.GREATERTHAN, new DateTimeDt("2011-01-02"));
|
||||||
new DateParam(QuantityCompararatorEnum.GREATERTHAN,InstantDt.withCurrentTime());
|
new DateParam(QuantityCompararatorEnum.GREATERTHAN, InstantDt.withCurrentTime());
|
||||||
new DateParam(QuantityCompararatorEnum.GREATERTHAN,"2011-01-02");
|
new DateParam(QuantityCompararatorEnum.GREATERTHAN, "2011-01-02");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParse() {
|
public void testParse() {
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
|
|
||||||
DateParam param = new DateParam();
|
DateParam param = new DateParam();
|
||||||
param.setValueAsString("gt2016-06-09T20:38:14.591-05:00");
|
param.setValueAsString("gt2016-06-09T20:38:14.591-05:00");
|
||||||
|
|
||||||
|
@ -48,4 +52,56 @@ public class DateParamTest {
|
||||||
assertEquals("2016-06-09T21:38:14.591-04:00", dt.getValueAsString());
|
assertEquals("2016-06-09T21:38:14.591-04:00", dt.getValueAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseMinutePrecision() {
|
||||||
|
DateParam param = new DateParam();
|
||||||
|
param.setValueAsString("2016-06-09T20:38Z");
|
||||||
|
|
||||||
|
assertEquals(null, param.getPrefix());
|
||||||
|
assertEquals("2016-06-09T20:38Z", param.getValueAsString());
|
||||||
|
|
||||||
|
ourLog.info("PRE: " + param.getValue());
|
||||||
|
ourLog.info("PRE: " + param.getValue().getTime());
|
||||||
|
|
||||||
|
InstantDt dt = new InstantDt(new Date(param.getValue().getTime()));
|
||||||
|
dt.setTimeZone(TimeZone.getTimeZone("America/Toronto"));
|
||||||
|
ourLog.info("POST: " + dt.getValue());
|
||||||
|
assertEquals("2016-06-09T16:38:00.000-04:00", dt.getValueAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseMinutePrecisionWithoutTimezone() {
|
||||||
|
DateParam param = new DateParam();
|
||||||
|
param.setValueAsString("2016-06-09T20:38");
|
||||||
|
|
||||||
|
assertEquals(null, param.getPrefix());
|
||||||
|
assertEquals("2016-06-09T20:38", param.getValueAsString());
|
||||||
|
|
||||||
|
ourLog.info("PRE: " + param.getValue());
|
||||||
|
ourLog.info("PRE: " + param.getValue().getTime());
|
||||||
|
|
||||||
|
InstantDt dt = new InstantDt(new Date(param.getValue().getTime()));
|
||||||
|
dt.setTimeZone(TimeZone.getTimeZone("America/Toronto"));
|
||||||
|
ourLog.info("POST: " + dt.getValue());
|
||||||
|
assertThat(dt.getValueAsString(), startsWith("2016-06-09T"));
|
||||||
|
assertThat(dt.getValueAsString(), endsWith(":38:00.000-04:00"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseMinutePrecisionWithPrefix() {
|
||||||
|
DateParam param = new DateParam();
|
||||||
|
param.setValueAsString("gt2016-06-09T20:38Z");
|
||||||
|
|
||||||
|
assertEquals(ParamPrefixEnum.GREATERTHAN, param.getPrefix());
|
||||||
|
assertEquals("2016-06-09T20:38Z", param.getValueAsString());
|
||||||
|
|
||||||
|
ourLog.info("PRE: " + param.getValue());
|
||||||
|
ourLog.info("PRE: " + param.getValue().getTime());
|
||||||
|
|
||||||
|
InstantDt dt = new InstantDt(new Date(param.getValue().getTime()));
|
||||||
|
dt.setTimeZone(TimeZone.getTimeZone("America/Toronto"));
|
||||||
|
ourLog.info("POST: " + dt.getValue());
|
||||||
|
assertEquals("2016-06-09T16:38:00.000-04:00", dt.getValueAsString());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import org.apache.commons.lang3.Validate;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
import org.apache.commons.lang3.time.FastDateFormat;
|
import org.apache.commons.lang3.time.FastDateFormat;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
|
|
||||||
public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
||||||
|
@ -44,9 +45,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
||||||
*/
|
*/
|
||||||
public BaseDateTimeType(Date theDate, TemporalPrecisionEnum thePrecision) {
|
public BaseDateTimeType(Date theDate, TemporalPrecisionEnum thePrecision) {
|
||||||
setValue(theDate, thePrecision);
|
setValue(theDate, thePrecision);
|
||||||
if (isPrecisionAllowed(thePrecision) == false) {
|
validatePrecisionAndThrowDataFormatException(getValueAsString(), getPrecision());
|
||||||
throw new IllegalArgumentException("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support " + thePrecision + " precision): " + theDate);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,6 +54,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
||||||
public BaseDateTimeType(Date theDate, TemporalPrecisionEnum thePrecision, TimeZone theTimeZone) {
|
public BaseDateTimeType(Date theDate, TemporalPrecisionEnum thePrecision, TimeZone theTimeZone) {
|
||||||
this(theDate, thePrecision);
|
this(theDate, thePrecision);
|
||||||
setTimeZone(theTimeZone);
|
setTimeZone(theTimeZone);
|
||||||
|
validatePrecisionAndThrowDataFormatException(getValueAsString(), getPrecision());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,12 +65,10 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
||||||
*/
|
*/
|
||||||
public BaseDateTimeType(String theString) {
|
public BaseDateTimeType(String theString) {
|
||||||
setValueAsString(theString);
|
setValueAsString(theString);
|
||||||
if (isPrecisionAllowed(getPrecision()) == false) {
|
validatePrecisionAndThrowDataFormatException(theString, getPrecision());
|
||||||
throw new IllegalArgumentException("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support " + getPrecision() + " precision): " + theString);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given amount to the field specified by theField
|
* Adds the given amount to the field specified by theField
|
||||||
*
|
*
|
||||||
* @param theField
|
* @param theField
|
||||||
|
@ -307,7 +305,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
||||||
*/
|
*/
|
||||||
public TimeZone getTimeZone() {
|
public TimeZone getTimeZone() {
|
||||||
if (myTimeZoneZulu) {
|
if (myTimeZoneZulu) {
|
||||||
return TimeZone.getTimeZone("GMT");
|
return TimeZone.getTimeZone("Z");
|
||||||
}
|
}
|
||||||
return myTimeZone;
|
return myTimeZone;
|
||||||
}
|
}
|
||||||
|
@ -471,6 +469,10 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
||||||
myFractionalSeconds = "";
|
myFractionalSeconds = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (precision == TemporalPrecisionEnum.MINUTE) {
|
||||||
|
validatePrecisionAndThrowDataFormatException(value, precision);
|
||||||
|
}
|
||||||
|
|
||||||
myPrecision = precision;
|
myPrecision = precision;
|
||||||
return cal.getTime();
|
return cal.getTime();
|
||||||
|
|
||||||
|
@ -818,6 +820,12 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validatePrecisionAndThrowDataFormatException(String theValue, TemporalPrecisionEnum thePrecision) {
|
||||||
|
if (isPrecisionAllowed(thePrecision) == false) {
|
||||||
|
throw new DataFormatException("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support " + thePrecision + " precision): " + theValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void validateValueInRange(long theValue, long theMinimum, long theMaximum) {
|
private void validateValueInRange(long theValue, long theMinimum, long theMaximum) {
|
||||||
if (theValue < theMinimum || theValue > theMaximum) {
|
if (theValue < theMinimum || theValue > theMaximum) {
|
||||||
throw new IllegalArgumentException("Value " + theValue + " is not between allowable range: " + theMinimum + " - " + theMaximum);
|
throw new IllegalArgumentException("Value " + theValue + " is not between allowable range: " + theMinimum + " - " + theMaximum);
|
||||||
|
|
|
@ -36,6 +36,7 @@ import java.util.zip.DataFormatException;
|
||||||
|
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -29,18 +29,14 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
package org.hl7.fhir.dstu3.model;
|
package org.hl7.fhir.dstu3.model;
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Primitive type "date" in FHIR: any day in a gregorian calendar
|
* Primitive type "date" in FHIR: any day in a gregorian calendar
|
||||||
*/
|
*/
|
||||||
|
import java.util.*;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -31,11 +31,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
package org.hl7.fhir.dstu3.model;
|
package org.hl7.fhir.dstu3.model;
|
||||||
|
|
||||||
import java.util.Calendar;
|
import java.util.*;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
import java.util.zip.DataFormatException;
|
import java.util.zip.DataFormatException;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,16 +30,14 @@ package org.hl7.fhir.dstu3.model;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Generated on Mon, Apr 17, 2017 17:38-0400 for FHIR v3.0.1
|
// Generated on Mon, Apr 17, 2017 17:38-0400 for FHIR v3.0.1
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.model.api.annotation.Child;
|
|
||||||
import ca.uhn.fhir.model.api.annotation.ChildOrder;
|
|
||||||
import ca.uhn.fhir.model.api.annotation.Description;
|
|
||||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
|
||||||
import ca.uhn.fhir.model.api.annotation.Block;
|
|
||||||
import org.hl7.fhir.instance.model.api.*;
|
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
import org.hl7.fhir.instance.model.api.ICompositeType;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
|
import ca.uhn.fhir.model.api.annotation.*;
|
||||||
/**
|
/**
|
||||||
* A time period defined by a start and end date and optionally time.
|
* A time period defined by a start and end date and optionally time.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
package org.hl7.fhir.dstu3.model;
|
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
|
||||||
|
|
||||||
public enum TemporalPrecisionEnum {
|
|
||||||
|
|
||||||
YEAR(Calendar.YEAR) {
|
|
||||||
@Override
|
|
||||||
public Date add(Date theInput, int theAmount) {
|
|
||||||
return DateUtils.addYears(theInput, theAmount);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
MONTH(Calendar.MONTH) {
|
|
||||||
@Override
|
|
||||||
public Date add(Date theInput, int theAmount) {
|
|
||||||
return DateUtils.addMonths(theInput, theAmount);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
DAY(Calendar.DATE) {
|
|
||||||
@Override
|
|
||||||
public Date add(Date theInput, int theAmount) {
|
|
||||||
return DateUtils.addDays(theInput, theAmount);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MINUTE(Calendar.MINUTE) {
|
|
||||||
@Override
|
|
||||||
public Date add(Date theInput, int theAmount) {
|
|
||||||
return DateUtils.addMinutes(theInput, theAmount);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
SECOND(Calendar.SECOND) {
|
|
||||||
@Override
|
|
||||||
public Date add(Date theInput, int theAmount) {
|
|
||||||
return DateUtils.addSeconds(theInput, theAmount);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
MILLI(Calendar.MILLISECOND) {
|
|
||||||
@Override
|
|
||||||
public Date add(Date theInput, int theAmount) {
|
|
||||||
return DateUtils.addMilliseconds(theInput, theAmount);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
private int myCalendarConstant;
|
|
||||||
|
|
||||||
TemporalPrecisionEnum(int theCalendarConstant) {
|
|
||||||
myCalendarConstant = theCalendarConstant;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Date add(Date theInput, int theAmount);
|
|
||||||
|
|
||||||
public int getCalendarConstant() {
|
|
||||||
return myCalendarConstant;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,49 +1,22 @@
|
||||||
package org.hl7.fhir.dstu3.utils;
|
package org.hl7.fhir.dstu3.utils;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.hl7.fhir.dstu3.context.IWorkerContext;
|
import org.hl7.fhir.dstu3.context.IWorkerContext;
|
||||||
import org.hl7.fhir.dstu3.model.Base;
|
import org.hl7.fhir.dstu3.model.*;
|
||||||
import org.hl7.fhir.dstu3.model.BooleanType;
|
|
||||||
import org.hl7.fhir.dstu3.model.DateTimeType;
|
|
||||||
import org.hl7.fhir.dstu3.model.DateType;
|
|
||||||
import org.hl7.fhir.dstu3.model.DecimalType;
|
|
||||||
import org.hl7.fhir.dstu3.model.ElementDefinition;
|
|
||||||
import org.hl7.fhir.dstu3.model.ElementDefinition.TypeRefComponent;
|
import org.hl7.fhir.dstu3.model.ElementDefinition.TypeRefComponent;
|
||||||
import org.hl7.fhir.dstu3.model.ExpressionNode;
|
import org.hl7.fhir.dstu3.model.ExpressionNode.*;
|
||||||
import org.hl7.fhir.dstu3.model.ExpressionNode.CollectionStatus;
|
|
||||||
import org.hl7.fhir.dstu3.model.ExpressionNode.Function;
|
|
||||||
import org.hl7.fhir.dstu3.model.ExpressionNode.Kind;
|
|
||||||
import org.hl7.fhir.dstu3.model.ExpressionNode.Operation;
|
|
||||||
import org.hl7.fhir.dstu3.model.ExpressionNode.SourceLocation;
|
|
||||||
import org.hl7.fhir.dstu3.model.IntegerType;
|
|
||||||
import org.hl7.fhir.dstu3.model.Property;
|
|
||||||
import org.hl7.fhir.dstu3.model.Resource;
|
|
||||||
import org.hl7.fhir.dstu3.model.StringType;
|
|
||||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
|
||||||
import org.hl7.fhir.dstu3.model.StructureDefinition.StructureDefinitionKind;
|
import org.hl7.fhir.dstu3.model.StructureDefinition.StructureDefinitionKind;
|
||||||
import org.hl7.fhir.dstu3.model.StructureDefinition.TypeDerivationRule;
|
import org.hl7.fhir.dstu3.model.StructureDefinition.TypeDerivationRule;
|
||||||
import org.hl7.fhir.dstu3.model.TemporalPrecisionEnum;
|
|
||||||
import org.hl7.fhir.dstu3.model.TimeType;
|
|
||||||
import org.hl7.fhir.dstu3.model.TypeDetails;
|
|
||||||
import org.hl7.fhir.dstu3.model.TypeDetails.ProfiledType;
|
import org.hl7.fhir.dstu3.model.TypeDetails.ProfiledType;
|
||||||
import org.hl7.fhir.dstu3.utils.FHIRLexer.FHIRLexerException;
|
import org.hl7.fhir.dstu3.utils.FHIRLexer.FHIRLexerException;
|
||||||
import org.hl7.fhir.dstu3.utils.FHIRPathEngine.IEvaluationContext.FunctionDetails;
|
import org.hl7.fhir.dstu3.utils.FHIRPathEngine.IEvaluationContext.FunctionDetails;
|
||||||
import org.hl7.fhir.exceptions.DefinitionException;
|
import org.hl7.fhir.exceptions.*;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
|
||||||
import org.hl7.fhir.exceptions.PathEngineException;
|
|
||||||
import org.hl7.fhir.exceptions.UcumException;
|
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
import org.hl7.fhir.utilities.ucum.Decimal;
|
import org.hl7.fhir.utilities.ucum.Decimal;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.util.ElementUtil;
|
import ca.uhn.fhir.util.ElementUtil;
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,30 @@
|
||||||
package org.hl7.fhir.dstu3.model;
|
package org.hl7.fhir.dstu3.model;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import static org.hamcrest.Matchers.either;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import static org.hamcrest.Matchers.endsWith;
|
||||||
import ca.uhn.fhir.validation.ValidationResult;
|
import static org.junit.Assert.assertEquals;
|
||||||
import org.apache.commons.lang3.time.FastDateFormat;
|
import static org.junit.Assert.assertFalse;
|
||||||
import org.hamcrest.Matchers;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import org.junit.AfterClass;
|
import static org.junit.Assert.assertNull;
|
||||||
import org.junit.Assert;
|
import static org.junit.Assert.assertThat;
|
||||||
import org.junit.Before;
|
import static org.junit.Assert.assertTrue;
|
||||||
import org.junit.BeforeClass;
|
import static org.junit.Assert.fail;
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.util.Calendar;
|
import java.util.*;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import org.apache.commons.lang3.time.FastDateFormat;
|
||||||
import static org.junit.Assert.*;
|
import org.hamcrest.Matchers;
|
||||||
|
import org.junit.*;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import ca.uhn.fhir.validation.ValidationResult;
|
||||||
|
|
||||||
public class BaseDateTimeTypeDstu3Test {
|
public class BaseDateTimeTypeDstu3Test {
|
||||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||||
|
@ -60,6 +62,29 @@ public class BaseDateTimeTypeDstu3Test {
|
||||||
assertFalse(new DateTimeType("2011-01-01T12:12:12Z").before(new DateTimeType("2011-01-01T12:12:12Z")));
|
assertFalse(new DateTimeType("2011-01-01T12:12:12Z").before(new DateTimeType("2011-01-01T12:12:12Z")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseMinuteShouldFail() throws DataFormatException {
|
||||||
|
DateTimeType dt = new DateTimeType();
|
||||||
|
try {
|
||||||
|
dt.setValueAsString("2013-02-03T11:22");
|
||||||
|
fail();
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
assertEquals(e.getMessage(), "Invalid date/time string (datatype DateTimeType does not support MINUTE precision): 2013-02-03T11:22");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseMinuteZuluShouldFail() throws DataFormatException {
|
||||||
|
DateTimeType dt = new DateTimeType();
|
||||||
|
try {
|
||||||
|
dt.setValueAsString("2013-02-03T11:22Z");
|
||||||
|
fail();
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
assertEquals(e.getMessage(), "Invalid date/time string (datatype DateTimeType does not support MINUTE precision): 2013-02-03T11:22Z");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test()
|
@Test()
|
||||||
public void testAfterNull() {
|
public void testAfterNull() {
|
||||||
try {
|
try {
|
||||||
|
@ -107,19 +132,18 @@ public class BaseDateTimeTypeDstu3Test {
|
||||||
/**
|
/**
|
||||||
* Test for #57
|
* Test for #57
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@Test
|
@Test
|
||||||
public void testConstructorRejectsInvalidPrecision() {
|
public void testConstructorRejectsInvalidPrecision() {
|
||||||
try {
|
try {
|
||||||
new DateType("2001-01-02T11:13:33");
|
new DateType("2001-01-02T11:13:33");
|
||||||
fail();
|
fail();
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (DataFormatException e) {
|
||||||
assertThat(e.getMessage(), containsString("precision"));
|
assertThat(e.getMessage(), containsString("precision"));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
new InstantType("2001-01-02");
|
new InstantType("2001-01-02");
|
||||||
fail();
|
fail();
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (DataFormatException e) {
|
||||||
assertThat(e.getMessage(), containsString("precision"));
|
assertThat(e.getMessage(), containsString("precision"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -330,7 +354,7 @@ public class BaseDateTimeTypeDstu3Test {
|
||||||
cal.set(1990, Calendar.JANUARY, 3, 3, 22, 11);
|
cal.set(1990, Calendar.JANUARY, 3, 3, 22, 11);
|
||||||
|
|
||||||
DateTimeType date = new DateTimeType();
|
DateTimeType date = new DateTimeType();
|
||||||
date.setValue(cal.getTime(), TemporalPrecisionEnum.MINUTE);
|
date.setValue(cal.getTime(), ca.uhn.fhir.model.api.TemporalPrecisionEnum.MINUTE);
|
||||||
date.setTimeZone(TimeZone.getTimeZone("EST"));
|
date.setTimeZone(TimeZone.getTimeZone("EST"));
|
||||||
assertEquals("1990-01-02T21:22-05:00", date.getValueAsString());
|
assertEquals("1990-01-02T21:22-05:00", date.getValueAsString());
|
||||||
|
|
||||||
|
@ -538,24 +562,21 @@ public class BaseDateTimeTypeDstu3Test {
|
||||||
@Test
|
@Test
|
||||||
public void testParseMinute() throws DataFormatException {
|
public void testParseMinute() throws DataFormatException {
|
||||||
DateTimeType dt = new DateTimeType();
|
DateTimeType dt = new DateTimeType();
|
||||||
dt.setValueAsString("2013-02-03T11:22");
|
try {
|
||||||
|
dt.setValueAsString("2013-02-03T11:22");
|
||||||
assertEquals("2013-02-03 11:22", myDateInstantParser.format(dt.getValue()).substring(0, 16));
|
} catch (DataFormatException e) {
|
||||||
assertEquals("2013-02-03T11:22", dt.getValueAsString());
|
assertEquals("Invalid date/time string (datatype DateTimeType does not support MINUTE precision): 2013-02-03T11:22", e.getMessage());
|
||||||
assertEquals(false, dt.isTimeZoneZulu());
|
}
|
||||||
assertNull(dt.getTimeZone());
|
|
||||||
assertEquals(TemporalPrecisionEnum.MINUTE, dt.getPrecision());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseMinuteZulu() throws DataFormatException {
|
public void testParseMinuteZulu() throws DataFormatException {
|
||||||
DateTimeType dt = new DateTimeType();
|
DateTimeType dt = new DateTimeType();
|
||||||
dt.setValueAsString("2013-02-03T11:22Z");
|
try {
|
||||||
|
dt.setValueAsString("2013-02-03T11:22Z");
|
||||||
assertEquals("2013-02-03T11:22Z", dt.getValueAsString());
|
} catch (Exception e) {
|
||||||
assertEquals(true, dt.isTimeZoneZulu());
|
assertEquals("Invalid date/time string (datatype DateTimeType does not support MINUTE precision): 2013-02-03T11:22Z", e.getMessage());
|
||||||
assertEquals("GMT", dt.getTimeZone().getID());
|
}
|
||||||
assertEquals(TemporalPrecisionEnum.MINUTE, dt.getPrecision());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -739,7 +760,7 @@ public class BaseDateTimeTypeDstu3Test {
|
||||||
Date time = cal.getTime();
|
Date time = cal.getTime();
|
||||||
|
|
||||||
DateType date = new DateType();
|
DateType date = new DateType();
|
||||||
date.setValue(time, TemporalPrecisionEnum.DAY);
|
date.setValue(time, ca.uhn.fhir.model.api.TemporalPrecisionEnum.DAY);
|
||||||
assertEquals("2012-01-02", date.getValueAsString());
|
assertEquals("2012-01-02", date.getValueAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,10 @@
|
||||||
looked like before the update. This change was made to support the change above, but
|
looked like before the update. This change was made to support the change above, but
|
||||||
seems like a useful feature all around.
|
seems like a useful feature all around.
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix" issue="604">
|
||||||
|
Allow DateParam (used in servers) to handle values with MINUTE precision. Thanks to
|
||||||
|
Christian Ohr for the pull request!
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="2.5" date="2017-06-08">
|
<release version="2.5" date="2017-06-08">
|
||||||
<action type="fix">
|
<action type="fix">
|
||||||
|
@ -191,11 +195,6 @@
|
||||||
was preventing the CLI from uploading definitions correctly. Thanks to
|
was preventing the CLI from uploading definitions correctly. Thanks to
|
||||||
Joel Schneider for the Pull Request!
|
Joel Schneider for the Pull Request!
|
||||||
</action>
|
</action>
|
||||||
<action type="fix" issue="655">
|
|
||||||
DateTime datatypes (both DSTU1/2 and RI STU3) did not properly parse
|
|
||||||
values with MINUTE precision. Thanks to Christian Ohr for the pull
|
|
||||||
request!
|
|
||||||
</action>
|
|
||||||
<action type="add" issue="656">
|
<action type="add" issue="656">
|
||||||
Improve handling in JPA server when doing code:above and code:below
|
Improve handling in JPA server when doing code:above and code:below
|
||||||
searches to use a disjunction of AND and IN in order to avoid failures
|
searches to use a disjunction of AND and IN in order to avoid failures
|
||||||
|
|
Loading…
Reference in New Issue