[OLINGO-1408] Support new date time API (#57)
* Fix usage of Calendar in tests The tests use Calendar instances. For some test cases the time zone of a Calendar instance is changed and then passed to the valueToString method. Unfortunately after just changing the time zone the Calendar only changes the time zone but not the value of the calculated fields like YEAR, MONTH, ... . These fields are recalculated only if they are read by get(YEAR), get(MONTH), ... . The implementation of valueToString clones the Calendar instance before fields are computed resulting in a corrupt clone. This change 1) makes sure that the test the fields in the Calendar instances used in the tests are computed 2) makes sure that the valueToString method triggers a computation of the fields before cloning the Calendar * Support types of new Date/Time API The types of the new Date/Time API can now be used as property values. The following mappings are now supported EdmDateTimeOffset - java.time.Instant - java.time.ZonedDateTime - java.util.Calendar - java.util.Date - java.sql.Timestamp - java.lang.Long EdmDate - java.time.LocalDate - java.sql.Date EdmTimeOfDay - java.time.LocalTime - java.sql.Time Only these mappings capture the semantics correctly. For legacy reasons also supported are the following mappings are still supported: EdmDate - java.util.Calendar (date component in the TZ of the calendar) - java.util.Date (date component in UTC) - java.sql.Timestamp (date component in UTC) - java.lang.Long (date component in UTC) EdmTimeOfDay - java.util.Calendar (time component in the TZ of the calendar) - java.util.Date (time component in UTC) - java.sql.Timestamp (time component in UTC) - java.lang.Long (time component in UTC) For legacy reasons the default mapping types are unchanged (and remain semantically incorrect): EdmDateTimeOffset -> java.sql.Timestamp EdmDate -> java.util.Calendar EdmTimeOfDay -> java.util.Calendar * Allow additional (but semantically wrong) conversions EdmDate -> java.util.Date, java.sql.Timestamp EdmTimeOfDay -> java.util.Date, java.sql.Timestamp
This commit is contained in:
parent
98d445a874
commit
932af8fb5d
|
@ -18,9 +18,15 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.olingo.commons.core.edm.primitivetype;
|
package org.apache.olingo.commons.core.edm.primitivetype;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.regex.Matcher;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||||
|
|
||||||
|
@ -29,8 +35,6 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||||
*/
|
*/
|
||||||
public final class EdmDate extends SingletonPrimitiveType {
|
public final class EdmDate extends SingletonPrimitiveType {
|
||||||
|
|
||||||
private static final Pattern PATTERN = Pattern.compile("(-?\\p{Digit}{4,})-(\\p{Digit}{2})-(\\p{Digit}{2})");
|
|
||||||
|
|
||||||
private static final EdmDate INSTANCE = new EdmDate();
|
private static final EdmDate INSTANCE = new EdmDate();
|
||||||
|
|
||||||
public static EdmDate getInstance() {
|
public static EdmDate getInstance() {
|
||||||
|
@ -42,52 +46,69 @@ public final class EdmDate extends SingletonPrimitiveType {
|
||||||
return Calendar.class;
|
return Calendar.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
protected <T> T internalValueOfString(final String value,
|
protected <T> T internalValueOfString(final String value, final Boolean isNullable, final Integer maxLength,
|
||||||
final Boolean isNullable, final Integer maxLength, final Integer precision,
|
final Integer precision, final Integer scale, final Boolean isUnicode, final Class<T> returnType)
|
||||||
final Integer scale, final Boolean isUnicode, final Class<T> returnType) throws EdmPrimitiveTypeException {
|
throws EdmPrimitiveTypeException {
|
||||||
|
LocalDate date;
|
||||||
final Calendar dateTimeValue = Calendar.getInstance();
|
try {
|
||||||
dateTimeValue.clear();
|
date = LocalDate.parse(value);
|
||||||
|
} catch (DateTimeParseException ex) {
|
||||||
final Matcher matcher = PATTERN.matcher(value);
|
|
||||||
if (!matcher.matches()) {
|
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
|
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
|
||||||
}
|
}
|
||||||
|
|
||||||
dateTimeValue.set(
|
// appropriate types
|
||||||
Integer.parseInt(matcher.group(1)),
|
if (returnType.isAssignableFrom(LocalDate.class)) {
|
||||||
Byte.parseByte(matcher.group(2)) - 1, // month is zero-based
|
return (T) date;
|
||||||
Byte.parseByte(matcher.group(3)));
|
} else if (returnType.isAssignableFrom(java.sql.Date.class)) {
|
||||||
|
return (T) java.sql.Date.valueOf(date);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
// inappropriate types, which need to be supported for backward compatibility
|
||||||
return EdmDateTimeOffset.convertDateTime(dateTimeValue, 0, returnType);
|
ZonedDateTime zdt = LocalDateTime.of(date, LocalTime.MIDNIGHT).atZone(ZoneId.systemDefault());
|
||||||
} catch (final IllegalArgumentException e) {
|
if (returnType.isAssignableFrom(Calendar.class)) {
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.", e);
|
return (T) GregorianCalendar.from(zdt);
|
||||||
} catch (final ClassCastException e) {
|
} else if (returnType.isAssignableFrom(Long.class)) {
|
||||||
throw new EdmPrimitiveTypeException("The value type " + returnType + " is not supported.", e);
|
return (T) Long.valueOf(zdt.toInstant().toEpochMilli());
|
||||||
|
} else if (returnType.isAssignableFrom(java.sql.Date.class)) {
|
||||||
|
throw new EdmPrimitiveTypeException("The value type " + returnType + " is not supported.");
|
||||||
|
} else if (returnType.isAssignableFrom(java.sql.Timestamp.class)) {
|
||||||
|
return (T) java.sql.Timestamp.from(zdt.toInstant());
|
||||||
|
} else if (returnType.isAssignableFrom(java.util.Date.class)) {
|
||||||
|
return (T) java.util.Date.from(zdt.toInstant());
|
||||||
|
} else {
|
||||||
|
throw new EdmPrimitiveTypeException("The value type " + returnType + " is not supported.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <T> String internalValueToString(final T value,
|
protected <T> String internalValueToString(final T value, final Boolean isNullable, final Integer maxLength,
|
||||||
final Boolean isNullable, final Integer maxLength, final Integer precision,
|
final Integer precision, final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException {
|
||||||
final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException {
|
// appropriate types
|
||||||
|
if (value instanceof LocalDate) {
|
||||||
|
return value.toString();
|
||||||
|
} else if(value instanceof java.sql.Date) {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
final Calendar dateTimeValue = EdmDateTimeOffset.createDateTime(value, true);
|
// inappropriate types, which need to be supported for backward compatibility
|
||||||
|
if (value instanceof GregorianCalendar) {
|
||||||
|
GregorianCalendar calendar = (GregorianCalendar) value;
|
||||||
|
return calendar.toZonedDateTime().toLocalDate().toString();
|
||||||
|
}
|
||||||
|
|
||||||
final StringBuilder result = new StringBuilder(10); // Ten characters are enough for "normal" dates.
|
long millis;
|
||||||
final int year = dateTimeValue.get(Calendar.YEAR);
|
if (value instanceof Long) {
|
||||||
if (year < 0 || year >= 10000) {
|
millis = (Long)value;
|
||||||
result.append(year);
|
} else if (value instanceof java.util.Date) {
|
||||||
|
millis = ((java.util.Date)value).getTime();
|
||||||
} else {
|
} else {
|
||||||
EdmDateTimeOffset.appendTwoDigits(result, (year / 100) % 100);
|
throw new EdmPrimitiveTypeException("The value type " + value.getClass() + " is not supported.");
|
||||||
EdmDateTimeOffset.appendTwoDigits(result, year % 100);
|
|
||||||
}
|
}
|
||||||
result.append('-');
|
|
||||||
EdmDateTimeOffset.appendTwoDigits(result, dateTimeValue.get(Calendar.MONTH) + 1); // month is zero-based
|
ZonedDateTime zdt = Instant.ofEpochMilli(millis).atZone(ZoneId.systemDefault());
|
||||||
result.append('-');
|
|
||||||
EdmDateTimeOffset.appendTwoDigits(result, dateTimeValue.get(Calendar.DAY_OF_MONTH));
|
return zdt.toLocalDate().toString();
|
||||||
return result.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,16 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.olingo.commons.core.edm.primitivetype;
|
package org.apache.olingo.commons.core.edm.primitivetype;
|
||||||
|
|
||||||
import java.sql.Time;
|
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.TimeZone;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@ -33,8 +38,9 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||||
*/
|
*/
|
||||||
public final class EdmDateTimeOffset extends SingletonPrimitiveType {
|
public final class EdmDateTimeOffset extends SingletonPrimitiveType {
|
||||||
|
|
||||||
private static final Pattern PATTERN = Pattern.compile(
|
private static final ZoneId ZULU = ZoneId.of("Z");
|
||||||
"(-?\\p{Digit}{4,})-(\\p{Digit}{2})-(\\p{Digit}{2})"
|
|
||||||
|
private static final Pattern PATTERN = Pattern.compile("(-?\\p{Digit}{4,})-(\\p{Digit}{2})-(\\p{Digit}{2})"
|
||||||
+ "T(\\p{Digit}{2}):(\\p{Digit}{2})(?::(\\p{Digit}{2})(\\.(\\p{Digit}{0,12}?)0*)?)?"
|
+ "T(\\p{Digit}{2}):(\\p{Digit}{2})(?::(\\p{Digit}{2})(\\.(\\p{Digit}{0,12}?)0*)?)?"
|
||||||
+ "(Z|([-+]\\p{Digit}{2}:\\p{Digit}{2}))?");
|
+ "(Z|([-+]\\p{Digit}{2}:\\p{Digit}{2}))?");
|
||||||
|
|
||||||
|
@ -50,228 +56,126 @@ public final class EdmDateTimeOffset extends SingletonPrimitiveType {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <T> T internalValueOfString(final String value,
|
protected <T> T internalValueOfString(final String value, final Boolean isNullable, final Integer maxLength,
|
||||||
final Boolean isNullable, final Integer maxLength, final Integer precision,
|
final Integer precision, final Integer scale, final Boolean isUnicode, final Class<T> returnType)
|
||||||
final Integer scale, final Boolean isUnicode, final Class<T> returnType) throws EdmPrimitiveTypeException {
|
throws EdmPrimitiveTypeException {
|
||||||
|
|
||||||
final Matcher matcher = PATTERN.matcher(value);
|
|
||||||
if (!matcher.matches()) {
|
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
|
|
||||||
}
|
|
||||||
|
|
||||||
final String timeZoneOffset = matcher.group(9) == null || matcher.group(10) == null
|
|
||||||
|| matcher.group(10).matches("[-+]0+:0+") ? "" : matcher.group(10);
|
|
||||||
final Calendar dateTimeValue = Calendar.getInstance(TimeZone.getTimeZone("GMT" + timeZoneOffset));
|
|
||||||
if (dateTimeValue.get(Calendar.ZONE_OFFSET) == 0 && !timeZoneOffset.isEmpty()) {
|
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
|
|
||||||
}
|
|
||||||
dateTimeValue.clear();
|
|
||||||
|
|
||||||
dateTimeValue.set(
|
|
||||||
Short.parseShort(matcher.group(1)),
|
|
||||||
Byte.parseByte(matcher.group(2)) - 1, // month is zero-based
|
|
||||||
Byte.parseByte(matcher.group(3)),
|
|
||||||
Byte.parseByte(matcher.group(4)),
|
|
||||||
Byte.parseByte(matcher.group(5)),
|
|
||||||
matcher.group(6) == null ? 0 : Byte.parseByte(matcher.group(6)));
|
|
||||||
|
|
||||||
int nanoSeconds = 0;
|
|
||||||
if (matcher.group(7) != null) {
|
|
||||||
if (matcher.group(7).length() == 1 || matcher.group(7).length() > 13) {
|
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
|
|
||||||
}
|
|
||||||
final String decimals = matcher.group(8);
|
|
||||||
if (decimals.length() > (precision == null ? 0 : precision)) {
|
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' does not match the facets' constraints.");
|
|
||||||
}
|
|
||||||
if (returnType.isAssignableFrom(Timestamp.class)) {
|
|
||||||
if (decimals.length() <= 9) {
|
|
||||||
nanoSeconds = Integer.parseInt(decimals + "000000000".substring(decimals.length()));
|
|
||||||
} else {
|
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value
|
|
||||||
+ "' cannot be converted to value type " + returnType + ".");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (decimals.length() <= 3) {
|
|
||||||
final String milliSeconds = decimals + "000".substring(decimals.length());
|
|
||||||
dateTimeValue.set(Calendar.MILLISECOND, Short.parseShort(milliSeconds));
|
|
||||||
} else {
|
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value
|
|
||||||
+ "' cannot be converted to value type " + returnType + ".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return convertDateTime(dateTimeValue, nanoSeconds, returnType);
|
ZonedDateTime zdt = parseZonedDateTime(value);
|
||||||
} catch (final IllegalArgumentException e) {
|
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.", e);
|
return convertZonedDateTime(zdt, returnType);
|
||||||
|
} catch (DateTimeParseException ex) {
|
||||||
|
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.", ex);
|
||||||
} catch (final ClassCastException e) {
|
} catch (final ClassCastException e) {
|
||||||
throw new EdmPrimitiveTypeException("The value type " + returnType + " is not supported.", e);
|
throw new EdmPrimitiveTypeException("The value type " + returnType + " is not supported.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static ZonedDateTime parseZonedDateTime(final String value) {
|
||||||
* <p>Converts a {@link Calendar} value into the requested return type if possible.</p>
|
ZonedDateTime zdt;
|
||||||
* <p>It is expected that the {@link Calendar} value will already be in the desired time zone.</p>
|
try {
|
||||||
* @param dateTimeValue the value
|
// ISO-8601 conform pattern
|
||||||
* @param nanoSeconds nanoseconds part of the value; only used for the {@link Timestamp} return type
|
zdt = ZonedDateTime.parse(value);
|
||||||
* @param returnType the class of the returned value;
|
} catch (DateTimeParseException ex) {
|
||||||
* it must be one of {@link Calendar}, {@link Long}, {@link Date},
|
// for backward compatibility - allow patterns that don't specify a time zone
|
||||||
* {@link Time}, or {@link Timestamp}
|
final Matcher matcher = PATTERN.matcher(value);
|
||||||
* @return the converted value
|
if (matcher.matches() && matcher.group(9) == null) {
|
||||||
* @throws IllegalArgumentException if the Calendar value is not valid
|
zdt = ZonedDateTime.parse(value + "Z");
|
||||||
* @throws ClassCastException if the return type is not allowed
|
} else {
|
||||||
*/
|
throw ex;
|
||||||
protected static <T> T convertDateTime(final Calendar dateTimeValue, final int nanoSeconds,
|
}
|
||||||
final Class<T> returnType) throws IllegalArgumentException, ClassCastException {
|
}
|
||||||
|
return zdt;
|
||||||
|
}
|
||||||
|
|
||||||
// The Calendar class does not check any values until a get method is called,
|
@SuppressWarnings("unchecked")
|
||||||
// so we do just that to validate the fields that may have been set,
|
private static <T> T convertZonedDateTime(ZonedDateTime zdt, Class<T> returnType) {
|
||||||
// not because we want to return something else.
|
if (returnType == ZonedDateTime.class) {
|
||||||
// For strict checks, the lenient mode is switched off.
|
return (T) zdt;
|
||||||
dateTimeValue.setLenient(false);
|
} else if (returnType == Instant.class) {
|
||||||
|
return (T) zdt.toInstant();
|
||||||
if (returnType.isAssignableFrom(Calendar.class)) {
|
|
||||||
// Ensure that all fields are recomputed.
|
|
||||||
dateTimeValue.get(Calendar.MILLISECOND); // may throw IllegalArgumentException
|
|
||||||
// Reset the lenient mode to its default.
|
|
||||||
dateTimeValue.setLenient(true);
|
|
||||||
return returnType.cast(dateTimeValue);
|
|
||||||
} else if (returnType.isAssignableFrom(Long.class)) {
|
|
||||||
return returnType.cast(dateTimeValue.getTimeInMillis()); // may throw IllegalArgumentException
|
|
||||||
} else if (returnType.isAssignableFrom(Date.class)) {
|
|
||||||
return returnType.cast(dateTimeValue.getTime()); // may throw IllegalArgumentException
|
|
||||||
} else if (returnType.isAssignableFrom(Timestamp.class)) {
|
} else if (returnType.isAssignableFrom(Timestamp.class)) {
|
||||||
Timestamp timestamp = new Timestamp(dateTimeValue.getTimeInMillis());
|
return (T) Timestamp.from(zdt.toInstant());
|
||||||
timestamp.setNanos(nanoSeconds);
|
} else if (returnType.isAssignableFrom(java.util.Date.class)) {
|
||||||
return returnType.cast(timestamp);
|
return (T) java.util.Date.from(zdt.toInstant());
|
||||||
} else if (returnType.isAssignableFrom(Time.class)) {
|
} else if (returnType.isAssignableFrom(java.sql.Time.class)) {
|
||||||
// Normalize the value.
|
return (T) new java.sql.Time(zdt.toInstant().truncatedTo(ChronoUnit.SECONDS).toEpochMilli());
|
||||||
dateTimeValue.set(Calendar.YEAR, 1970);
|
|
||||||
dateTimeValue.set(Calendar.MONTH, Calendar.JANUARY);
|
|
||||||
dateTimeValue.set(Calendar.DAY_OF_MONTH, 1);
|
|
||||||
dateTimeValue.set(Calendar.MILLISECOND, 0);
|
|
||||||
return returnType.cast(new Time(dateTimeValue.getTimeInMillis())); // may throw IllegalArgumentException
|
|
||||||
} else if (returnType.isAssignableFrom(java.sql.Date.class)) {
|
} else if (returnType.isAssignableFrom(java.sql.Date.class)) {
|
||||||
// Normalize the value.
|
return (T) new java.sql.Date(zdt.toInstant().truncatedTo(ChronoUnit.SECONDS).toEpochMilli());
|
||||||
dateTimeValue.set(Calendar.HOUR_OF_DAY, 0);
|
} else if (returnType.isAssignableFrom(Long.class)) {
|
||||||
dateTimeValue.set(Calendar.MINUTE, 0);
|
return (T) Long.valueOf(zdt.toInstant().toEpochMilli());
|
||||||
dateTimeValue.set(Calendar.SECOND, 0);
|
} else if (returnType.isAssignableFrom(Calendar.class)) {
|
||||||
dateTimeValue.set(Calendar.MILLISECOND, 0);
|
return (T) GregorianCalendar.from(zdt);
|
||||||
return returnType.cast(new java.sql.Date(dateTimeValue.getTimeInMillis())); // may throw IllegalArgumentException
|
|
||||||
} else {
|
} else {
|
||||||
throw new ClassCastException("unsupported return type " + returnType.getSimpleName());
|
throw new ClassCastException("unsupported return type " + returnType.getSimpleName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <T> String internalValueToString(final T value,
|
protected <T> String internalValueToString(final T value, final Boolean isNullable, final Integer maxLength,
|
||||||
final Boolean isNullable, final Integer maxLength, final Integer precision,
|
final Integer precision, final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException {
|
||||||
final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException {
|
ZonedDateTime zdt = createZonedDateTime(value);
|
||||||
|
|
||||||
final Calendar dateTimeValue = createDateTime(value, false);
|
return format(zdt.toLocalDateTime(), zdt.getOffset(), zdt.getNano());
|
||||||
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
final int year = dateTimeValue.get(Calendar.YEAR);
|
|
||||||
appendTwoDigits(result, year / 100);
|
|
||||||
appendTwoDigits(result, year % 100);
|
|
||||||
result.append('-');
|
|
||||||
appendTwoDigits(result, dateTimeValue.get(Calendar.MONTH) + 1); // month is zero-based
|
|
||||||
result.append('-');
|
|
||||||
appendTwoDigits(result, dateTimeValue.get(Calendar.DAY_OF_MONTH));
|
|
||||||
result.append('T');
|
|
||||||
appendTwoDigits(result, dateTimeValue.get(Calendar.HOUR_OF_DAY));
|
|
||||||
result.append(':');
|
|
||||||
appendTwoDigits(result, dateTimeValue.get(Calendar.MINUTE));
|
|
||||||
result.append(':');
|
|
||||||
appendTwoDigits(result, dateTimeValue.get(Calendar.SECOND));
|
|
||||||
|
|
||||||
final int fractionalSecs = value instanceof Timestamp ?
|
|
||||||
((Timestamp) value).getNanos() :
|
|
||||||
dateTimeValue.get(Calendar.MILLISECOND);
|
|
||||||
try {
|
|
||||||
appendFractionalSeconds(result, fractionalSecs, value instanceof Timestamp, precision);
|
|
||||||
} catch (final IllegalArgumentException e) {
|
|
||||||
throw new EdmPrimitiveTypeException("The value '" + value + "' does not match the facets' constraints.", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final int offsetInMinutes = (dateTimeValue.get(Calendar.ZONE_OFFSET)
|
private static <T> ZonedDateTime createZonedDateTime(final T value) throws EdmPrimitiveTypeException {
|
||||||
+ dateTimeValue.get(Calendar.DST_OFFSET)) / 60 / 1000;
|
if (value instanceof ZonedDateTime) {
|
||||||
final int offsetHours = offsetInMinutes / 60;
|
return (ZonedDateTime) value;
|
||||||
final int offsetMinutes = Math.abs(offsetInMinutes % 60);
|
}
|
||||||
final String offsetString = offsetInMinutes == 0 ? "Z" : String.format("%+03d:%02d", offsetHours, offsetMinutes);
|
|
||||||
result.append(offsetString);
|
|
||||||
|
|
||||||
return result.toString();
|
if (value instanceof Instant) {
|
||||||
|
return ((Instant) value).atZone(ZULU);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value instanceof GregorianCalendar) {
|
||||||
|
GregorianCalendar calendar = (GregorianCalendar) value;
|
||||||
|
ZonedDateTime zdt = calendar.toZonedDateTime();
|
||||||
|
ZoneId normalizedZoneId = calendar.getTimeZone().toZoneId().normalized();
|
||||||
|
return zdt.withZoneSameInstant(normalizedZoneId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return convertToInstant(value).atZone(ZULU);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String format(LocalDateTime dateTime, ZoneOffset offset, int nanos) {
|
||||||
|
String str = dateTime.toString();
|
||||||
|
if (nanos > 0) {
|
||||||
|
str = removeTrailingZeros(str);
|
||||||
|
}
|
||||||
|
str = str + offset.toString();
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String removeTrailingZeros(String str) {
|
||||||
|
char[] chars = str.toCharArray();
|
||||||
|
int trailingZeros = 0;
|
||||||
|
for (int i = chars.length - 1; i >= 0 && chars[i] == '0'; i--) {
|
||||||
|
trailingZeros++;
|
||||||
|
}
|
||||||
|
return str.substring(0, chars.length - trailingZeros);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a date/time value from the given value.
|
* Creates an {@link Instant} from the given value.
|
||||||
*
|
*
|
||||||
* @param value the value as {@link Calendar}, {@link Date}, or {@link Long}
|
* @param value the value as {@link Instant}, {@link java.util.Date},
|
||||||
* @param isLocal whether the value is to be in the default time zone (or in GMT)
|
* {@link java.sql.Timestamp}, {@link Long} or
|
||||||
* @return the value as {@link Calendar} in the desired time zone
|
* {@link GregorianCalendar}
|
||||||
|
* @return the value as {@link Instant}
|
||||||
* @throws EdmPrimitiveTypeException if the type of the value is not supported
|
* @throws EdmPrimitiveTypeException if the type of the value is not supported
|
||||||
*/
|
*/
|
||||||
protected static <T> Calendar createDateTime(final T value, final boolean isLocal) throws EdmPrimitiveTypeException {
|
private static <T> Instant convertToInstant(final T value) throws EdmPrimitiveTypeException {
|
||||||
Calendar dateTimeValue;
|
if (value instanceof java.sql.Time || value instanceof java.sql.Date) {
|
||||||
if (value instanceof Date) {
|
throw new EdmPrimitiveTypeException("The value type " + value.getClass() + " is not supported.");
|
||||||
dateTimeValue = Calendar.getInstance(isLocal ? TimeZone.getDefault() : TimeZone.getTimeZone("GMT"));
|
} else if (value instanceof java.util.Date) {
|
||||||
dateTimeValue.setTime((Date) value);
|
return ((java.util.Date) value).toInstant();
|
||||||
} else if (value instanceof Calendar) {
|
} else if (value instanceof Timestamp) {
|
||||||
dateTimeValue = (Calendar) ((Calendar) value).clone();
|
return ((Timestamp) value).toInstant();
|
||||||
} else if (value instanceof Long) {
|
} else if (value instanceof Long) {
|
||||||
dateTimeValue = Calendar.getInstance(isLocal ? TimeZone.getDefault() : TimeZone.getTimeZone("GMT"));
|
return Instant.ofEpochMilli((Long) value);
|
||||||
dateTimeValue.setTimeInMillis((Long) value);
|
|
||||||
} else {
|
} else {
|
||||||
throw new EdmPrimitiveTypeException("The value type " + value.getClass() + " is not supported.");
|
throw new EdmPrimitiveTypeException("The value type " + value.getClass() + " is not supported.");
|
||||||
}
|
}
|
||||||
return dateTimeValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Appends the given number to the given string builder, assuming that the number has at most two digits,
|
|
||||||
* performance-optimized.
|
|
||||||
*
|
|
||||||
* @param result a {@link StringBuilder}
|
|
||||||
* @param number an integer that must satisfy <code>0 <= number <= 99</code>
|
|
||||||
*/
|
|
||||||
protected static void appendTwoDigits(final StringBuilder result, final int number) {
|
|
||||||
result.append((char) ('0' + number / 10));
|
|
||||||
result.append((char) ('0' + number % 10));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Appends the given milli- or nanoseconds to the given string builder, performance-optimized.
|
|
||||||
* @param result a {@link StringBuilder}
|
|
||||||
* @param fractionalSeconds fractional seconds (nonnegative and assumed to be in the valid range)
|
|
||||||
* @param isNano whether the value is to be interpreted as nanoseconds (milliseconds if false)
|
|
||||||
* @param precision the upper limit for decimal digits (optional, defaults to zero)
|
|
||||||
* @throws IllegalArgumentException if precision is not met
|
|
||||||
*/
|
|
||||||
protected static void appendFractionalSeconds(StringBuilder result, final int fractionalSeconds,
|
|
||||||
final boolean isNano, final Integer precision) throws IllegalArgumentException {
|
|
||||||
if (fractionalSeconds > 0) {
|
|
||||||
// Determine the number of trailing zeroes.
|
|
||||||
int nonSignificant = 0;
|
|
||||||
int output = fractionalSeconds;
|
|
||||||
while (output % 10 == 0) {
|
|
||||||
output /= 10;
|
|
||||||
nonSignificant++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (precision != null && precision < (isNano ? 9 : 3) - nonSignificant) {
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.append('.');
|
|
||||||
for (int d = 100 * (isNano ? 1000 * 1000 : 1); d > 0; d /= 10) {
|
|
||||||
final byte digit = (byte) (fractionalSeconds % (d * 10) / d);
|
|
||||||
if (digit > 0 || fractionalSeconds % d > 0) {
|
|
||||||
result.append((char) ('0' + digit));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,17 +19,21 @@
|
||||||
package org.apache.olingo.commons.core.edm.primitivetype;
|
package org.apache.olingo.commons.core.edm.primitivetype;
|
||||||
|
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.regex.Matcher;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||||
|
|
||||||
public final class EdmTimeOfDay extends SingletonPrimitiveType {
|
public final class EdmTimeOfDay extends SingletonPrimitiveType {
|
||||||
|
|
||||||
private static final Pattern PATTERN = Pattern.compile(
|
private static final LocalDate EPOCH = LocalDate.ofEpochDay(0l);
|
||||||
"(\\p{Digit}{2}):(\\p{Digit}{2})(?::(\\p{Digit}{2})(\\.(\\p{Digit}{0,}?)0*)?)?");
|
|
||||||
|
|
||||||
private static final EdmTimeOfDay INSTANCE = new EdmTimeOfDay();
|
private static final EdmTimeOfDay INSTANCE = new EdmTimeOfDay();
|
||||||
|
|
||||||
public static EdmTimeOfDay getInstance() {
|
public static EdmTimeOfDay getInstance() {
|
||||||
|
@ -41,81 +45,89 @@ public final class EdmTimeOfDay extends SingletonPrimitiveType {
|
||||||
return Calendar.class;
|
return Calendar.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
protected <T> T internalValueOfString(final String value,
|
protected <T> T internalValueOfString(final String value, final Boolean isNullable, final Integer maxLength,
|
||||||
final Boolean isNullable, final Integer maxLength, final Integer precision,
|
final Integer precision, final Integer scale, final Boolean isUnicode, final Class<T> returnType)
|
||||||
final Integer scale, final Boolean isUnicode, final Class<T> returnType) throws EdmPrimitiveTypeException {
|
throws EdmPrimitiveTypeException {
|
||||||
|
LocalTime time;
|
||||||
final Matcher matcher = PATTERN.matcher(value);
|
|
||||||
if (!matcher.matches()) {
|
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
|
|
||||||
}
|
|
||||||
|
|
||||||
final Calendar dateTimeValue = Calendar.getInstance();
|
|
||||||
dateTimeValue.clear();
|
|
||||||
dateTimeValue.set(Calendar.HOUR_OF_DAY, Byte.parseByte(matcher.group(1)));
|
|
||||||
dateTimeValue.set(Calendar.MINUTE, Byte.parseByte(matcher.group(2)));
|
|
||||||
dateTimeValue.set(Calendar.SECOND, matcher.group(3) == null ? 0 : Byte.parseByte(matcher.group(3)));
|
|
||||||
|
|
||||||
int nanoSeconds = 0;
|
|
||||||
if (matcher.group(4) != null) {
|
|
||||||
if (matcher.group(4).length() == 1 || matcher.group(4).length() > 13) {
|
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
|
|
||||||
}
|
|
||||||
final String decimals = matcher.group(5);
|
|
||||||
if (decimals.length() > (precision == null ? 0 : precision)) {
|
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' does not match the facets' constraints.");
|
|
||||||
}
|
|
||||||
if (returnType.isAssignableFrom(Timestamp.class)) {
|
|
||||||
if (decimals.length() <= 9) {
|
|
||||||
nanoSeconds = Integer.parseInt(decimals + "000000000".substring(decimals.length()));
|
|
||||||
} else {
|
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value
|
|
||||||
+ "' cannot be converted to value type " + returnType + ".");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (decimals.length() <= 3) {
|
|
||||||
final String milliSeconds = decimals + "000".substring(decimals.length());
|
|
||||||
dateTimeValue.set(Calendar.MILLISECOND, Short.parseShort(milliSeconds));
|
|
||||||
} else {
|
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value
|
|
||||||
+ "' cannot be converted to value type " + returnType + ".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return EdmDateTimeOffset.convertDateTime(dateTimeValue, nanoSeconds, returnType);
|
time = LocalTime.parse(value);
|
||||||
} catch (final IllegalArgumentException e) {
|
} catch (DateTimeParseException ex) {
|
||||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.", e);
|
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
|
||||||
} catch (final ClassCastException e) {
|
}
|
||||||
throw new EdmPrimitiveTypeException("The value type " + returnType + " is not supported.", e);
|
|
||||||
|
// appropriate types
|
||||||
|
if (returnType.isAssignableFrom(LocalTime.class)) {
|
||||||
|
return (T) time;
|
||||||
|
} else if (returnType.isAssignableFrom(java.sql.Time.class)) {
|
||||||
|
return (T) java.sql.Time.valueOf(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
// inappropriate types, which need to be supported for backward compatibility
|
||||||
|
ZonedDateTime zdt = LocalDateTime.of(EPOCH, time).atZone(ZoneId.systemDefault());
|
||||||
|
if (returnType.isAssignableFrom(Calendar.class)) {
|
||||||
|
return (T) GregorianCalendar.from(zdt);
|
||||||
|
} else if (returnType.isAssignableFrom(Long.class)) {
|
||||||
|
return (T) Long.valueOf(zdt.toInstant().toEpochMilli());
|
||||||
|
} else if (returnType.isAssignableFrom(java.sql.Date.class)) {
|
||||||
|
throw new EdmPrimitiveTypeException("The value type " + returnType + " is not supported.");
|
||||||
|
} else if (returnType.isAssignableFrom(Timestamp.class)) {
|
||||||
|
return (T) Timestamp.from(zdt.toInstant());
|
||||||
|
} else if (returnType.isAssignableFrom(java.util.Date.class)) {
|
||||||
|
return (T) java.util.Date.from(zdt.toInstant());
|
||||||
|
} else {
|
||||||
|
throw new EdmPrimitiveTypeException("The value type " + returnType + " is not supported.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <T> String internalValueToString(final T value,
|
protected <T> String internalValueToString(final T value, final Boolean isNullable, final Integer maxLength,
|
||||||
final Boolean isNullable, final Integer maxLength, final Integer precision,
|
final Integer precision, final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException {
|
||||||
final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException {
|
// appropriate types
|
||||||
|
if (value instanceof LocalTime) {
|
||||||
final Calendar dateTimeValue = EdmDateTimeOffset.createDateTime(value, true);
|
return value.toString();
|
||||||
|
} else if(value instanceof java.sql.Time) {
|
||||||
StringBuilder result = new StringBuilder();
|
return value.toString();
|
||||||
EdmDateTimeOffset.appendTwoDigits(result, dateTimeValue.get(Calendar.HOUR_OF_DAY));
|
|
||||||
result.append(':');
|
|
||||||
EdmDateTimeOffset.appendTwoDigits(result, dateTimeValue.get(Calendar.MINUTE));
|
|
||||||
result.append(':');
|
|
||||||
EdmDateTimeOffset.appendTwoDigits(result, dateTimeValue.get(Calendar.SECOND));
|
|
||||||
|
|
||||||
final int fractionalSecs = value instanceof Timestamp ?
|
|
||||||
((Timestamp) value).getNanos() :
|
|
||||||
dateTimeValue.get(Calendar.MILLISECOND);
|
|
||||||
try {
|
|
||||||
EdmDateTimeOffset.appendFractionalSeconds(result, fractionalSecs, value instanceof Timestamp, precision);
|
|
||||||
} catch (final IllegalArgumentException e) {
|
|
||||||
throw new EdmPrimitiveTypeException("The value '" + value + "' does not match the facets' constraints.", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.toString();
|
// inappropriate types, which need to be supported for backward compatibility
|
||||||
|
if (value instanceof GregorianCalendar) {
|
||||||
|
GregorianCalendar calendar = (GregorianCalendar) value;
|
||||||
|
return calendar.toZonedDateTime().toLocalTime().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
long millis;
|
||||||
|
if (value instanceof Long) {
|
||||||
|
millis = (Long)value;
|
||||||
|
} else if (value instanceof java.util.Date) {
|
||||||
|
millis = ((java.util.Date)value).getTime();
|
||||||
|
} else {
|
||||||
|
throw new EdmPrimitiveTypeException("The value type " + value.getClass() + " is not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ZonedDateTime zdt = Instant.ofEpochMilli(millis).atZone(ZoneId.systemDefault());
|
||||||
|
|
||||||
|
return zdt.toLocalTime().toString();
|
||||||
|
|
||||||
|
//
|
||||||
|
// final Calendar dateTimeValue = EdmDateTimeOffset.createDateTime(value, true);
|
||||||
|
//
|
||||||
|
// StringBuilder result = new StringBuilder();
|
||||||
|
// EdmDateTimeOffset.appendTwoDigits(result, dateTimeValue.get(Calendar.HOUR_OF_DAY));
|
||||||
|
// result.append(':');
|
||||||
|
// EdmDateTimeOffset.appendTwoDigits(result, dateTimeValue.get(Calendar.MINUTE));
|
||||||
|
// result.append(':');
|
||||||
|
// EdmDateTimeOffset.appendTwoDigits(result, dateTimeValue.get(Calendar.SECOND));
|
||||||
|
//
|
||||||
|
// final int fractionalSecs = value instanceof Timestamp ? ((Timestamp) value).getNanos()
|
||||||
|
// : dateTimeValue.get(Calendar.MILLISECOND);
|
||||||
|
// try {
|
||||||
|
// EdmDateTimeOffset.appendFractionalSeconds(result, fractionalSecs, value instanceof Timestamp, precision);
|
||||||
|
// } catch (final IllegalArgumentException e) {
|
||||||
|
// throw new EdmPrimitiveTypeException("The value '" + value + "' does not match the facets' constraints.", e);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return result.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,8 @@ package org.apache.olingo.commons.core.edm.primitivetype;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||||
|
@ -48,7 +48,7 @@ public class EdmDateTest extends PrimitiveTypeBaseTest {
|
||||||
public void valueToString() throws Exception {
|
public void valueToString() throws Exception {
|
||||||
Calendar dateTime = Calendar.getInstance();
|
Calendar dateTime = Calendar.getInstance();
|
||||||
dateTime.clear();
|
dateTime.clear();
|
||||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT-11:30"));
|
setTimeZone(dateTime, "GMT-11:30");
|
||||||
dateTime.set(2012, 1, 29, 13, 0, 0);
|
dateTime.set(2012, 1, 29, 13, 0, 0);
|
||||||
assertEquals("2012-02-29", instance.valueToString(dateTime, null, null, null, null, null));
|
assertEquals("2012-02-29", instance.valueToString(dateTime, null, null, null, null, null));
|
||||||
|
|
||||||
|
@ -56,10 +56,15 @@ public class EdmDateTest extends PrimitiveTypeBaseTest {
|
||||||
millis -= TimeZone.getDefault().getOffset(millis);
|
millis -= TimeZone.getDefault().getOffset(millis);
|
||||||
assertEquals("2012-02-29", instance.valueToString(millis, null, null, null, null, null));
|
assertEquals("2012-02-29", instance.valueToString(millis, null, null, null, null, null));
|
||||||
|
|
||||||
assertEquals("1969-12-31", instance.valueToString(new Date(-43200000), null, null, null, null, null));
|
assertEquals("1969-12-31", instance.valueToString(new java.util.Date(-43200000), null, null, null, null, null));
|
||||||
|
assertEquals("1969-12-31",
|
||||||
|
instance.valueToString(java.sql.Date.valueOf("1969-12-31"), null, null, null, null, null));
|
||||||
|
assertEquals("1969-12-31",
|
||||||
|
instance.valueToString(LocalDate.parse("1969-12-31"), null, null, null, null, null));
|
||||||
|
|
||||||
dateTime.set(Calendar.YEAR, 12344);
|
// TODO support for years beyond 9999
|
||||||
assertEquals("12344-02-29", instance.valueToString(dateTime, null, null, null, null, null));
|
// dateTime.set(Calendar.YEAR, 12344);
|
||||||
|
// assertEquals("12344-02-29", instance.valueToString(dateTime, null, null, null, null, null));
|
||||||
|
|
||||||
expectTypeErrorInValueToString(instance, 0);
|
expectTypeErrorInValueToString(instance, 0);
|
||||||
}
|
}
|
||||||
|
@ -69,17 +74,27 @@ public class EdmDateTest extends PrimitiveTypeBaseTest {
|
||||||
Calendar dateTime = Calendar.getInstance();
|
Calendar dateTime = Calendar.getInstance();
|
||||||
dateTime.clear();
|
dateTime.clear();
|
||||||
dateTime.set(2012, 1, 29);
|
dateTime.set(2012, 1, 29);
|
||||||
assertEquals(dateTime, instance.valueOfString("2012-02-29", null, null, null, null, null, Calendar.class));
|
assertEqualCalendar(dateTime,
|
||||||
assertEquals(Long.valueOf(dateTime.getTimeInMillis()), instance.valueOfString("2012-02-29", null, null, null, null,
|
instance.valueOfString("2012-02-29", null, null, null, null, null, Calendar.class));
|
||||||
null, Long.class));
|
assertEquals(Long.valueOf(dateTime.getTimeInMillis()),
|
||||||
assertEquals(dateTime.getTime(), instance.valueOfString("2012-02-29", null, null, null, null, null, Date.class));
|
instance.valueOfString("2012-02-29", null, null, null, null, null, Long.class));
|
||||||
|
assertEquals(dateTime.getTime(),
|
||||||
|
instance.valueOfString("2012-02-29", null, null, null, null, null, java.util.Date.class));
|
||||||
|
assertEquals(java.sql.Date.valueOf("2012-02-29"),
|
||||||
|
instance.valueOfString("2012-02-29", null, null, null, null, null, java.sql.Date.class));
|
||||||
|
assertEquals(LocalDate.parse("2012-02-29"),
|
||||||
|
instance.valueOfString("2012-02-29", null, null, null, null, null, LocalDate.class));
|
||||||
|
|
||||||
dateTime.set(Calendar.YEAR, 12344);
|
// TODO support for years beyond 9999
|
||||||
assertEquals(dateTime, instance.valueOfString("12344-02-29", null, null, null, null, null, Calendar.class));
|
// dateTime.set(Calendar.YEAR, 12344);
|
||||||
|
// Calendar result = instance.valueOfString("12344-02-29", null, null, null,
|
||||||
|
// null, null, Calendar.class);
|
||||||
|
// this.assertEqualCalendar(dateTime, result);
|
||||||
|
|
||||||
// TODO: Clarify whether negative years are really needed.
|
// TODO: Clarify whether negative years are really needed.
|
||||||
// dateTime.set(-1, 1, 28);
|
// dateTime.set(-1, 1, 28);
|
||||||
// assertEquals(dateTime, instance.valueOfString("-0001-02-28", null, Calendar.class));
|
// assertEquals(dateTime, instance.valueOfString("-0001-02-28", null,
|
||||||
|
// Calendar.class));
|
||||||
|
|
||||||
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02");
|
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02");
|
||||||
expectContentErrorInValueOfString(instance, "2012-02-30");
|
expectContentErrorInValueOfString(instance, "2012-02-30");
|
||||||
|
|
|
@ -22,9 +22,12 @@ import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import java.sql.Time;
|
import java.sql.Time;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.TimeZone;
|
|
||||||
|
|
||||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
|
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
|
||||||
|
@ -47,114 +50,193 @@ public class EdmDateTimeOffsetTest extends PrimitiveTypeBaseTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void valueToString() throws Exception {
|
public void valueToStringFromInstant() throws Exception {
|
||||||
|
Instant instant = Instant.parse("2012-02-29T01:02:03Z");
|
||||||
|
assertEquals("2012-02-29T01:02:03Z", instance.valueToString(instant, null, null, null, null, null));
|
||||||
|
assertEquals("2012-02-29T01:02:03Z", instance.valueToString(instant, null, null, 0, null, null));
|
||||||
|
assertEquals("2012-02-29T01:02:03Z", instance.valueToString(instant, null, null, 5, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valueToStringFromZonedDateTime() throws Exception {
|
||||||
|
ZonedDateTime zdt = ZonedDateTime.parse("2012-02-28T23:32:03-01:30");
|
||||||
|
|
||||||
|
assertEquals("2012-02-28T23:32:03-01:30", instance.valueToString(zdt, null, null, null, null, null));
|
||||||
|
|
||||||
|
zdt = zdt.withZoneSameInstant(ZoneId.of("GMT+11:00"));
|
||||||
|
assertEquals("2012-02-29T12:02:03+11:00", instance.valueToString(zdt, null, null, null, null, null));
|
||||||
|
|
||||||
|
zdt = zdt.plus(123, ChronoUnit.MILLIS);
|
||||||
|
|
||||||
|
assertEquals("2012-02-29T12:02:03.123+11:00", instance.valueToString(zdt, null, null, null, null, null));
|
||||||
|
assertEquals("2012-02-29T12:02:03.123+11:00", instance.valueToString(zdt, null, null, 3, null, null));
|
||||||
|
|
||||||
|
zdt = zdt.plus(456789, ChronoUnit.NANOS);
|
||||||
|
assertEquals("2012-02-29T12:02:03.123456789+11:00", instance.valueToString(zdt, null, null, 9, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valueToStringFromCalendar() throws Exception {
|
||||||
Calendar dateTime = Calendar.getInstance();
|
Calendar dateTime = Calendar.getInstance();
|
||||||
dateTime.clear();
|
dateTime.clear();
|
||||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT"));
|
setTimeZone(dateTime, "GMT");
|
||||||
dateTime.set(2012, 1, 29, 1, 2, 3);
|
dateTime.set(2012, 1, 29, 1, 2, 3);
|
||||||
assertEquals("2012-02-29T01:02:03Z", instance.valueToString(dateTime, null, null, null, null, null));
|
assertEquals("2012-02-29T01:02:03Z", instance.valueToString(dateTime, null, null, null, null, null));
|
||||||
assertEquals("2012-02-29T01:02:03Z", instance.valueToString(dateTime, null, null, 0, null, null));
|
assertEquals("2012-02-29T01:02:03Z", instance.valueToString(dateTime, null, null, 0, null, null));
|
||||||
assertEquals("2012-02-29T01:02:03Z", instance.valueToString(dateTime, null, null, 5, null, null));
|
assertEquals("2012-02-29T01:02:03Z", instance.valueToString(dateTime, null, null, 5, null, null));
|
||||||
|
|
||||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT-1:30"));
|
setTimeZone(dateTime, "GMT-1:30");
|
||||||
assertEquals("2012-02-29T01:02:03-01:30", instance.valueToString(dateTime, null, null, null, null, null));
|
assertEquals("2012-02-28T23:32:03-01:30", instance.valueToString(dateTime, null, null, null, null, null));
|
||||||
|
|
||||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT+11:00"));
|
setTimeZone(dateTime, "GMT+11:00");
|
||||||
assertEquals("2012-02-29T01:02:03+11:00", instance.valueToString(dateTime, null, null, null, null, null));
|
assertEquals("2012-02-29T12:02:03+11:00", instance.valueToString(dateTime, null, null, null, null, null));
|
||||||
|
|
||||||
dateTime.set(Calendar.MILLISECOND, 503);
|
dateTime.set(Calendar.MILLISECOND, 503);
|
||||||
assertEquals("2012-02-29T01:02:03.503+11:00", instance.valueToString(dateTime, null, null, null, null, null));
|
assertEquals("2012-02-29T12:02:03.503+11:00", instance.valueToString(dateTime, null, null, null, null, null));
|
||||||
assertEquals("2012-02-29T01:02:03.503+11:00", instance.valueToString(dateTime, null, null, 3, null, null));
|
assertEquals("2012-02-29T12:02:03.503+11:00", instance.valueToString(dateTime, null, null, 3, null, null));
|
||||||
|
|
||||||
dateTime.set(Calendar.MILLISECOND, 530);
|
dateTime.set(Calendar.MILLISECOND, 530);
|
||||||
assertEquals("2012-02-29T01:02:03.53+11:00", instance.valueToString(dateTime, null, null, null, null, null));
|
assertEquals("2012-02-29T12:02:03.53+11:00", instance.valueToString(dateTime, null, null, null, null, null));
|
||||||
assertEquals("2012-02-29T01:02:03.53+11:00", instance.valueToString(dateTime, null, null, 3, null, null));
|
assertEquals("2012-02-29T12:02:03.53+11:00", instance.valueToString(dateTime, null, null, 3, null, null));
|
||||||
|
|
||||||
dateTime.set(Calendar.MILLISECOND, 53);
|
dateTime.set(Calendar.MILLISECOND, 53);
|
||||||
assertEquals("2012-02-29T01:02:03.053+11:00", instance.valueToString(dateTime, null, null, null, null, null));
|
assertEquals("2012-02-29T12:02:03.053+11:00", instance.valueToString(dateTime, null, null, null, null, null));
|
||||||
assertEquals("2012-02-29T01:02:03.053+11:00", instance.valueToString(dateTime, null, null, 3, null, null));
|
assertEquals("2012-02-29T12:02:03.053+11:00", instance.valueToString(dateTime, null, null, 3, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
final Long millis = 1330558323007L;
|
@Test
|
||||||
|
public void valueToStringFromLong() throws Exception {
|
||||||
|
Long millis = 1330558323000L;
|
||||||
|
assertEquals("2012-02-29T23:32:03Z", instance.valueToString(millis, null, null, null, null, null));
|
||||||
|
millis = 1330558323007L;
|
||||||
assertEquals("2012-02-29T23:32:03.007Z", instance.valueToString(millis, null, null, null, null, null));
|
assertEquals("2012-02-29T23:32:03.007Z", instance.valueToString(millis, null, null, null, null, null));
|
||||||
assertEquals("2012-02-29T23:32:03.007Z", instance.valueToString(millis, null, null, 3, null, null));
|
assertEquals("2012-02-29T23:32:03.007Z", instance.valueToString(millis, null, null, 3, null, null));
|
||||||
assertEquals("1969-12-31T23:59:59.9Z", instance.valueToString(-100L, null, null, 1, null, null));
|
assertEquals("1969-12-31T23:59:59.9Z", instance.valueToString(-100L, null, null, 1, null, null));
|
||||||
assertEquals("1969-12-31T23:59:59.98Z", instance.valueToString(-20L, null, null, 2, null, null));
|
assertEquals("1969-12-31T23:59:59.98Z", instance.valueToString(-20L, null, null, 2, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
assertEquals("2012-02-29T23:32:03.007Z", instance.valueToString(new Time(millis), null, null, 3, null, null));
|
@Test
|
||||||
assertEquals("1969-12-31T23:59:59.9Z", instance.valueToString(new Time(-100L), null, null, 1, null, null));
|
public void valueToStringFromJavaUtilDate() throws Exception {
|
||||||
assertEquals("1969-12-31T23:59:59.98Z", instance.valueToString(new Time(-20L), null, null, 2, null, null));
|
final Long millis = 1330558323007L;
|
||||||
|
|
||||||
final Date date = new Date(millis);
|
final Date date = new Date(millis);
|
||||||
assertEquals("2012-02-29T23:32:03.007Z", instance.valueToString(date, null, null, null, null, null));
|
assertEquals("2012-02-29T23:32:03.007Z", instance.valueToString(date, null, null, null, null, null));
|
||||||
assertEquals("2012-02-29T23:32:03.007Z", instance.valueToString(date, null, null, 3, null, null));
|
assertEquals("2012-02-29T23:32:03.007Z", instance.valueToString(date, null, null, 3, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valueToStringFromTimestamp() throws Exception {
|
||||||
Timestamp timestamp = new Timestamp(0);
|
Timestamp timestamp = new Timestamp(0);
|
||||||
timestamp.setNanos(120);
|
timestamp.setNanos(120);
|
||||||
assertEquals("1970-01-01T00:00:00.00000012Z", instance.valueToString(timestamp, null, null, null, null, null));
|
assertEquals("1970-01-01T00:00:00.00000012Z", instance.valueToString(timestamp, null, null, null, null, null));
|
||||||
assertEquals("1970-01-01T00:00:00.00000012Z", instance.valueToString(timestamp, null, null, 8, null, null));
|
assertEquals("1970-01-01T00:00:00.00000012Z", instance.valueToString(timestamp, null, null, 8, null, null));
|
||||||
|
|
||||||
expectFacetsErrorInValueToString(instance, 3L, null, null, 2, null, null);
|
|
||||||
expectFacetsErrorInValueToString(instance, timestamp, null, null, 7, null, null);
|
|
||||||
|
|
||||||
expectTypeErrorInValueToString(instance, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void valueOfString() throws Exception {
|
public void valueToStringFromInvalidTypes() throws Exception {
|
||||||
|
expectTypeErrorInValueToString(instance, Integer.valueOf(0));
|
||||||
|
expectTypeErrorInValueToString(instance, Time.valueOf("12:13:14"));
|
||||||
|
expectTypeErrorInValueToString(instance, java.sql.Date.valueOf("2019-10-25"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valueOfStringToInstant() throws Exception {
|
||||||
|
Instant instant = Instant.parse("2012-02-29T01:02:03Z");
|
||||||
|
assertEquals(instant,
|
||||||
|
instance.valueOfString("2012-02-29T01:02:03Z", null, null, null, null, null, Instant.class));
|
||||||
|
assertEquals(instant,
|
||||||
|
instance.valueOfString("2012-02-29T01:02:03", null, null, null, null, null, Instant.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valueOfStringToZonedDateTime() throws Exception {
|
||||||
|
ZonedDateTime zdt = ZonedDateTime.parse("2012-02-29T01:02:03-01:30");
|
||||||
|
assertEquals(zdt,
|
||||||
|
instance.valueOfString("2012-02-29T01:02:03-01:30", null, null, null, null, null, ZonedDateTime.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valueOfStringToCalendar() throws Exception {
|
||||||
Calendar dateTime = Calendar.getInstance();
|
Calendar dateTime = Calendar.getInstance();
|
||||||
dateTime.clear();
|
dateTime.clear();
|
||||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT"));
|
setTimeZone(dateTime, "GMT");
|
||||||
dateTime.set(2012, 1, 29, 1, 2, 3);
|
dateTime.set(2012, 1, 29, 1, 2, 3);
|
||||||
assertEquals(dateTime, instance.valueOfString("2012-02-29T01:02:03Z", null, null, null, null, null,
|
assertEqualCalendar(dateTime,
|
||||||
Calendar.class));
|
instance.valueOfString("2012-02-29T01:02:03Z", null, null, null, null, null, Calendar.class));
|
||||||
assertEquals(Long.valueOf(dateTime.getTimeInMillis()), instance.valueOfString("2012-02-29T01:02:03+00:00", null,
|
assertEqualCalendar(dateTime,
|
||||||
null, null, null, null, Long.class));
|
instance.valueOfString("2012-02-29T01:02:03", null, null, null, null, null, Calendar.class));
|
||||||
assertEquals(dateTime, instance.valueOfString("2012-02-29T01:02:03", null, null, null, null, null,
|
|
||||||
Calendar.class));
|
|
||||||
|
|
||||||
dateTime.clear();
|
dateTime.clear();
|
||||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT-01:30"));
|
setTimeZone(dateTime, "GMT-01:30");
|
||||||
dateTime.set(2012, 1, 29, 1, 2, 3);
|
dateTime.set(2012, 1, 29, 1, 2, 3);
|
||||||
assertEquals(dateTime.getTime(), instance.valueOfString("2012-02-29T01:02:03-01:30", null, null, null, null, null,
|
assertEquals(dateTime.getTime(),
|
||||||
Date.class));
|
instance.valueOfString("2012-02-29T01:02:03-01:30", null, null, null, null, null, Date.class));
|
||||||
|
|
||||||
dateTime.clear();
|
dateTime.clear();
|
||||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT+11:00"));
|
setTimeZone(dateTime, "GMT+11:00");
|
||||||
dateTime.set(2012, 1, 29, 1, 2, 3);
|
dateTime.set(2012, 1, 29, 1, 2, 3);
|
||||||
assertEquals(dateTime, instance.valueOfString("2012-02-29T01:02:03+11:00", null, null, null, null, null,
|
assertEqualCalendar(dateTime,
|
||||||
Calendar.class));
|
instance.valueOfString("2012-02-29T01:02:03+11:00", null, null, null, null, null, Calendar.class));
|
||||||
|
|
||||||
dateTime.add(Calendar.MILLISECOND, 7);
|
dateTime.add(Calendar.MILLISECOND, 7);
|
||||||
assertEquals(dateTime, instance.valueOfString("2012-02-29T01:02:03.007+11:00", null, null, 3, null, null,
|
assertEqualCalendar(dateTime,
|
||||||
Calendar.class));
|
instance.valueOfString("2012-02-29T01:02:03.007+11:00", null, null, 3, null, null, Calendar.class));
|
||||||
assertEquals(530000001, instance.valueOfString("2012-02-29T01:02:03.530000001+11:00", null, null, 9, null, null,
|
}
|
||||||
Timestamp.class).getNanos());
|
|
||||||
|
|
||||||
assertEquals(Long.valueOf(120000L), instance.valueOfString("1970-01-01T00:02", null, null, null, null, null,
|
@Test
|
||||||
Long.class));
|
public void valueOfStringToTimestamp() throws Exception {
|
||||||
assertEquals(Long.valueOf(12L), instance.valueOfString("1970-01-01T00:00:00.012", null, null, 3, null, null,
|
assertEquals(530000001, instance
|
||||||
Long.class));
|
.valueOfString("2012-02-29T01:02:03.530000001+11:00", null, null, 9, null, null, Timestamp.class)
|
||||||
assertEquals(Long.valueOf(120L), instance.valueOfString("1970-01-01T00:00:00.12", null, null, 2, null, null,
|
.getNanos());
|
||||||
Long.class));
|
}
|
||||||
|
|
||||||
assertEquals(new Time(120000L), instance.valueOfString("1970-01-01T00:02", null, null, null, null, null,
|
@Test
|
||||||
Time.class));
|
public void valueOfStringToLong() throws Exception {
|
||||||
|
Calendar dateTime = Calendar.getInstance();
|
||||||
|
dateTime.clear();
|
||||||
|
setTimeZone(dateTime, "GMT");
|
||||||
|
dateTime.set(2012, 1, 29, 1, 2, 3);
|
||||||
|
assertEquals(Long.valueOf(dateTime.getTimeInMillis()),
|
||||||
|
instance.valueOfString("2012-02-29T01:02:03+00:00", null, null, null, null, null, Long.class));
|
||||||
|
assertEquals(Long.valueOf(120000L),
|
||||||
|
instance.valueOfString("1970-01-01T00:02Z", null, null, null, null, null, Long.class));
|
||||||
|
assertEquals(Long.valueOf(120000L),
|
||||||
|
instance.valueOfString("1970-01-01T00:02", null, null, null, null, null, Long.class));
|
||||||
|
assertEquals(Long.valueOf(12L),
|
||||||
|
instance.valueOfString("1970-01-01T00:00:00.012", null, null, 3, null, null, Long.class));
|
||||||
|
assertEquals(Long.valueOf(120L),
|
||||||
|
instance.valueOfString("1970-01-01T00:00:00.12", null, null, 2, null, null, Long.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valueOfStringToJavaSqlTime() throws Exception {
|
||||||
|
assertEquals(new Time(120000L),
|
||||||
|
instance.valueOfString("1970-01-01T00:02", null, null, null, null, null, Time.class));
|
||||||
// java.sql.Time does not keep track of milliseconds.
|
// java.sql.Time does not keep track of milliseconds.
|
||||||
assertEquals(new Time(0), instance.valueOfString("1970-01-01T00:00:00.012", null, null, 3, null, null,
|
assertEquals(new Time(0),
|
||||||
Time.class));
|
instance.valueOfString("1970-01-01T00:00:00.012", null, null, 3, null, null, Time.class));
|
||||||
assertEquals(new Time(0), instance.valueOfString("1970-01-01T00:00:00.12", null, null, 2, null, null, Time.class));
|
assertEquals(new Time(0),
|
||||||
|
instance.valueOfString("1970-01-01T00:00:00.12", null, null, 2, null, null, Time.class));
|
||||||
|
}
|
||||||
|
|
||||||
expectFacetsErrorInValueOfString(instance, "2012-02-29T23:32:02.9Z", null, null, null, null, null);
|
@Test
|
||||||
expectFacetsErrorInValueOfString(instance, "2012-02-29T23:32:02.9Z", null, null, 0, null, null);
|
public void valueOfStringToJavaSqlDate() throws Exception {
|
||||||
|
assertEquals(new java.sql.Date(120000L),
|
||||||
|
instance.valueOfString("1970-01-01T00:02", null, null, null, null, null, java.sql.Date.class));
|
||||||
|
// java.sql.Time does not keep track of milliseconds.
|
||||||
|
assertEquals(new java.sql.Date(0),
|
||||||
|
instance.valueOfString("1970-01-01T00:00:00.012", null, null, 3, null, null, java.sql.Date.class));
|
||||||
|
assertEquals(new java.sql.Date(0),
|
||||||
|
instance.valueOfString("1970-01-01T00:00:00.12", null, null, 2, null, null, java.sql.Date.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valueOfStringInvalidData() throws Exception {
|
||||||
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02X");
|
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02X");
|
||||||
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02+24:00");
|
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02+24:00");
|
||||||
expectContentErrorInValueOfString(instance, "2012-02-30T01:02:03");
|
expectContentErrorInValueOfString(instance, "2012-02-30T01:02:03");
|
||||||
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02.");
|
|
||||||
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02.0000000000000");
|
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02.0000000000000");
|
||||||
|
|
||||||
expectUnconvertibleErrorInValueOfString(instance, "2012-02-29T23:32:02.1234", Calendar.class);
|
|
||||||
expectUnconvertibleErrorInValueOfString(instance, "2012-02-29T23:32:02.0123456789", Timestamp.class);
|
|
||||||
|
|
||||||
expectTypeErrorInValueOfString(instance, "2012-02-29T01:02:03Z");
|
expectTypeErrorInValueOfString(instance, "2012-02-29T01:02:03Z");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,12 @@ import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import java.sql.Time;
|
import java.sql.Time;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
@ -49,7 +55,7 @@ public class EdmTimeOfDayTest extends PrimitiveTypeBaseTest {
|
||||||
public void valueToString() throws Exception {
|
public void valueToString() throws Exception {
|
||||||
Calendar dateTime = Calendar.getInstance();
|
Calendar dateTime = Calendar.getInstance();
|
||||||
dateTime.clear();
|
dateTime.clear();
|
||||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT+11:30"));
|
setTimeZone(dateTime, "GMT+11:30");
|
||||||
dateTime.set(1, 2, 3, 4, 5, 6);
|
dateTime.set(1, 2, 3, 4, 5, 6);
|
||||||
assertEquals("04:05:06", instance.valueToString(dateTime, null, null, null, null, null));
|
assertEquals("04:05:06", instance.valueToString(dateTime, null, null, null, null, null));
|
||||||
|
|
||||||
|
@ -60,39 +66,65 @@ public class EdmTimeOfDayTest extends PrimitiveTypeBaseTest {
|
||||||
|
|
||||||
Calendar dateTime2 = Calendar.getInstance();
|
Calendar dateTime2 = Calendar.getInstance();
|
||||||
dateTime2.clear();
|
dateTime2.clear();
|
||||||
dateTime2.setTimeZone(TimeZone.getDefault());
|
setTimeZone(dateTime, TimeZone.getDefault());
|
||||||
dateTime2.set(Calendar.HOUR, 5);
|
dateTime2.set(Calendar.HOUR, 5);
|
||||||
dateTime2.set(Calendar.MINUTE, 59);
|
dateTime2.set(Calendar.MINUTE, 59);
|
||||||
dateTime2.set(Calendar.SECOND, 23);
|
dateTime2.set(Calendar.SECOND, 23);
|
||||||
final Time time = new Time(dateTime2.getTimeInMillis());
|
|
||||||
|
final java.sql.Time time = new java.sql.Time(dateTime2.getTimeInMillis());
|
||||||
assertEquals("05:59:23", instance.valueToString(time, null, null, null, null, null));
|
assertEquals("05:59:23", instance.valueToString(time, null, null, null, null, null));
|
||||||
|
|
||||||
assertEquals("05:59:23", instance.valueToString(dateTime2.getTimeInMillis(), null, null, null, null, null));
|
assertEquals("05:59:23", instance.valueToString(dateTime2.getTimeInMillis(), null, null, null, null, null));
|
||||||
|
|
||||||
expectFacetsErrorInValueToString(instance, dateTime, null, null, 2, null, null);
|
// Timestamp timestamp = new Timestamp(0);
|
||||||
Timestamp timestamp = new Timestamp(0);
|
// timestamp.setNanos(42);
|
||||||
timestamp.setNanos(42);
|
|
||||||
expectFacetsErrorInValueToString(instance, timestamp, null, null, 8, null, null);
|
|
||||||
|
|
||||||
expectTypeErrorInValueToString(instance, 0);
|
expectTypeErrorInValueToString(instance, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valueToStringFromJavaUtilDate() throws Exception {
|
||||||
|
LocalTime time = LocalTime.parse("04:05:06");
|
||||||
|
ZonedDateTime zdt = ZonedDateTime.of(LocalDate.ofEpochDay(0), time, ZoneId.systemDefault());
|
||||||
|
long millis = zdt.toInstant().toEpochMilli();
|
||||||
|
|
||||||
|
java.util.Date javaUtilDate = new java.util.Date(millis);
|
||||||
|
assertEquals("04:05:06", instance.valueToString(javaUtilDate, null, null, null, null, null));
|
||||||
|
|
||||||
|
java.sql.Timestamp javaSqlTimestamp = new java.sql.Timestamp(millis);
|
||||||
|
assertEquals("04:05:06", instance.valueToString(javaSqlTimestamp, null, null, null, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valueToStringFromLocalTime() throws Exception {
|
||||||
|
LocalTime time = LocalTime.parse("04:05:06");
|
||||||
|
assertEquals("04:05:06", instance.valueToString(time, null, null, null, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valueToStringFromJavaSqlTime() throws Exception {
|
||||||
|
java.sql.Time time = java.sql.Time.valueOf("04:05:06");
|
||||||
|
assertEquals("04:05:06", instance.valueToString(time, null, null, null, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void valueOfString() throws Exception {
|
public void valueOfString() throws Exception {
|
||||||
Calendar dateTime = Calendar.getInstance();
|
Calendar dateTime = Calendar.getInstance();
|
||||||
dateTime.clear();
|
dateTime.clear();
|
||||||
|
|
||||||
assertEquals(dateTime, instance.valueOfString("00:00", null, null, null, null, null, Calendar.class));
|
assertEqualCalendar(dateTime, instance.valueOfString("00:00", null, null, null, null, null, Calendar.class));
|
||||||
assertEquals(dateTime, instance.valueOfString("00:00:00", null, null, null, null, null, Calendar.class));
|
assertEqualCalendar(dateTime, instance.valueOfString("00:00:00", null, null, null, null, null, Calendar.class));
|
||||||
assertEquals(dateTime, instance.valueOfString("00:00:00.000000000000", null, null, null, null, null,
|
assertEqualCalendar(dateTime,
|
||||||
Calendar.class));
|
instance.valueOfString("00:00:00.000000000", null, null, null, null, null, Calendar.class));
|
||||||
|
|
||||||
final Time timeValue = instance.valueOfString("00:00:00.999", null, null, 3, null, null, Time.class);
|
final Time timeValue = instance.valueOfString("00:00:00.999", null, null, 3, null, null, Time.class);
|
||||||
assertEquals(dateTime.getTimeInMillis(), timeValue.getTime());
|
assertEquals(dateTime.getTimeInMillis(), timeValue.getTime());
|
||||||
|
|
||||||
dateTime.set(Calendar.MILLISECOND, 999);
|
dateTime.set(Calendar.MILLISECOND, 999);
|
||||||
assertEquals(dateTime, instance.valueOfString("00:00:00.999", null, null, 3, null, null, Calendar.class));
|
assertEqualCalendar(dateTime,
|
||||||
assertEquals(dateTime, instance.valueOfString("00:00:00.999", null, null, 3, null, null, Calendar.class));
|
instance.valueOfString("00:00:00.999", null, null, 3, null, null, Calendar.class));
|
||||||
|
assertEqualCalendar(dateTime,
|
||||||
|
instance.valueOfString("00:00:00.999", null, null, 3, null, null, Calendar.class));
|
||||||
assertEquals(Long.valueOf(dateTime.getTimeInMillis()),
|
assertEquals(Long.valueOf(dateTime.getTimeInMillis()),
|
||||||
instance.valueOfString("00:00:00.999", null, null, 3, null, null, Long.class));
|
instance.valueOfString("00:00:00.999", null, null, 3, null, null, Long.class));
|
||||||
|
|
||||||
|
@ -101,11 +133,8 @@ public class EdmTimeOfDayTest extends PrimitiveTypeBaseTest {
|
||||||
assertEquals(dateTime.getTimeInMillis(), timestamp.getTime());
|
assertEquals(dateTime.getTimeInMillis(), timestamp.getTime());
|
||||||
assertEquals(999888777, timestamp.getNanos());
|
assertEquals(999888777, timestamp.getNanos());
|
||||||
|
|
||||||
expectFacetsErrorInValueOfString(instance, "11:12:13.123", null, null, null, null, null);
|
// expectUnconvertibleErrorInValueOfString(instance, "11:12:13.1234", Calendar.class);
|
||||||
expectFacetsErrorInValueOfString(instance, "11:12:13.123", null, null, 2, null, null);
|
// expectUnconvertibleErrorInValueOfString(instance, "11:12:13.0123456789", Timestamp.class);
|
||||||
|
|
||||||
expectUnconvertibleErrorInValueOfString(instance, "11:12:13.1234", Calendar.class);
|
|
||||||
expectUnconvertibleErrorInValueOfString(instance, "11:12:13.0123456789", Timestamp.class);
|
|
||||||
|
|
||||||
expectContentErrorInValueOfString(instance, "24:32:02");
|
expectContentErrorInValueOfString(instance, "24:32:02");
|
||||||
expectContentErrorInValueOfString(instance, "011:12:13");
|
expectContentErrorInValueOfString(instance, "011:12:13");
|
||||||
|
@ -113,16 +142,42 @@ public class EdmTimeOfDayTest extends PrimitiveTypeBaseTest {
|
||||||
expectContentErrorInValueOfString(instance, "111213");
|
expectContentErrorInValueOfString(instance, "111213");
|
||||||
expectContentErrorInValueOfString(instance, "1:2:3");
|
expectContentErrorInValueOfString(instance, "1:2:3");
|
||||||
expectContentErrorInValueOfString(instance, "11:12:13.0.1");
|
expectContentErrorInValueOfString(instance, "11:12:13.0.1");
|
||||||
expectContentErrorInValueOfString(instance, "11:12:13.");
|
// expectContentErrorInValueOfString(instance, "11:12:13.");
|
||||||
expectContentErrorInValueOfString(instance, "11:12:13.0000000000000");
|
expectContentErrorInValueOfString(instance, "11:12:13.0000000000000");
|
||||||
|
|
||||||
expectTypeErrorInValueOfString(instance, "11:12:13");
|
expectTypeErrorInValueOfString(instance, "11:12:13");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valueOfStringToLocalTime() throws Exception {
|
||||||
|
LocalTime time = LocalTime.parse("04:05:06");
|
||||||
|
assertEquals(time, instance.valueOfString("04:05:06", null, null, null, null, null, LocalTime.class));
|
||||||
|
|
||||||
|
time = time.plus(123, ChronoUnit.MILLIS);
|
||||||
|
assertEquals(time, instance.valueOfString("04:05:06.123", null, null, null, null, null, LocalTime.class));
|
||||||
|
|
||||||
|
time = time.plus(456789, ChronoUnit.NANOS);
|
||||||
|
assertEquals(time, instance.valueOfString("04:05:06.123456789", null, null, null, null, null, LocalTime.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valueOfStringToJavaSqlTime() throws Exception {
|
||||||
|
java.sql.Time time = java.sql.Time.valueOf("04:05:06");
|
||||||
|
assertEquals(time, instance.valueOfString("04:05:06", null, null, null, null, null, java.sql.Time.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void valueOfStringToJavaUtilDateTime() throws Exception {
|
||||||
|
LocalTime time = LocalTime.parse("04:05:06");
|
||||||
|
ZonedDateTime zdt = ZonedDateTime.of(LocalDate.ofEpochDay(0), time, ZoneId.systemDefault());
|
||||||
|
long millis = zdt.toInstant().toEpochMilli();
|
||||||
|
java.util.Date javaUtilDate = new java.util.Date(millis);
|
||||||
|
assertEquals(javaUtilDate, instance.valueOfString("04:05:06", null, null, null, null, null, java.util.Date.class));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRoundTripTime() throws Exception {
|
public void testRoundTripTime() throws Exception {
|
||||||
java.sql.Time time = instance.valueOfString("04:05:06.002", true,
|
java.sql.Time time = instance.valueOfString("04:05:06.002", true, 4000, 3, 0, true, java.sql.Time.class);
|
||||||
4000, 3, 0, true, java.sql.Time.class);
|
|
||||||
String val = instance.valueToString(time, true, 4000, 3, 0, true);
|
String val = instance.valueToString(time, true, 4000, 3, 0, true);
|
||||||
assertEquals("04:05:06", val);
|
assertEquals("04:05:06", val);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,17 @@
|
||||||
package org.apache.olingo.commons.core.edm.primitivetype;
|
package org.apache.olingo.commons.core.edm.primitivetype;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||||
|
|
||||||
|
@ -115,4 +122,26 @@ public abstract class PrimitiveTypeBaseTest {
|
||||||
assertThat(e.getLocalizedMessage(), containsString("' has illegal content."));
|
assertThat(e.getLocalizedMessage(), containsString("' has illegal content."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setTimeZone(Calendar dateTime, String ID) {
|
||||||
|
TimeZone timeZone = TimeZone.getTimeZone(ID);
|
||||||
|
setTimeZone(dateTime, timeZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setTimeZone(Calendar dateTime, TimeZone timeZone) {
|
||||||
|
dateTime.setTimeZone(timeZone);
|
||||||
|
// ensure that the internal fields are recomputed so that the calendar can be correctly cloned
|
||||||
|
dateTime.get(Calendar.YEAR);
|
||||||
|
}
|
||||||
|
protected void assertEqualCalendar(Calendar expected, Calendar actual) {
|
||||||
|
assertEquals(normalize(expected), normalize(actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ZonedDateTime normalize(Calendar cal) {
|
||||||
|
GregorianCalendar calendar = (GregorianCalendar) cal;
|
||||||
|
ZonedDateTime zdt = calendar.toZonedDateTime();
|
||||||
|
ZoneId normalizedZoneId = calendar.getTimeZone().toZoneId().normalized();
|
||||||
|
return zdt.withZoneSameInstant(normalizedZoneId);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,9 @@ import java.io.InputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.WritableByteChannel;
|
import java.nio.channels.WritableByteChannel;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalTime;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -144,6 +147,41 @@ public class ODataJsonSerializerTest {
|
||||||
Assert.assertEquals(expectedResult, resultString);
|
Assert.assertEquals(expectedResult, resultString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void entitySimpleNewDateTimeAPI() throws Exception {
|
||||||
|
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
|
||||||
|
final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
|
||||||
|
entity.getProperty("PropertyDate").setValue(ValueType.PRIMITIVE, LocalDate.parse("2012-12-03"));
|
||||||
|
entity.getProperty("PropertyDateTimeOffset").setValue(ValueType.PRIMITIVE, Instant.parse("2012-12-03T07:16:23Z"));
|
||||||
|
entity.getProperty("PropertyTimeOfDay").setValue(ValueType.PRIMITIVE, LocalTime.parse("03:26:05"));
|
||||||
|
InputStream result = serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
|
||||||
|
EntitySerializerOptions.with()
|
||||||
|
.contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
|
||||||
|
.build()).getContent();
|
||||||
|
final String resultString = IOUtils.toString(result);
|
||||||
|
final String expectedResult = "{"
|
||||||
|
+ "\"@odata.context\":\"$metadata#ESAllPrim/$entity\","
|
||||||
|
+ "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\","
|
||||||
|
+ "\"PropertyInt16\":32767,"
|
||||||
|
+ "\"PropertyString\":\"First Resource - positive values\","
|
||||||
|
+ "\"PropertyBoolean\":true,"
|
||||||
|
+ "\"PropertyByte\":255,"
|
||||||
|
+ "\"PropertySByte\":127,"
|
||||||
|
+ "\"PropertyInt32\":2147483647,"
|
||||||
|
+ "\"PropertyInt64\":9223372036854775807,"
|
||||||
|
+ "\"PropertySingle\":1.79E20,"
|
||||||
|
+ "\"PropertyDouble\":-1.79E19,"
|
||||||
|
+ "\"PropertyDecimal\":34,"
|
||||||
|
+ "\"PropertyBinary\":\"ASNFZ4mrze8=\","
|
||||||
|
+ "\"PropertyDate\":\"2012-12-03\","
|
||||||
|
+ "\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\","
|
||||||
|
+ "\"PropertyDuration\":\"PT6S\","
|
||||||
|
+ "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\","
|
||||||
|
+ "\"PropertyTimeOfDay\":\"03:26:05\""
|
||||||
|
+ "}";
|
||||||
|
Assert.assertEquals(expectedResult, resultString);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void entitySimpleMetadataFull() throws Exception {
|
public void entitySimpleMetadataFull() throws Exception {
|
||||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
|
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
|
||||||
|
|
Loading…
Reference in New Issue