You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2019/11/25 18:33:06 UTC

[olingo-odata4] branch OLINGO-1408 updated: [OLINGO-1408] Support new date time API (#57)

This is an automated email from the ASF dual-hosted git repository.

mibo pushed a commit to branch OLINGO-1408
in repository https://gitbox.apache.org/repos/asf/olingo-odata4.git


The following commit(s) were added to refs/heads/OLINGO-1408 by this push:
     new 932af8f  [OLINGO-1408] Support new date time API (#57)
932af8f is described below

commit 932af8fb5d68efe67fb6040dc697852173435437
Author: Adrian Görler <ad...@me.com>
AuthorDate: Mon Nov 25 19:32:58 2019 +0100

    [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
---
 .../commons/core/edm/primitivetype/EdmDate.java    | 135 ++++---
 .../core/edm/primitivetype/EdmDateTimeOffset.java  | 392 ++++++++-------------
 .../core/edm/primitivetype/EdmTimeOfDay.java       | 198 ++++++-----
 .../core/edm/primitivetype/EdmDateTest.java        | 137 +++----
 .../edm/primitivetype/EdmDateTimeOffsetTest.java   | 334 +++++++++++-------
 .../core/edm/primitivetype/EdmTimeOfDayTest.java   | 255 ++++++++------
 .../edm/primitivetype/PrimitiveTypeBaseTest.java   |  31 +-
 .../serializer/json/ODataJsonSerializerTest.java   |  38 ++
 8 files changed, 838 insertions(+), 682 deletions(-)

diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDate.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDate.java
index b0903ed..e658295 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDate.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDate.java
@@ -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();
+	}
 }
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTimeOffset.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTimeOffset.java
index bb1cbb0..9f8ff4c 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTimeOffset.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTimeOffset.java
@@ -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 EdmDateTimeOffset INSTANCE = new EdmDateTimeOffset();
-
-  public static EdmDateTimeOffset getInstance() {
-    return INSTANCE;
-  }
-
-  @Override
-  public Class<?> getDefaultType() {
-    return Timestamp.class;
-  }
-
-  @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 {
-
-    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 {
-      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);
-    }
-  }
-
-  /**
-   * <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 {
-
-    // 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);
-
-    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());
-    }
-  }
-
-  @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 = createDateTime(value, false);
-
-    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)
-        + 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);
-
-    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));
-        }
-      }
-    }
-  }
+	private static final ZoneId ZULU = ZoneId.of("Z");
+
+	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 EdmDateTimeOffset INSTANCE = new EdmDateTimeOffset();
+
+	public static EdmDateTimeOffset getInstance() {
+		return INSTANCE;
+	}
+
+	@Override
+	public Class<?> getDefaultType() {
+		return Timestamp.class;
+	}
+
+	@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);
+
+			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);
+		}
+	}
+
+	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;
+	}
+
+	@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());
+		}
+	}
+
+	@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);
+
+		return format(zdt.toLocalDateTime(), zdt.getOffset(), zdt.getNano());
+	}
+
+	private static <T> ZonedDateTime createZonedDateTime(final T value) throws EdmPrimitiveTypeException {
+		if (value instanceof ZonedDateTime) {
+			return (ZonedDateTime) value;
+		}
+
+		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 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.");
+		}
+	}
 }
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmTimeOfDay.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmTimeOfDay.java
index 86934b8..b404dbd 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmTimeOfDay.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmTimeOfDay.java
@@ -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 EdmTimeOfDay INSTANCE = new EdmTimeOfDay();
-
-  public static EdmTimeOfDay getInstance() {
-    return INSTANCE;
-  }
-
-  @Override
-  public Class<?> getDefaultType() {
-    return Calendar.class;
-  }
-
-  @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 {
-
-    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 {
-      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();
-  }
+	private static final LocalDate EPOCH = LocalDate.ofEpochDay(0l);
+	private static final EdmTimeOfDay INSTANCE = new EdmTimeOfDay();
+
+	public static EdmTimeOfDay getInstance() {
+		return INSTANCE;
+	}
+
+	@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.");
+		}
+
+		// 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
+	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();
+
+//
+//		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();
+	}
 }
diff --git a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTest.java b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTest.java
index ec88c4f..197e00e 100644
--- a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTest.java
+++ b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTest.java
@@ -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);
-
-  @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 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));
-
-    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));
-
-    dateTime.set(Calendar.YEAR, 12344);
-    assertEquals("12344-02-29", instance.valueToString(dateTime, null, null, null, null, null));
-
-    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));
-
-    dateTime.set(Calendar.YEAR, 12344);
-    assertEquals(dateTime, instance.valueOfString("12344-02-29", null, null, null, null, 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");
-
-    expectTypeErrorInValueOfString(instance, "2012-02-29");
-  }
+	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 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();
+		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));
+
+		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));
+
+		// 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);
+	}
+
+	@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));
+
+		// 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));
+
+		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");
+	}
 }
diff --git a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTimeOffsetTest.java b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTimeOffsetTest.java
index f5150b1..c144ac3 100644
--- a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTimeOffsetTest.java
+++ b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDateTimeOffsetTest.java
@@ -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);
-
-  @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 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));
-
-    dateTime.setTimeZone(TimeZone.getTimeZone("GMT-1:30"));
-    assertEquals("2012-02-29T01:02:03-01:30", instance.valueToString(dateTime, null, null, null, null, null));
-
-    dateTime.setTimeZone(TimeZone.getTimeZone("GMT+11:00"));
-    assertEquals("2012-02-29T01:02:03+11:00", instance.valueToString(dateTime, 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));
-
-    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));
-
-    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));
-
-    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));
-
-    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));
-
-    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));
-
-    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));
-
-    expectFacetsErrorInValueToString(instance, 3L, null, null, 2, null, null);
-    expectFacetsErrorInValueToString(instance, timestamp, null, null, 7, null, null);
-
-    expectTypeErrorInValueToString(instance, 0);
-  }
-
-  @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));
-
-    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));
-
-    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));
-
-    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));
-
-    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));
-
-    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");
-
-    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");
-  }
+	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 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 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();
+		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));
+
+		setTimeZone(dateTime, "GMT-1:30");
+		assertEquals("2012-02-28T23:32:03-01:30", instance.valueToString(dateTime, null, null, null, null, null));
+
+		setTimeZone(dateTime, "GMT+11:00");
+		assertEquals("2012-02-29T12:02:03+11:00", instance.valueToString(dateTime, null, null, null, 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));
+
+		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));
+
+		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 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));
+	}
+
+	@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));
+	}
+
+	@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));
+
+	}
+
+	@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"));
+	}
+
+	@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();
+		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");
+	}
+
 }
diff --git a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmTimeOfDayTest.java b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmTimeOfDayTest.java
index 700a387..ddcbc65 100644
--- a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmTimeOfDayTest.java
+++ b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmTimeOfDayTest.java
@@ -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);
-
-  @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 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));
-
-    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));
-
-    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);
-
-    expectTypeErrorInValueToString(instance, 0);
-  }
-
-  @Test
-  public void valueOfString() throws Exception {
-    Calendar dateTime = Calendar.getInstance();
-    dateTime.clear();
-
-    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));
-
-    final Time timeValue = instance.valueOfString("00:00:00.999", null, null, 3, null, null, Time.class);
-    assertEquals(dateTime.getTimeInMillis(), timeValue.getTime());
-
-    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 Timestamp timestamp = instance.valueOfString("00:00:00.999888777", null, null, 9, null, null,
-        Timestamp.class);
-    assertEquals(dateTime.getTimeInMillis(), timestamp.getTime());
-    assertEquals(999888777, timestamp.getNanos());
-
-    expectFacetsErrorInValueOfString(instance, "11:12:13.123", null, null, null, null, null);
-    expectFacetsErrorInValueOfString(instance, "11:12:13.123", null, null, 2, null, null);
-
-    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");
-
-    expectTypeErrorInValueOfString(instance, "11:12:13");
-  }
-
-  @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);
-  }
+	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 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();
+		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));
+
+		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));
+
+//    Timestamp timestamp = new Timestamp(0);
+//    timestamp.setNanos(42);
+
+		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
+	public void valueOfString() throws Exception {
+		Calendar dateTime = Calendar.getInstance();
+		dateTime.clear();
+
+		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));
+
+		final Time timeValue = instance.valueOfString("00:00:00.999", null, null, 3, null, null, Time.class);
+		assertEquals(dateTime.getTimeInMillis(), timeValue.getTime());
+
+		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));
+
+		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);
+
+		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");
+	}
+	
+	@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 tests() throws Exception {
+		instance.validate("12:34:55", null, null, null, null, null);
+	}
 
 }
diff --git a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/PrimitiveTypeBaseTest.java b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/PrimitiveTypeBaseTest.java
index 5d5851c..d01160e 100644
--- a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/PrimitiveTypeBaseTest.java
+++ b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/PrimitiveTypeBaseTest.java
@@ -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);
+   }
+
 }
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
index 52849b2..d196330 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
@@ -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;
@@ -145,6 +148,41 @@ public class ODataJsonSerializerTest {
   }
   
   @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");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);