Work on #381 - Still need to apply these changes to STU3 type
This commit is contained in:
parent
8dc4eaf0e0
commit
a3484f84c1
|
@ -1,41 +1,12 @@
|
|||
package ca.uhn.fhir.model.primitive;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
import static ca.uhn.fhir.model.api.TemporalPrecisionEnum.DAY;
|
||||
import static ca.uhn.fhir.model.api.TemporalPrecisionEnum.MILLI;
|
||||
import static ca.uhn.fhir.model.api.TemporalPrecisionEnum.MONTH;
|
||||
import static ca.uhn.fhir.model.api.TemporalPrecisionEnum.SECOND;
|
||||
import static ca.uhn.fhir.model.api.TemporalPrecisionEnum.YEAR;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.apache.commons.lang3.time.FastDateFormat;
|
||||
|
@ -46,52 +17,13 @@ import ca.uhn.fhir.parser.DataFormatException;
|
|||
|
||||
public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
||||
|
||||
/*
|
||||
* Add any new formatters to the static block below!!
|
||||
*/
|
||||
private static final List<FastDateFormat> ourFormatters;
|
||||
|
||||
private static final Pattern ourYearDashMonthDashDayPattern = Pattern.compile("[0-9]{4}-[0-9]{2}-[0-9]{2}");
|
||||
private static final Pattern ourYearDashMonthPattern = Pattern.compile("[0-9]{4}-[0-9]{2}");
|
||||
private static final FastDateFormat ourYearFormat = FastDateFormat.getInstance("yyyy");
|
||||
private static final FastDateFormat ourYearMonthDayFormat = FastDateFormat.getInstance("yyyy-MM-dd");
|
||||
private static final FastDateFormat ourYearMonthDayNoDashesFormat = FastDateFormat.getInstance("yyyyMMdd");
|
||||
private static final Pattern ourYearMonthDayPattern = Pattern.compile("[0-9]{4}[0-9]{2}[0-9]{2}");
|
||||
private static final FastDateFormat ourYearMonthDayTimeFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
|
||||
private static final FastDateFormat ourYearMonthDayTimeMilliFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSS");
|
||||
private static final FastDateFormat ourYearMonthDayTimeMilliUTCZFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", TimeZone.getTimeZone("UTC"));
|
||||
private static final FastDateFormat ourYearMonthDayTimeMilliZoneFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSZZ");
|
||||
private static final FastDateFormat ourYearMonthDayTimeUTCZFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone("UTC"));
|
||||
private static final FastDateFormat ourYearMonthDayTimeZoneFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZZ");
|
||||
private static final FastDateFormat ourYearMonthFormat = FastDateFormat.getInstance("yyyy-MM");
|
||||
private static final FastDateFormat ourYearMonthNoDashesFormat = FastDateFormat.getInstance("yyyyMM");
|
||||
private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM);
|
||||
private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM);
|
||||
private static final Pattern ourYearMonthPattern = Pattern.compile("[0-9]{4}[0-9]{2}");
|
||||
private static final Pattern ourYearPattern = Pattern.compile("[0-9]{4}");
|
||||
private static final FastDateFormat ourYearMonthDayTimeMinsFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm");
|
||||
private static final FastDateFormat ourYearMonthDayTimeMinsZoneFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mmZZ");
|
||||
|
||||
static {
|
||||
ArrayList<FastDateFormat> formatters = new ArrayList<FastDateFormat>();
|
||||
formatters.add(ourYearFormat);
|
||||
formatters.add(ourYearMonthDayFormat);
|
||||
formatters.add(ourYearMonthDayNoDashesFormat);
|
||||
formatters.add(ourYearMonthDayTimeFormat);
|
||||
formatters.add(ourYearMonthDayTimeMilliFormat);
|
||||
formatters.add(ourYearMonthDayTimeUTCZFormat);
|
||||
formatters.add(ourYearMonthDayTimeMilliUTCZFormat);
|
||||
formatters.add(ourYearMonthDayTimeMilliZoneFormat);
|
||||
formatters.add(ourYearMonthDayTimeZoneFormat);
|
||||
formatters.add(ourYearMonthFormat);
|
||||
formatters.add(ourYearMonthNoDashesFormat);
|
||||
ourFormatters = Collections.unmodifiableList(formatters);
|
||||
}
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseDateTimeDt.class);
|
||||
private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM);
|
||||
|
||||
private int myFractionalSeconds;
|
||||
private TemporalPrecisionEnum myPrecision = TemporalPrecisionEnum.SECOND;
|
||||
private TimeZone myTimeZone;
|
||||
|
||||
private boolean myTimeZoneZulu = false;
|
||||
|
||||
/**
|
||||
|
@ -155,33 +87,50 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
}
|
||||
cal.setTime(theValue);
|
||||
|
||||
switch (myPrecision) {
|
||||
case DAY:
|
||||
return ourYearMonthDayFormat.format(cal);
|
||||
case MONTH:
|
||||
return ourYearMonthFormat.format(cal);
|
||||
case YEAR:
|
||||
return ourYearFormat.format(cal);
|
||||
case MINUTE:
|
||||
if (myTimeZoneZulu) {
|
||||
return ourYearMonthDayTimeMinsFormat.format(cal) + "Z";
|
||||
} else {
|
||||
return ourYearMonthDayTimeMinsZoneFormat.format(cal);
|
||||
}
|
||||
case SECOND:
|
||||
if (myTimeZoneZulu) {
|
||||
return ourYearMonthDayTimeFormat.format(cal) + "Z";
|
||||
} else {
|
||||
return ourYearMonthDayTimeZoneFormat.format(cal);
|
||||
}
|
||||
case MILLI:
|
||||
if (myTimeZoneZulu) {
|
||||
return ourYearMonthDayTimeMilliFormat.format(cal) + "Z";
|
||||
} else {
|
||||
return ourYearMonthDayTimeMilliZoneFormat.format(cal);
|
||||
StringBuilder b = new StringBuilder();
|
||||
leftPadWithZeros(cal.get(Calendar.YEAR), 4, b);
|
||||
if (myPrecision.ordinal() > TemporalPrecisionEnum.YEAR.ordinal()) {
|
||||
b.append('-');
|
||||
leftPadWithZeros(cal.get(Calendar.MONTH) + 1, 2, b);
|
||||
if (myPrecision.ordinal() > TemporalPrecisionEnum.MONTH.ordinal()) {
|
||||
b.append('-');
|
||||
leftPadWithZeros(cal.get(Calendar.DATE), 2, b);
|
||||
if (myPrecision.ordinal() > TemporalPrecisionEnum.DAY.ordinal()) {
|
||||
b.append('T');
|
||||
leftPadWithZeros(cal.get(Calendar.HOUR_OF_DAY), 2, b);
|
||||
b.append(':');
|
||||
leftPadWithZeros(cal.get(Calendar.MINUTE), 2, b);
|
||||
if (myPrecision.ordinal() > TemporalPrecisionEnum.MINUTE.ordinal()) {
|
||||
b.append(':');
|
||||
leftPadWithZeros(cal.get(Calendar.SECOND), 2, b);
|
||||
if (myPrecision.ordinal() > TemporalPrecisionEnum.SECOND.ordinal()) {
|
||||
b.append('.');
|
||||
leftPadWithZeros(myFractionalSeconds, 3, b);
|
||||
}
|
||||
}
|
||||
|
||||
if (myTimeZoneZulu) {
|
||||
b.append('Z');
|
||||
} else if (myTimeZone != null) {
|
||||
int offset = myTimeZone.getOffset(theValue.getTime());
|
||||
if (offset >= 0) {
|
||||
b.append('+');
|
||||
} else {
|
||||
b.append('-');
|
||||
offset = Math.abs(offset);
|
||||
}
|
||||
|
||||
int hoursOffset = (int) (offset / DateUtils.MILLIS_PER_HOUR);
|
||||
leftPadWithZeros(hoursOffset, 2, b);
|
||||
b.append(':');
|
||||
int minutesOffset = (int) (offset % DateUtils.MILLIS_PER_HOUR);
|
||||
minutesOffset = (int) (minutesOffset / DateUtils.MILLIS_PER_MINUTE);
|
||||
leftPadWithZeros(minutesOffset, 2, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Invalid precision (this is a HAPI bug, shouldn't happen): " + myPrecision);
|
||||
return b.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,6 +139,21 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
*/
|
||||
protected abstract TemporalPrecisionEnum getDefaultPrecisionForDatatype();
|
||||
|
||||
private int getOffsetIndex(String theValueString) {
|
||||
int plusIndex = theValueString.indexOf('+', 16);
|
||||
int minusIndex = theValueString.indexOf('-', 16);
|
||||
int zIndex = theValueString.indexOf('Z', 16);
|
||||
int retVal = Math.max(Math.max(plusIndex, minusIndex), zIndex);
|
||||
if (retVal == -1) {
|
||||
return -1;
|
||||
}
|
||||
if ((retVal - 2) != (plusIndex + minusIndex + zIndex)) {
|
||||
// This means we have more than one separator
|
||||
throw new DataFormatException("Invalid FHIR date/time string: " + theValueString);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the precision for this datatype (using the default for the given type if not set)
|
||||
*
|
||||
|
@ -207,6 +171,9 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
* supplied.
|
||||
*/
|
||||
public TimeZone getTimeZone() {
|
||||
if (myTimeZoneZulu) {
|
||||
return TimeZone.getTimeZone("Z");
|
||||
}
|
||||
return myTimeZone;
|
||||
}
|
||||
|
||||
|
@ -248,113 +215,223 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
return DateUtils.isSameDay(new Date(), getValue());
|
||||
}
|
||||
|
||||
private void leftPadWithZeros(int theInteger, int theLength, StringBuilder theTarget) {
|
||||
String string = Integer.toString(theInteger);
|
||||
for (int i = string.length(); i < theLength; i++) {
|
||||
theTarget.append('0');
|
||||
}
|
||||
theTarget.append(string);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Date parse(String theValue) throws DataFormatException {
|
||||
try {
|
||||
if (theValue.length() == 4 && ourYearPattern.matcher(theValue).matches()) {
|
||||
if (!isPrecisionAllowed(YEAR)) {
|
||||
ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support YEAR precision): " + theValue);
|
||||
}
|
||||
setPrecision(YEAR);
|
||||
clearTimeZone();
|
||||
return ((ourYearFormat).parse(theValue));
|
||||
} else if (theValue.length() == 6 && ourYearMonthPattern.matcher(theValue).matches()) {
|
||||
// Eg. 198401 (allow this just to be lenient)
|
||||
if (!isPrecisionAllowed(MONTH)) {
|
||||
ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support DAY precision): " + theValue);
|
||||
}
|
||||
setPrecision(MONTH);
|
||||
clearTimeZone();
|
||||
return ((ourYearMonthNoDashesFormat).parse(theValue));
|
||||
} else if (theValue.length() == 7 && ourYearDashMonthPattern.matcher(theValue).matches()) {
|
||||
// E.g. 1984-01 (this is valid according to the spec)
|
||||
if (!isPrecisionAllowed(MONTH)) {
|
||||
ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support MONTH precision): " + theValue);
|
||||
}
|
||||
setPrecision(MONTH);
|
||||
clearTimeZone();
|
||||
return ((ourYearMonthFormat).parse(theValue));
|
||||
} else if (theValue.length() == 8 && ourYearMonthDayPattern.matcher(theValue).matches()) {
|
||||
// Eg. 19840101 (allow this just to be lenient)
|
||||
if (!isPrecisionAllowed(DAY)) {
|
||||
ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support DAY precision): " + theValue);
|
||||
}
|
||||
setPrecision(DAY);
|
||||
clearTimeZone();
|
||||
return ((ourYearMonthDayNoDashesFormat).parse(theValue));
|
||||
} else if (theValue.length() == 10 && ourYearDashMonthDashDayPattern.matcher(theValue).matches()) {
|
||||
// E.g. 1984-01-01 (this is valid according to the spec)
|
||||
if (!isPrecisionAllowed(DAY)) {
|
||||
ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support DAY precision): " + theValue);
|
||||
}
|
||||
setPrecision(DAY);
|
||||
clearTimeZone();
|
||||
return ((ourYearMonthDayFormat).parse(theValue));
|
||||
} else if (theValue.length() >= 18) { // date and time with possible time zone
|
||||
char timeSeparator = theValue.charAt(10);
|
||||
if (timeSeparator != 'T') {
|
||||
throw new DataFormatException("Invalid date/time string: " + theValue);
|
||||
}
|
||||
int dotIndex = theValue.indexOf('.', 18);
|
||||
boolean hasMillis = dotIndex > -1;
|
||||
Calendar cal = new GregorianCalendar(0, 0, 0);
|
||||
cal.setTimeZone(TimeZone.getDefault());
|
||||
int length = theValue.length();
|
||||
|
||||
if (!hasMillis && !isPrecisionAllowed(SECOND)) {
|
||||
ourLog.debug("Invalid date/time string (data type does not support SECONDS precision): " + theValue);
|
||||
} else if (hasMillis && !isPrecisionAllowed(MILLI)) {
|
||||
ourLog.debug("Invalid date/time string (data type " + getClass().getSimpleName() + " does not support MILLIS precision):" + theValue);
|
||||
}
|
||||
|
||||
Date retVal;
|
||||
if (hasMillis) {
|
||||
String value = theValue;
|
||||
|
||||
/*
|
||||
* If we have more than 3 digits of precision after the decimal point, we
|
||||
* only parse the first 3 since Java Dates don't support more than that and
|
||||
* FastDateFormat gets confused
|
||||
*/
|
||||
int offsetIndex = getOffsetIndex(theValue);
|
||||
if (offsetIndex >= 24) {
|
||||
value = theValue.substring(0, 23) + theValue.substring(offsetIndex);
|
||||
}
|
||||
|
||||
try {
|
||||
if (hasOffset(value)) {
|
||||
retVal = ourYearMonthDayTimeMilliZoneFormat.parse(value);
|
||||
} else if (value.endsWith("Z")) {
|
||||
retVal = ourYearMonthDayTimeMilliUTCZFormat.parse(value);
|
||||
} else {
|
||||
retVal = ourYearMonthDayTimeMilliFormat.parse(value);
|
||||
}
|
||||
} catch (ParseException p2) {
|
||||
throw new DataFormatException("Invalid data/time string (" + p2.getMessage() + "): " + theValue);
|
||||
}
|
||||
setTimeZone(theValue);
|
||||
setPrecision(TemporalPrecisionEnum.MILLI);
|
||||
} else {
|
||||
try {
|
||||
if (hasOffset(theValue)) {
|
||||
retVal = ourYearMonthDayTimeZoneFormat.parse(theValue);
|
||||
} else if (theValue.endsWith("Z")) {
|
||||
retVal = ourYearMonthDayTimeUTCZFormat.parse(theValue);
|
||||
} else {
|
||||
retVal = ourYearMonthDayTimeFormat.parse(theValue);
|
||||
}
|
||||
} catch (ParseException p2) {
|
||||
throw new DataFormatException("Invalid data/time string (" + p2.getMessage() + "): " + theValue);
|
||||
}
|
||||
|
||||
setTimeZone(theValue);
|
||||
setPrecision(TemporalPrecisionEnum.SECOND);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
} else {
|
||||
throw new DataFormatException("Invalid date/time string (invalid length): " + theValue);
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
throw new DataFormatException("Invalid date string (" + e.getMessage() + "): " + theValue);
|
||||
if (length == 0) {
|
||||
return null;
|
||||
}
|
||||
if (length < 4) {
|
||||
throwBadDateFormat(theValue);
|
||||
}
|
||||
|
||||
TemporalPrecisionEnum precision = null;
|
||||
cal.set(Calendar.YEAR, parseInt(theValue, theValue.substring(0, 4), 0, 9999));
|
||||
precision = TemporalPrecisionEnum.YEAR;
|
||||
if (length > 4) {
|
||||
validateCharAtIndexIs(theValue, 4, '-');
|
||||
validateLengthIsAtLeast(theValue, 7);
|
||||
int monthVal = parseInt(theValue, theValue.substring(5, 7), 1, 12) - 1;
|
||||
cal.set(Calendar.MONTH, monthVal);
|
||||
precision = TemporalPrecisionEnum.MONTH;
|
||||
if (length > 7) {
|
||||
validateCharAtIndexIs(theValue, 7, '-');
|
||||
validateLengthIsAtLeast(theValue, 10);
|
||||
cal.set(Calendar.DATE, 1); // for some reason getActualMaximum works incorrectly if date isn't set
|
||||
int actualMaximum = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||
cal.set(Calendar.DAY_OF_MONTH, parseInt(theValue, theValue.substring(8, 10), 1, actualMaximum));
|
||||
precision = TemporalPrecisionEnum.DAY;
|
||||
if (length > 10) {
|
||||
validateLengthIsAtLeast(theValue, 17);
|
||||
validateCharAtIndexIs(theValue, 10, 'T'); // yyyy-mm-ddThh:mm:ss
|
||||
int offsetIdx = getOffsetIndex(theValue);
|
||||
String time;
|
||||
if (offsetIdx == -1) {
|
||||
//throwBadDateFormat(theValue);
|
||||
// No offset - should this be an error?
|
||||
time = theValue.substring(11);
|
||||
} else {
|
||||
time = theValue.substring(11, offsetIdx);
|
||||
String offsetString = theValue.substring(offsetIdx);
|
||||
setTimeZone(offsetString);
|
||||
cal.setTimeZone(getTimeZone());
|
||||
}
|
||||
int timeLength = time.length();
|
||||
|
||||
validateCharAtIndexIs(theValue, 13, ':');
|
||||
cal.set(Calendar.HOUR_OF_DAY, parseInt(theValue, theValue.substring(11, 13), 0, 23));
|
||||
cal.set(Calendar.MINUTE, parseInt(theValue, theValue.substring(14, 16), 0, 59));
|
||||
precision = TemporalPrecisionEnum.MINUTE;
|
||||
if (timeLength > 5) {
|
||||
validateLengthIsAtLeast(theValue, 19);
|
||||
validateCharAtIndexIs(theValue, 16, ':'); // yyyy-mm-ddThh:mm:ss
|
||||
cal.set(Calendar.SECOND, parseInt(theValue, theValue.substring(17, 19), 0, 59));
|
||||
precision = TemporalPrecisionEnum.SECOND;
|
||||
if (timeLength > 8) {
|
||||
validateCharAtIndexIs(theValue, 19, '.'); // yyyy-mm-ddThh:mm:ss.SSSS
|
||||
validateLengthIsAtLeast(theValue, 20);
|
||||
int endIndex = getOffsetIndex(theValue);
|
||||
if (endIndex == -1) {
|
||||
endIndex = theValue.length();
|
||||
}
|
||||
int millis;
|
||||
if (endIndex > 23) {
|
||||
myFractionalSeconds = parseInt(theValue, theValue.substring(20,endIndex), 0, Integer.MAX_VALUE);
|
||||
endIndex = 23;
|
||||
String millisString = theValue.substring(20, endIndex);
|
||||
millis = parseInt(theValue, millisString, 0, 999);
|
||||
} else {
|
||||
String millisString = theValue.substring(20, endIndex);
|
||||
millis = parseInt(theValue, millisString, 0, 999);
|
||||
myFractionalSeconds = millis;
|
||||
}
|
||||
cal.set(Calendar.MILLISECOND, millis);
|
||||
precision = TemporalPrecisionEnum.MILLI;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cal.set(Calendar.DATE, 1);
|
||||
}
|
||||
} else {
|
||||
cal.set(Calendar.DATE, 1);
|
||||
}
|
||||
|
||||
setPrecision(precision);
|
||||
return cal.getTime();
|
||||
|
||||
// try {
|
||||
// if (theValue.length() == 4 && ourYearPattern.matcher(theValue).matches()) {
|
||||
// if (!isPrecisionAllowed(YEAR)) {
|
||||
// ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support YEAR precision): " + theValue);
|
||||
// }
|
||||
// setPrecision(YEAR);
|
||||
// clearTimeZone();
|
||||
// return ((ourYearFormat).parse(theValue));
|
||||
// } else if (theValue.length() == 6 && ourYearMonthPattern.matcher(theValue).matches()) {
|
||||
// // Eg. 198401 (allow this just to be lenient)
|
||||
// if (!isPrecisionAllowed(MONTH)) {
|
||||
// ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support DAY precision): " + theValue);
|
||||
// }
|
||||
// setPrecision(MONTH);
|
||||
// clearTimeZone();
|
||||
// return ((ourYearMonthNoDashesFormat).parse(theValue));
|
||||
// } else if (theValue.length() == 7 && ourYearDashMonthPattern.matcher(theValue).matches()) {
|
||||
// // E.g. 1984-01 (this is valid according to the spec)
|
||||
// if (!isPrecisionAllowed(MONTH)) {
|
||||
// ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support MONTH precision): " + theValue);
|
||||
// }
|
||||
// setPrecision(MONTH);
|
||||
// clearTimeZone();
|
||||
// return ((ourYearMonthFormat).parse(theValue));
|
||||
// } else if (theValue.length() == 8 && ourYearMonthDayPattern.matcher(theValue).matches()) {
|
||||
// // Eg. 19840101 (allow this just to be lenient)
|
||||
// if (!isPrecisionAllowed(DAY)) {
|
||||
// ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support DAY precision): " + theValue);
|
||||
// }
|
||||
// setPrecision(DAY);
|
||||
// clearTimeZone();
|
||||
// return ((ourYearMonthDayNoDashesFormat).parse(theValue));
|
||||
// } else if (theValue.length() == 10 && ourYearDashMonthDashDayPattern.matcher(theValue).matches()) {
|
||||
// // E.g. 1984-01-01 (this is valid according to the spec)
|
||||
// if (!isPrecisionAllowed(DAY)) {
|
||||
// ourLog.debug("Invalid date/time string (datatype " + getClass().getSimpleName() + " does not support DAY precision): " + theValue);
|
||||
// }
|
||||
// setPrecision(DAY);
|
||||
// clearTimeZone();
|
||||
// return ((ourYearMonthDayFormat).parse(theValue));
|
||||
// } else if (theValue.length() >= 18) { // date and time with possible time zone
|
||||
// char timeSeparator = theValue.charAt(10);
|
||||
// if (timeSeparator != 'T') {
|
||||
// throw new DataFormatException("Invalid date/time string: " + theValue);
|
||||
// }
|
||||
// int dotIndex = theValue.indexOf('.', 18);
|
||||
// boolean hasMillis = dotIndex > -1;
|
||||
//
|
||||
// if (!hasMillis && !isPrecisionAllowed(SECOND)) {
|
||||
// ourLog.debug("Invalid date/time string (data type does not support SECONDS precision): " + theValue);
|
||||
// } else if (hasMillis && !isPrecisionAllowed(MILLI)) {
|
||||
// ourLog.debug("Invalid date/time string (data type " + getClass().getSimpleName() + " does not support MILLIS precision):" + theValue);
|
||||
// }
|
||||
//
|
||||
// Date retVal;
|
||||
// if (hasMillis) {
|
||||
// String value = theValue;
|
||||
//
|
||||
// /*
|
||||
// * If we have more than 3 digits of precision after the decimal point, we
|
||||
// * only parse the first 3 since Java Dates don't support more than that and
|
||||
// * FastDateFormat gets confused
|
||||
// */
|
||||
// int offsetIndex = getOffsetIndex(theValue);
|
||||
// if (offsetIndex >= 24) {
|
||||
// value = theValue.substring(0, 23) + theValue.substring(offsetIndex);
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// if (hasOffset(value)) {
|
||||
// retVal = ourYearMonthDayTimeMilliZoneFormat.parse(value);
|
||||
// } else if (value.endsWith("Z")) {
|
||||
// retVal = ourYearMonthDayTimeMilliUTCZFormat.parse(value);
|
||||
// } else {
|
||||
// retVal = ourYearMonthDayTimeMilliFormat.parse(value);
|
||||
// }
|
||||
// } catch (ParseException p2) {
|
||||
// throw new DataFormatException("Invalid data/time string (" + p2.getMessage() + "): " + theValue);
|
||||
// }
|
||||
// setTimeZone(theValue);
|
||||
// setPrecision(TemporalPrecisionEnum.MILLI);
|
||||
// } else {
|
||||
// try {
|
||||
// if (hasOffset(theValue)) {
|
||||
// retVal = ourYearMonthDayTimeZoneFormat.parse(theValue);
|
||||
// } else if (theValue.endsWith("Z")) {
|
||||
// retVal = ourYearMonthDayTimeUTCZFormat.parse(theValue);
|
||||
// } else {
|
||||
// retVal = ourYearMonthDayTimeFormat.parse(theValue);
|
||||
// }
|
||||
// } catch (ParseException p2) {
|
||||
// throw new DataFormatException("Invalid data/time string (" + p2.getMessage() + "): " + theValue);
|
||||
// }
|
||||
//
|
||||
// setTimeZone(theValue);
|
||||
// setPrecision(TemporalPrecisionEnum.SECOND);
|
||||
// }
|
||||
//
|
||||
// return retVal;
|
||||
// } else {
|
||||
// throw new DataFormatException("Invalid date/time string (invalid length): " + theValue);
|
||||
// }
|
||||
// } catch (ParseException e) {
|
||||
// throw new DataFormatException("Invalid date string (" + e.getMessage() + "): " + theValue);
|
||||
// }
|
||||
}
|
||||
|
||||
private int parseInt(String theValue, String theSubstring, int theLowerBound, int theUpperBound) {
|
||||
int retVal = 0;
|
||||
try {
|
||||
retVal = Integer.parseInt(theSubstring);
|
||||
} catch (NumberFormatException e) {
|
||||
throwBadDateFormat(theValue);
|
||||
}
|
||||
|
||||
if (retVal < theLowerBound || retVal > theUpperBound) {
|
||||
throwBadDateFormat(theValue);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -370,33 +447,17 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
updateStringValue();
|
||||
}
|
||||
|
||||
private int getOffsetIndex(String theValueString) {
|
||||
int plusIndex = theValueString.indexOf('+', 19);
|
||||
int minusIndex = theValueString.indexOf('-', 19);
|
||||
int zIndex = theValueString.indexOf('Z', 19);
|
||||
int retVal = Math.max(Math.max(plusIndex, minusIndex), zIndex);
|
||||
if (retVal == -1) {
|
||||
return -1;
|
||||
}
|
||||
if ((retVal - 2) != (plusIndex + minusIndex + zIndex)) {
|
||||
// This means we have more than one separator
|
||||
throw new DataFormatException("Invalid FHIR date/time string: " + theValueString);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private BaseDateTimeDt setTimeZone(String theValueString) {
|
||||
clearTimeZone();
|
||||
|
||||
int sepIndex = getOffsetIndex(theValueString);
|
||||
if (sepIndex != -1) {
|
||||
if (theValueString.charAt(sepIndex) == 'Z') {
|
||||
if (isBlank(theValueString)) {
|
||||
throw new DataFormatException("Invalid time zone offset string: \"" + theValueString + "\"");
|
||||
}
|
||||
clearTimeZone();
|
||||
if (theValueString.charAt(0) == 'Z') {
|
||||
setTimeZoneZulu(true);
|
||||
} else {
|
||||
String offsetString = theValueString.substring(sepIndex);
|
||||
setTimeZone(TimeZone.getTimeZone("GMT" + offsetString));
|
||||
setTimeZone(TimeZone.getTimeZone("GMT" + theValueString));
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -439,6 +500,10 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
setTimeZone(TimeZone.getDefault());
|
||||
myPrecision = thePrecision;
|
||||
super.setValue(theValue);
|
||||
myFractionalSeconds = 0;
|
||||
if (theValue != null) {
|
||||
myFractionalSeconds = (int) (theValue.getTime() % 1000);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -447,6 +512,14 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
super.setValueAsString(theValue);
|
||||
}
|
||||
|
||||
private void throwBadDateFormat(String theValue) {
|
||||
throw new DataFormatException("Invalid date/time format: \"" + theValue + "\"");
|
||||
}
|
||||
|
||||
private void throwBadDateFormat(String theValue, String theMesssage) {
|
||||
throw new DataFormatException("Invalid date/time format: \"" + theValue + "\": " + theMesssage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human readable version of this date/time using the system local format.
|
||||
* <p>
|
||||
|
@ -493,11 +566,16 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For unit tests only
|
||||
*/
|
||||
static List<FastDateFormat> getFormatters() {
|
||||
return ourFormatters;
|
||||
private void validateCharAtIndexIs(String theValue, int theIndex, char theChar) {
|
||||
if (theValue.charAt(theIndex) != theChar) {
|
||||
throwBadDateFormat(theValue, "Expected character '" + theChar + "' at index " + theIndex + " but found " + theValue.charAt(theIndex));
|
||||
}
|
||||
}
|
||||
|
||||
private void validateLengthIsAtLeast(String theValue, int theLength) {
|
||||
if (theValue.length() < theLength) {
|
||||
throwBadDateFormat(theValue);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1109,6 +1109,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
|
||||
if (theEntity.getPublished() == null) {
|
||||
ourLog.info("Entity has published time: {}", new InstantDt(theUpdateTime));
|
||||
|
||||
theEntity.setPublished(theUpdateTime);
|
||||
}
|
||||
|
||||
|
@ -1187,7 +1189,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
coordsParams = extractSearchParamCoords(theEntity, theResource);
|
||||
|
||||
// ourLog.info("Indexing resource: {}", entity.getId());
|
||||
ourLog.trace("Storing string indexes: {}", stringParams);
|
||||
ourLog.info("Storing date indexes: {}", dateParams);
|
||||
|
||||
tokenParams = new HashSet<ResourceIndexedSearchParamToken>();
|
||||
for (BaseResourceIndexedSearchParam next : extractSearchParamTokens(theEntity, theResource)) {
|
||||
|
|
|
@ -2053,6 +2053,7 @@ public class SearchBuilder {
|
|||
List<Predicate> lastUpdatedPredicates = new ArrayList<Predicate>();
|
||||
if (theLastUpdated != null) {
|
||||
if (theLastUpdated.getLowerBoundAsInstant() != null) {
|
||||
ourLog.info("LastUpdated lower bound: {}", new InstantDt(theLastUpdated.getLowerBoundAsInstant()));
|
||||
Predicate predicateLower = builder.greaterThanOrEqualTo(from.<Date> get("myUpdated"), theLastUpdated.getLowerBoundAsInstant());
|
||||
lastUpdatedPredicates.add(predicateLower);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
|
|||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.hibernate.search.annotations.Field;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
|
||||
//@formatter:off
|
||||
@Embeddable
|
||||
@Entity
|
||||
|
@ -139,8 +141,8 @@ public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchPar
|
|||
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
||||
b.append("paramName", getParamName());
|
||||
b.append("resourceId", getResource().getId()); // TODO: add a field so we don't need to resolve this
|
||||
b.append("valueLow", getValueLow());
|
||||
b.append("valueHigh", getValueHigh());
|
||||
b.append("valueLow", new InstantDt(getValueLow()));
|
||||
b.append("valueHigh", new InstantDt(getValueHigh()));
|
||||
return b.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1591,16 +1591,7 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
|
|||
id2 = (IdDt) ourClient.create().resource(patient).execute().getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
{
|
||||
//@formatter:off
|
||||
Bundle found = ourClient.search()
|
||||
.forResource(Patient.class)
|
||||
.where(Patient.NAME.matches().value("testSearchLastUpdatedParamRp"))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
List<IdDt> patients = toIdListUnqualifiedVersionless(found);
|
||||
assertThat(patients, hasItems(id1a, id1b, id2));
|
||||
}
|
||||
ourLog.info("Before: {}", beforeAny.getValue());
|
||||
{
|
||||
//@formatter:off
|
||||
Bundle found = ourClient.search()
|
||||
|
@ -1612,6 +1603,18 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
|
|||
List<IdDt> patients = toIdListUnqualifiedVersionless(found);
|
||||
assertThat(patients, hasItems(id1a, id1b, id2));
|
||||
}
|
||||
|
||||
{
|
||||
//@formatter:off
|
||||
Bundle found = ourClient.search()
|
||||
.forResource(Patient.class)
|
||||
.where(Patient.NAME.matches().value("testSearchLastUpdatedParamRp"))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
List<IdDt> patients = toIdListUnqualifiedVersionless(found);
|
||||
assertThat(patients, hasItems(id1a, id1b, id2));
|
||||
}
|
||||
|
||||
{
|
||||
//@formatter:off
|
||||
Bundle found = ourClient.search()
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
package ca.uhn.fhir.model.primitive;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.commons.lang3.time.FastDateFormat;
|
||||
|
@ -15,6 +18,7 @@ import org.hamcrest.Matchers;
|
|||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
|
@ -53,6 +57,10 @@ public class BaseDateTimeDtTest {
|
|||
assertThat(out, containsString("<birthDate value=\"2012-01-02\"/>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseDate() {
|
||||
new DateDt("2012-03-31");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setTimezoneToZulu() {
|
||||
|
@ -126,7 +134,22 @@ public class BaseDateTimeDtTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See #381
|
||||
*/
|
||||
@Test
|
||||
public void testParseFailsForInvalidDate() {
|
||||
try {
|
||||
DateTimeDt dt = new DateTimeDt("9999-13-01");
|
||||
fail(dt.getValue().toString());
|
||||
} catch (DataFormatException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testFormats() throws Exception {
|
||||
Date instant = myDateInstantParser.parse("2001-02-03 13:01:02.555");
|
||||
for (FastDateFormat next : BaseDateTimeDt.getFormatters()) {
|
||||
|
@ -156,11 +179,9 @@ public class BaseDateTimeDtTest {
|
|||
assertEquals(TemporalPrecisionEnum.DAY, dt.getPrecision());
|
||||
}
|
||||
|
||||
@Test()
|
||||
@Test(expected=DataFormatException.class)
|
||||
public void testParseMalformatted() throws DataFormatException {
|
||||
DateTimeDt dt = new DateTimeDt("20120102");
|
||||
assertEquals("20120102", dt.getValueAsString());
|
||||
assertEquals("2012-01-02", new SimpleDateFormat("yyyy-MM-dd").format(dt.getValue()));
|
||||
new DateTimeDt("20120102");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -195,7 +216,7 @@ public class BaseDateTimeDtTest {
|
|||
assertEquals("2013-02-03 09:22:33.234-0200", myDateInstantZoneParser.format(dt.getValue()));
|
||||
assertEquals("2013-02-03T11:22:33.234Z", dt.getValueAsString());
|
||||
assertEquals(true, dt.isTimeZoneZulu());
|
||||
assertNull(dt.getTimeZone());
|
||||
assertEquals("GMT", dt.getTimeZone().getID());
|
||||
assertEquals(TemporalPrecisionEnum.MILLI, dt.getPrecision());
|
||||
}
|
||||
|
||||
|
@ -204,23 +225,19 @@ public class BaseDateTimeDtTest {
|
|||
DateTimeDt dt = new DateTimeDt();
|
||||
dt.setValueAsString("2013-02");
|
||||
|
||||
assertEquals("2013-02", myDateInstantParser.format(dt.getValue()).substring(0, 7));
|
||||
ourLog.info("Date: {}", dt.getValue());
|
||||
assertEquals("2013-02", dt.getValueAsString());
|
||||
assertEquals(false, dt.isTimeZoneZulu());
|
||||
assertNull(dt.getTimeZone());
|
||||
assertEquals(TemporalPrecisionEnum.MONTH, dt.getPrecision());
|
||||
|
||||
assertEquals("2013-02", myDateInstantParser.format(dt.getValue()).substring(0, 7));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected=DataFormatException.class)
|
||||
public void testParseMonthNoDashes() throws DataFormatException {
|
||||
DateTimeDt dt = new DateTimeDt();
|
||||
dt.setValueAsString("201302");
|
||||
|
||||
assertEquals("2013-02", myDateInstantParser.format(dt.getValue()).substring(0, 7));
|
||||
assertEquals("201302", dt.getValueAsString());
|
||||
assertEquals(false, dt.isTimeZoneZulu());
|
||||
assertNull(dt.getTimeZone());
|
||||
assertEquals(TemporalPrecisionEnum.MONTH, dt.getPrecision());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -242,7 +259,7 @@ public class BaseDateTimeDtTest {
|
|||
|
||||
assertEquals("2013-02-03T11:22:33Z", dt.getValueAsString());
|
||||
assertEquals(true, dt.isTimeZoneZulu());
|
||||
assertEquals(null, dt.getTimeZone());
|
||||
assertEquals("GMT", dt.getTimeZone().getID());
|
||||
assertEquals(TemporalPrecisionEnum.SECOND, dt.getPrecision());
|
||||
}
|
||||
|
||||
|
@ -281,7 +298,6 @@ public class BaseDateTimeDtTest {
|
|||
assertEquals("2014-06-20T20:22:09Z", i.getValueAsString());
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
|
|
|
@ -151,7 +151,7 @@ public class XmlParserTest {
|
|||
MyPatientWithUnorderedExtensions pat = new MyPatientWithUnorderedExtensions();
|
||||
pat.getExtAtt1().setValue(true);
|
||||
pat.getExtAtt2().setValue("val2");
|
||||
pat.getExtAtt3().setValueAsString("20110102");
|
||||
pat.getExtAtt3().setValueAsString("2011-01-02");
|
||||
|
||||
String string = ourCtx.newXmlParser().encodeResourceToString(pat);
|
||||
ourLog.info(string);
|
||||
|
@ -160,7 +160,7 @@ public class XmlParserTest {
|
|||
assertThat(string, stringContainsInOrder(Arrays.asList(
|
||||
"<extension url=\"urn:ex1\"><valueBoolean value=\"true\"/></extension>",
|
||||
"<extension url=\"urn:ex2\"><valueString value=\"val2\"/></extension>",
|
||||
"<extension url=\"urn:ex3\"><valueDate value=\"20110102\"/></extension>"
|
||||
"<extension url=\"urn:ex3\"><valueDate value=\"2011-01-02\"/></extension>"
|
||||
)));
|
||||
//@formatter:on
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
|||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.dstu.valueset.ContactSystemEnum;
|
||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class ResourceValidatorTest {
|
||||
|
@ -71,21 +72,18 @@ public class ResourceValidatorTest {
|
|||
/**
|
||||
* See issue #50
|
||||
*/
|
||||
@Test
|
||||
@Test(expected=DataFormatException.class)
|
||||
public void testOutOfBoundsDate() {
|
||||
Patient p = new Patient();
|
||||
p.setBirthDate(new DateTimeDt("2000-15-31"));
|
||||
p.setBirthDate(new DateTimeDt("2000-12-31"));
|
||||
|
||||
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
|
||||
// Put in an invalid date
|
||||
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p).replace("2000-12-31", "2000-15-31");
|
||||
ourLog.info(encoded);
|
||||
|
||||
assertThat(encoded, StringContains.containsString("2000-15-31"));
|
||||
|
||||
p = ourCtx.newXmlParser().parseResource(Patient.class, encoded);
|
||||
assertEquals("2000-15-31", p.getBirthDate().getValueAsString());
|
||||
assertEquals("2001-03-31", new SimpleDateFormat("yyyy-MM-dd").format(p.getBirthDate().getValue()));
|
||||
|
||||
ValidationResult result = ourCtx.newValidator().validateWithResult(p);
|
||||
ValidationResult result = ourCtx.newValidator().validateWithResult(encoded);
|
||||
String resultString = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
|
||||
ourLog.info(resultString);
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package ca.uhn.fhir.model.primitive;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
@ -36,6 +38,24 @@ public class BaseDateTimeDtDstu2Test {
|
|||
myDateInstantParser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testLargePrecision() {
|
||||
DateTimeDt dt = new DateTimeDt("2014-03-06T22:09:58.9121174+04:30");
|
||||
|
||||
myDateInstantParser.setTimeZone(TimeZone.getTimeZone("Z"));
|
||||
assertEquals("2014-03-06 17:39:58.912", myDateInstantParser.format(dt.getValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeOffset() throws Exception {
|
||||
myDateInstantParser.parse("2011-01-01 11:11:11.0");
|
||||
myDateInstantParser.setTimeZone(TimeZone.getTimeZone("America/Toronto"));
|
||||
String offset = InstantDt.withCurrentTime().setTimeZone(TimeZone.getTimeZone("America/Toronto")).getValueAsString();
|
||||
assertThat(offset, endsWith("-05:00"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testParseInvalid() {
|
||||
try {
|
||||
|
@ -43,14 +63,14 @@ public class BaseDateTimeDtDstu2Test {
|
|||
dt.setValueAsString("1974-12-25+10:00");
|
||||
fail();
|
||||
} catch (ca.uhn.fhir.parser.DataFormatException e) {
|
||||
assertEquals("Invalid date/time string (invalid length): 1974-12-25+10:00", e.getMessage());
|
||||
assertEquals("Invalid date/time format: \"1974-12-25+10:00\"", e.getMessage());
|
||||
}
|
||||
try {
|
||||
DateTimeDt dt = new DateTimeDt();
|
||||
dt.setValueAsString("1974-12-25Z");
|
||||
fail();
|
||||
} catch (ca.uhn.fhir.parser.DataFormatException e) {
|
||||
assertEquals("Invalid date/time string (invalid length): 1974-12-25Z", e.getMessage());
|
||||
assertEquals("Invalid date/time format: \"1974-12-25Z\"", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,7 +156,7 @@ public class BaseDateTimeDtDstu2Test {
|
|||
assertEquals(-32400000L, dt.getTimeZone().getRawOffset());
|
||||
|
||||
dt.setTimeZoneZulu(true);
|
||||
assertEquals("2010-01-01T09:00:00.123Z", dt.getValueAsString());
|
||||
assertEquals("2010-01-01T09:00:00.1234Z", dt.getValueAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -151,7 +171,7 @@ public class BaseDateTimeDtDstu2Test {
|
|||
assertEquals(-32400000L, dt.getTimeZone().getRawOffset());
|
||||
|
||||
dt.setTimeZoneZulu(true);
|
||||
assertEquals("2010-01-01T09:00:00.123Z", dt.getValueAsString());
|
||||
assertEquals("2010-01-01T09:00:00.12345Z", dt.getValueAsString());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package ca.uhn.fhir.rest.param;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
|
||||
public class DateParamTest {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DateParamTest.class);
|
||||
|
||||
@Test
|
||||
public void testParse() {
|
||||
Date date = new Date();
|
||||
|
||||
DateParam param = new DateParam();
|
||||
param.setValueAsString("gt2016-06-09T20:38:14.591-05:00");
|
||||
|
||||
assertEquals(ParamPrefixEnum.GREATERTHAN, param.getPrefix());
|
||||
assertEquals("2016-06-09T20:38:14.591-05:00", 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-09T21:38:14.591-04:00", dt.getValueAsString());
|
||||
}
|
||||
|
||||
}
|
|
@ -11,6 +11,7 @@ import static org.junit.Assert.assertTrue;
|
|||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
@ -41,6 +42,7 @@ import ca.uhn.fhir.model.dstu2.valueset.UnitsOfTimeEnum;
|
|||
import ca.uhn.fhir.model.primitive.DateDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.parser.XmlParserDstu2Test.TestPatientFor327;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
@ -69,7 +71,7 @@ public class ResourceValidatorDstu2Test {
|
|||
/**
|
||||
* See issue #50
|
||||
*/
|
||||
@Test
|
||||
@Test(expected=DataFormatException.class)
|
||||
public void testOutOfBoundsDate() {
|
||||
Patient p = new Patient();
|
||||
p.setBirthDate(new DateDt("2000-15-31"));
|
||||
|
|
|
@ -17,8 +17,13 @@ import org.hl7.fhir.dstu3.hapi.validation.DefaultProfileValidationSupport;
|
|||
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.HapiWorkerContext;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport.CodeValidationResult;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.ValidationSupportChain;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.ConformanceResourceStatus;
|
||||
import org.hl7.fhir.dstu3.model.CodeType;
|
||||
import org.hl7.fhir.dstu3.model.Coding;
|
||||
import org.hl7.fhir.dstu3.model.IntegerType;
|
||||
import org.hl7.fhir.dstu3.model.Questionnaire;
|
||||
|
@ -35,6 +40,7 @@ import org.hl7.fhir.dstu3.utils.IWorkerContext;
|
|||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.internal.stubbing.answers.ThrowsException;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
@ -105,14 +111,16 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq("http://example.com/Questionnaire/q1"))).thenReturn(q);
|
||||
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
|
||||
codeSystem.setUrl("http://codesystems.com/system");
|
||||
codeSystem.addConcept().setCode("code0");
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(CodeSystem.class), eq("http://codesystems.com/system"))).thenReturn(codeSystem);
|
||||
when(myValSupport.fetchCodeSystem(any(FhirContext.class), eq("http://codesystems.com/system"))).thenReturn(codeSystem);
|
||||
|
||||
CodeSystem codeSystem2 = new CodeSystem();
|
||||
codeSystem2.setContent(CodeSystemContentMode.COMPLETE);
|
||||
codeSystem2.setUrl("http://codesystems.com/system2");
|
||||
codeSystem2.addConcept().setCode("code2");
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(CodeSystem.class), eq("http://codesystems.com/system2"))).thenReturn(codeSystem2);
|
||||
when(myValSupport.fetchCodeSystem(any(FhirContext.class), eq("http://codesystems.com/system2"))).thenReturn(codeSystem2);
|
||||
|
||||
ValueSet options = new ValueSet();
|
||||
options.getCompose().addInclude().setSystem("http://codesystems.com/system").addConcept().setCode("code0");
|
||||
|
@ -226,20 +234,24 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(questionnaireRef))).thenReturn(q);
|
||||
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
|
||||
codeSystem.setUrl("http://codesystems.com/system");
|
||||
codeSystem.addConcept().setCode("code0");
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(CodeSystem.class), eq("http://codesystems.com/system"))).thenReturn(codeSystem);
|
||||
when(myValSupport.fetchCodeSystem(any(FhirContext.class), eq("http://codesystems.com/system"))).thenReturn(codeSystem);
|
||||
|
||||
CodeSystem codeSystem2 = new CodeSystem();
|
||||
codeSystem2.setContent(CodeSystemContentMode.COMPLETE);
|
||||
codeSystem2.setUrl("http://codesystems.com/system2");
|
||||
codeSystem2.addConcept().setCode("code2");
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(CodeSystem.class), eq("http://codesystems.com/system2"))).thenReturn(codeSystem2);
|
||||
when(myValSupport.fetchCodeSystem(any(FhirContext.class), eq("http://codesystems.com/system2"))).thenReturn(codeSystem2);
|
||||
|
||||
ValueSet options = new ValueSet();
|
||||
options.getCompose().addInclude().setSystem("http://codesystems.com/system").addConcept().setCode("code0");
|
||||
options.getCompose().addInclude().setSystem("http://codesystems.com/system2").addConcept().setCode("code2");
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(ValueSet.class), eq("http://somevalueset"))).thenReturn(options);
|
||||
|
||||
when(myValSupport.validateCode(any(FhirContext.class), eq("http://codesystems.com/system"), eq("code0"), any(String.class))).thenReturn(new CodeValidationResult(new ConceptDefinitionComponent(new CodeType("code0"))));
|
||||
|
||||
QuestionnaireResponse qa;
|
||||
ValidationResult errors;
|
||||
|
||||
|
|
Loading…
Reference in New Issue