Repository: olingo-odata2
Updated Branches:
  refs/heads/master 55655f3d9 -> d18f9f0bd


[OLINGO-881] support for java.sql.Timestamp in simple types

Signed-off-by: Christian Amend <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/olingo-odata2/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata2/commit/d18f9f0b
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata2/tree/d18f9f0b
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata2/diff/d18f9f0b

Branch: refs/heads/master
Commit: d18f9f0bdf915031e31d796250aea30b7fbf9a9b
Parents: 55655f3
Author: Klaus Straubinger <[email protected]>
Authored: Fri Feb 12 09:53:48 2016 +0100
Committer: Christian Amend <[email protected]>
Committed: Fri Feb 12 10:39:44 2016 +0100

----------------------------------------------------------------------
 .../olingo/odata2/api/edm/EdmSimpleType.java    |  52 +++---
 .../api/processor/ODataSingleProcessor.java     |  10 +-
 .../olingo/odata2/core/edm/EdmDateTime.java     | 121 ++++++++------
 .../odata2/core/edm/EdmDateTimeOffset.java      |  39 +++--
 .../apache/olingo/odata2/core/edm/EdmTime.java  |  75 +++++----
 .../odata2/core/edm/EdmSimpleTypeTest.java      | 162 ++++++++++---------
 6 files changed, 257 insertions(+), 202 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/d18f9f0b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/EdmSimpleType.java
----------------------------------------------------------------------
diff --git 
a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/EdmSimpleType.java
 
b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/EdmSimpleType.java
index 99da498..2cbe4b9 100644
--- 
a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/EdmSimpleType.java
+++ 
b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/EdmSimpleType.java
@@ -30,8 +30,10 @@ package org.apache.olingo.odata2.api.edm;
  * <tr><td>Binary</td><td>byte[], {@link Byte}[]</td></tr>
  * <tr><td>Boolean</td><td>{@link Boolean}</td></tr>
  * <tr><td>Byte</td><td>{@link Short}, {@link Byte}, {@link Integer}, {@link 
Long}</td></tr>
- * <tr><td>DateTime</td><td>{@link java.util.Calendar}, {@link 
java.util.Date}, {@link Long}</td></tr>
- * <tr><td>DateTimeOffset</td><td>{@link java.util.Calendar}, {@link 
java.util.Date}, {@link Long}</td></tr>
+ * <tr><td>DateTime</td><td>{@link java.util.Calendar}, {@link 
java.util.Date}, {@link java.sql.Timestamp},
+ * {@link Long}</td></tr>
+ * <tr><td>DateTimeOffset</td><td>{@link java.util.Calendar}, {@link 
java.util.Date}, {@link java.sql.Timestamp},
+ * {@link Long}</td></tr>
  * <tr><td>Decimal</td><td>{@link java.math.BigDecimal}, {@link 
java.math.BigInteger}, {@link Double}, {@link Float},
  * {@link Byte}, {@link Short}, {@link Integer}, {@link Long}</td></tr>
  * <tr><td>Double</td><td>{@link Double}, {@link Float}, {@link 
java.math.BigDecimal}, {@link Byte}, {@link Short},
@@ -45,7 +47,8 @@ package org.apache.olingo.odata2.api.edm;
  * <tr><td>Single</td><td>{@link Float}, {@link Double}, {@link 
java.math.BigDecimal}, {@link Byte}, {@link Short},
  * {@link Integer}, {@link Long}</td></tr>
  * <tr><td>String</td><td>{@link String}</td></tr>
- * <tr><td>Time</td><td>{@link java.util.Calendar}, {@link java.util.Date}, 
{@link Long}</td></tr>
+ * <tr><td>Time</td><td>{@link java.util.Calendar}, {@link java.util.Date}, 
{@link java.sql.Timestamp},
+ * {@link java.sql.Time}, {@link Long}</td></tr>
  * </tbody>
  * </table></p>
  * <p>The first Java type is the default type for the respective EDM simple 
type.</p>
@@ -57,38 +60,25 @@ package org.apache.olingo.odata2.api.edm;
  * The EDM simple types <code>DateTime</code>, <code>DateTimeOffset</code>, and
  * <code>Time</code> can have a <code>Precision</code> facet.
  * <code>Decimal</code> can have the facets <code>Precision</code> and 
<code>Scale</code>.</p>
- * <p>
- * <table frame="box" rules="all">
- * <thead>
- * <tr><th>EDM simple type</th><th>Parsing details</th></tr>
- * </thead>
- * <tbody>
- * <tr><td><b>DateTimeOffset</b></td>
- * <td>
- * When an time string is parsed to an according 
<code>EdmDateTimeOffset</code> object it is assumed that this time
- * string represents the local time with a timezone set.
- * <br/>
- * As an example, when the following time string 
<code>"2012-02-29T15:33:00-04:00"</code> is parsed it is assumed that
- * we have the local time ("15:33:00") which is in a timezone with an offset 
from UTC of "-04:00".
- * Hence the result is a calendar object within the local time (which is 
"15:33:00") and the according timezone offset
- * ("-04:00") which then results in the UTC time of "19:33:00+00:00" 
("15:33:00" - "-04:00" -> "19:33:00 UTC").
- * <br/>
- * As further explanation about our date time handling I reference to the 
following ISO specification: ISO 8601 -
- * http://en.wikipedia.org/wiki/ISO_8601 and the copied section:
- * Time_offsets_from_UTC - 
http://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC
- * <blockquote>>
- * The following times all refer to the same moment: "18:30Z", "22:30+04:00", 
and "15:00-03:30". Nautical time zone
- * letters are not used with the exception of Z.
+ *
+ * <p><b>Parsing details for the EDM simple type DateTimeOffset</b></p>
+ * <p>When an time string is parsed to an according value object it is assumed 
that the time part
+ * in this string represents the local time with a timezone set.</p>
+ * <p>As an example, when the following string 
<code>"2012-02-29T15:33:00-04:00"</code> is parsed
+ * it is assumed that we have the local time ("15:33:00") which is in a 
timezone with an offset from UTC of "-04:00".
+ * Hence the result is a calendar object with the local time (which is 
"15:33:00") and the according timezone offset
+ * ("-04:00") which then results in the UTC time of "19:33:00+00:00" 
("15:33:00" - "-04:00" -> "19:33:00 UTC").</p>
+ * <p>Please see ISO specification <a 
href="http://www.iso.org/iso/iso8601";>ISO 8601</a> for further details.
+ * Time offsets are also explained in
+ * <a 
href="https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC";>Wikipedia</a>:
+ * <blockquote>
+ * The following times all refer to the same moment: "18:30Z", "22:30+04:00", 
and "15:00-03:30".
+ * Nautical time zone letters are not used with the exception of Z.
  * To calculate UTC time one has to subtract the offset from the local time, 
