Merge pull request #672 from jamesagnew/minute_precision_in_searchparams

Minute precision in searchparams
This commit is contained in:
James Agnew 2017-06-12 11:50:09 -04:00 committed by GitHub
commit 959cb700fd
19 changed files with 426 additions and 456 deletions

View File

@ -84,9 +84,7 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
*/
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);
}
validatePrecisionAndThrowDataFormatException(theString, getPrecision());
}
private void clearTimeZone() {
@ -158,11 +156,74 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
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
*/
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) {
int plusIndex = theValueString.indexOf('+', 16);
int minusIndex = theValueString.indexOf('-', 16);
@ -189,6 +250,13 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
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
* supplied.
@ -217,10 +285,17 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
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
*/
abstract boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision);
protected abstract boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision);
/**
* Returns true if the timezone is set to GMT-0:00 (Z)
@ -285,7 +360,7 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
cal.set(Calendar.DAY_OF_MONTH, parseInt(value, value.substring(8, 10), 1, actualMaximum));
precision = TemporalPrecisionEnum.DAY;
if (length > 10) {
validateLengthIsAtLeast(value, 17);
validateLengthIsAtLeast(value, 16);
validateCharAtIndexIs(value, 10, 'T'); // yyyy-mm-ddThh:mm:ss
int offsetIdx = getOffsetIndex(value);
String time;
@ -352,6 +427,10 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
myFractionalSeconds = "";
}
if (precision == TemporalPrecisionEnum.MINUTE) {
validatePrecisionAndThrowDataFormatException(value, precision);
}
setPrecision(precision);
return cal.getTime();
@ -372,6 +451,92 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
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
*
@ -386,6 +551,14 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
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) {
if (isBlank(theValue)) {
@ -465,6 +638,14 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
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) {
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) {
if (theValue < theMinimum || theValue > theMaximum) {
throw new IllegalArgumentException("Value " + theValue + " is not between allowable range: " + theMinimum + " - " + theMaximum);
}
}
private Integer getFieldValue(int theField) {
if (getValue() == null) {
return null;
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);
}
Calendar cal = getValueAsCalendar();
return cal.get(theField);
}
}

View File

@ -133,7 +133,7 @@ public class DateDt extends BaseDateTimeDt {
}
@Override
boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
protected boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
switch (thePrecision) {
case YEAR:
case MONTH:

View File

@ -105,7 +105,7 @@ public class DateTimeDt extends BaseDateTimeDt {
}
@Override
boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
protected boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
switch (thePrecision) {
case YEAR:
case MONTH:

View File

@ -157,7 +157,7 @@ public class InstantDt extends BaseDateTimeDt {
}
@Override
boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
protected boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
switch (thePrecision) {
case SECOND:
case MILLI:

View File

@ -34,17 +34,18 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.primitive.DateDt;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.*;
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.util.ValidateUtil;
@SuppressWarnings("deprecation")
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
@ -223,6 +224,11 @@ public class DateParam extends BaseParamWithPrefix<DateParam> implements /*IQuer
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
* 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) {
if (theComparator != null) {
return ParamPrefixEnum.forDstu1Value(theComparator.getCode());
@ -282,24 +302,18 @@ public class DateParam extends BaseParamWithPrefix<DateParam> implements /*IQuer
return b.build();
}
@Override
public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, QualifiedParamList theParameters) {
setMissing(null);
setPrefix(null);
setValueAsString(null);
public class DateParamDateTimeHolder extends BaseDateTimeDt {
@Override
protected TemporalPrecisionEnum getDefaultPrecisionForDatatype() {
return TemporalPrecisionEnum.SECOND;
}
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);
@Override
protected boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
return true;
}
}
@Override
public List<DateParam> getValuesAsQueryTokens() {
return Collections.singletonList(this);
}
}

View File

@ -68,7 +68,6 @@ import org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelType;
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatus;
import org.hl7.fhir.dstu3.model.Substance;
import org.hl7.fhir.dstu3.model.Task;
import org.hl7.fhir.dstu3.model.TemporalPrecisionEnum;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -93,6 +92,7 @@ import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamUri;
import ca.uhn.fhir.jpa.entity.ResourceLink;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.parser.StrictErrorHandler;
import ca.uhn.fhir.rest.api.SortOrderEnum;

View File

@ -21,22 +21,10 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.*;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
@ -44,89 +32,29 @@ import org.apache.commons.lang3.Validate;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.client.methods.*;
import org.apache.http.entity.*;
import org.apache.http.message.BasicNameValuePair;
import org.hl7.fhir.dstu3.model.AuditEvent;
import org.hl7.fhir.dstu3.model.BaseResource;
import org.hl7.fhir.dstu3.model.Basic;
import org.hl7.fhir.dstu3.model.Binary;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleLinkComponent;
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
import org.hl7.fhir.dstu3.model.Bundle.SearchEntryMode;
import org.hl7.fhir.dstu3.model.CodeSystem;
import org.hl7.fhir.dstu3.model.CodeType;
import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.Condition;
import org.hl7.fhir.dstu3.model.DateTimeType;
import org.hl7.fhir.dstu3.model.DateType;
import org.hl7.fhir.dstu3.model.Device;
import org.hl7.fhir.dstu3.model.ProcedureRequest;
import org.hl7.fhir.dstu3.model.DocumentManifest;
import org.hl7.fhir.dstu3.model.DocumentReference;
import org.hl7.fhir.dstu3.model.Encounter;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.Bundle.*;
import org.hl7.fhir.dstu3.model.Encounter.EncounterLocationComponent;
import org.hl7.fhir.dstu3.model.Encounter.EncounterStatus;
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
import org.hl7.fhir.dstu3.model.Extension;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.ImagingStudy;
import org.hl7.fhir.dstu3.model.InstantType;
import org.hl7.fhir.dstu3.model.IntegerType;
import org.hl7.fhir.dstu3.model.Location;
import org.hl7.fhir.dstu3.model.Medication;
import org.hl7.fhir.dstu3.model.MedicationAdministration;
import org.hl7.fhir.dstu3.model.MedicationRequest;
import org.hl7.fhir.dstu3.model.Meta;
import org.hl7.fhir.dstu3.model.Narrative.NarrativeStatus;
import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.dstu3.model.Organization;
import org.hl7.fhir.dstu3.model.Parameters;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Period;
import org.hl7.fhir.dstu3.model.Practitioner;
import org.hl7.fhir.dstu3.model.Quantity;
import org.hl7.fhir.dstu3.model.Questionnaire;
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType;
import org.hl7.fhir.dstu3.model.QuestionnaireResponse;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.dstu3.model.StructureDefinition;
import org.hl7.fhir.dstu3.model.Subscription;
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelType;
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatus;
import org.hl7.fhir.dstu3.model.TemporalPrecisionEnum;
import org.hl7.fhir.dstu3.model.UnsignedIntType;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.hl7.fhir.instance.model.api.*;
import org.junit.*;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import com.google.common.collect.Lists;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.entity.Search;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.parser.IParser;
@ -135,18 +63,9 @@ import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.gclient.StringClientParam;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.exceptions.*;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.util.UrlUtil;

View File

@ -569,6 +569,28 @@ public class BaseDateTimeDtDstu2Test {
dt.setValueAsString("201302");
}
@Test
public void testParseMinuteShouldFail() throws DataFormatException {
DateTimeDt dt = new DateTimeDt();
try {
dt.setValueAsString("2013-02-03T11:22");
fail();
} catch (DataFormatException e) {
assertEquals(e.getMessage(), "Invalid date/time string (datatype DateTimeDt does not support MINUTE precision): 2013-02-03T11:22");
}
}
@Test
public void testParseMinuteZuluShouldFail() throws DataFormatException {
DateTimeDt dt = new DateTimeDt();
try {
dt.setValueAsString("2013-02-03T11:22Z");
fail();
} catch (DataFormatException e) {
assertEquals(e.getMessage(), "Invalid date/time string (datatype DateTimeDt does not support MINUTE precision): 2013-02-03T11:22Z");
}
}
@Test
public void testParseSecond() throws DataFormatException {
DateTimeDt dt = new DateTimeDt();
@ -582,7 +604,7 @@ public class BaseDateTimeDtDstu2Test {
}
@Test
public void testParseSecondulu() throws DataFormatException {
public void testParseSecondZulu() throws DataFormatException {
DateTimeDt dt = new DateTimeDt();
dt.setValueAsString("2013-02-03T11:22:33Z");

View File

@ -1,6 +1,10 @@
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.assertThat;
import java.util.Date;
import java.util.TimeZone;
@ -19,15 +23,15 @@ public class DateParamTest {
public void testConstructors() {
new DateParam();
new DateParam("2011-01-02");
new DateParam(ParamPrefixEnum.GREATERTHAN,new Date());
new DateParam(ParamPrefixEnum.GREATERTHAN,new DateTimeDt("2011-01-02"));
new DateParam(ParamPrefixEnum.GREATERTHAN,InstantDt.withCurrentTime());
new DateParam(ParamPrefixEnum.GREATERTHAN,"2011-01-02");
new DateParam(ParamPrefixEnum.GREATERTHAN, new Date());
new DateParam(ParamPrefixEnum.GREATERTHAN, new DateTimeDt("2011-01-02"));
new DateParam(ParamPrefixEnum.GREATERTHAN, InstantDt.withCurrentTime());
new DateParam(ParamPrefixEnum.GREATERTHAN, "2011-01-02");
new DateParam(QuantityCompararatorEnum.GREATERTHAN,new Date());
new DateParam(QuantityCompararatorEnum.GREATERTHAN,new DateTimeDt("2011-01-02"));
new DateParam(QuantityCompararatorEnum.GREATERTHAN,InstantDt.withCurrentTime());
new DateParam(QuantityCompararatorEnum.GREATERTHAN,"2011-01-02");
new DateParam(QuantityCompararatorEnum.GREATERTHAN, new Date());
new DateParam(QuantityCompararatorEnum.GREATERTHAN, new DateTimeDt("2011-01-02"));
new DateParam(QuantityCompararatorEnum.GREATERTHAN, InstantDt.withCurrentTime());
new DateParam(QuantityCompararatorEnum.GREATERTHAN, "2011-01-02");
}
@Test
@ -48,4 +52,56 @@ public class DateParamTest {
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("8: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());
}
}

View File

@ -12,6 +12,7 @@ import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.parser.DataFormatException;
public abstract class BaseDateTimeType extends PrimitiveType<Date> {
@ -44,9 +45,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
*/
public BaseDateTimeType(Date theDate, TemporalPrecisionEnum thePrecision) {
setValue(theDate, thePrecision);
if (isPrecisionAllowed(thePrecision) == false) {
throw new IllegalArgumentException("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support " + thePrecision + " precision): " + theDate);
}
validatePrecisionAndThrowDataFormatException(getValueAsString(), getPrecision());
}
/**
@ -55,6 +54,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
public BaseDateTimeType(Date theDate, TemporalPrecisionEnum thePrecision, TimeZone theTimeZone) {
this(theDate, thePrecision);
setTimeZone(theTimeZone);
validatePrecisionAndThrowDataFormatException(getValueAsString(), getPrecision());
}
/**
@ -65,12 +65,10 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
*/
public BaseDateTimeType(String theString) {
setValueAsString(theString);
if (isPrecisionAllowed(getPrecision()) == false) {
throw new IllegalArgumentException("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support " + getPrecision() + " precision): " + theString);
}
validatePrecisionAndThrowDataFormatException(theString, getPrecision());
}
/**
/**
* Adds the given amount to the field specified by theField
*
* @param theField
@ -307,7 +305,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
*/
public TimeZone getTimeZone() {
if (myTimeZoneZulu) {
return TimeZone.getTimeZone("GMT");
return TimeZone.getTimeZone("Z");
}
return myTimeZone;
}
@ -404,7 +402,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
cal.set(Calendar.DAY_OF_MONTH, parseInt(value, value.substring(8, 10), 1, actualMaximum));
precision = TemporalPrecisionEnum.DAY;
if (length > 10) {
validateLengthIsAtLeast(value, 17);
validateLengthIsAtLeast(value, 16);
validateCharAtIndexIs(value, 10, 'T'); // yyyy-mm-ddThh:mm:ss
int offsetIdx = getOffsetIndex(value);
String time;
@ -471,6 +469,10 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
myFractionalSeconds = "";
}
if (precision == TemporalPrecisionEnum.MINUTE) {
validatePrecisionAndThrowDataFormatException(value, precision);
}
myPrecision = precision;
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) {
if (theValue < theMinimum || theValue > theMaximum) {
throw new IllegalArgumentException("Value " + theValue + " is not between allowable range: " + theMinimum + " - " + theMaximum);

View File

@ -36,6 +36,7 @@ import java.util.zip.DataFormatException;
import org.apache.commons.lang3.time.DateUtils;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
/**

View File

@ -29,18 +29,14 @@ POSSIBILITY OF SUCH DAMAGE.
package org.hl7.fhir.dstu3.model;
import java.util.Calendar;
/**
* Primitive type "date" in FHIR: any day in a gregorian calendar
*/
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.*;
import org.apache.commons.lang3.Validate;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
/**

View File

@ -31,11 +31,10 @@ POSSIBILITY OF SUCH DAMAGE.
*/
package org.hl7.fhir.dstu3.model;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.*;
import java.util.zip.DataFormatException;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
/**

View File

@ -30,16 +30,14 @@ package org.hl7.fhir.dstu3.model;
*/
// 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.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.
*/

View File

@ -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;
}
}

