[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;
|
||||
|
||||
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.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
|
||||
|
@ -29,65 +35,80 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
|||
*/
|
||||
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() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static EdmDate getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
@Override
|
||||
public Class<?> getDefaultType() {
|
||||
return Calendar.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getDefaultType() {
|
||||
return Calendar.class;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected <T> T internalValueOfString(final String value, final Boolean isNullable, final Integer maxLength,
|
||||
final Integer precision, final Integer scale, final Boolean isUnicode, final Class<T> returnType)
|
||||
throws EdmPrimitiveTypeException {
|
||||
LocalDate date;
|
||||
try {
|
||||
date = LocalDate.parse(value);
|
||||
} catch (DateTimeParseException ex) {
|
||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> T internalValueOfString(final String value,
|
||||
final Boolean isNullable, final Integer maxLength, final Integer precision,
|
||||
final Integer scale, final Boolean isUnicode, final Class<T> returnType) throws EdmPrimitiveTypeException {
|
||||
// appropriate types
|
||||
if (returnType.isAssignableFrom(LocalDate.class)) {
|
||||
return (T) date;
|
||||
} else if (returnType.isAssignableFrom(java.sql.Date.class)) {
|
||||
return (T) java.sql.Date.valueOf(date);
|
||||
}
|
||||
|
||||
final Calendar dateTimeValue = Calendar.getInstance();
|
||||
dateTimeValue.clear();
|
||||
// inappropriate types, which need to be supported for backward compatibility
|
||||
ZonedDateTime zdt = LocalDateTime.of(date, LocalTime.MIDNIGHT).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(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.");
|
||||
}
|
||||
}
|
||||
|
||||
final Matcher matcher = PATTERN.matcher(value);
|
||||
if (!matcher.matches()) {
|
||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
|
||||
}
|
||||
|
||||
dateTimeValue.set(
|
||||
Integer.parseInt(matcher.group(1)),
|
||||
Byte.parseByte(matcher.group(2)) - 1, // month is zero-based
|
||||
Byte.parseByte(matcher.group(3)));
|
||||
|
||||
try {
|
||||
return EdmDateTimeOffset.convertDateTime(dateTimeValue, 0, returnType);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.", e);
|
||||
} catch (final ClassCastException e) {
|
||||
throw new EdmPrimitiveTypeException("The value type " + returnType + " is not supported.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> String internalValueToString(final T value,
|
||||
final Boolean isNullable, final Integer maxLength, final Integer precision,
|
||||
final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException {
|
||||
|
||||
final Calendar dateTimeValue = EdmDateTimeOffset.createDateTime(value, true);
|
||||
|
||||
final StringBuilder result = new StringBuilder(10); // Ten characters are enough for "normal" dates.
|
||||
final int year = dateTimeValue.get(Calendar.YEAR);
|
||||
if (year < 0 || year >= 10000) {
|
||||
result.append(year);
|
||||
} else {
|
||||
EdmDateTimeOffset.appendTwoDigits(result, (year / 100) % 100);
|
||||
EdmDateTimeOffset.appendTwoDigits(result, year % 100);
|
||||
}
|
||||
result.append('-');
|
||||
EdmDateTimeOffset.appendTwoDigits(result, dateTimeValue.get(Calendar.MONTH) + 1); // month is zero-based
|
||||
result.append('-');
|
||||
EdmDateTimeOffset.appendTwoDigits(result, dateTimeValue.get(Calendar.DAY_OF_MONTH));
|
||||
return result.toString();
|
||||
}
|
||||
@Override
|
||||
protected <T> String internalValueToString(final T value, final Boolean isNullable, final Integer maxLength,
|
||||
final Integer precision, 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();
|
||||
}
|
||||
|
||||
// inappropriate types, which need to be supported for backward compatibility
|
||||
if (value instanceof GregorianCalendar) {
|
||||
GregorianCalendar calendar = (GregorianCalendar) value;
|
||||
return calendar.toZonedDateTime().toLocalDate().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.toLocalDate().toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,11 +18,16 @@
|
|||
*/
|
||||
package org.apache.olingo.commons.core.edm.primitivetype;
|
||||
|
||||
import java.sql.Time;
|
||||
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.Date;
|
||||
import java.util.TimeZone;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -33,245 +38,144 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
|||
*/
|
||||
public final class EdmDateTimeOffset extends SingletonPrimitiveType {
|
||||
|
||||
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*)?)?"
|
||||
+ "(Z|([-+]\\p{Digit}{2}:\\p{Digit}{2}))?");
|
||||
private static final ZoneId ZULU = ZoneId.of("Z");
|
||||
|
||||
private static final EdmDateTimeOffset INSTANCE = new EdmDateTimeOffset();
|
||||
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*)?)?"
|
||||
+ "(Z|([-+]\\p{Digit}{2}:\\p{Digit}{2}))?");
|
||||
|
||||
public static EdmDateTimeOffset getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
private static final EdmDateTimeOffset INSTANCE = new EdmDateTimeOffset();
|
||||
|
||||
@Override
|
||||
public Class<?> getDefaultType() {
|
||||
return Timestamp.class;
|
||||
}
|
||||
public static EdmDateTimeOffset getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> T internalValueOfString(final String value,
|
||||
final Boolean isNullable, final Integer maxLength, final Integer precision,
|
||||
final Integer scale, final Boolean isUnicode, final Class<T> returnType) throws EdmPrimitiveTypeException {
|
||||
@Override
|
||||
public Class<?> getDefaultType() {
|
||||
return Timestamp.class;
|
||||
}
|
||||
|
||||
final Matcher matcher = PATTERN.matcher(value);
|
||||
if (!matcher.matches()) {
|
||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
|
||||
}
|
||||
@Override
|
||||
protected <T> T internalValueOfString(final String value, final Boolean isNullable, final Integer maxLength,
|
||||
final Integer precision, final Integer scale, final Boolean isUnicode, final Class<T> returnType)
|
||||
throws EdmPrimitiveTypeException {
|
||||
try {
|
||||
ZonedDateTime zdt = parseZonedDateTime(value);
|
||||
|
||||
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();
|
||||
return convertZonedDateTime(zdt, returnType);
|
||||
} catch (DateTimeParseException ex) {
|
||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.", ex);
|
||||
} catch (final ClassCastException e) {
|
||||
throw new EdmPrimitiveTypeException("The value type " + returnType + " is not supported.", e);
|
||||
}
|
||||
}
|
||||
|
||||
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)));
|
||||
private static ZonedDateTime parseZonedDateTime(final String value) {
|
||||
ZonedDateTime zdt;
|
||||
try {
|
||||
// ISO-8601 conform pattern
|
||||
zdt = ZonedDateTime.parse(value);
|
||||
} catch (DateTimeParseException ex) {
|
||||
// for backward compatibility - allow patterns that don't specify a time zone
|
||||
final Matcher matcher = PATTERN.matcher(value);
|
||||
if (matcher.matches() && matcher.group(9) == null) {
|
||||
zdt = ZonedDateTime.parse(value + "Z");
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
return zdt;
|
||||
}
|
||||
|
||||
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 + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T convertZonedDateTime(ZonedDateTime zdt, Class<T> returnType) {
|
||||
if (returnType == ZonedDateTime.class) {
|
||||
return (T) zdt;
|
||||
} else if (returnType == Instant.class) {
|
||||
return (T) zdt.toInstant();
|
||||
} 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 if (returnType.isAssignableFrom(java.sql.Time.class)) {
|
||||
return (T) new java.sql.Time(zdt.toInstant().truncatedTo(ChronoUnit.SECONDS).toEpochMilli());
|
||||
} else if (returnType.isAssignableFrom(java.sql.Date.class)) {
|
||||
return (T) new java.sql.Date(zdt.toInstant().truncatedTo(ChronoUnit.SECONDS).toEpochMilli());
|
||||
} else if (returnType.isAssignableFrom(Long.class)) {
|
||||
return (T) Long.valueOf(zdt.toInstant().toEpochMilli());
|
||||
} else if (returnType.isAssignableFrom(Calendar.class)) {
|
||||
return (T) GregorianCalendar.from(zdt);
|
||||
} else {
|
||||
throw new ClassCastException("unsupported return type " + returnType.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return convertDateTime(dateTimeValue, nanoSeconds, returnType);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.", e);
|
||||
} catch (final ClassCastException e) {
|
||||
throw new EdmPrimitiveTypeException("The value type " + returnType + " is not supported.", e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected <T> String internalValueToString(final T value, final Boolean isNullable, final Integer maxLength,
|
||||
final Integer precision, final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException {
|
||||
ZonedDateTime zdt = createZonedDateTime(value);
|
||||
|
||||
/**
|
||||
* <p>Converts a {@link Calendar} value into the requested return type if possible.</p>
|
||||
* <p>It is expected that the {@link Calendar} value will already be in the desired time zone.</p>
|
||||
* @param dateTimeValue the value
|
||||
* @param nanoSeconds nanoseconds part of the value; only used for the {@link Timestamp} return type
|
||||
* @param returnType the class of the returned value;
|
||||
* it must be one of {@link Calendar}, {@link Long}, {@link Date},
|
||||
* {@link Time}, or {@link Timestamp}
|
||||
* @return the converted value
|
||||
* @throws IllegalArgumentException if the Calendar value is not valid
|
||||
* @throws ClassCastException if the return type is not allowed
|
||||
*/
|
||||
protected static <T> T convertDateTime(final Calendar dateTimeValue, final int nanoSeconds,
|
||||
final Class<T> returnType) throws IllegalArgumentException, ClassCastException {
|
||||
return format(zdt.toLocalDateTime(), zdt.getOffset(), zdt.getNano());
|
||||
}
|
||||
|
||||
// The Calendar class does not check any values until a get method is called,
|
||||
// so we do just that to validate the fields that may have been set,
|
||||
// not because we want to return something else.
|
||||
// For strict checks, the lenient mode is switched off.
|
||||
dateTimeValue.setLenient(false);
|
||||
private static <T> ZonedDateTime createZonedDateTime(final T value) throws EdmPrimitiveTypeException {
|
||||
if (value instanceof ZonedDateTime) {
|
||||
return (ZonedDateTime) value;
|
||||
}
|
||||
|
||||
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)) {
|
||||
Timestamp timestamp = new Timestamp(dateTimeValue.getTimeInMillis());
|
||||
timestamp.setNanos(nanoSeconds);
|
||||
return returnType.cast(timestamp);
|
||||
} else if (returnType.isAssignableFrom(Time.class)) {
|
||||
// Normalize the value.
|
||||
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)) {
|
||||
// Normalize the value.
|
||||
dateTimeValue.set(Calendar.HOUR_OF_DAY, 0);
|
||||
dateTimeValue.set(Calendar.MINUTE, 0);
|
||||
dateTimeValue.set(Calendar.SECOND, 0);
|
||||
dateTimeValue.set(Calendar.MILLISECOND, 0);
|
||||
return returnType.cast(new java.sql.Date(dateTimeValue.getTimeInMillis())); // may throw IllegalArgumentException
|
||||
} else {
|
||||
throw new ClassCastException("unsupported return type " + returnType.getSimpleName());
|
||||
}
|
||||
}
|
||||
if (value instanceof Instant) {
|
||||
return ((Instant) value).atZone(ZULU);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> String internalValueToString(final T value,
|
||||
final Boolean isNullable, final Integer maxLength, final Integer precision,
|
||||
final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException {
|
||||
if (value instanceof GregorianCalendar) {
|
||||
GregorianCalendar calendar = (GregorianCalendar) value;
|
||||
ZonedDateTime zdt = calendar.toZonedDateTime();
|
||||
ZoneId normalizedZoneId = calendar.getTimeZone().toZoneId().normalized();
|
||||
return zdt.withZoneSameInstant(normalizedZoneId);
|
||||
}
|
||||
|
||||
final Calendar dateTimeValue = createDateTime(value, false);
|
||||
return convertToInstant(value).atZone(ZULU);
|
||||
}
|
||||
|
||||
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));
|
||||
private static String format(LocalDateTime dateTime, ZoneOffset offset, int nanos) {
|
||||
String str = dateTime.toString();
|
||||
if (nanos > 0) {
|
||||
str = removeTrailingZeros(str);
|
||||
}
|
||||
str = str + offset.toString();
|
||||
|
||||
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);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
final int offsetInMinutes = (dateTimeValue.get(Calendar.ZONE_OFFSET)
|
||||
+ dateTimeValue.get(Calendar.DST_OFFSET)) / 60 / 1000;
|
||||
final int offsetHours = offsetInMinutes / 60;
|
||||
final int offsetMinutes = Math.abs(offsetInMinutes % 60);
|
||||
final String offsetString = offsetInMinutes == 0 ? "Z" : String.format("%+03d:%02d", offsetHours, offsetMinutes);
|
||||
result.append(offsetString);
|
||||
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);
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a date/time value from the given value.
|
||||
*
|
||||
* @param value the value as {@link Calendar}, {@link Date}, or {@link Long}
|
||||
* @param isLocal whether the value is to be in the default time zone (or in GMT)
|
||||
* @return the value as {@link Calendar} in the desired time zone
|
||||
* @throws EdmPrimitiveTypeException if the type of the value is not supported
|
||||
*/
|
||||
protected static <T> Calendar createDateTime(final T value, final boolean isLocal) throws EdmPrimitiveTypeException {
|
||||
Calendar dateTimeValue;
|
||||
if (value instanceof Date) {
|
||||
dateTimeValue = Calendar.getInstance(isLocal ? TimeZone.getDefault() : TimeZone.getTimeZone("GMT"));
|
||||
dateTimeValue.setTime((Date) value);
|
||||
} else if (value instanceof Calendar) {
|
||||
dateTimeValue = (Calendar) ((Calendar) value).clone();
|
||||
} else if (value instanceof Long) {
|
||||
dateTimeValue = Calendar.getInstance(isLocal ? TimeZone.getDefault() : TimeZone.getTimeZone("GMT"));
|
||||
dateTimeValue.setTimeInMillis((Long) value);
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates an {@link Instant} from the given value.
|
||||
*
|
||||
* @param value the value as {@link Instant}, {@link java.util.Date},
|
||||
* {@link java.sql.Timestamp}, {@link Long} or
|
||||
* {@link GregorianCalendar}
|
||||
* @return the value as {@link Instant}
|
||||
* @throws EdmPrimitiveTypeException if the type of the value is not supported
|
||||
*/
|
||||
private static <T> Instant convertToInstant(final T value) throws EdmPrimitiveTypeException {
|
||||
if (value instanceof java.sql.Time || value instanceof java.sql.Date) {
|
||||
throw new EdmPrimitiveTypeException("The value type " + value.getClass() + " is not supported.");
|
||||
} else if (value instanceof java.util.Date) {
|
||||
return ((java.util.Date) value).toInstant();
|
||||
} else if (value instanceof Timestamp) {
|
||||
return ((Timestamp) value).toInstant();
|
||||
} else if (value instanceof Long) {
|
||||
return Instant.ofEpochMilli((Long) value);
|
||||
} else {
|
||||
throw new EdmPrimitiveTypeException("The value type " + value.getClass() + " is not supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,103 +19,115 @@
|
|||
package org.apache.olingo.commons.core.edm.primitivetype;
|
||||
|
||||
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.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.GregorianCalendar;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
|
||||
public final class EdmTimeOfDay extends SingletonPrimitiveType {
|
||||
|
||||
private static final Pattern PATTERN = Pattern.compile(
|
||||
"(\\p{Digit}{2}):(\\p{Digit}{2})(?::(\\p{Digit}{2})(\\.(\\p{Digit}{0,}?)0*)?)?");
|
||||
private static final LocalDate EPOCH = LocalDate.ofEpochDay(0l);
|
||||
private static final EdmTimeOfDay INSTANCE = new EdmTimeOfDay();
|
||||
|
||||
private static final EdmTimeOfDay INSTANCE = new EdmTimeOfDay();
|
||||
public static EdmTimeOfDay getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static EdmTimeOfDay getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
@Override
|
||||
public Class<?> getDefaultType() {
|
||||
return Calendar.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getDefaultType() {
|
||||
return Calendar.class;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected <T> T internalValueOfString(final String value, final Boolean isNullable, final Integer maxLength,
|
||||
final Integer precision, final Integer scale, final Boolean isUnicode, final Class<T> returnType)
|
||||
throws EdmPrimitiveTypeException {
|
||||
LocalTime time;
|
||||
try {
|
||||
time = LocalTime.parse(value);
|
||||
} catch (DateTimeParseException ex) {
|
||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> T internalValueOfString(final String value,
|
||||
final Boolean isNullable, final Integer maxLength, final Integer precision,
|
||||
final Integer scale, final Boolean isUnicode, final Class<T> returnType) throws EdmPrimitiveTypeException {
|
||||
// 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);
|
||||
}
|
||||
|
||||
final Matcher matcher = PATTERN.matcher(value);
|
||||
if (!matcher.matches()) {
|
||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
|
||||
}
|
||||
// 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.");
|
||||
}
|
||||
}
|
||||
|
||||
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)));
|
||||
@Override
|
||||
protected <T> String internalValueToString(final T value, final Boolean isNullable, final Integer maxLength,
|
||||
final Integer precision, final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException {
|
||||
// appropriate types
|
||||
if (value instanceof LocalTime) {
|
||||
return value.toString();
|
||||
} else if(value instanceof java.sql.Time) {
|
||||
return value.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();
|
||||
|
||||
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 {
|
||||
return EdmDateTimeOffset.convertDateTime(dateTimeValue, nanoSeconds, returnType);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.", e);
|
||||
} catch (final ClassCastException e) {
|
||||
throw new EdmPrimitiveTypeException("The value type " + returnType + " is not supported.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> String internalValueToString(final T value,
|
||||
final Boolean isNullable, final Integer maxLength, final Integer precision,
|
||||
final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException {
|
||||
|
||||
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();
|
||||
}
|
||||
//
|
||||
// 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 java.time.LocalDate;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||
|
@ -30,64 +30,79 @@ import org.junit.Test;
|
|||
|
||||
public class EdmDateTest extends PrimitiveTypeBaseTest {
|
||||
|
||||
private final EdmPrimitiveType instance = EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Date);
|
||||
private final EdmPrimitiveType instance = EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Date);
|
||||
|
||||
@Test
|
||||
public void toUriLiteral() throws Exception {
|
||||
assertEquals("2009-12-26", instance.toUriLiteral("2009-12-26"));
|
||||
assertEquals("-2009-12-26", instance.toUriLiteral("-2009-12-26"));
|
||||
}
|
||||
@Test
|
||||
public void toUriLiteral() throws Exception {
|
||||
assertEquals("2009-12-26", instance.toUriLiteral("2009-12-26"));
|
||||
assertEquals("-2009-12-26", instance.toUriLiteral("-2009-12-26"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromUriLiteral() throws Exception {
|
||||
assertEquals("2009-12-26", instance.fromUriLiteral("2009-12-26"));
|
||||
assertEquals("-2009-12-26", instance.fromUriLiteral("-2009-12-26"));
|
||||
}
|
||||
@Test
|
||||
public void fromUriLiteral() throws Exception {
|
||||
assertEquals("2009-12-26", instance.fromUriLiteral("2009-12-26"));
|
||||
assertEquals("-2009-12-26", instance.fromUriLiteral("-2009-12-26"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valueToString() throws Exception {
|
||||
Calendar dateTime = Calendar.getInstance();
|
||||
dateTime.clear();
|
||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT-11:30"));
|
||||
dateTime.set(2012, 1, 29, 13, 0, 0);
|
||||
assertEquals("2012-02-29", instance.valueToString(dateTime, null, null, null, null, null));
|
||||
@Test
|
||||
public void valueToString() throws Exception {
|
||||
Calendar dateTime = Calendar.getInstance();
|
||||
dateTime.clear();
|
||||
setTimeZone(dateTime, "GMT-11:30");
|
||||
dateTime.set(2012, 1, 29, 13, 0, 0);
|
||||
assertEquals("2012-02-29", instance.valueToString(dateTime, null, null, null, null, null));
|
||||
|
||||
Long millis = 1330558323007L;
|
||||
millis -= TimeZone.getDefault().getOffset(millis);
|
||||
assertEquals("2012-02-29", instance.valueToString(millis, null, null, null, null, null));
|
||||
Long millis = 1330558323007L;
|
||||
millis -= TimeZone.getDefault().getOffset(millis);
|
||||
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);
|
||||
assertEquals("12344-02-29", instance.valueToString(dateTime, null, null, null, null, null));
|
||||
// TODO support for years beyond 9999
|
||||
// dateTime.set(Calendar.YEAR, 12344);
|
||||
// assertEquals("12344-02-29", instance.valueToString(dateTime, null, null, null, null, null));
|
||||
|
||||
expectTypeErrorInValueToString(instance, 0);
|
||||
}
|
||||
expectTypeErrorInValueToString(instance, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valueOfString() throws Exception {
|
||||
Calendar dateTime = Calendar.getInstance();
|
||||
dateTime.clear();
|
||||
dateTime.set(2012, 1, 29);
|
||||
assertEquals(dateTime, instance.valueOfString("2012-02-29", null, null, null, null, null, Calendar.class));
|
||||
assertEquals(Long.valueOf(dateTime.getTimeInMillis()), 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, Date.class));
|
||||
@Test
|
||||
public void valueOfString() throws Exception {
|
||||
Calendar dateTime = Calendar.getInstance();
|
||||
dateTime.clear();
|
||||
dateTime.set(2012, 1, 29);
|
||||
assertEqualCalendar(dateTime,
|
||||
instance.valueOfString("2012-02-29", null, null, null, null, null, Calendar.class));
|
||||
assertEquals(Long.valueOf(dateTime.getTimeInMillis()),
|
||||
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);
|
||||
assertEquals(dateTime, instance.valueOfString("12344-02-29", null, null, null, null, null, Calendar.class));
|
||||
// TODO support for years beyond 9999
|
||||
// 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.
|
||||
// dateTime.set(-1, 1, 28);
|
||||
// assertEquals(dateTime, instance.valueOfString("-0001-02-28", null, Calendar.class));
|
||||
// TODO: Clarify whether negative years are really needed.
|
||||
// dateTime.set(-1, 1, 28);
|
||||
// assertEquals(dateTime, instance.valueOfString("-0001-02-28", null,
|
||||
// Calendar.class));
|
||||
|
||||
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02");
|
||||
expectContentErrorInValueOfString(instance, "2012-02-30");
|
||||
expectContentErrorInValueOfString(instance, "20120229");
|
||||
expectContentErrorInValueOfString(instance, "2012-02-1");
|
||||
expectContentErrorInValueOfString(instance, "2012-2-12");
|
||||
expectContentErrorInValueOfString(instance, "123-02-03");
|
||||
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02");
|
||||
expectContentErrorInValueOfString(instance, "2012-02-30");
|
||||
expectContentErrorInValueOfString(instance, "20120229");
|
||||
expectContentErrorInValueOfString(instance, "2012-02-1");
|
||||
expectContentErrorInValueOfString(instance, "2012-2-12");
|
||||
expectContentErrorInValueOfString(instance, "123-02-03");
|
||||
|
||||
expectTypeErrorInValueOfString(instance, "2012-02-29");
|
||||
}
|
||||
expectTypeErrorInValueOfString(instance, "2012-02-29");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,12 @@ import static org.junit.Assert.assertEquals;
|
|||
|
||||
import java.sql.Time;
|
||||
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.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
|
||||
|
@ -32,129 +35,208 @@ import org.junit.Test;
|
|||
|
||||
public class EdmDateTimeOffsetTest extends PrimitiveTypeBaseTest {
|
||||
|
||||
final EdmPrimitiveType instance = EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.DateTimeOffset);
|
||||
final EdmPrimitiveType instance = EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.DateTimeOffset);
|
||||
|
||||
@Test
|
||||
public void toUriLiteral() throws Exception {
|
||||
assertEquals("2009-12-26T21:23:38Z", instance.toUriLiteral("2009-12-26T21:23:38Z"));
|
||||
assertEquals("2002-10-10T12:00:00-05:00", instance.toUriLiteral("2002-10-10T12:00:00-05:00"));
|
||||
}
|
||||
@Test
|
||||
public void toUriLiteral() throws Exception {
|
||||
assertEquals("2009-12-26T21:23:38Z", instance.toUriLiteral("2009-12-26T21:23:38Z"));
|
||||
assertEquals("2002-10-10T12:00:00-05:00", instance.toUriLiteral("2002-10-10T12:00:00-05:00"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromUriLiteral() throws Exception {
|
||||
assertEquals("2009-12-26T21:23:38Z", instance.fromUriLiteral("2009-12-26T21:23:38Z"));
|
||||
assertEquals("2002-10-10T12:00:00-05:00", instance.fromUriLiteral("2002-10-10T12:00:00-05:00"));
|
||||
}
|
||||
@Test
|
||||
public void fromUriLiteral() throws Exception {
|
||||
assertEquals("2009-12-26T21:23:38Z", instance.fromUriLiteral("2009-12-26T21:23:38Z"));
|
||||
assertEquals("2002-10-10T12:00:00-05:00", instance.fromUriLiteral("2002-10-10T12:00:00-05:00"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valueToString() throws Exception {
|
||||
Calendar dateTime = Calendar.getInstance();
|
||||
dateTime.clear();
|
||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
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, 0, null, null));
|
||||
assertEquals("2012-02-29T01:02:03Z", instance.valueToString(dateTime, null, null, 5, null, null));
|
||||
@Test
|
||||
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));
|
||||
}
|
||||
|
||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT-1:30"));
|
||||
assertEquals("2012-02-29T01:02:03-01:30", instance.valueToString(dateTime, null, null, null, null, null));
|
||||
@Test
|
||||
public void valueToStringFromZonedDateTime() throws Exception {
|
||||
ZonedDateTime zdt = ZonedDateTime.parse("2012-02-28T23:32:03-01:30");
|
||||
|
||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT+11:00"));
|
||||
assertEquals("2012-02-29T01:02:03+11:00", instance.valueToString(dateTime, null, null, null, null, null));
|
||||
assertEquals("2012-02-28T23:32:03-01:30", instance.valueToString(zdt, null, null, null, null, null));
|
||||
|
||||
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-29T01:02:03.503+11:00", instance.valueToString(dateTime, null, null, 3, 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));
|
||||
|
||||
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-29T01:02:03.53+11:00", instance.valueToString(dateTime, null, null, 3, null, null));
|
||||
zdt = zdt.plus(123, ChronoUnit.MILLIS);
|
||||
|
||||
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-29T01:02:03.053+11:00", instance.valueToString(dateTime, null, null, 3, null, null));
|
||||
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));
|
||||
}
|
||||
|
||||
final Long 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, 3, 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));
|
||||
@Test
|
||||
public void valueToStringFromCalendar() throws Exception {
|
||||
Calendar dateTime = Calendar.getInstance();
|
||||
dateTime.clear();
|
||||
setTimeZone(dateTime, "GMT");
|
||||
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, 0, null, null));
|
||||
assertEquals("2012-02-29T01:02:03Z", instance.valueToString(dateTime, null, null, 5, null, null));
|
||||
|
||||
assertEquals("2012-02-29T23:32:03.007Z", instance.valueToString(new Time(millis), null, null, 3, null, null));
|
||||
assertEquals("1969-12-31T23:59:59.9Z", instance.valueToString(new Time(-100L), null, null, 1, null, null));
|
||||
assertEquals("1969-12-31T23:59:59.98Z", instance.valueToString(new Time(-20L), null, null, 2, null, null));
|
||||
setTimeZone(dateTime, "GMT-1:30");
|
||||
assertEquals("2012-02-28T23:32:03-01:30", instance.valueToString(dateTime, null, null, null, null, null));
|
||||
|
||||
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, 3, null, null));
|
||||
setTimeZone(dateTime, "GMT+11:00");
|
||||
assertEquals("2012-02-29T12:02:03+11:00", instance.valueToString(dateTime, null, null, null, null, null));
|
||||
|
||||
Timestamp timestamp = new Timestamp(0);
|
||||
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, 8, null, null));
|
||||
dateTime.set(Calendar.MILLISECOND, 503);
|
||||
assertEquals("2012-02-29T12: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, 3, null, null));
|
||||
|
||||
expectFacetsErrorInValueToString(instance, 3L, null, null, 2, null, null);
|
||||
expectFacetsErrorInValueToString(instance, timestamp, null, null, 7, null, null);
|
||||
dateTime.set(Calendar.MILLISECOND, 530);
|
||||
assertEquals("2012-02-29T12: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, 3, null, null));
|
||||
|
||||
expectTypeErrorInValueToString(instance, 0);
|
||||
}
|
||||
dateTime.set(Calendar.MILLISECOND, 53);
|
||||
assertEquals("2012-02-29T12: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, 3, null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valueOfString() throws Exception {
|
||||
Calendar dateTime = Calendar.getInstance();
|
||||
dateTime.clear();
|
||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
dateTime.set(2012, 1, 29, 1, 2, 3);
|
||||
assertEquals(dateTime, 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,
|
||||
null, null, null, null, Long.class));
|
||||
assertEquals(dateTime, instance.valueOfString("2012-02-29T01:02:03", null, null, null, null, null,
|
||||
Calendar.class));
|
||||
@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, 3, 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));
|
||||
}
|
||||
|
||||
dateTime.clear();
|
||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT-01:30"));
|
||||
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,
|
||||
Date.class));
|
||||
@Test
|
||||
public void valueToStringFromJavaUtilDate() throws Exception {
|
||||
final Long millis = 1330558323007L;
|
||||
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, 3, null, null));
|
||||
}
|
||||
|
||||
dateTime.clear();
|
||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT+11:00"));
|
||||
dateTime.set(2012, 1, 29, 1, 2, 3);
|
||||
assertEquals(dateTime, instance.valueOfString("2012-02-29T01:02:03+11:00", null, null, null, null, null,
|
||||
Calendar.class));
|
||||
@Test
|
||||
public void valueToStringFromTimestamp() throws Exception {
|
||||
Timestamp timestamp = new Timestamp(0);
|
||||
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, 8, null, null));
|
||||
|
||||
dateTime.add(Calendar.MILLISECOND, 7);
|
||||
assertEquals(dateTime, 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,
|
||||
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 valueToStringFromInvalidTypes() throws Exception {
|
||||
expectTypeErrorInValueToString(instance, Integer.valueOf(0));
|
||||
expectTypeErrorInValueToString(instance, Time.valueOf("12:13:14"));
|
||||
expectTypeErrorInValueToString(instance, java.sql.Date.valueOf("2019-10-25"));
|
||||
}
|
||||
|
||||
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.
|
||||
assertEquals(new Time(0), 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));
|
||||
@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));
|
||||
}
|
||||
|
||||
expectFacetsErrorInValueOfString(instance, "2012-02-29T23:32:02.9Z", null, null, null, null, null);
|
||||
expectFacetsErrorInValueOfString(instance, "2012-02-29T23:32:02.9Z", null, null, 0, null, null);
|
||||
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02X");
|
||||
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02+24:00");
|
||||
expectContentErrorInValueOfString(instance, "2012-02-30T01:02:03");
|
||||
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02.");
|
||||
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02.0000000000000");
|
||||
@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));
|
||||
}
|
||||
|
||||
expectUnconvertibleErrorInValueOfString(instance, "2012-02-29T23:32:02.1234", Calendar.class);
|
||||
expectUnconvertibleErrorInValueOfString(instance, "2012-02-29T23:32:02.0123456789", Timestamp.class);
|
||||
@Test
|
||||
public void valueOfStringToCalendar() throws Exception {
|
||||
Calendar dateTime = Calendar.getInstance();
|
||||
dateTime.clear();
|
||||
setTimeZone(dateTime, "GMT");
|
||||
dateTime.set(2012, 1, 29, 1, 2, 3);
|
||||
assertEqualCalendar(dateTime,
|
||||
instance.valueOfString("2012-02-29T01:02:03Z", null, null, null, null, null, Calendar.class));
|
||||
assertEqualCalendar(dateTime,
|
||||
instance.valueOfString("2012-02-29T01:02:03", null, null, null, null, null, Calendar.class));
|
||||
|
||||
dateTime.clear();
|
||||
setTimeZone(dateTime, "GMT-01:30");
|
||||
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, Date.class));
|
||||
|
||||
dateTime.clear();
|
||||
setTimeZone(dateTime, "GMT+11:00");
|
||||
dateTime.set(2012, 1, 29, 1, 2, 3);
|
||||
assertEqualCalendar(dateTime,
|
||||
instance.valueOfString("2012-02-29T01:02:03+11:00", null, null, null, null, null, Calendar.class));
|
||||
dateTime.add(Calendar.MILLISECOND, 7);
|
||||
assertEqualCalendar(dateTime,
|
||||
instance.valueOfString("2012-02-29T01:02:03.007+11:00", null, null, 3, null, null, Calendar.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valueOfStringToTimestamp() throws Exception {
|
||||
assertEquals(530000001, instance
|
||||
.valueOfString("2012-02-29T01:02:03.530000001+11:00", null, null, 9, null, null, Timestamp.class)
|
||||
.getNanos());
|
||||
}
|
||||
|
||||
@Test
|
||||
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.
|
||||
assertEquals(new Time(0),
|
||||
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));
|
||||
}
|
||||
|
||||
@Test
|
||||
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:02+24:00");
|
||||
expectContentErrorInValueOfString(instance, "2012-02-30T01:02:03");
|
||||
expectContentErrorInValueOfString(instance, "2012-02-29T23:32:02.0000000000000");
|
||||
|
||||
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.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.TimeZone;
|
||||
|
||||
|
@ -31,105 +37,154 @@ import org.junit.Test;
|
|||
|
||||
public class EdmTimeOfDayTest extends PrimitiveTypeBaseTest {
|
||||
|
||||
private final EdmPrimitiveType instance = EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.TimeOfDay);
|
||||
private final EdmPrimitiveType instance = EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.TimeOfDay);
|
||||
|
||||
@Test
|
||||
public void toUriLiteral() throws Exception {
|
||||
assertEquals("11:12", instance.toUriLiteral("11:12"));
|
||||
assertEquals("11:12:13.012", instance.toUriLiteral("11:12:13.012"));
|
||||
}
|
||||
@Test
|
||||
public void toUriLiteral() throws Exception {
|
||||
assertEquals("11:12", instance.toUriLiteral("11:12"));
|
||||
assertEquals("11:12:13.012", instance.toUriLiteral("11:12:13.012"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromUriLiteral() throws Exception {
|
||||
assertEquals("11:12", instance.fromUriLiteral("11:12"));
|
||||
assertEquals("11:12:13.012", instance.fromUriLiteral("11:12:13.012"));
|
||||
}
|
||||
@Test
|
||||
public void fromUriLiteral() throws Exception {
|
||||
assertEquals("11:12", instance.fromUriLiteral("11:12"));
|
||||
assertEquals("11:12:13.012", instance.fromUriLiteral("11:12:13.012"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valueToString() throws Exception {
|
||||
Calendar dateTime = Calendar.getInstance();
|
||||
dateTime.clear();
|
||||
dateTime.setTimeZone(TimeZone.getTimeZone("GMT+11:30"));
|
||||
dateTime.set(1, 2, 3, 4, 5, 6);
|
||||
assertEquals("04:05:06", instance.valueToString(dateTime, null, null, null, null, null));
|
||||
@Test
|
||||
public void valueToString() throws Exception {
|
||||
Calendar dateTime = Calendar.getInstance();
|
||||
dateTime.clear();
|
||||
setTimeZone(dateTime, "GMT+11:30");
|
||||
dateTime.set(1, 2, 3, 4, 5, 6);
|
||||
assertEquals("04:05:06", instance.valueToString(dateTime, null, null, null, null, null));
|
||||
|
||||
dateTime.add(Calendar.MILLISECOND, 42);
|
||||
assertEquals("04:05:06.042", instance.valueToString(dateTime, null, null, null, null, null));
|
||||
assertEquals("04:05:06.042", instance.valueToString(dateTime, null, null, 3, null, null));
|
||||
assertEquals("04:05:06.042", instance.valueToString(dateTime, null, null, 4, null, null));
|
||||
dateTime.add(Calendar.MILLISECOND, 42);
|
||||
assertEquals("04:05:06.042", instance.valueToString(dateTime, null, null, null, null, null));
|
||||
assertEquals("04:05:06.042", instance.valueToString(dateTime, null, null, 3, null, null));
|
||||
assertEquals("04:05:06.042", instance.valueToString(dateTime, null, null, 4, null, null));
|
||||
|
||||
Calendar dateTime2 = Calendar.getInstance();
|
||||
dateTime2.clear();
|
||||
dateTime2.setTimeZone(TimeZone.getDefault());
|
||||
dateTime2.set(Calendar.HOUR, 5);
|
||||
dateTime2.set(Calendar.MINUTE, 59);
|
||||
dateTime2.set(Calendar.SECOND, 23);
|
||||
final Time time = new Time(dateTime2.getTimeInMillis());
|
||||
assertEquals("05:59:23", instance.valueToString(time, null, null, null, null, null));
|
||||
Calendar dateTime2 = Calendar.getInstance();
|
||||
dateTime2.clear();
|
||||
setTimeZone(dateTime, TimeZone.getDefault());
|
||||
dateTime2.set(Calendar.HOUR, 5);
|
||||
dateTime2.set(Calendar.MINUTE, 59);
|
||||
dateTime2.set(Calendar.SECOND, 23);
|
||||
|
||||
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(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.setNanos(42);
|
||||
expectFacetsErrorInValueToString(instance, timestamp, null, null, 8, null, null);
|
||||
// Timestamp timestamp = new Timestamp(0);
|
||||
// timestamp.setNanos(42);
|
||||
|
||||
expectTypeErrorInValueToString(instance, 0);
|
||||
}
|
||||
expectTypeErrorInValueToString(instance, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valueOfString() throws Exception {
|
||||
Calendar dateTime = Calendar.getInstance();
|
||||
dateTime.clear();
|
||||
@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));
|
||||
}
|
||||
|
||||
assertEquals(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));
|
||||
assertEquals(dateTime, instance.valueOfString("00:00:00.000000000000", null, null, null, null, null,
|
||||
Calendar.class));
|
||||
@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
|
||||
public void valueOfString() throws Exception {
|
||||
Calendar dateTime = Calendar.getInstance();
|
||||
dateTime.clear();
|
||||
|
||||
final Time timeValue = instance.valueOfString("00:00:00.999", null, null, 3, null, null, Time.class);
|
||||
assertEquals(dateTime.getTimeInMillis(), timeValue.getTime());
|
||||
assertEqualCalendar(dateTime, instance.valueOfString("00:00", null, null, null, null, null, Calendar.class));
|
||||
assertEqualCalendar(dateTime, instance.valueOfString("00:00:00", null, null, null, null, null, Calendar.class));
|
||||
assertEqualCalendar(dateTime,
|
||||
instance.valueOfString("00:00:00.000000000", null, null, null, null, null, Calendar.class));
|
||||
|
||||
dateTime.set(Calendar.MILLISECOND, 999);
|
||||
assertEquals(dateTime, instance.valueOfString("00:00:00.999", null, null, 3, null, null, Calendar.class));
|
||||
assertEquals(dateTime, instance.valueOfString("00:00:00.999", null, null, 3, null, null, Calendar.class));
|
||||
assertEquals(Long.valueOf(dateTime.getTimeInMillis()),
|
||||
instance.valueOfString("00:00:00.999", null, null, 3, null, null, Long.class));
|
||||
final Time timeValue = instance.valueOfString("00:00:00.999", null, null, 3, null, null, Time.class);
|
||||
assertEquals(dateTime.getTimeInMillis(), timeValue.getTime());
|
||||
|
||||
final Timestamp timestamp = instance.valueOfString("00:00:00.999888777", null, null, 9, null, null,
|
||||
Timestamp.class);
|
||||
assertEquals(dateTime.getTimeInMillis(), timestamp.getTime());
|
||||
assertEquals(999888777, timestamp.getNanos());
|
||||
dateTime.set(Calendar.MILLISECOND, 999);
|
||||
assertEqualCalendar(dateTime,
|
||||
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()),
|
||||
instance.valueOfString("00:00:00.999", null, null, 3, null, null, Long.class));
|
||||
|
||||
expectFacetsErrorInValueOfString(instance, "11:12:13.123", null, null, null, null, null);
|
||||
expectFacetsErrorInValueOfString(instance, "11:12:13.123", null, null, 2, null, null);
|
||||
final Timestamp timestamp = instance.valueOfString("00:00:00.999888777", null, null, 9, null, null,
|
||||
Timestamp.class);
|
||||
assertEquals(dateTime.getTimeInMillis(), timestamp.getTime());
|
||||
assertEquals(999888777, timestamp.getNanos());
|
||||
|
||||
expectUnconvertibleErrorInValueOfString(instance, "11:12:13.1234", Calendar.class);
|
||||
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, "011:12:13");
|
||||
expectContentErrorInValueOfString(instance, "11:12:13:14");
|
||||
expectContentErrorInValueOfString(instance, "111213");
|
||||
expectContentErrorInValueOfString(instance, "1:2:3");
|
||||
expectContentErrorInValueOfString(instance, "11:12:13.0.1");
|
||||
expectContentErrorInValueOfString(instance, "11:12:13.");
|
||||
expectContentErrorInValueOfString(instance, "11:12:13.0000000000000");
|
||||
expectContentErrorInValueOfString(instance, "24:32:02");
|
||||
expectContentErrorInValueOfString(instance, "011:12:13");
|
||||
expectContentErrorInValueOfString(instance, "11:12:13:14");
|
||||
expectContentErrorInValueOfString(instance, "111213");
|
||||
expectContentErrorInValueOfString(instance, "1:2:3");
|
||||
expectContentErrorInValueOfString(instance, "11:12:13.0.1");
|
||||
// expectContentErrorInValueOfString(instance, "11:12:13.");
|
||||
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
|
||||
public void testRoundTripTime() throws Exception {
|
||||
java.sql.Time time = instance.valueOfString("04:05:06.002", true, 4000, 3, 0, true, java.sql.Time.class);
|
||||
String val = instance.valueToString(time, true, 4000, 3, 0, true);
|
||||
assertEquals("04:05:06", val);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoundTripTime() throws Exception {
|
||||
java.sql.Time time = instance.valueOfString("04:05:06.002", true,
|
||||
4000, 3, 0, true, java.sql.Time.class);
|
||||
String val = instance.valueToString(time, true, 4000, 3, 0, true);
|
||||
assertEquals("04:05:06", val);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tests() throws Exception {
|
||||
instance.validate("12:34:55", null, null, null, null, null);
|
||||
}
|
||||
@Test
|
||||
public void tests() throws Exception {
|
||||
instance.validate("12:34:55", null, null, null, null, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,16 +19,23 @@
|
|||
package org.apache.olingo.commons.core.edm.primitivetype;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
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.EdmPrimitiveTypeException;
|
||||
|
||||
public abstract class PrimitiveTypeBaseTest {
|
||||
|
||||
private void expectErrorInValueToString(final EdmPrimitiveType instance,
|
||||
private void expectErrorInValueToString(final EdmPrimitiveType instance,
|
||||
final Object value, final Boolean isNullable, final Integer maxLength,
|
||||
final Integer precision, final Integer scale, final Boolean isUnicode,
|
||||
final String message) {
|
||||
|
@ -115,4 +122,26 @@ public abstract class PrimitiveTypeBaseTest {
|
|||
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.nio.ByteBuffer;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
@ -144,6 +147,41 @@ public class ODataJsonSerializerTest {
|
|||
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
|
||||
public void entitySimpleMetadataFull() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
|
||||
|
|
Loading…
Reference in New Issue