e.g. for "15:00-03:30" do 15:00 - (-03:30)
  * to get 18:30 UTC.
  * </blockquote>
- * <em>The behavior of our ABAP OData Library and Microsoft examples is the 
same as described above.</em>
- * </td>
- * </tr>
- * </tbody>
- * </table></p>
  * </p>
- * 
+ *
  * @org.apache.olingo.odata2.DoNotImplement
  */
 public interface EdmSimpleType extends EdmType {

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/d18f9f0b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/processor/ODataSingleProcessor.java
----------------------------------------------------------------------
diff --git 
a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/processor/ODataSingleProcessor.java
 
b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/processor/ODataSingleProcessor.java
index 27b8aa2..e5ee823 100644
--- 
a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/processor/ODataSingleProcessor.java
+++ 
b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/processor/ODataSingleProcessor.java
@@ -32,7 +32,6 @@ import org.apache.olingo.odata2.api.edm.EdmServiceMetadata;
 import org.apache.olingo.odata2.api.ep.EntityProvider;
 import org.apache.olingo.odata2.api.exception.ODataException;
 import org.apache.olingo.odata2.api.exception.ODataNotImplementedException;
-import 
org.apache.olingo.odata2.api.processor.ODataResponse.ODataResponseBuilder;
 import org.apache.olingo.odata2.api.processor.feature.CustomContentType;
 import org.apache.olingo.odata2.api.processor.part.BatchProcessor;
 import 
org.apache.olingo.odata2.api.processor.part.EntityComplexPropertyProcessor;
@@ -358,13 +357,14 @@ public abstract class ODataSingleProcessor implements 
MetadataProcessor, Service
   @Override
   public ODataResponse readServiceDocument(final GetServiceDocumentUriInfo 
uriInfo, final String contentType)
       throws ODataException {
-    final Edm entityDataModel = getContext().getService().getEntityDataModel();
-    final String serviceRoot = 
getContext().getPathInfo().getServiceRoot().toASCIIString();
+    final Edm edm = getContext().getService().getEntityDataModel();
 
-    if(getContext().getHttpMethod().equals("HEAD")) {
+    //Service Document has version 1.0 specifically
+    if (getContext().getHttpMethod().equals("HEAD")) {
       return ODataResponse.header(ODataHttpHeaders.DATASERVICEVERSION, 
ODataServiceVersion.V10).build();
     } else {
-      final ODataResponse response = 
EntityProvider.writeServiceDocument(contentType, entityDataModel, serviceRoot);
+      final String serviceRoot = 
getContext().getPathInfo().getServiceRoot().toASCIIString();
+      final ODataResponse response = 
EntityProvider.writeServiceDocument(contentType, edm, serviceRoot);
       return ODataResponse.fromResponse(response)
           .header(ODataHttpHeaders.DATASERVICEVERSION, 
ODataServiceVersion.V10).build();
     }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/d18f9f0b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTime.java
----------------------------------------------------------------------
diff --git 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTime.java
 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTime.java
index e33d217..38b213d 100644
--- 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTime.java
+++ 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTime.java
@@ -18,6 +18,7 @@
  
******************************************************************************/
 package org.apache.olingo.odata2.core.edm;
 
+import java.sql.Timestamp;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.TimeZone;
@@ -36,7 +37,7 @@ public class EdmDateTime extends AbstractSimpleType {
 
   private static final Pattern PATTERN = Pattern.compile(
       "(\\p{Digit}{1,4})-(\\p{Digit}{1,2})-(\\p{Digit}{1,2})"
-          + 
"T(\\p{Digit}{1,2}):(\\p{Digit}{1,2})(?::(\\p{Digit}{1,2})(\\.(\\p{Digit}{0,3}?)0*)?)?");
+          + 
"T(\\p{Digit}{1,2}):(\\p{Digit}{1,2})(?::(\\p{Digit}{1,2})(\\.(\\p{Digit}{0,9}?)0*)?)?");
   private static final Pattern JSON_PATTERN = 
Pattern.compile("/Date\\((-?\\p{Digit}+)\\)/");
   private static final EdmDateTime instance = new EdmDateTime();
 
@@ -81,37 +82,18 @@ public class EdmDateTime extends AbstractSimpleType {
     Calendar dateTimeValue = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
     dateTimeValue.clear();
 
+    String valueString;
     if (literalKind == EdmLiteralKind.URI) {
       if (value.length() > 10 && value.startsWith("datetime'") && 
value.endsWith("'")) {
-        parseLiteral(value.substring(9, value.length() - 1), facets, 
dateTimeValue);
+        valueString = value.substring(9, value.length() - 1);
       } else {
         throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(value));
       }
     } else {
-      parseLiteral(value, facets, dateTimeValue);
+      valueString = value;
     }
 
-    if (returnType.isAssignableFrom(Calendar.class)) {
-      return returnType.cast(dateTimeValue);
-    } else if (returnType.isAssignableFrom(Long.class)) {
-      return returnType.cast(dateTimeValue.getTimeInMillis());
-    } else if (returnType.isAssignableFrom(Date.class)) {
-      return returnType.cast(dateTimeValue.getTime());
-    } else {
-      throw new 
EdmSimpleTypeException(EdmSimpleTypeException.VALUE_TYPE_NOT_SUPPORTED.addContent(returnType));
-    }
-  }
-
-  /**
-   * Parses a formatted date/time value and sets the values of a {@link 
Calendar} object accordingly.
-   * @param value the formatted date/time value as String
-   * @param facets additional constraints for parsing (optional)
-   * @param dateTimeValue the Calendar object to be set to the parsed value
-   * @throws EdmSimpleTypeException
-   */
-  protected static void parseLiteral(final String value, final EdmFacets 
facets, final Calendar dateTimeValue)
-      throws EdmSimpleTypeException {
-    final Matcher matcher = PATTERN.matcher(value);
+    final Matcher matcher = PATTERN.matcher(valueString);
     if (!matcher.matches()) {
       throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(value));
     }
@@ -124,16 +106,23 @@ public class EdmDateTime extends AbstractSimpleType {
         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() > 8) {
+      if (matcher.group(7).length() == 1 || matcher.group(7).length() > 10) {
         throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(value));
       }
       final String decimals = matcher.group(8);
       if (facets != null && facets.getPrecision() != null && 
facets.getPrecision() < decimals.length()) {
         throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_FACETS_NOT_MATCHED.addContent(value,
 facets));
       }
-      final String milliSeconds = decimals + 
"000".substring(decimals.length());
-      dateTimeValue.set(Calendar.MILLISECOND, Short.parseShort(milliSeconds));
+      nanoSeconds = Integer.parseInt(decimals + 
"000000000".substring(decimals.length()));
+      if (!(returnType.isAssignableFrom(Timestamp.class))) {
+        if (nanoSeconds % (1000 * 1000) == 0) {
+          dateTimeValue.set(Calendar.MILLISECOND, nanoSeconds / (1000 * 1000));
+        } else {
+          throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(value));
+        }
+      }
     }
 
     // The Calendar class does not check any values until a get method is 