View File

@ -1,49 +1,22 @@
package org.hl7.fhir.dstu3.utils;
import java.math.BigDecimal;
import java.util.ArrayList;
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 java.util.*;
import org.hl7.fhir.dstu3.context.IWorkerContext;
import org.hl7.fhir.dstu3.model.Base;
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.*;
import org.hl7.fhir.dstu3.model.ElementDefinition.TypeRefComponent;
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.ExpressionNode.*;
import org.hl7.fhir.dstu3.model.StructureDefinition.StructureDefinitionKind;
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.utils.FHIRLexer.FHIRLexerException;
import org.hl7.fhir.dstu3.utils.FHIRPathEngine.IEvaluationContext.FunctionDetails;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.exceptions.UcumException;
import org.hl7.fhir.exceptions.*;
import org.hl7.fhir.utilities.Utilities;
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.util.ElementUtil;

View File

@ -3,29 +3,26 @@ package org.hl7.fhir.dstu3.model;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.either;
import static org.hamcrest.Matchers.endsWith;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
import java.util.*;
import org.apache.commons.lang3.time.FastDateFormat;
import org.hamcrest.Matchers;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
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.parser.IParser;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.ValidationResult;
@ -65,6 +62,29 @@ public class BaseDateTimeTypeDstu3Test {
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()
public void testAfterNull() {
try {
@ -112,19 +132,18 @@ public class BaseDateTimeTypeDstu3Test {
/**
* Test for #57
*/
@SuppressWarnings("unused")
@Test
public void testConstructorRejectsInvalidPrecision() {
try {
new DateType("2001-01-02T11:13:33");
fail();
} catch (IllegalArgumentException e) {
} catch (DataFormatException e) {
assertThat(e.getMessage(), containsString("precision"));
}
try {
new InstantType("2001-01-02");
fail();
} catch (IllegalArgumentException e) {
} catch (DataFormatException e) {
assertThat(e.getMessage(), containsString("precision"));
}
}
@ -335,7 +354,7 @@ public class BaseDateTimeTypeDstu3Test {
cal.set(1990, Calendar.JANUARY, 3, 3, 22, 11);
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"));
assertEquals("1990-01-02T21:22-05:00", date.getValueAsString());
@ -458,7 +477,7 @@ public class BaseDateTimeTypeDstu3Test {
dt.setValueAsString("1974-12-25+10:00");
fail();
} catch (ca.uhn.fhir.parser.DataFormatException e) {
assertEquals("Invalid date/time format: \"1974-12-25+10:00\"", e.getMessage());
assertEquals("Invalid date/time format: \"1974-12-25+10:00\": Expected character 'T' at index 10 but found +", e.getMessage());
}
try {
DateTimeType dt = new DateTimeType();
@ -540,6 +559,26 @@ public class BaseDateTimeTypeDstu3Test {
dt.setValueAsString("201302");
}
@Test
public void testParseMinute() throws DataFormatException {
DateTimeType dt = new DateTimeType();
try {
dt.setValueAsString("2013-02-03T11:22");
} catch (DataFormatException e) {
assertEquals("Invalid date/time string (datatype DateTimeType does not support MINUTE precision): 2013-02-03T11:22", e.getMessage());
}
}
@Test
public void testParseMinuteZulu() throws DataFormatException {
DateTimeType dt = new DateTimeType();
try {
dt.setValueAsString("2013-02-03T11:22Z");
} catch (Exception e) {
assertEquals("Invalid date/time string (datatype DateTimeType does not support MINUTE precision): 2013-02-03T11:22Z", e.getMessage());
}
}
@Test
public void testParseSecond() throws DataFormatException {
DateTimeType dt = new DateTimeType();
@ -553,7 +592,7 @@ public class BaseDateTimeTypeDstu3Test {
}
@Test
public void testParseSecondulu() throws DataFormatException {
public void testParseSecondZulu() throws DataFormatException {
DateTimeType dt = new DateTimeType();
dt.setValueAsString("2013-02-03T11:22:33Z");
@ -721,7 +760,7 @@ public class BaseDateTimeTypeDstu3Test {
Date time = cal.getTime();
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());
}

View File

@ -343,7 +343,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
retVal = ourYearMonthDayTimeMilliFormat.parse(theValue);
}
} catch (ParseException p2) {
throw new IllegalArgumentException("Invalid data/time string (" + p2.getMessage() + "): " + theValue);
throw new IllegalArgumentException("Invalid date/time string (" + p2.getMessage() + "): " + theValue);
}
setTimeZone(theValue, hasMillis);
setPrecision(TemporalPrecisionEnum.MILLI);
@ -357,7 +357,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
retVal = ourYearMonthDayTimeFormat.parse(theValue);
}
} catch (ParseException p2) {
throw new IllegalArgumentException("Invalid data/time string (" + p2.getMessage() + "): " + theValue);
throw new IllegalArgumentException("Invalid date/time string (" + p2.getMessage() + "): " + theValue);
}
setTimeZone(theValue, hasMillis);
@ -372,7 +372,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
retVal = ourYearMonthDayTimeMinsFormat.parse(theValue);
}
} catch (ParseException p2) {
throw new IllegalArgumentException("Invalid data/time string (" + p2.getMessage() + "): " + theValue, p2);
throw new IllegalArgumentException("Invalid date/time string (" + p2.getMessage() + "): " + theValue, p2);
}
setTimeZone(theValue, hasMillis);

View File

@ -24,6 +24,10 @@
looked like before the update. This change was made to support the change above, but
seems like a useful feature all around.
</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>
<action type="fix">
Fix HTTP 500 error in JPA server if a numeric search parameter was supplied with no value, e.g.
<![CDATA[<code>GET /Observation?value-quantity=</code>]]>
@ -195,11 +199,6 @@
was preventing the CLI from uploading definitions correctly. Thanks to
Joel Schneider for the Pull Request!
</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">
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