Ensure ' ' is treated as '+' in timezones with offsets. (#6115)
This commit is contained in:
parent
13e2d41165
commit
e3b749e61b
|
@ -230,17 +230,41 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
return Long.parseLong(retVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the offset for a timestamp. If it exists. An offset may start either with '-', 'Z', '+', or ' '.
|
||||
* <p/>
|
||||
* There is a special case where ' ' is considered a valid offset initial character and this is because when
|
||||
* handling URLs with timestamps, '+' is considered an escape character for ' ', so '+' may have been replaced with
|
||||
* ' ' by the time execution reaches this method. This is why this method handles both characters.
|
||||
*
|
||||
* @param theValueString A timestamp containing either a timezone offset or nothing.
|
||||
* @return The index of the offset portion of the timestamp, if applicable, otherwise -1
|
||||
*/
|
||||
private int getOffsetIndex(String theValueString) {
|
||||
int plusIndex = theValueString.indexOf('+', 16);
|
||||
int spaceIndex = 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) {
|
||||
int maxIndexPlusAndMinus = Math.max(Math.max(plusIndex, minusIndex), zIndex);
|
||||
int maxIndexSpaceAndMinus = Math.max(Math.max(spaceIndex, minusIndex), zIndex);
|
||||
if (maxIndexPlusAndMinus == -1 && maxIndexSpaceAndMinus == -1) {
|
||||
return -1;
|
||||
}
|
||||
if ((retVal - 2) != (plusIndex + minusIndex + zIndex)) {
|
||||
throwBadDateFormat(theValueString);
|
||||
int retVal = 0;
|
||||
if (maxIndexPlusAndMinus != -1) {
|
||||
if ((maxIndexPlusAndMinus - 2) != (plusIndex + minusIndex + zIndex)) {
|
||||
throwBadDateFormat(theValueString);
|
||||
}
|
||||
retVal = maxIndexPlusAndMinus;
|
||||
}
|
||||
|
||||
if (maxIndexSpaceAndMinus != -1) {
|
||||
if ((maxIndexSpaceAndMinus - 2) != (spaceIndex + minusIndex + zIndex)) {
|
||||
throwBadDateFormat(theValueString);
|
||||
}
|
||||
retVal = maxIndexSpaceAndMinus;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
@ -574,13 +598,15 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||
setTimeZoneZulu(true);
|
||||
} else if (theValue.length() != 6) {
|
||||
throwBadDateFormat(theWholeValue, "Timezone offset must be in the form \"Z\", \"-HH:mm\", or \"+HH:mm\"");
|
||||
} else if (theValue.charAt(3) != ':' || !(theValue.charAt(0) == '+' || theValue.charAt(0) == '-')) {
|
||||
} else if (theValue.charAt(3) != ':'
|
||||
|| !(theValue.charAt(0) == '+' || theValue.charAt(0) == ' ' || theValue.charAt(0) == '-')) {
|
||||
throwBadDateFormat(theWholeValue, "Timezone offset must be in the form \"Z\", \"-HH:mm\", or \"+HH:mm\"");
|
||||
} else {
|
||||
parseInt(theWholeValue, theValue.substring(1, 3), 0, 23);
|
||||
parseInt(theWholeValue, theValue.substring(4, 6), 0, 59);
|
||||
clearTimeZone();
|
||||
setTimeZone(getTimeZone("GMT" + theValue));
|
||||
final String valueToUse = theValue.startsWith(" ") ? theValue.replace(' ', '+') : theValue;
|
||||
setTimeZone(getTimeZone("GMT" + valueToUse));
|
||||
}
|
||||
|
||||
return this;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 6094
|
||||
jira: SMILE-8693
|
||||
title: "Searching or conditional creating/updating with a timestamp with an offset containing '+' fails with HAPI-1883.
|
||||
For example: 'Observation?date=2024-07-08T20:47:12.123+03:30'
|
||||
This has been fixed."
|
|
@ -13,6 +13,8 @@ import org.junit.jupiter.api.AfterAll;
|
|||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
|
@ -721,6 +723,22 @@ public class BaseDateTimeDtDstu2Test {
|
|||
assertEquals("2010-01-01T09:00:00.12345Z", dt.getValueAsString());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"2024-07-08T20:47:12.123+03:30", "2024-07-08T20:47:12.123 03:30"})
|
||||
public void testParseTimeZonePositiveOffset(String theTimestampLiteral) {
|
||||
myDateInstantParser.setTimeZone(TimeZone.getTimeZone("Asia/Tehran"));
|
||||
|
||||
final DateTimeDt dt = new DateTimeDt(theTimestampLiteral);
|
||||
|
||||
assertEquals(theTimestampLiteral, dt.getValueAsString());
|
||||
assertEquals("2024-07-08 20:47:12.123", myDateInstantParser.format(dt.getValue()));
|
||||
assertEquals("GMT+03:30", dt.getTimeZone().getID());
|
||||
assertEquals(12600000, dt.getTimeZone().getRawOffset());
|
||||
|
||||
dt.setTimeZoneZulu(true);
|
||||
assertEquals("2024-07-08T17:17:12.123Z", dt.getValueAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseYear() throws DataFormatException {
|
||||
DateTimeDt dt = new DateTimeDt();
|
||||
|
|
Loading…
Reference in New Issue