called,
@@ -147,6 +136,20 @@ public class EdmDateTime extends AbstractSimpleType {
       throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(value),
 e);
     }
     dateTimeValue.setLenient(true);
+
+    if (returnType.isAssignableFrom(Calendar.class)) {
+      return returnType.cast(dateTimeValue);
+    } else if (returnType.isAssignableFrom(Long.class)) {
+      return returnType.cast(dateTimeValue.getTimeInMillis());
+    } else if (returnType.isAssignableFrom(Date.class)) {
+      return returnType.cast(dateTimeValue.getTime());
+    } else if (returnType.isAssignableFrom(Timestamp.class)) {
+        Timestamp timestamp = new Timestamp(dateTimeValue.getTimeInMillis());
+        timestamp.setNanos(nanoSeconds);
+        return returnType.cast(timestamp);
+    } else {
+      throw new 
EdmSimpleTypeException(EdmSimpleTypeException.VALUE_TYPE_NOT_SUPPORTED.addContent(returnType));
+    }
   }
 
   @Override
@@ -164,13 +167,17 @@ public class EdmDateTime extends AbstractSimpleType {
     }
 
     if (literalKind == EdmLiteralKind.JSON) {
-      return "/Date(" + timeInMillis + ")/";
+      if (value instanceof Timestamp && ((Timestamp) value).getNanos() % (1000 
* 1000) != 0) {
+        throw new 
EdmSimpleTypeException(EdmSimpleTypeException.VALUE_ILLEGAL_CONTENT.addContent(value));
+      } else {
+        return "/Date(" + timeInMillis + ")/";
+      }
     }
 
     Calendar dateTimeValue = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
     dateTimeValue.setTimeInMillis(timeInMillis);
 
-    StringBuilder result = new StringBuilder(23); // 23 characters are enough 
for millisecond precision.
+    StringBuilder result = new StringBuilder(29); // 29 characters are enough 
for nanosecond precision.
     final int year = dateTimeValue.get(Calendar.YEAR);
     appendTwoDigits(result, year / 100);
     appendTwoDigits(result, year % 100);
@@ -185,8 +192,11 @@ public class EdmDateTime extends AbstractSimpleType {
     result.append(':');
     appendTwoDigits(result, dateTimeValue.get(Calendar.SECOND));
 
+    final int fractionalSecs = value instanceof Timestamp ?
+        ((Timestamp) value).getNanos() :
+        dateTimeValue.get(Calendar.MILLISECOND);
     try {
-      appendMilliseconds(result, dateTimeValue.get(Calendar.MILLISECOND), 
facets);
+      appendFractionalSeconds(result, fractionalSecs, value instanceof 
Timestamp, facets);
     } catch (final IllegalArgumentException e) {
       throw new 
EdmSimpleTypeException(EdmSimpleTypeException.VALUE_FACETS_NOT_MATCHED.addContent(value,
 facets), e);
     }
@@ -205,29 +215,48 @@ public class EdmDateTime extends AbstractSimpleType {
     result.append((char) ('0' + number % 10));
   }
 
-  protected static void appendMilliseconds(final StringBuilder result, final 
long milliseconds, final EdmFacets facets)
-      throws IllegalArgumentException {
-    final int digits = milliseconds % 1000 == 0 ? 0 : milliseconds % 100 == 0 
? 1 : milliseconds % 10 == 0 ? 2 : 3;
-    if (digits > 0) {
+  /**
+   * 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 facets the EDM facets containing an 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 EdmFacets facets) throws 
IllegalArgumentException {
+    int significantDigits = 0;
+    if (fractionalSeconds > 0) {
+      // Determine the number of significant digits.
+      significantDigits = isNano ? 9 : 3;
+      int output = fractionalSeconds;
+      while (output % 10 == 0) {
+        output /= 10;
+        significantDigits--;
+      }
+
       result.append('.');
-      for (int d = 100; d > 0; d /= 10) {
-        final byte digit = (byte) (milliseconds % (d * 10) / d);
-        if (digit > 0 || milliseconds % d > 0) {
+      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));
         }
       }
     }
 
-    if (facets != null && facets.getPrecision() != null) {
-      final int precision = facets.getPrecision();
-      if (digits > precision) {
+    // Check precision constraint.
+    final Integer precision = facets == null || facets.getPrecision() == null 
? null : facets.getPrecision();
+    if (precision != null) {
+      if (precision < significantDigits) {
         throw new IllegalArgumentException();
-      }
-      if (digits == 0 && precision > 0) {
-        result.append('.');
-      }
-      for (int i = digits; i < precision; i++) {
-        result.append('0');
+      } else {
+        // Add additional zeroes if the precision is larger than the number of 
significant digits.
+        if (significantDigits == 0 && precision > 0) {
+          result.append('.');
+        }
+        for (int i = significantDigits; i < precision; i++) {
+          result.append('0');
+        }
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/d18f9f0b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTimeOffset.java
----------------------------------------------------------------------
diff --git 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTimeOffset.java
 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTimeOffset.java
index 6c01ac0..16f867f 100644
--- 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTimeOffset.java
+++ 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTimeOffset.java
@@ -18,6 +18,7 @@
  
******************************************************************************/
 package org.apache.olingo.odata2.core.edm;
 
+import java.sql.Timestamp;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.TimeZone;
@@ -31,10 +32,8 @@ import 
org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
 /**
  * Implementation of the EDM simple type DateTimeOffset.
  * 
- * Details about parsing of time strings to {@link EdmDateTimeOffset} objects 
can be found in
+ * Details about parsing of time strings to value objects can be found in the
  * {@link org.apache.olingo.odata2.api.edm.EdmSimpleType} documentation.
- * 
- * 
  */
 public class EdmDateTimeOffset extends AbstractSimpleType {
 
@@ -68,11 +67,11 @@ public class EdmDateTimeOffset extends AbstractSimpleType {
     }
 
     Calendar dateTimeValue = null;
+    long millis = 0;
 
     if (literalKind == EdmLiteralKind.JSON) {
       final Matcher matcher = JSON_PATTERN.matcher(value);
       if (matcher.matches()) {
-        long millis;
         try {
           millis = Long.parseLong(matcher.group(1));
         } catch (final NumberFormatException e) {
@@ -92,11 +91,10 @@ public class EdmDateTimeOffset extends AbstractSimpleType {
           }
         }
         dateTimeValue = Calendar.getInstance(TimeZone.getTimeZone(timeZone));
-        dateTimeValue.clear();
-        dateTimeValue.setTimeInMillis(millis);
       }
     }
 
+    int nanoSeconds = 0;
     if (dateTimeValue == null) {
       final Matcher matcher = PATTERN.matcher(value);
       if (!matcher.matches()) {
@@ -111,16 +109,28 @@ public class EdmDateTimeOffset extends AbstractSimpleType 
{
         throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(value));
       }
       dateTimeValue.clear();
-      EdmDateTime.parseLiteral(value.substring(0, matcher.group(1) == null ? 
value.length() : matcher.start(1)),
-          facets, dateTimeValue);
+      final Timestamp timestamp = 
EdmDateTime.getInstance().internalValueOfString(
+          value.substring(0, matcher.group(1) == null ? value.length() : 
matcher.start(1)),
+          EdmLiteralKind.DEFAULT, facets, Timestamp.class);
+      millis = timestamp.getTime() - dateTimeValue.get(Calendar.ZONE_OFFSET);
+      nanoSeconds = timestamp.getNanos();
+      if (nanoSeconds % (1000 * 1000) != 0 && 
!returnType.isAssignableFrom(Timestamp.class)) {
+        throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(value));
+      }
     }
 
     if (returnType.isAssignableFrom(Calendar.class)) {
+      dateTimeValue.clear();
+      dateTimeValue.setTimeInMillis(millis);
       return returnType.cast(dateTimeValue);
     } else if (returnType.isAssignableFrom(Long.class)) {
-      return returnType.cast(dateTimeValue.getTimeInMillis());
+      return returnType.cast(millis);
     } else if (returnType.isAssignableFrom(Date.class)) {
-      return returnType.cast(dateTimeValue.getTime());
+      return returnType.cast(new Date(millis));
+    } else if (returnType.isAssignableFrom(Timestamp.class)) {
+        Timestamp timestamp = new Timestamp(millis);
+        timestamp.setNanos(nanoSeconds);
+        return returnType.cast(timestamp);
     } else {
       throw new 
EdmSimpleTypeException(EdmSimpleTypeException.VALUE_TYPE_NOT_SUPPORTED.addContent(returnType));
     }
@@ -154,11 +164,16 @@ public class EdmDateTimeOffset extends AbstractSimpleType 
{
     final int offsetInMinutes = offset / 60 / 1000;
 
     if (literalKind == EdmLiteralKind.JSON) {
-      return "/Date(" + milliSeconds + (offset == 0 ? "" : 
String.format("%+05d", offsetInMinutes)) + ")/";
+      if (value instanceof Timestamp && ((Timestamp) value).getNanos() % (1000 
* 1000) != 0) {
+        throw new 
EdmSimpleTypeException(EdmSimpleTypeException.VALUE_ILLEGAL_CONTENT.addContent(value));
+      } else {
+        return "/Date(" + milliSeconds + (offset == 0 ? "" : 
String.format("%+05d", offsetInMinutes)) + ")/";
+      }
 
     } else {
       final String localTimeString =
-          EdmDateTime.getInstance().valueToString(milliSeconds, 
EdmLiteralKind.DEFAULT, facets);
+          EdmDateTime.getInstance().valueToString(
+              value instanceof Timestamp ? value : milliSeconds, 
EdmLiteralKind.DEFAULT, facets);
       final int offsetHours = offsetInMinutes / 60;
       final int offsetMinutes = Math.abs(offsetInMinutes % 60);
       final String offsetString = offset == 0 ? "Z" : 
String.format("%+03d:%02d", offsetHours, offsetMinutes);

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/d18f9f0b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmTime.java
----------------------------------------------------------------------
diff --git 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmTime.java
 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmTime.java
index 7b7680b..fb80227 100644
--- 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmTime.java
+++ 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmTime.java
@@ -18,6 +18,8 @@
  
******************************************************************************/
 package org.apache.olingo.odata2.core.edm;
 
+import java.sql.Time;
+import java.sql.Timestamp;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.TimeZone;
@@ -54,33 +56,17 @@ public class EdmTime extends AbstractSimpleType {
   @Override
   protected <T> T internalValueOfString(final String value, final 
EdmLiteralKind literalKind, final EdmFacets facets,
       final Class<T> returnType) throws EdmSimpleTypeException {
-    Calendar valueCalendar;
-    if (literalKind == EdmLiteralKind.URI) {
-      if (value.length() > 6 && value.startsWith("time'") && 
value.endsWith("'")) {
-        valueCalendar = parseLiteral(value.substring(5, value.length() - 1), 
facets);
-      } else {
-        throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(value));
-      }
-    } else {
-      valueCalendar = parseLiteral(value, facets);
-    }
 
-    if (returnType.isAssignableFrom(Calendar.class)) {
-      return returnType.cast(valueCalendar);
-    } else if (returnType.isAssignableFrom(Long.class)) {
-      return returnType.cast(valueCalendar.getTimeInMillis());
-    } else if (returnType.isAssignableFrom(Date.class)) {
-      return returnType.cast(valueCalendar.getTime());
-    } else {
-      throw new 
EdmSimpleTypeException(EdmSimpleTypeException.VALUE_TYPE_NOT_SUPPORTED.addContent(returnType));
+    if (literalKind == EdmLiteralKind.URI
+        && (value.length() <= 6 || !value.startsWith("time'") || 
!value.endsWith("'"))) {
+      throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(value));
     }
-  }
 
-  private Calendar parseLiteral(final String literal, final EdmFacets facets) 
throws EdmSimpleTypeException {
-    final Matcher matcher = PATTERN.matcher(literal);
+    final Matcher matcher = PATTERN.matcher(
+        literalKind == EdmLiteralKind.URI ? value.substring(5, value.length() 
- 1) : value);
     if (!matcher.matches()
         || (matcher.group(1) == null && matcher.group(2) == null && 
matcher.group(3) == null)) {
-      throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(literal));
+      throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(value));
     }
 
     Calendar dateTimeValue = Calendar.getInstance();
@@ -93,23 +79,41 @@ public class EdmTime extends AbstractSimpleType {
     dateTimeValue.set(Calendar.SECOND,
         matcher.group(3) == null ? 0 : Integer.parseInt(matcher.group(3)));
 
+    int nanoSeconds = 0;
     if (matcher.group(4) != null) {
-      if (facets == null || facets.getPrecision() == null || 
facets.getPrecision() >= matcher.group(4).length()) {
-        if (matcher.group(4).length() <= 3) {
-          dateTimeValue.set(Calendar.MILLISECOND,
-              Short.parseShort(matcher.group(4) + "000".substring(0, 3 - 
matcher.group(4).length())));
-        } else {
-          throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(literal));
+      final String decimals = matcher.group(4);
+      if (facets == null || facets.getPrecision() == null || 
facets.getPrecision() >= decimals.length()) {
+        nanoSeconds = Integer.parseInt(decimals + 
"000000000".substring(decimals.length()));
+        if (!(returnType.isAssignableFrom(Timestamp.class))) {
+          if (nanoSeconds % (1000 * 1000) == 0) {
+            dateTimeValue.set(Calendar.MILLISECOND, nanoSeconds / (1000 * 
1000));
+          } else {
+            throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(value));
+          }
         }
       } else {
-        throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_FACETS_NOT_MATCHED.addContent(literal,
 facets));
+        throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_FACETS_NOT_MATCHED.addContent(value,
 facets));
       }
     }
 
-    if (dateTimeValue.get(Calendar.DAY_OF_YEAR) == 1) {
-      return dateTimeValue;
+    if (dateTimeValue.get(Calendar.DAY_OF_YEAR) != 1) {
+      throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(value));
+    }
+
+    if (returnType.isAssignableFrom(Calendar.class)) {
+      return returnType.cast(dateTimeValue);
+    } else if (returnType.isAssignableFrom(Long.class)) {
+      return returnType.cast(dateTimeValue.getTimeInMillis());
+    } else if (returnType.isAssignableFrom(Date.class)) {
+      return returnType.cast(dateTimeValue.getTime());
+    } else if (returnType.isAssignableFrom(Time.class)) {
+      return returnType.cast(new Time(dateTimeValue.getTimeInMillis()));
+    } else if (returnType.isAssignableFrom(Timestamp.class)) {
+      Timestamp timestamp = new Timestamp(dateTimeValue.getTimeInMillis());
+      timestamp.setNanos(nanoSeconds);
+      return returnType.cast(timestamp);
     } else {
-      throw new 
EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(literal));
+      throw new 
EdmSimpleTypeException(EdmSimpleTypeException.VALUE_TYPE_NOT_SUPPORTED.addContent(returnType));
     }
   }
 
@@ -131,7 +135,7 @@ public class EdmTime extends AbstractSimpleType {
       throw new 
EdmSimpleTypeException(EdmSimpleTypeException.VALUE_TYPE_NOT_SUPPORTED.addContent(value.getClass()));
     }
 
-    StringBuilder result = new StringBuilder(15); // 15 characters are enough 
for millisecond precision.
+    StringBuilder result = new StringBuilder(21); // 21 characters are enough 
for nanosecond precision.
     result.append('P');
     result.append('T');
     result.append(dateTimeValue.get(Calendar.HOUR_OF_DAY));
@@ -140,8 +144,11 @@ public class EdmTime extends AbstractSimpleType {
     result.append('M');
     result.append(dateTimeValue.get(Calendar.SECOND));
 
+    final int fractionalSecs = value instanceof Timestamp ?
+        ((Timestamp) value).getNanos() :
+        dateTimeValue.get(Calendar.MILLISECOND);
     try {
-      EdmDateTime.appendMilliseconds(result, 
dateTimeValue.get(Calendar.MILLISECOND), facets);
+      EdmDateTime.appendFractionalSeconds(result, fractionalSecs, value 
instanceof Timestamp, facets);
     } catch (final IllegalArgumentException e) {
       throw new 
EdmSimpleTypeException(EdmSimpleTypeException.VALUE_FACETS_NOT_MATCHED.addContent(value,
 facets), e);
     }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/d18f9f0b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/edm/EdmSimpleTypeTest.java
----------------------------------------------------------------------
diff --git 
a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/edm/EdmSimpleTypeTest.java
 
b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/edm/EdmSimpleTypeTest.java
index 47a9417..5b1b50b 100644
--- 
a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/edm/EdmSimpleTypeTest.java
+++ 
b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/edm/EdmSimpleTypeTest.java
@@ -29,6 +29,8 @@ import static org.mockito.Mockito.when;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.sql.Time;
+import java.sql.Timestamp;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
@@ -563,7 +565,39 @@ public class EdmSimpleTypeTest extends BaseTest {
     Calendar dateTime2 = 
Calendar.getInstance(TimeZone.getTimeZone("GMT-11:30"));
     dateTime2.clear();
     dateTime2.set(1969, 11, 31, 12, 29, 58);
-    assertEquals("/Date(-2000)/", instance.valueToString(dateTime2, 
EdmLiteralKind.JSON, null));
+    dateTime2.set(Calendar.MILLISECOND, 1);
+    assertEquals("/Date(-1999)/", instance.valueToString(dateTime2, 
EdmLiteralKind.JSON, null));
+
+    Calendar dateTime3 = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+    dateTime3.clear();
+    dateTime3.set(1954, 7, 4);
+    dateTime3.set(Calendar.MILLISECOND, 42);
+    expectErrorInValueToString(instance, dateTime3, EdmLiteralKind.DEFAULT, 
getPrecisionScaleFacets(0, null),
+        EdmSimpleTypeException.VALUE_FACETS_NOT_MATCHED);
+    expectErrorInValueToString(instance, dateTime3, EdmLiteralKind.DEFAULT, 
getPrecisionScaleFacets(1, null),
+        EdmSimpleTypeException.VALUE_FACETS_NOT_MATCHED);
+    expectErrorInValueToString(instance, dateTime3, EdmLiteralKind.DEFAULT, 
getPrecisionScaleFacets(2, null),
+        EdmSimpleTypeException.VALUE_FACETS_NOT_MATCHED);
+    assertEquals("1954-08-04T00:00:00.042", instance.valueToString(dateTime3, 
EdmLiteralKind.DEFAULT,
+        getPrecisionScaleFacets(3, null)));
+    assertEquals("1954-08-04T00:00:00.0420", instance.valueToString(dateTime3, 
EdmLiteralKind.DEFAULT,
+        getPrecisionScaleFacets(4, null)));
+    assertEquals("1954-08-04T00:00:00.04200", 
instance.valueToString(dateTime3, EdmLiteralKind.DEFAULT,
+        getPrecisionScaleFacets(5, null)));
+
+    Timestamp timestamp = new Timestamp(0);
+    assertEquals("1970-01-01T00:00:00", instance.valueToString(timestamp, 
EdmLiteralKind.DEFAULT, null));
+    timestamp.setNanos(1000 * 1000);
+    assertEquals("/Date(1)/", instance.valueToString(timestamp, 
EdmLiteralKind.JSON, null));
+    timestamp.setNanos(1500 * 1000);
+    assertEquals("1970-01-01T00:00:00.0015", instance.valueToString(timestamp, 
EdmLiteralKind.DEFAULT, null));
+    timestamp.setNanos(42);
+    assertEquals("1970-01-01T00:00:00.000000042", 
instance.valueToString(timestamp, EdmLiteralKind.DEFAULT,
+        getPrecisionScaleFacets(9, null)));
+    expectErrorInValueToString(instance, timestamp, EdmLiteralKind.DEFAULT, 
getPrecisionScaleFacets(8, null),
+        EdmSimpleTypeException.VALUE_FACETS_NOT_MATCHED);
+    expectErrorInValueToString(instance, timestamp, EdmLiteralKind.JSON, null,
+        EdmSimpleTypeException.VALUE_ILLEGAL_CONTENT);
 
     dateTime.add(Calendar.MILLISECOND, -100);
     expectErrorInValueToString(instance, dateTime, EdmLiteralKind.DEFAULT, 
getPrecisionScaleFacets(0, null),
@@ -574,64 +608,6 @@ public class EdmSimpleTypeTest extends BaseTest {
     expectErrorInValueToString(instance, dateTime, null, null, 
EdmSimpleTypeException.LITERAL_KIND_MISSING);
   }
 
-  /**
-   * Extended test for combination of precision with dates before 1970 (and 
for regression after 1970)
-   */
-  @Test
-  public void valueToStringDateTimeSpecial() throws Exception {
-
-    for (int precision = 0; precision < 3; precision++) {
-      final EdmSimpleType instance = 
EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance();
-      final EdmFacets facets = getPrecisionScaleFacets(precision, null);
-      final Calendar date = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
-      date.set(Calendar.MILLISECOND, 10 * precision + 1);
-
-      date.set(1954, 7, 4);
-      expectErrorInValueToString(instance, date, EdmLiteralKind.DEFAULT, 
facets,
-          EdmSimpleTypeException.VALUE_FACETS_NOT_MATCHED);
-
-      date.set(1999, 7, 4);
-      expectErrorInValueToString(instance, date, EdmLiteralKind.DEFAULT, 
facets,
-          EdmSimpleTypeException.VALUE_FACETS_NOT_MATCHED);
-    }
-
-    for (int precision = 3; precision < 6; precision++) {
-      assertValueToStringDateTimeSpecial(1954, 7, 4, precision);
-      assertValueToStringDateTimeSpecial(1999, 7, 4, precision);
-    }
-  }
-
-  private void assertValueToStringDateTimeSpecial(final int year, final int 
month, final int day, final int precision)
-      throws Exception {
-    final EdmSimpleType instance = 
EdmSimpleTypeKind.DateTime.getEdmSimpleTypeInstance();
-    final StringBuilder regExToMatch = new StringBuilder();// = new 
StringBuilder("1954-08-04T\\d\\d:\\d\\d:\\d\\d");
-    regExToMatch.append(year).append("-");
-    if (month < 9) {
-      regExToMatch.append("0");
-    }
-    // add '1' to the month because java calendar month begin with '0'
-    regExToMatch.append(month + 1).append("-");
-    if (day < 10) {
-      regExToMatch.append("0");
-    }
-    regExToMatch.append(day).append("T\\d\\d:\\d\\d:\\d\\d");
-
-    if (precision > 0) {
-      regExToMatch.append("\\.");
-    }
-    for (int i = 0; i < precision; i++) {
-      regExToMatch.append("\\d");
-    }
-    Calendar date = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
-    date.set(year, month, day);
-    date.set(Calendar.MILLISECOND, 10 * precision + 1);
-
-    //
-    String formated = instance.valueToString(date, EdmLiteralKind.DEFAULT, 
getPrecisionScaleFacets(precision, null));
-    assertTrue("Formated date '" + formated + "' is wrong for precision '" + 
precision +
-        "'. (used regex = [" + regExToMatch.toString() + "])", 
formated.matches(regExToMatch.toString()));
-  }
-
   @Test
   public void valueToStringDateTimeOffset() throws Exception {
     final EdmSimpleType instance = 
EdmSimpleTypeKind.DateTimeOffset.getEdmSimpleTypeInstance();
@@ -668,6 +644,14 @@ public class EdmSimpleTypeTest extends BaseTest {
     final String time = date.toString().substring(11, 19);
     assertTrue(instance.valueToString(date, EdmLiteralKind.DEFAULT, 
null).contains(time));
 
+    Timestamp timestamp = new Timestamp(millis);
+    assertTrue(instance.valueToString(timestamp, EdmLiteralKind.JSON, 
null).contains("007"));
+    timestamp.setNanos(42);
+    expectErrorInValueToString(instance, timestamp, EdmLiteralKind.DEFAULT, 
getPrecisionScaleFacets(8, null),
+        EdmSimpleTypeException.VALUE_FACETS_NOT_MATCHED);
+    expectErrorInValueToString(instance, timestamp, EdmLiteralKind.JSON, null,
+        EdmSimpleTypeException.VALUE_ILLEGAL_CONTENT);
+
     expectErrorInValueToString(instance, 0, EdmLiteralKind.DEFAULT, null,
         EdmSimpleTypeException.VALUE_TYPE_NOT_SUPPORTED);
     expectErrorInValueToString(instance, dateTime, null, null, 
EdmSimpleTypeException.LITERAL_KIND_MISSING);
@@ -958,6 +942,12 @@ public class EdmSimpleTypeTest extends BaseTest {
     assertEquals("PT23H32M2.9S", instance.valueToString(dateTime, 
EdmLiteralKind.DEFAULT, getPrecisionScaleFacets(1,
         null)));
 
+    Timestamp timestamp = new Timestamp(millis);
+    timestamp.setNanos(123456789);
+    assertTrue(instance.valueToString(timestamp, EdmLiteralKind.DEFAULT, 
null).contains("M3.123456789S"));
+    expectErrorInValueToString(instance, timestamp, EdmLiteralKind.DEFAULT, 
getPrecisionScaleFacets(8, null),
+        EdmSimpleTypeException.VALUE_FACETS_NOT_MATCHED);
+
     expectErrorInValueToString(instance, dateTime, EdmLiteralKind.DEFAULT, 
getPrecisionScaleFacets(0, null),
         EdmSimpleTypeException.VALUE_FACETS_NOT_MATCHED);
     expectErrorInValueToString(instance, 0, EdmLiteralKind.DEFAULT, null,
@@ -1177,15 +1167,20 @@ public class EdmSimpleTypeTest extends BaseTest {
     dateTime.set(1969, 11, 31, 23, 59, 18);
     assertEquals(dateTime, instance.valueOfString("/Date(-42000)/", 
EdmLiteralKind.JSON, null, Calendar.class));
 
-    expectErrorInValueOfString(instance, "2012-02-29T23:32:02.9", 
EdmLiteralKind.DEFAULT, getPrecisionScaleFacets(0,
-        null), EdmSimpleTypeException.LITERAL_FACETS_NOT_MATCHED);
-    expectErrorInValueOfString(instance, "2012-02-29T23:32:02.98700", 
EdmLiteralKind.DEFAULT, getPrecisionScaleFacets(
-        2, null), EdmSimpleTypeException.LITERAL_FACETS_NOT_MATCHED);
+    Timestamp timestamp = new Timestamp(0);
+    timestamp.setNanos(987654321);
+    assertEquals(timestamp, 
instance.valueOfString("1970-01-01T00:00:00.987654321", EdmLiteralKind.DEFAULT, 
null,
+        Timestamp.class));
+
+    expectErrorInValueOfString(instance, "2012-02-29T23:32:02.9", 
EdmLiteralKind.DEFAULT,
+        getPrecisionScaleFacets(0, null), 
EdmSimpleTypeException.LITERAL_FACETS_NOT_MATCHED);
+    expectErrorInValueOfString(instance, "2012-02-29T23:32:02.98700", 
EdmLiteralKind.DEFAULT,
+        getPrecisionScaleFacets(2, null), 
EdmSimpleTypeException.LITERAL_FACETS_NOT_MATCHED);
     expectErrorInValueOfString(instance, "2012-02-29T23:32:02.9876", 
EdmLiteralKind.DEFAULT, null,
         EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT);
     expectErrorInValueOfString(instance, "2012-02-29T23:32:02.", 
EdmLiteralKind.DEFAULT, null,
         EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT);
-    expectErrorInValueOfString(instance, "2012-02-29T23:32:02.00000000", 
EdmLiteralKind.DEFAULT, null,
+    expectErrorInValueOfString(instance, "2012-02-29T23:32:02.0000000000", 
EdmLiteralKind.DEFAULT, null,
         EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT);
     expectErrorInValueOfString(instance, "20120229T233202", 
EdmLiteralKind.DEFAULT, null,
         EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT);
@@ -1264,8 +1259,18 @@ public class EdmSimpleTypeTest extends BaseTest {
     dateTime.set(1969, 11, 31, 23, 59, 18);
     assertEquals(dateTime, instance.valueOfString("/Date(-42000+0660)/", 
EdmLiteralKind.JSON, null, Calendar.class));
 
-    expectErrorInValueOfString(instance, "2012-02-29T23:32:02.9Z", 
EdmLiteralKind.DEFAULT, getPrecisionScaleFacets(0,
-        null), EdmSimpleTypeException.LITERAL_FACETS_NOT_MATCHED);
+    assertEquals(Long.valueOf(3601234L),
+        instance.valueOfString("1970-01-01T00:00:01.234-01:00", 
EdmLiteralKind.DEFAULT, null, Long.class));
+
+    Timestamp timestamp = new Timestamp(0);
+    timestamp.setNanos(987654300);
+    assertEquals(timestamp, 
instance.valueOfString("1970-01-01T00:00:00.9876543Z", EdmLiteralKind.DEFAULT, 
null,
+        Timestamp.class));
+
+    expectErrorInValueOfString(instance, "2012-02-29T23:32:02.9Z", 
EdmLiteralKind.DEFAULT,
+        getPrecisionScaleFacets(0, null), 
EdmSimpleTypeException.LITERAL_FACETS_NOT_MATCHED);
+    expectErrorInValueOfString(instance, "2012-02-29T23:32:02.9876Z", 
EdmLiteralKind.DEFAULT, null,
+        EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT);
     expectErrorInValueOfString(instance, "datetime'2012-02-29T23:32:02'", 
EdmLiteralKind.URI, null,
         EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT);
     expectErrorInValueOfString(instance, "2012-02-29T23:32:02X", 
EdmLiteralKind.DEFAULT, null,
@@ -1652,16 +1657,16 @@ public class EdmSimpleTypeTest extends BaseTest {
     assertEquals(dateTime, instance.valueOfString("PT23H32M3S", 
EdmLiteralKind.DEFAULT,
         getPrecisionScaleFacets(0, null), Calendar.class));
     dateTime.add(Calendar.MILLISECOND, 10);
-    assertEquals(dateTime, instance.valueOfString("PT23H32M3.01S", 
EdmLiteralKind.DEFAULT, getPrecisionScaleFacets(2,
-        null), Calendar.class));
+    assertEquals(dateTime, instance.valueOfString("PT23H32M3.01S", 
EdmLiteralKind.DEFAULT,
+        getPrecisionScaleFacets(2, null), Calendar.class));
     dateTime.add(Calendar.MILLISECOND, -23);
-    assertEquals(dateTime, instance.valueOfString("PT23H32M2.987S", 
EdmLiteralKind.DEFAULT, getPrecisionScaleFacets(
-        null, null), Calendar.class));
-    assertEquals(dateTime, instance.valueOfString("PT23H32M2.98700S", 
EdmLiteralKind.DEFAULT, getPrecisionScaleFacets(
-        5, null), Calendar.class));
+    assertEquals(dateTime, instance.valueOfString("PT23H32M2.987S", 
EdmLiteralKind.DEFAULT,
+        getPrecisionScaleFacets(null, null), Calendar.class));
+    assertEquals(dateTime, instance.valueOfString("PT23H32M2.98700S", 
EdmLiteralKind.DEFAULT,
+        getPrecisionScaleFacets(5, null), Calendar.class));
     dateTime.add(Calendar.MILLISECOND, -87);
-    assertEquals(dateTime, instance.valueOfString("PT23H32M2.9S", 
EdmLiteralKind.DEFAULT, getPrecisionScaleFacets(1,
-        null), Calendar.class));
+    assertEquals(dateTime, instance.valueOfString("PT23H32M2.9S", 
EdmLiteralKind.DEFAULT,
+        getPrecisionScaleFacets(1, null), Calendar.class));
 
     dateTime.add(Calendar.HOUR, -23);
     assertEquals(dateTime, instance.valueOfString("PT32M2.9S", 
EdmLiteralKind.DEFAULT, null, Calendar.class));
@@ -1673,6 +1678,15 @@ public class EdmSimpleTypeTest extends BaseTest {
     dateTime.add(Calendar.MINUTE, 59);
     assertEquals(dateTime, instance.valueOfString("PT59M", 
EdmLiteralKind.DEFAULT, null, Calendar.class));
 
+    assertEquals(Long.valueOf(dateTime.getTimeInMillis()),
+        instance.valueOfString("PT59M", EdmLiteralKind.DEFAULT, null, 
Long.class));
+
+    assertEquals(dateTime.getTimeInMillis(),
+        instance.valueOfString("PT59M", EdmLiteralKind.DEFAULT, null, 
Time.class).getTime());
+
+    assertEquals(123456789,
+        instance.valueOfString("PT59M0.123456789S", EdmLiteralKind.DEFAULT, 
null, Timestamp.class).getNanos());
+
     expectErrorInValueOfString(instance, "PT1H2M3.1234S", 
EdmLiteralKind.DEFAULT, null,
         EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT);
     expectErrorInValueOfString(instance, "PT13H2M3.9S", 
EdmLiteralKind.DEFAULT, getPrecisionScaleFacets(0, null),

Reply via email to