You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2017/05/31 17:54:32 UTC

[3/5] calcite git commit: [CALCITE-1690] Calcite timestamp literals cannot express precision above millisecond, TIMESTAMP(3)

[CALCITE-1690] Calcite timestamp literals cannot express precision above millisecond, TIMESTAMP(3)


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/205af813
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/205af813
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/205af813

Branch: refs/heads/master
Commit: 205af8134857ba312415b9a5b4a48020fe0ce888
Parents: 915c218
Author: Julian Hyde <jh...@apache.org>
Authored: Mon May 1 21:53:12 2017 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Wed May 31 08:17:28 2017 -0700

----------------------------------------------------------------------
 core/src/main/codegen/templates/Parser.jj       |  73 +----
 .../adapter/enumerable/RexToLixTranslator.java  |  40 +--
 .../apache/calcite/interpreter/Interpreter.java |   2 +-
 .../apache/calcite/interpreter/SortNode.java    |   5 +-
 .../java/org/apache/calcite/plan/Strong.java    |   2 +-
 .../calcite/rel/metadata/RelMdCollation.java    |   8 +-
 .../rel/metadata/RelMdColumnUniqueness.java     |   4 +-
 .../apache/calcite/rel/metadata/RelMdSize.java  |   6 +-
 .../apache/calcite/rel/metadata/RelMdUtil.java  |  19 +-
 .../calcite/rel/rel2sql/SqlImplementor.java     |  25 +-
 .../calcite/rel/rules/DateRangeRules.java       |   7 +-
 .../java/org/apache/calcite/rex/RexBuilder.java | 124 +++++----
 .../java/org/apache/calcite/rex/RexLiteral.java | 275 +++++++++++++++----
 .../org/apache/calcite/rex/RexSimplify.java     |  10 +-
 .../calcite/rex/RexToSqlNodeConverterImpl.java  |  18 +-
 .../calcite/sql/SqlAbstractDateTimeLiteral.java |  81 +-----
 .../org/apache/calcite/sql/SqlDateLiteral.java  |  23 +-
 .../java/org/apache/calcite/sql/SqlLiteral.java |  96 ++++++-
 .../org/apache/calcite/sql/SqlTimeLiteral.java  |  48 +---
 .../apache/calcite/sql/SqlTimestampLiteral.java |  49 +---
 .../calcite/sql/parser/SqlParserUtil.java       |  85 ++++++
 .../calcite/sql/type/SqlTypeFactoryImpl.java    |   8 +
 .../apache/calcite/sql/type/SqlTypeName.java    |  15 +-
 .../calcite/sql/validate/SqlValidatorImpl.java  |   2 +-
 .../sql2rel/SqlNodeToRexConverterImpl.java      |  35 +--
 .../org/apache/calcite/util/BasicDatetime.java  |  63 -----
 .../org/apache/calcite/util/DateString.java     |  98 +++++++
 .../org/apache/calcite/util/TimeString.java     | 192 +++++++++++++
 .../apache/calcite/util/TimestampString.java    | 252 +++++++++++++++++
 .../main/java/org/apache/calcite/util/Util.java |  20 +-
 .../org/apache/calcite/util/ZonelessDate.java   | 135 ---------
 .../apache/calcite/util/ZonelessDatetime.java   | 199 --------------
 .../org/apache/calcite/util/ZonelessTime.java   | 175 ------------
 .../apache/calcite/util/ZonelessTimestamp.java  | 160 -----------
 .../rel/rel2sql/RelToSqlConverterTest.java      |  20 ++
 .../org/apache/calcite/rex/RexBuilderTest.java  | 209 +++++++++++++-
 .../org/apache/calcite/rex/RexExecutorTest.java |  16 +-
 .../calcite/sql/parser/SqlParserTest.java       |  11 +-
 .../calcite/sql/test/SqlOperatorBaseTest.java   |   6 +-
 .../calcite/test/RexImplicationCheckerTest.java |  34 +--
 .../org/apache/calcite/test/RexProgramTest.java |  10 +-
 core/src/test/resources/sql/misc.iq             |   2 +-
 .../adapter/druid/DruidDateTimeUtils.java       |  57 ++--
 .../calcite/test/DruidDateRangeRulesTest.java   |  14 +-
 44 files changed, 1505 insertions(+), 1228 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/codegen/templates/Parser.jj
----------------------------------------------------------------------
diff --git a/core/src/main/codegen/templates/Parser.jj b/core/src/main/codegen/templates/Parser.jj
index b776e92..3543da6 100644
--- a/core/src/main/codegen/templates/Parser.jj
+++ b/core/src/main/codegen/templates/Parser.jj
@@ -411,63 +411,6 @@ JAVACODE void checkNonQueryExpression(ExprContext exprContext)
     }
 }
 
-// The date/time parse utilities have to live here, instead of in the
-// SqlParserUtil class because ParseException is ambiguous, and
-// CommonParser has to live in multiple packages.
-
-JAVACODE SqlDateLiteral parseDateLiteral(String s, SqlParserPos pos) {
-    String dateStr = SqlParserUtil.parseString(s);
-    Calendar cal = DateTimeUtils.parseDateFormat(
-        dateStr, DateTimeUtils.DATE_FORMAT_STRING, DateTimeUtils.UTC_ZONE);
-    if (null == cal) {
-        throw SqlUtil.newContextException(pos,
-            RESOURCE.illegalLiteral("DATE", s,
-                RESOURCE.badFormat(DateTimeUtils.DATE_FORMAT_STRING).str()));
-    }
-    return SqlLiteral.createDate(cal, pos);
-}
-
-JAVACODE SqlTimeLiteral parseTimeLiteral(String s, SqlParserPos pos) {
-    String dateStr = SqlParserUtil.parseString(s);
-    DateTimeUtils.PrecisionTime pt =
-    DateTimeUtils.parsePrecisionDateTimeLiteral(
-        dateStr, DateTimeUtils.TIME_FORMAT_STRING, DateTimeUtils.UTC_ZONE);
-    if (null == pt) {
-        throw SqlUtil.newContextException(pos,
-            RESOURCE.illegalLiteral("TIME", s,
-                RESOURCE.badFormat(DateTimeUtils.TIME_FORMAT_STRING).str()));
-    }
-    return SqlLiteral.createTime(pt.getCalendar(), pt.getPrecision(), pos);
-}
-
-JAVACODE SqlTimestampLiteral parseTimestampLiteral(String s, SqlParserPos pos) {
-    String dateStr = SqlParserUtil.parseString(s);
-    DateTimeUtils.PrecisionTime pt =
-    DateTimeUtils.parsePrecisionDateTimeLiteral(
-        dateStr, DateTimeUtils.TIMESTAMP_FORMAT_STRING, DateTimeUtils.UTC_ZONE);
-    if (null == pt) {
-        throw SqlUtil.newContextException(pos,
-            RESOURCE.illegalLiteral("TIMESTAMP", s,
-                RESOURCE.badFormat(DateTimeUtils.TIMESTAMP_FORMAT_STRING).str()));
-    }
-    return SqlLiteral.createTimestamp(pt.getCalendar(), pt.getPrecision(), pos);
-}
-
-JAVACODE SqlIntervalLiteral parseIntervalLiteral(
-    SqlParserPos pos,
-    int sign,
-    String s,
-    SqlIntervalQualifier intervalQualifier) throws ParseException
-{
-    String intervalStr = SqlParserUtil.parseString(s);
-    if ("".equals(intervalStr)) {
-        throw new ParseException(
-            RESOURCE.illegalIntervalLiteral(s + " "
-                + intervalQualifier.toString(), pos.toString()).str());
-    }
-    return SqlLiteral.createInterval(sign, intervalStr, intervalQualifier, pos);
-}
-
 /**
  * Converts a ParseException (local to this particular instantiation
  * of the parser) into a SqlParseException (common to all parsers).
@@ -3693,33 +3636,33 @@ SqlLiteral DateTimeLiteral() :
         p = token.image;
     }
     <RBRACE> {
-        return parseDateLiteral(p, getPos());
+        return SqlParserUtil.parseDateLiteral(p, getPos());
     }
 |
     <LBRACE_T> <QUOTED_STRING> {
         p = token.image;
     }
     <RBRACE> {
-        return parseTimeLiteral(p, getPos());
+        return SqlParserUtil.parseTimeLiteral(p, getPos());
     }
 |
     <LBRACE_TS> { s = span(); } <QUOTED_STRING> {
         p = token.image;
     }
     <RBRACE> {
-        return parseTimestampLiteral(p, s.end(this));
+        return SqlParserUtil.parseTimestampLiteral(p, s.end(this));
     }
 |
     <DATE> { s = span(); } <QUOTED_STRING> {
-        return parseDateLiteral(token.image, s.end(this));
+        return SqlParserUtil.parseDateLiteral(token.image, s.end(this));
     }
 |
     <TIME> { s = span(); } <QUOTED_STRING> {
-        return parseTimeLiteral(token.image, s.end(this));
+        return SqlParserUtil.parseTimeLiteral(token.image, s.end(this));
     }
 |
     <TIMESTAMP> { s = span(); } <QUOTED_STRING> {
-        return parseTimestampLiteral(token.image, s.end(this));
+        return SqlParserUtil.parseTimestampLiteral(token.image, s.end(this));
     }
 }
 
@@ -3862,8 +3805,8 @@ SqlLiteral IntervalLiteral() :
     ]
     <QUOTED_STRING> { p = token.image; }
     intervalQualifier = IntervalQualifier() {
-        return parseIntervalLiteral(s.end(intervalQualifier), sign, p,
-            intervalQualifier);
+        return SqlParserUtil.parseIntervalLiteral(s.end(intervalQualifier),
+            sign, p, intervalQualifier);
     }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
index 7d5ef75..10e969f 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/RexToLixTranslator.java
@@ -48,7 +48,6 @@ import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.util.BuiltInMethod;
 import org.apache.calcite.util.ControlFlowException;
-import org.apache.calcite.util.NlsString;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
@@ -59,7 +58,6 @@ import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -588,8 +586,7 @@ public class RexToLixTranslator {
       RelDataType type,
       JavaTypeFactory typeFactory,
       RexImpTable.NullAs nullAs) {
-    final Comparable value = literal.getValue();
-    if (value == null) {
+    if (literal.isNull()) {
       switch (nullAs) {
       case TRUE:
       case IS_NULL:
@@ -615,26 +612,22 @@ public class RexToLixTranslator {
     final Object value2;
     switch (literal.getType().getSqlTypeName()) {
     case DECIMAL:
+      final BigDecimal bd = literal.getValueAs(BigDecimal.class);
       if (javaClass == float.class) {
-        return Expressions.constant(value, javaClass);
+        return Expressions.constant(bd, javaClass);
       }
       assert javaClass == BigDecimal.class;
       return Expressions.new_(BigDecimal.class,
-          Expressions.constant(value.toString()));
+          Expressions.constant(bd.toString()));
     case DATE:
-      value2 = (int)
-          (((Calendar) value).getTimeInMillis() / DateTimeUtils.MILLIS_PER_DAY);
-      javaClass = int.class;
-      break;
     case TIME:
-      value2 = (int)
-          (((Calendar) value).getTimeInMillis() % DateTimeUtils.MILLIS_PER_DAY);
+    case INTERVAL_YEAR:
+    case INTERVAL_YEAR_MONTH:
+    case INTERVAL_MONTH:
+      value2 = literal.getValueAs(Integer.class);
       javaClass = int.class;
       break;
     case TIMESTAMP:
-      value2 = ((Calendar) value).getTimeInMillis();
-      javaClass = long.class;
-      break;
     case INTERVAL_DAY:
     case INTERVAL_DAY_HOUR:
     case INTERVAL_DAY_MINUTE:
@@ -645,32 +638,27 @@ public class RexToLixTranslator {
     case INTERVAL_MINUTE:
     case INTERVAL_MINUTE_SECOND:
     case INTERVAL_SECOND:
-      value2 = ((BigDecimal) value).longValue();
+      value2 = literal.getValueAs(Long.class);
       javaClass = long.class;
       break;
-    case INTERVAL_YEAR:
-    case INTERVAL_YEAR_MONTH:
-    case INTERVAL_MONTH:
-      value2 = ((BigDecimal) value).intValue();
-      javaClass = int.class;
-      break;
     case CHAR:
     case VARCHAR:
-      value2 = ((NlsString) value).getValue();
+      value2 = literal.getValueAs(String.class);
       break;
     case BINARY:
     case VARBINARY:
       return Expressions.new_(
           ByteString.class,
           Expressions.constant(
-              ((ByteString) value).getBytes(),
+              literal.getValueAs(byte[].class),
               byte[].class));
     case SYMBOL:
-      value2 = value;
-      javaClass = value.getClass();
+      value2 = literal.getValueAs(Enum.class);
+      javaClass = value2.getClass();
       break;
     default:
       final Primitive primitive = Primitive.ofBoxOr(javaClass);
+      final Comparable value = literal.getValueAs(Comparable.class);
       if (primitive != null && value instanceof Number) {
         value2 = primitive.number((Number) value);
       } else {

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
index 51aa082..16b70de 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/Interpreter.java
@@ -238,7 +238,7 @@ public class Interpreter extends AbstractEnumerable<Object[]>
         public Object execute(Context context) {
           switch (node.getKind()) {
           case LITERAL:
-            return ((RexLiteral) node).getValue();
+            return ((RexLiteral) node).getValueAs(Comparable.class);
           case INPUT_REF:
             return context.values[((RexInputRef) node).getIndex()];
           default:

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/interpreter/SortNode.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/interpreter/SortNode.java b/core/src/main/java/org/apache/calcite/interpreter/SortNode.java
index e2c0eeb..5eaaaf6 100644
--- a/core/src/main/java/org/apache/calcite/interpreter/SortNode.java
+++ b/core/src/main/java/org/apache/calcite/interpreter/SortNode.java
@@ -25,7 +25,6 @@ import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Ordering;
 
-import java.math.BigDecimal;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
@@ -43,11 +42,11 @@ public class SortNode extends AbstractSingleNode<Sort> {
     final int offset =
         rel.offset == null
             ? 0
-            : ((BigDecimal) ((RexLiteral) rel.offset).getValue()).intValue();
+            : ((RexLiteral) rel.offset).getValueAs(Integer.class);
     final int fetch =
         rel.fetch == null
             ? -1
-            : ((BigDecimal) ((RexLiteral) rel.fetch).getValue()).intValue();
+            : ((RexLiteral) rel.fetch).getValueAs(Integer.class);
     // In pure limit mode. No sort required.
     Row row;
   loop:

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/plan/Strong.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/Strong.java b/core/src/main/java/org/apache/calcite/plan/Strong.java
index 99a1b4e..e631d90 100644
--- a/core/src/main/java/org/apache/calcite/plan/Strong.java
+++ b/core/src/main/java/org/apache/calcite/plan/Strong.java
@@ -118,7 +118,7 @@ public class Strong {
 
     switch (node.getKind()) {
     case LITERAL:
-      return ((RexLiteral) node).getValue() == null;
+      return ((RexLiteral) node).isNull();
     // We can only guarantee AND to return NULL if both inputs are NULL  (similar for OR)
     // AND(NULL, FALSE) = FALSE
     case AND:

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
index 2867657..32596ed 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
@@ -335,16 +335,16 @@ public class RelMdCollation
     case ASCENDING:
       return new Ordering<List<RexLiteral>>() {
         public int compare(List<RexLiteral> o1, List<RexLiteral> o2) {
-          final Comparable c1 = o1.get(x).getValue();
-          final Comparable c2 = o2.get(x).getValue();
+          final Comparable c1 = o1.get(x).getValueAs(Comparable.class);
+          final Comparable c2 = o2.get(x).getValueAs(Comparable.class);
           return RelFieldCollation.compare(c1, c2, nullComparison);
         }
       };
     default:
       return new Ordering<List<RexLiteral>>() {
         public int compare(List<RexLiteral> o1, List<RexLiteral> o2) {
-          final Comparable c1 = o1.get(x).getValue();
-          final Comparable c2 = o2.get(x).getValue();
+          final Comparable c1 = o1.get(x).getValueAs(Comparable.class);
+          final Comparable c2 = o2.get(x).getValueAs(Comparable.class);
           return RelFieldCollation.compare(c2, c1, -nullComparison);
         }
       };

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
index 9b5d38c..e7032c6 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
@@ -333,7 +333,9 @@ public class RelMdColumnUniqueness
     final List<Comparable> values = new ArrayList<>();
     for (ImmutableList<RexLiteral> tuple : rel.tuples) {
       for (RexLiteral literal : tuple) {
-        values.add(NullSentinel.mask(literal.getValue()));
+        values.add(literal.isNull()
+            ? NullSentinel.INSTANCE
+            : literal.getValueAs(Comparable.class));
       }
       if (!set.add(ImmutableList.copyOf(values))) {
         return false;

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
index 744d241..bd12347 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
@@ -145,7 +145,8 @@ public class RelMdSize implements MetadataHandler<BuiltInMetadata.Size> {
       } else {
         d = 0;
         for (ImmutableList<RexLiteral> literals : rel.getTuples()) {
-          d += typeValueSize(field.getType(), literals.get(i).getValue());
+          d += typeValueSize(field.getType(),
+              literals.get(i).getValueAs(Comparable.class));
         }
         d /= rel.getTuples().size();
       }
@@ -372,7 +373,8 @@ public class RelMdSize implements MetadataHandler<BuiltInMetadata.Size> {
     case INPUT_REF:
       return inputColumnSizes.get(((RexInputRef) node).getIndex());
     case LITERAL:
-      return typeValueSize(node.getType(), ((RexLiteral) node).getValue());
+      return typeValueSize(node.getType(),
+          ((RexLiteral) node).getValueAs(Comparable.class));
     default:
       if (node instanceof RexCall) {
         RexCall call = (RexCall) node;

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java
index 7b63ac9..6a896ad 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java
@@ -86,24 +86,23 @@ public class RelMdUtil {
     RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
     double selectivity =
         computeSemiJoinSelectivity(mq, rel.getLeft(), rel.getRight(), rel);
-    RexNode selec =
-        rexBuilder.makeApproxLiteral(new BigDecimal(selectivity));
-    return rexBuilder.makeCall(ARTIFICIAL_SELECTIVITY_FUNC, selec);
+    return rexBuilder.makeCall(ARTIFICIAL_SELECTIVITY_FUNC,
+        rexBuilder.makeApproxLiteral(new BigDecimal(selectivity)));
   }
 
   /**
-   * Returns the selectivity value stored in the rexnode
+   * Returns the selectivity value stored in a call.
    *
-   * @param artificialSelecFuncNode rexnode containing the selectivity value
+   * @param artificialSelectivityFuncNode Call containing the selectivity value
    * @return selectivity value
    */
-  public static double getSelectivityValue(RexNode artificialSelecFuncNode) {
-    assert artificialSelecFuncNode instanceof RexCall;
-    RexCall call = (RexCall) artificialSelecFuncNode;
+  public static double getSelectivityValue(
+      RexNode artificialSelectivityFuncNode) {
+    assert artificialSelectivityFuncNode instanceof RexCall;
+    RexCall call = (RexCall) artificialSelectivityFuncNode;
     assert call.getOperator() == ARTIFICIAL_SELECTIVITY_FUNC;
     RexNode operand = call.getOperands().get(0);
-    BigDecimal bd = (BigDecimal) ((RexLiteral) operand).getValue();
-    return bd.doubleValue();
+    return ((RexLiteral) operand).getValueAs(Double.class);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
index 826cebc..1e477d2 100644
--- a/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
+++ b/core/src/main/java/org/apache/calcite/rel/rel2sql/SqlImplementor.java
@@ -67,6 +67,9 @@ import org.apache.calcite.sql.type.SqlTypeFamily;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
+import org.apache.calcite.util.DateString;
+import org.apache.calcite.util.TimeString;
+import org.apache.calcite.util.TimestampString;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Preconditions;
@@ -78,9 +81,9 @@ import com.google.common.collect.Iterables;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.math.BigDecimal;
 import java.util.AbstractList;
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -481,7 +484,8 @@ public abstract class SqlImplementor {
         || node instanceof SqlMatchRecognize
         || node instanceof SqlCall
             && (((SqlCall) node).getOperator() instanceof SqlSetOperator
-                || ((SqlCall) node).getOperator() == SqlStdOperatorTable.AS)
+                || ((SqlCall) node).getOperator() == SqlStdOperatorTable.AS
+                || ((SqlCall) node).getOperator() == SqlStdOperatorTable.VALUES)
         : node;
     return new SqlSelect(POS, SqlNodeList.EMPTY, null, node, null, null, null,
         SqlNodeList.EMPTY, null, null, null);
@@ -542,20 +546,23 @@ public abstract class SqlImplementor {
           return SqlLiteral.createCharString((String) literal.getValue2(), POS);
         case NUMERIC:
         case EXACT_NUMERIC:
-          return SqlLiteral.createExactNumeric(literal.getValue().toString(),
-              POS);
+          return SqlLiteral.createExactNumeric(
+              literal.getValueAs(BigDecimal.class).toString(), POS);
         case APPROXIMATE_NUMERIC:
           return SqlLiteral.createApproxNumeric(
-              literal.getValue().toString(), POS);
+              literal.getValueAs(BigDecimal.class).toString(), POS);
         case BOOLEAN:
-          return SqlLiteral.createBoolean((Boolean) literal.getValue(), POS);
+          return SqlLiteral.createBoolean(literal.getValueAs(Boolean.class),
+              POS);
         case DATE:
-          return SqlLiteral.createDate((Calendar) literal.getValue(), POS);
+          return SqlLiteral.createDate(literal.getValueAs(DateString.class),
+              POS);
         case TIME:
-          return SqlLiteral.createTime((Calendar) literal.getValue(),
+          return SqlLiteral.createTime(literal.getValueAs(TimeString.class),
               literal.getType().getPrecision(), POS);
         case TIMESTAMP:
-          return SqlLiteral.createTimestamp((Calendar) literal.getValue(),
+          return SqlLiteral.createTimestamp(
+              literal.getValueAs(TimestampString.class),
               literal.getType().getPrecision(), POS);
         case ANY:
         case NULL:

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java b/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java
index 1bfb813..2a185a1 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/DateRangeRules.java
@@ -35,6 +35,7 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.Bug;
+import org.apache.calcite.util.DateString;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Predicate;
@@ -355,7 +356,8 @@ public abstract class DateRangeRules {
             : SqlStdOperatorTable.GREATER_THAN;
         nodes.add(
             rexBuilder.makeCall(op, operand,
-                rexBuilder.makeDateLiteral(r.lowerEndpoint())));
+                rexBuilder.makeDateLiteral(
+                    DateString.fromCalendarFields(r.lowerEndpoint()))));
       }
       if (r.hasUpperBound()) {
         final SqlBinaryOperator op = r.upperBoundType() == BoundType.CLOSED
@@ -363,7 +365,8 @@ public abstract class DateRangeRules {
             : SqlStdOperatorTable.LESS_THAN;
         nodes.add(
             rexBuilder.makeCall(op, operand,
-                rexBuilder.makeDateLiteral(r.upperEndpoint())));
+                rexBuilder.makeDateLiteral(
+                    DateString.fromCalendarFields(r.upperEndpoint()))));
       }
       return RexUtil.composeConjunction(rexBuilder, nodes, false);
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
index 1906227..adf7fee 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
@@ -28,7 +28,6 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.runtime.FlatLists;
-import org.apache.calcite.runtime.SqlFunctions;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlIntervalQualifier;
 import org.apache.calcite.sql.SqlKind;
@@ -43,8 +42,11 @@ import org.apache.calcite.sql.type.MultisetSqlType;
 import org.apache.calcite.sql.type.SqlTypeFamily;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.type.SqlTypeUtil;
+import org.apache.calcite.util.DateString;
 import org.apache.calcite.util.NlsString;
 import org.apache.calcite.util.Pair;
+import org.apache.calcite.util.TimeString;
+import org.apache.calcite.util.TimestampString;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Function;
@@ -477,21 +479,6 @@ public class RexBuilder {
   }
 
   /**
-   * Rounds the time part of a TIME or TIMESTAMP value to the given precision.
-   *
-   * @param timestamp The value to be rounded, will change in place
-   * @param precision the desired precision
-   */
-  private void roundTime(Calendar timestamp, long precision) {
-    if (precision == RelDataType.PRECISION_NOT_SPECIFIED) {
-      precision = 0;
-    }
-    final long pow = DateTimeUtils.powerX(10, 3 - precision);
-    final long timeMs = SqlFunctions.round(timestamp.getTimeInMillis(), pow);
-    timestamp.setTimeInMillis(timeMs);
-  }
-
-  /**
    * Creates a call to the CAST operator, expanding if possible, and optionally
    * also preserving nullability.
    *
@@ -512,7 +499,7 @@ public class RexBuilder {
     final SqlTypeName sqlType = type.getSqlTypeName();
     if (exp instanceof RexLiteral) {
       RexLiteral literal = (RexLiteral) exp;
-      Comparable value = literal.getValue();
+      Comparable value = literal.getValueAs(Comparable.class);
       SqlTypeName typeName = literal.getTypeName();
       if (canRemoveCastFromLiteral(type, value, typeName)) {
         switch (typeName) {
@@ -836,7 +823,7 @@ public class RexBuilder {
   /**
    * Internal method to create a call to a literal. Code outside this package
    * should call one of the type-specific methods such as
-   * {@link #makeDateLiteral(Calendar)}, {@link #makeLiteral(boolean)},
+   * {@link #makeDateLiteral(DateString)}, {@link #makeLiteral(boolean)},
    * {@link #makeLiteral(String)}.
    *
    * @param o        Value of literal, must be appropriate for the type
@@ -850,6 +837,7 @@ public class RexBuilder {
       SqlTypeName typeName) {
     // All literals except NULL have NOT NULL types.
     type = typeFactory.createTypeWithNullability(type, o == null);
+    int p;
     switch (typeName) {
     case CHAR:
       // Character literals must have a charset and collation. Populate
@@ -868,8 +856,21 @@ public class RexBuilder {
       }
       break;
     case TIME:
+      assert o instanceof TimeString;
+      p = type.getPrecision();
+      if (p == RelDataType.PRECISION_NOT_SPECIFIED) {
+        p = 0;
+      }
+      o = ((TimeString) o).round(p);
+      break;
     case TIMESTAMP:
-      roundTime((Calendar) o, type.getPrecision());
+      assert o instanceof TimestampString;
+      p = type.getPrecision();
+      if (p == RelDataType.PRECISION_NOT_SPECIFIED) {
+        p = 0;
+      }
+      o = ((TimestampString) o).round(p);
+      break;
     }
     return new RexLiteral(o, type, typeName);
   }
@@ -1054,37 +1055,48 @@ public class RexBuilder {
     return makeLiteral(str, type, SqlTypeName.CHAR);
   }
 
+  /** @deprecated Use {@link #makeDateLiteral(DateString)}. */
+  @Deprecated // to be removed before 2.0
+  public RexLiteral makeDateLiteral(Calendar calendar) {
+    return makeDateLiteral(DateString.fromCalendarFields(calendar));
+  }
+
   /**
    * Creates a Date literal.
    */
-  public RexLiteral makeDateLiteral(Calendar date) {
-    assert date != null;
-    return makeLiteral(
-        date, typeFactory.createSqlType(SqlTypeName.DATE), SqlTypeName.DATE);
+  public RexLiteral makeDateLiteral(DateString date) {
+    return makeLiteral(Preconditions.checkNotNull(date),
+        typeFactory.createSqlType(SqlTypeName.DATE), SqlTypeName.DATE);
+  }
+
+  /** @deprecated Use {@link #makeTimeLiteral(TimeString, int)}. */
+  @Deprecated // to be removed before 2.0
+  public RexLiteral makeTimeLiteral(Calendar calendar, int precision) {
+    return makeTimeLiteral(TimeString.fromCalendarFields(calendar), precision);
   }
 
   /**
    * Creates a Time literal.
    */
-  public RexLiteral makeTimeLiteral(
-      Calendar time,
-      int precision) {
-    assert time != null;
-    return makeLiteral(
-        time,
+  public RexLiteral makeTimeLiteral(TimeString time, int precision) {
+    return makeLiteral(Preconditions.checkNotNull(time),
         typeFactory.createSqlType(SqlTypeName.TIME, precision),
         SqlTypeName.TIME);
   }
 
+  /** @deprecated Use {@link #makeTimestampLiteral(TimestampString, int)}. */
+  @Deprecated // to be removed before 2.0
+  public RexLiteral makeTimestampLiteral(Calendar calendar, int precision) {
+    return makeTimestampLiteral(TimestampString.fromCalendarFields(calendar),
+        precision);
+  }
+
   /**
    * Creates a Timestamp literal.
    */
-  public RexLiteral makeTimestampLiteral(
-      Calendar timestamp,
+  public RexLiteral makeTimestampLiteral(TimestampString timestamp,
       int precision) {
-    assert timestamp != null;
-    return makeLiteral(
-        timestamp,
+    return makeLiteral(Preconditions.checkNotNull(timestamp),
         typeFactory.createSqlType(SqlTypeName.TIMESTAMP, precision),
         SqlTypeName.TIMESTAMP);
   }
@@ -1275,11 +1287,11 @@ public class RexBuilder {
     case BOOLEAN:
       return (Boolean) value ? booleanTrue : booleanFalse;
     case TIME:
-      return makeTimeLiteral((Calendar) value, type.getPrecision());
+      return makeTimeLiteral((TimeString) value, type.getPrecision());
     case DATE:
-      return makeDateLiteral((Calendar) value);
+      return makeDateLiteral((DateString) value);
     case TIMESTAMP:
-      return makeTimestampLiteral((Calendar) value, type.getPrecision());
+      return makeTimestampLiteral((TimestampString) value, type.getPrecision());
     case INTERVAL_YEAR:
     case INTERVAL_YEAR_MONTH:
     case INTERVAL_MONTH:
@@ -1357,7 +1369,6 @@ public class RexBuilder {
     if (o == null) {
       return null;
     }
-    final Calendar calendar;
     switch (type.getSqlTypeName()) {
     case TINYINT:
     case SMALLINT:
@@ -1402,27 +1413,38 @@ public class RexBuilder {
       return new NlsString((String) o, type.getCharset().name(),
           type.getCollation());
     case TIME:
-      if (o instanceof Calendar) {
+      if (o instanceof TimeString) {
         return o;
+      } else if (o instanceof Calendar) {
+        if (!((Calendar) o).getTimeZone().equals(DateTimeUtils.UTC_ZONE)) {
+          throw new AssertionError();
+        }
+        return TimeString.fromCalendarFields((Calendar) o);
+      } else {
+        return TimeString.fromMillisOfDay((Integer) o);
       }
-      calendar = Util.calendar();
-      calendar.setTimeInMillis((Integer) o);
-      return calendar;
     case DATE:
-      if (o instanceof Calendar) {
+      if (o instanceof DateString) {
         return o;
+      } else if (o instanceof Calendar) {
+        if (!((Calendar) o).getTimeZone().equals(DateTimeUtils.UTC_ZONE)) {
+          throw new AssertionError();
+        }
+        return DateString.fromCalendarFields((Calendar) o);
+      } else {
+        return DateString.fromDaysSinceEpoch((Integer) o);
       }
-      calendar = Util.calendar();
-      calendar.setTimeInMillis(0);
-      calendar.add(Calendar.DAY_OF_YEAR, (Integer) o);
-      return calendar;
     case TIMESTAMP:
-      if (o instanceof Calendar) {
+      if (o instanceof TimestampString) {
         return o;
+      } else if (o instanceof Calendar) {
+        if (!((Calendar) o).getTimeZone().equals(DateTimeUtils.UTC_ZONE)) {
+          throw new AssertionError();
+        }
+        return TimestampString.fromCalendarFields((Calendar) o);
+      } else {
+        return TimestampString.fromMillisSinceEpoch((Long) o);
       }
-      calendar = Util.calendar();
-      calendar.setTimeInMillis((Long) o);
-      return calendar;
     default:
       return o;
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
index f9be2bb..97e3055 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
@@ -26,14 +26,13 @@ import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.parser.SqlParserUtil;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.util.ConversionUtil;
+import org.apache.calcite.util.DateString;
 import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.NlsString;
 import org.apache.calcite.util.SaffronProperties;
+import org.apache.calcite.util.TimeString;
+import org.apache.calcite.util.TimestampString;
 import org.apache.calcite.util.Util;
-import org.apache.calcite.util.ZonelessDate;
-import org.apache.calcite.util.ZonelessDatetime;
-import org.apache.calcite.util.ZonelessTime;
-import org.apache.calcite.util.ZonelessTimestamp;
 
 import com.google.common.base.Preconditions;
 
@@ -42,9 +41,11 @@ import java.io.StringWriter;
 import java.math.BigDecimal;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
+import java.text.SimpleDateFormat;
 import java.util.AbstractList;
 import java.util.Calendar;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.TimeZone;
@@ -68,7 +69,7 @@ import java.util.TimeZone;
  * <caption>Allowable types for RexLiteral instances</caption>
  * <tr>
  * <th>TypeName</th>
- * <th>Meaing</th>
+ * <th>Meaning</th>
  * <th>Value type</th>
  * </tr>
  * <tr>
@@ -96,32 +97,63 @@ import java.util.TimeZone;
  * <tr>
  * <td>{@link SqlTypeName#DATE}</td>
  * <td>Date, for example <code>DATE '1969-04'29'</code></td>
- * <td>{@link Calendar}</td>
+ * <td>{@link Calendar};
+ *     also {@link Calendar} (UTC time zone)
+ *     and {@link Integer} (days since POSIX epoch)</td>
  * </tr>
  * <tr>
  * <td>{@link SqlTypeName#TIME}</td>
  * <td>Time, for example <code>TIME '18:37:42.567'</code></td>
- * <td>{@link Calendar}</td>
+ * <td>{@link Calendar};
+ *     also {@link Calendar} (UTC time zone)
+ *     and {@link Integer} (milliseconds since midnight)</td>
  * </tr>
  * <tr>
  * <td>{@link SqlTypeName#TIMESTAMP}</td>
  * <td>Timestamp, for example <code>TIMESTAMP '1969-04-29
  * 18:37:42.567'</code></td>
- * <td>{@link Calendar}</td>
+ * <td>{@link TimestampString};
+ *     also {@link Calendar} (UTC time zone)
+ *     and {@link Long} (milliseconds since POSIX epoch)</td>
+ * </tr>
+ * <tr>
+ * <td>{@link SqlTypeName#INTERVAL_DAY},
+ *     {@link SqlTypeName#INTERVAL_DAY_HOUR},
+ *     {@link SqlTypeName#INTERVAL_DAY_MINUTE},
+ *     {@link SqlTypeName#INTERVAL_DAY_SECOND},
+ *     {@link SqlTypeName#INTERVAL_HOUR},
+ *     {@link SqlTypeName#INTERVAL_HOUR_MINUTE},
+ *     {@link SqlTypeName#INTERVAL_HOUR_SECOND},
+ *     {@link SqlTypeName#INTERVAL_MINUTE},
+ *     {@link SqlTypeName#INTERVAL_MINUTE_SECOND},
+ *     {@link SqlTypeName#INTERVAL_SECOND}</td>
+ * <td>Interval, for example <code>INTERVAL '4:3:2' HOUR TO SECOND</code></td>
+ * <td>{@link BigDecimal};
+ *     also {@link Long} (milliseconds)</td>
+ * </tr>
+ * <tr>
+ * <td>{@link SqlTypeName#INTERVAL_YEAR},
+ *     {@link SqlTypeName#INTERVAL_YEAR_MONTH},
+ *     {@link SqlTypeName#INTERVAL_MONTH}</td>
+ * <td>Interval, for example <code>INTERVAL '2-3' YEAR TO MONTH</code></td>
+ * <td>{@link BigDecimal};
+ *     also {@link Integer} (months)</td>
  * </tr>
  * <tr>
  * <td>{@link SqlTypeName#CHAR}</td>
  * <td>Character constant, for example <code>'Hello, world!'</code>, <code>
  * ''</code>, <code>_N'Bonjour'</code>, <code>_ISO-8859-1'It''s superman!'
  * COLLATE SHIFT_JIS$ja_JP$2</code>. These are always CHAR, never VARCHAR.</td>
- * <td>{@link NlsString}</td>
+ * <td>{@link NlsString};
+ *     also {@link String}</td>
  * </tr>
  * <tr>
  * <td>{@link SqlTypeName#BINARY}</td>
  * <td>Binary constant, for example <code>X'7F34'</code>. (The number of hexits
  * must be even; see above.) These constants are always BINARY, never
  * VARBINARY.</td>
- * <td>{@link ByteBuffer}</td>
+ * <td>{@link ByteBuffer};
+ *     also {@code byte[]}</td>
  * </tr>
  * <tr>
  * <td>{@link SqlTypeName#SYMBOL}</td>
@@ -213,10 +245,11 @@ public class RexLiteral extends RexNode {
     case BIGINT:
       return value instanceof BigDecimal;
     case DATE:
+      return value instanceof DateString;
     case TIME:
+      return value instanceof TimeString;
     case TIMESTAMP:
-      return value instanceof Calendar
-          && ((Calendar) value).getTimeZone().equals(DateTimeUtils.UTC_ZONE);
+      return value instanceof TimestampString;
     case INTERVAL_YEAR:
     case INTERVAL_YEAR_MONTH:
     case INTERVAL_MONTH:
@@ -391,13 +424,16 @@ public class RexLiteral extends RexNode {
       pw.print(")");
       break;
     case DATE:
-      printDatetime(pw, new ZonelessDate(), value);
+      assert value instanceof DateString;
+      pw.print(value);
       break;
     case TIME:
-      printDatetime(pw, new ZonelessTime(), value);
+      assert value instanceof TimeString;
+      pw.print(value);
       break;
     case TIMESTAMP:
-      printDatetime(pw, new ZonelessTimestamp(), value);
+      assert value instanceof TimestampString;
+      pw.print(value);
       break;
     case INTERVAL_YEAR:
     case INTERVAL_YEAR_MONTH:
@@ -439,16 +475,6 @@ public class RexLiteral extends RexNode {
     }
   }
 
-  private static void printDatetime(
-      PrintWriter pw,
-      ZonelessDatetime datetime,
-      Comparable value) {
-    assert value instanceof Calendar;
-    datetime.setZonelessTime(
-        ((Calendar) value).getTimeInMillis());
-    pw.print(datetime);
-  }
-
   /**
    * Converts a Jdbc string into a RexLiteral. This method accepts a string,
    * as returned by the Jdbc method ResultSet.getString(), and restores the
@@ -521,25 +547,44 @@ public class RexLiteral extends RexNode {
     case TIMESTAMP:
       String format = getCalendarFormat(typeName);
       TimeZone tz = DateTimeUtils.UTC_ZONE;
-      Calendar cal = null;
-      if (typeName == SqlTypeName.DATE) {
-        cal =
-            DateTimeUtils.parseDateFormat(literal, format, tz);
-      } else {
+      final Comparable v;
+      switch (typeName) {
+      case DATE:
+        final Calendar cal = DateTimeUtils.parseDateFormat(literal,
+            new SimpleDateFormat(format, Locale.ROOT),
+            tz);
+        if (cal == null) {
+          throw new AssertionError("fromJdbcString: invalid date/time value '"
+              + literal + "'");
+        }
+        v = DateString.fromCalendarFields(cal);
+        break;
+      default:
         // Allow fractional seconds for times and timestamps
-        DateTimeUtils.PrecisionTime ts =
-            DateTimeUtils.parsePrecisionDateTimeLiteral(literal, format, tz);
-        if (ts != null) {
-          cal = ts.getCalendar();
+        assert format != null;
+        final DateTimeUtils.PrecisionTime ts =
+            DateTimeUtils.parsePrecisionDateTimeLiteral(literal,
+                new SimpleDateFormat(format, Locale.ROOT), tz, -1);
+        if (ts == null) {
+          throw new AssertionError("fromJdbcString: invalid date/time value '"
+              + literal + "'");
+        }
+        switch (typeName) {
+        case TIMESTAMP:
+          v = TimestampString.fromCalendarFields(ts.getCalendar())
+              .withFraction(ts.getFraction());
+          break;
+        case TIME:
+          v = TimeString.fromCalendarFields(ts.getCalendar())
+              .withFraction(ts.getFraction());
+          break;
+        default:
+          throw new AssertionError();
         }
       }
-      if (cal == null) {
-        throw new AssertionError("fromJdbcString: invalid date/time value '"
-            + literal + "'");
-      }
-      return new RexLiteral(cal, type, typeName);
-    case SYMBOL:
+      return new RexLiteral(v, type, typeName);
 
+    case SYMBOL:
       // Symbols are for internal use
     default:
       throw new AssertionError("fromJdbcString: unsupported type");
@@ -572,11 +617,31 @@ public class RexLiteral extends RexNode {
   }
 
   /**
+   * Returns whether this literal's value is null.
+   */
+  public boolean isNull() {
+    return value == null;
+  }
+
+  /**
    * Returns the value of this literal.
+   *
+   * <p>For backwards compatibility, returns DATE. TIME and TIMESTAMP as a
+   * {@link Calendar} value in UTC time zone.
    */
   public Comparable getValue() {
     assert valueMatchesType(value, typeName, true) : value;
-    return value;
+    if (value == null) {
+      return null;
+    }
+    switch (typeName) {
+    case TIME:
+    case DATE:
+    case TIMESTAMP:
+      return getValueAs(Calendar.class);
+    default:
+      return value;
+    }
   }
 
   /**
@@ -589,17 +654,13 @@ public class RexLiteral extends RexNode {
     }
     switch (typeName) {
     case CHAR:
-      return ((NlsString) value).getValue();
+      return getValueAs(String.class);
     case DECIMAL:
-      return ((BigDecimal) value).unscaledValue().longValue();
+    case TIMESTAMP:
+      return getValueAs(Long.class);
     case DATE:
-      return (int) (((Calendar) value).getTimeInMillis()
-          / DateTimeUtils.MILLIS_PER_DAY);
     case TIME:
-      return (int) (((Calendar) value).getTimeInMillis()
-          % DateTimeUtils.MILLIS_PER_DAY);
-    case TIMESTAMP:
-      return ((Calendar) value).getTimeInMillis();
+      return getValueAs(Integer.class);
     default:
       return value;
     }
@@ -619,6 +680,122 @@ public class RexLiteral extends RexNode {
     }
   }
 
+  /** Returns the value of this literal as an instance of the specified class.
+   *
+   * <p>The following SQL types allow more than one form:
+   *
+   * <ul>
+   * <li>CHAR as {@link NlsString} or {@link String}
+   * <li>TIME as {@link TimeString},
+   *   {@link Integer} (milliseconds since midnight),
+   *   {@link Calendar} (in UTC)
+   * <li>DATE as {@link DateString},
+   *   {@link Integer} (days since 1970-01-01),
+   *   {@link Calendar}
+   * <li>TIMESTAMP as {@link TimestampString},
+   *   {@link Long} (milliseconds since 1970-01-01 00:00:00),
+   *   {@link Calendar}
+   * <li>DECIMAL as {@link BigDecimal} or {@link Long}
+   * </ul>
+   *
+   * <p>Called with {@code clazz} = {@link Comparable}, returns the value in
+   * its native form.
+   *
+   * @param clazz Desired return type
+   * @param <T> Return type
+   * @return Value of this literal in the desired type
+   */
+  public <T> T getValueAs(Class<T> clazz) {
+    if (value == null || clazz.isInstance(value)) {
+      return clazz.cast(value);
+    }
+    switch (typeName) {
+    case BINARY:
+      if (clazz == byte[].class) {
+        return clazz.cast(((ByteString) value).getBytes());
+      }
+      break;
+    case CHAR:
+      if (clazz == String.class) {
+        return clazz.cast(((NlsString) value).getValue());
+      }
+      break;
+    case DECIMAL:
+      if (clazz == Long.class) {
+        return clazz.cast(((BigDecimal) value).unscaledValue().longValue());
+      }
+      // fall through
+    case BIGINT:
+    case INTEGER:
+    case SMALLINT:
+    case TINYINT:
+    case DOUBLE:
+    case REAL:
+    case FLOAT:
+      if (clazz == Long.class) {
+        return clazz.cast(((BigDecimal) value).longValue());
+      } else if (clazz == Integer.class) {
+        return clazz.cast(((BigDecimal) value).intValue());
+      } else if (clazz == Short.class) {
+        return clazz.cast(((BigDecimal) value).shortValue());
+      } else if (clazz == Byte.class) {
+        return clazz.cast(((BigDecimal) value).byteValue());
+      } else if (clazz == Double.class) {
+        return clazz.cast(((BigDecimal) value).doubleValue());
+      } else if (clazz == Float.class) {
+        return clazz.cast(((BigDecimal) value).floatValue());
+      }
+      break;
+    case DATE:
+      if (clazz == Integer.class) {
+        return clazz.cast(((DateString) value).getDaysSinceEpoch());
+      } else if (clazz == Calendar.class) {
+        return clazz.cast(((DateString) value).toCalendar());
+      }
+      break;
+    case TIME:
+      if (clazz == Integer.class) {
+        return clazz.cast(((TimeString) value).getMillisOfDay());
+      } else if (clazz == Calendar.class) {
+        // Note: Nanos are ignored
+        return clazz.cast(((TimeString) value).toCalendar());
+      }
+      break;
+    case TIMESTAMP:
+      if (clazz == Long.class) {
+        // Milliseconds since 1970-01-01 00:00:00
+        return clazz.cast(((TimestampString) value).getMillisSinceEpoch());
+      } else if (clazz == Calendar.class) {
+        // Note: Nanos are ignored
+        return clazz.cast(((TimestampString) value).toCalendar());
+      }
+      break;
+    case INTERVAL_YEAR:
+    case INTERVAL_YEAR_MONTH:
+    case INTERVAL_MONTH:
+      if (clazz == Integer.class) {
+        return clazz.cast(((BigDecimal) value).intValue());
+      }
+      break;
+    case INTERVAL_DAY:
+    case INTERVAL_DAY_HOUR:
+    case INTERVAL_DAY_MINUTE:
+    case INTERVAL_DAY_SECOND:
+    case INTERVAL_HOUR:
+    case INTERVAL_HOUR_MINUTE:
+    case INTERVAL_HOUR_SECOND:
+    case INTERVAL_MINUTE:
+    case INTERVAL_MINUTE_SECOND:
+    case INTERVAL_SECOND:
+      if (clazz == Long.class) {
+        return clazz.cast(((BigDecimal) value).longValue());
+      }
+      break;
+    }
+    throw new AssertionError("cannot convert " + typeName
+        + " literal to " + clazz);
+  }
+
   public static boolean booleanValue(RexNode node) {
     return (Boolean) ((RexLiteral) node).value;
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
index 9ac69f7..34f01a0 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexSimplify.java
@@ -177,8 +177,8 @@ public class RexSimplify {
     if (o0.isA(SqlKind.LITERAL)
         && o1.isA(SqlKind.LITERAL)
         && o0.getType().equals(o1.getType())) {
-      final Comparable v0 = ((RexLiteral) o0).getValue();
-      final Comparable v1 = ((RexLiteral) o1).getValue();
+      final Comparable v0 = ((RexLiteral) o0).getValueAs(Comparable.class);
+      final Comparable v1 = ((RexLiteral) o1).getValueAs(Comparable.class);
       if (v0 == null || v1 == null) {
         return unknownAsFalse
             ? rexBuilder.makeLiteral(false)
@@ -358,7 +358,7 @@ public class RexSimplify {
     case CUSTOM:
       switch (a.getKind()) {
       case LITERAL:
-        return rexBuilder.makeLiteral(((RexLiteral) a).getValue() != null);
+        return rexBuilder.makeLiteral(!((RexLiteral) a).isNull());
       default:
         throw new AssertionError("every CUSTOM policy needs a handler, "
             + a.getKind());
@@ -793,7 +793,7 @@ public class RexSimplify {
     switch (operand.getKind()) {
     case LITERAL:
       final RexLiteral literal = (RexLiteral) operand;
-      final Comparable value = literal.getValue();
+      final Comparable value = literal.getValueAs(Comparable.class);
       final SqlTypeName typeName = literal.getTypeName();
 
       // First, try to remove the cast without changing the value.
@@ -834,7 +834,7 @@ public class RexSimplify {
   private static RexNode processRange(RexBuilder rexBuilder,
       List<RexNode> terms, Map<String, Pair<Range, List<RexNode>>> rangeTerms,
       RexNode term, RexNode ref, RexLiteral constant, SqlKind comparison) {
-    final Comparable v0 = constant.getValue();
+    final Comparable v0 = constant.getValueAs(Comparable.class);
     Pair<Range, List<RexNode>> p = rangeTerms.get(ref.toString());
     if (p == null) {
       Range r;

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/rex/RexToSqlNodeConverterImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexToSqlNodeConverterImpl.java b/core/src/main/java/org/apache/calcite/rex/RexToSqlNodeConverterImpl.java
index 16b4203..f9a8932 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexToSqlNodeConverterImpl.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexToSqlNodeConverterImpl.java
@@ -20,9 +20,10 @@ import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.type.SqlTypeFamily;
+import org.apache.calcite.util.DateString;
 import org.apache.calcite.util.NlsString;
-
-import java.util.Calendar;
+import org.apache.calcite.util.TimeString;
+import org.apache.calcite.util.TimestampString;
 
 /**
  * Standard implementation of {@link RexToSqlNodeConverter}.
@@ -83,7 +84,7 @@ public class RexToSqlNodeConverterImpl implements RexToSqlNodeConverter {
     if (SqlTypeFamily.TIMESTAMP.getTypeNames().contains(
         literal.getTypeName())) {
       return SqlLiteral.createTimestamp(
-          (Calendar) literal.getValue(),
+          literal.getValueAs(TimestampString.class),
           0,
           SqlParserPos.ZERO);
     }
@@ -92,7 +93,16 @@ public class RexToSqlNodeConverterImpl implements RexToSqlNodeConverter {
     if (SqlTypeFamily.DATE.getTypeNames().contains(
         literal.getTypeName())) {
       return SqlLiteral.createDate(
-          (Calendar) literal.getValue(),
+          literal.getValueAs(DateString.class),
+          SqlParserPos.ZERO);
+    }
+
+    // Time
+    if (SqlTypeFamily.TIME.getTypeNames().contains(
+        literal.getTypeName())) {
+      return SqlLiteral.createTime(
+          literal.getValueAs(TimeString.class),
+          0,
           SqlParserPos.ZERO);
     }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/sql/SqlAbstractDateTimeLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlAbstractDateTimeLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlAbstractDateTimeLiteral.java
index 324b799..59dfc69 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlAbstractDateTimeLiteral.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlAbstractDateTimeLiteral.java
@@ -20,12 +20,7 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.type.SqlTypeName;
-import org.apache.calcite.util.ZonelessDate;
-import org.apache.calcite.util.ZonelessTime;
-import org.apache.calcite.util.ZonelessTimestamp;
-
-import java.util.Calendar;
-import java.util.TimeZone;
+import org.apache.calcite.util.TimestampString;
 
 /**
  * A SQL literal representing a DATE, TIME or TIMESTAMP value.
@@ -42,57 +37,29 @@ abstract class SqlAbstractDateTimeLiteral extends SqlLiteral {
   //~ Instance fields --------------------------------------------------------
 
   protected final boolean hasTimeZone;
-  protected final String formatString;
   protected final int precision;
 
   //~ Constructors -----------------------------------------------------------
 
   /**
-   * Constructs a datetime literal based on a Calendar. If the literal is to
-   * represent a Timestamp, the Calendar is expected to follow java.sql
-   * semantics. If the Calendar is to represent a Time or Date, the Calendar
-   * is expected to follow {@link org.apache.calcite.util.ZonelessTime}
-   * and {@link org.apache.calcite.util.ZonelessDate}
-   * semantics.
+   * Constructs a datetime literal.
    */
-  protected SqlAbstractDateTimeLiteral(
-      Calendar d,
-      boolean tz,
-      SqlTypeName typeName,
-      int precision,
-      String formatString,
-      SqlParserPos pos) {
+  protected SqlAbstractDateTimeLiteral(Object d, boolean tz,
+      SqlTypeName typeName, int precision, SqlParserPos pos) {
     super(d, typeName, pos);
     this.hasTimeZone = tz;
     this.precision = precision;
-    this.formatString = formatString;
   }
 
   //~ Methods ----------------------------------------------------------------
 
-  public int getPrec() {
-    return precision;
-  }
-
-  public String toValue() {
-    return Long.toString(getCal().getTimeInMillis());
-  }
-
-  public Calendar getCal() {
-    return (Calendar) value;
+  /** Converts this literal to a {@link TimestampString}. */
+  protected TimestampString getTimestamp() {
+    return (TimestampString) value;
   }
 
-  /**
-   * Returns time zone component of this literal. Technically, a SQL date
-   * doesn't come with a tz, but time and ts inherit this, and the calendar
-   * object has one, so it seems harmless.
-   *
-   * @return time zone
-   */
-  public TimeZone getTimeZone() {
-    assert hasTimeZone : "Attempt to get time zone on Literal date: "
-        + getCal() + ", which has no time zone";
-    return getCal().getTimeZone();
+  public int getPrec() {
+    return precision;
   }
 
   /**
@@ -117,36 +84,6 @@ abstract class SqlAbstractDateTimeLiteral extends SqlLiteral {
       int rightPrec) {
     writer.literal(this.toString());
   }
-
-  /**
-   * Converts this literal to a
-   * {@link org.apache.calcite.util.ZonelessDate} object.
-   */
-  protected ZonelessDate getDate() {
-    ZonelessDate zd = new ZonelessDate();
-    zd.setZonelessTime(getCal().getTimeInMillis());
-    return zd;
-  }
-
-  /**
-   * Converts this literal to a
-   * {@link org.apache.calcite.util.ZonelessTime} object.
-   */
-  protected ZonelessTime getTime() {
-    ZonelessTime zt = new ZonelessTime();
-    zt.setZonelessTime(getCal().getTimeInMillis());
-    return zt;
-  }
-
-  /**
-   * Converts this literal to a
-   * {@link org.apache.calcite.util.ZonelessTimestamp} object.
-   */
-  protected ZonelessTimestamp getTimestamp() {
-    ZonelessTimestamp zt = new ZonelessTimestamp();
-    zt.setZonelessTime(getCal().getTimeInMillis());
-    return zt;
-  }
 }
 
 // End SqlAbstractDateTimeLiteral.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/sql/SqlDateLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDateLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlDateLiteral.java
index 9a7aed9..1a757f6 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDateLiteral.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDateLiteral.java
@@ -16,13 +16,11 @@
  */
 package org.apache.calcite.sql;
 
-import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.type.SqlTypeName;
-
-import java.util.Calendar;
+import org.apache.calcite.util.DateString;
 
 /**
  * A SQL literal representing a DATE value, such as <code>DATE
@@ -33,21 +31,22 @@ import java.util.Calendar;
 public class SqlDateLiteral extends SqlAbstractDateTimeLiteral {
   //~ Constructors -----------------------------------------------------------
 
-  SqlDateLiteral(Calendar d, SqlParserPos pos) {
-    super(d, false, SqlTypeName.DATE, 0, DateTimeUtils.DATE_FORMAT_STRING, pos);
-  }
-
-  SqlDateLiteral(Calendar d, String format, SqlParserPos pos) {
-    super(d, false, SqlTypeName.DATE, 0, format, pos);
+  SqlDateLiteral(DateString d, SqlParserPos pos) {
+    super(d, false, SqlTypeName.DATE, 0, pos);
   }
 
   //~ Methods ----------------------------------------------------------------
 
+  /** Converts this literal to a {@link DateString}. */
+  protected DateString getDate() {
+    return (DateString) value;
+  }
+
   public SqlNode clone(SqlParserPos pos) {
-    return new SqlDateLiteral((Calendar) value, pos);
+    return new SqlDateLiteral((DateString) value, pos);
   }
 
-  public String toString() {
+  @Override public String toString() {
     return "DATE '" + toFormattedString() + "'";
   }
 
@@ -55,7 +54,7 @@ public class SqlDateLiteral extends SqlAbstractDateTimeLiteral {
    * Returns e.g. '1969-07-21'.
    */
   public String toFormattedString() {
-    return getDate().toString(formatString);
+    return getDate().toString();
   }
 
   public RelDataType createSqlType(RelDataTypeFactory typeFactory) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
index 228abfc..4fcafb9 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
@@ -31,8 +31,11 @@ import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql.validate.SqlValidatorScope;
 import org.apache.calcite.util.BitString;
+import org.apache.calcite.util.DateString;
 import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.NlsString;
+import org.apache.calcite.util.TimeString;
+import org.apache.calcite.util.TimestampString;
 import org.apache.calcite.util.Util;
 
 import java.math.BigDecimal;
@@ -195,9 +198,11 @@ public class SqlLiteral extends SqlNode {
     case DOUBLE:
       return value instanceof BigDecimal;
     case DATE:
+      return value instanceof DateString;
     case TIME:
+      return value instanceof TimeString;
     case TIMESTAMP:
-      return value instanceof Calendar;
+      return value instanceof TimestampString;
     case INTERVAL_YEAR:
     case INTERVAL_YEAR_MONTH:
     case INTERVAL_MONTH:
@@ -251,6 +256,61 @@ public class SqlLiteral extends SqlNode {
     return value;
   }
 
+  public <T> T getValueAs(Class<T> clazz) {
+    if (clazz.isInstance(value)) {
+      return clazz.cast(value);
+    }
+    switch (typeName) {
+    case DATE:
+      if (clazz == Calendar.class) {
+        return clazz.cast(((DateString) value).toCalendar());
+      }
+      break;
+    case TIME:
+      if (clazz == Calendar.class) {
+        return clazz.cast(((TimeString) value).toCalendar());
+      }
+      break;
+    case TIMESTAMP:
+      if (clazz == Calendar.class) {
+        return clazz.cast(((TimestampString) value).toCalendar());
+      }
+      break;
+    case INTERVAL_YEAR:
+    case INTERVAL_YEAR_MONTH:
+    case INTERVAL_MONTH:
+      if (clazz == Long.class) {
+        final SqlIntervalLiteral.IntervalValue valMonth =
+            (SqlIntervalLiteral.IntervalValue) value;
+        return clazz.cast(valMonth.getSign()
+            * SqlParserUtil.intervalToMonths(valMonth));
+      } else if (clazz == BigDecimal.class) {
+        return clazz.cast(BigDecimal.valueOf(getValueAs(Long.class)));
+      }
+      break;
+    case INTERVAL_DAY:
+    case INTERVAL_DAY_HOUR:
+    case INTERVAL_DAY_MINUTE:
+    case INTERVAL_DAY_SECOND:
+    case INTERVAL_HOUR:
+    case INTERVAL_HOUR_MINUTE:
+    case INTERVAL_HOUR_SECOND:
+    case INTERVAL_MINUTE:
+    case INTERVAL_MINUTE_SECOND:
+    case INTERVAL_SECOND:
+      if (clazz == Long.class) {
+        final SqlIntervalLiteral.IntervalValue valTime =
+            (SqlIntervalLiteral.IntervalValue) value;
+        return clazz.cast(valTime.getSign()
+            * SqlParserUtil.intervalToMillis(valTime));
+      } else if (clazz == BigDecimal.class) {
+        return clazz.cast(BigDecimal.valueOf(getValueAs(Long.class)));
+      }
+      break;
+    }
+    throw new AssertionError("cannot cast " + value + " as " + clazz);
+  }
+
   /** Returns the value as a symbol. */
   @Deprecated // to be removed before 2.0
   public <E extends Enum<E>> E symbolValue_() {
@@ -363,12 +423,12 @@ public class SqlLiteral extends SqlNode {
     if (node instanceof SqlLiteral) {
       SqlLiteral literal = (SqlLiteral) node;
       assert SqlTypeUtil.inCharFamily(literal.getTypeName());
-      return literal.toValue();
+      return literal.value.toString();
     } else if (SqlUtil.isLiteralChain(node)) {
       final SqlLiteral literal =
           SqlLiteralChainOperator.concatenateOperands((SqlCall) node);
       assert SqlTypeUtil.inCharFamily(literal.getTypeName());
-      return literal.toValue();
+      return literal.value.toString();
     } else if (node instanceof SqlCall
         && ((SqlCall) node).getOperator() == SqlStdOperatorTable.CAST) {
       //noinspection deprecation
@@ -680,24 +740,48 @@ public class SqlLiteral extends SqlNode {
     }
   }
 
+  @Deprecated // to be removed before 2.0
   public static SqlDateLiteral createDate(
       Calendar calendar,
       SqlParserPos pos) {
-    return new SqlDateLiteral(calendar, pos);
+    return createDate(DateString.fromCalendarFields(calendar), pos);
+  }
+
+  public static SqlDateLiteral createDate(
+      DateString date,
+      SqlParserPos pos) {
+    return new SqlDateLiteral(date, pos);
   }
 
+  @Deprecated // to be removed before 2.0
   public static SqlTimestampLiteral createTimestamp(
       Calendar calendar,
       int precision,
       SqlParserPos pos) {
-    return new SqlTimestampLiteral(calendar, precision, false, pos);
+    return createTimestamp(TimestampString.fromCalendarFields(calendar),
+        precision, pos);
+  }
+
+  public static SqlTimestampLiteral createTimestamp(
+      TimestampString ts,
+      int precision,
+      SqlParserPos pos) {
+    return new SqlTimestampLiteral(ts, precision, false, pos);
   }
 
+  @Deprecated // to be removed before 2.0
   public static SqlTimeLiteral createTime(
       Calendar calendar,
       int precision,
       SqlParserPos pos) {
-    return new SqlTimeLiteral(calendar, precision, false, pos);
+    return createTime(TimeString.fromCalendarFields(calendar), precision, pos);
+  }
+
+  public static SqlTimeLiteral createTime(
+      TimeString t,
+      int precision,
+      SqlParserPos pos) {
+    return new SqlTimeLiteral(t, precision, false, pos);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/sql/SqlTimeLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlTimeLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlTimeLiteral.java
index 79166c3..4327e2a 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlTimeLiteral.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlTimeLiteral.java
@@ -16,14 +16,12 @@
  */
 package org.apache.calcite.sql;
 
-import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.util.TimeString;
 
 import com.google.common.base.Preconditions;
 
-import java.util.Calendar;
-
 /**
  * A SQL literal representing a TIME value, for example <code>TIME
  * '14:33:44.567'</code>.
@@ -33,33 +31,21 @@ import java.util.Calendar;
 public class SqlTimeLiteral extends SqlAbstractDateTimeLiteral {
   //~ Constructors -----------------------------------------------------------
 
-  SqlTimeLiteral(
-      Calendar t,
-      int precision,
-      boolean hasTimeZone,
-      SqlParserPos pos) {
-    this(t, precision, hasTimeZone, DateTimeUtils.TIME_FORMAT_STRING, pos);
-  }
-
-  SqlTimeLiteral(
-      Calendar t,
-      int precision,
-      boolean hasTimeZone,
-      String format,
+  SqlTimeLiteral(TimeString t, int precision, boolean hasTimeZone,
       SqlParserPos pos) {
-    super(t, hasTimeZone, SqlTypeName.TIME, precision, format, pos);
-    Preconditions.checkArgument(this.precision >= 0 && this.precision <= 3);
+    super(t, hasTimeZone, SqlTypeName.TIME, precision, pos);
+    Preconditions.checkArgument(this.precision >= 0);
   }
 
   //~ Methods ----------------------------------------------------------------
 
+  /** Converts this literal to a {@link TimeString}. */
+  protected TimeString getTime() {
+    return (TimeString) value;
+  }
+
   public SqlNode clone(SqlParserPos pos) {
-    return new SqlTimeLiteral(
-        (Calendar) value,
-        precision,
-        hasTimeZone,
-        formatString,
-        pos);
+    return new SqlTimeLiteral((TimeString) value, precision, hasTimeZone, pos);
   }
 
   public String toString() {
@@ -70,19 +56,7 @@ public class SqlTimeLiteral extends SqlAbstractDateTimeLiteral {
    * Returns e.g. '03:05:67.456'.
    */
   public String toFormattedString() {
-    String result = getTime().toString(formatString);
-    final Calendar cal = getCal();
-    if (precision > 0) {
-      // get the millisecond count.  millisecond => at most 3 digits.
-      String digits = Long.toString(cal.getTimeInMillis());
-      result =
-          result + "."
-          + digits.substring(digits.length() - 3,
-              digits.length() - 3 + precision);
-    } else {
-      assert 0 == cal.get(Calendar.MILLISECOND);
-    }
-    return result;
+    return getTime().toString(precision);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/sql/SqlTimestampLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlTimestampLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlTimestampLiteral.java
index a620595..cc659d5 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlTimestampLiteral.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlTimestampLiteral.java
@@ -16,14 +16,12 @@
  */
 package org.apache.calcite.sql;
 
-import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.util.TimestampString;
 
 import com.google.common.base.Preconditions;
 
-import java.util.Calendar;
-
 /**
  * A SQL literal representing a TIMESTAMP value, for example <code>TIMESTAMP
  * '1969-07-21 03:15 GMT'</code>.
@@ -33,34 +31,17 @@ import java.util.Calendar;
 public class SqlTimestampLiteral extends SqlAbstractDateTimeLiteral {
   //~ Constructors -----------------------------------------------------------
 
-  public SqlTimestampLiteral(
-      Calendar cal,
-      int precision,
-      boolean hasTimeZone,
-      SqlParserPos pos) {
-    this(cal, precision, hasTimeZone, DateTimeUtils.TIMESTAMP_FORMAT_STRING,
-        pos);
-  }
-
-  public SqlTimestampLiteral(
-      Calendar cal,
-      int precision,
-      boolean hasTimeZone,
-      String format,
-      SqlParserPos pos) {
-    super(cal, hasTimeZone, SqlTypeName.TIMESTAMP, precision, format, pos);
-    Preconditions.checkArgument(this.precision >= 0 && this.precision <= 3);
+  SqlTimestampLiteral(TimestampString ts, int precision,
+      boolean hasTimeZone, SqlParserPos pos) {
+    super(ts, hasTimeZone, SqlTypeName.TIMESTAMP, precision, pos);
+    Preconditions.checkArgument(this.precision >= 0);
   }
 
   //~ Methods ----------------------------------------------------------------
 
   public SqlNode clone(SqlParserPos pos) {
-    return new SqlTimestampLiteral(
-        (Calendar) value,
-        precision,
-        hasTimeZone,
-        formatString,
-        pos);
+    return new SqlTimestampLiteral((TimestampString) value, precision,
+        hasTimeZone, pos);
   }
 
   public String toString() {
@@ -71,21 +52,11 @@ public class SqlTimestampLiteral extends SqlAbstractDateTimeLiteral {
    * Returns e.g. '03:05:67.456'.
    */
   public String toFormattedString() {
-    String result = getTimestamp().toString(formatString);
-    final Calendar cal = getCal();
+    TimestampString ts = getTimestamp();
     if (precision > 0) {
-      assert precision <= 3;
-
-      // get the millisecond count.  millisecond => at most 3 digits.
-      String digits = Long.toString(cal.getTimeInMillis());
-      result =
-          result + "."
-          + digits.substring(digits.length() - 3,
-              digits.length() - 3 + precision);
-    } else {
-      assert 0 == cal.get(Calendar.MILLISECOND);
+      ts = ts.round(precision);
     }
-    return result;
+    return ts.toString(precision);
   }
 
   public void unparse(

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java b/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java
index d4b7237..e82841a 100644
--- a/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/parser/SqlParserUtil.java
@@ -17,10 +17,12 @@
 package org.apache.calcite.sql.parser;
 
 import org.apache.calcite.avatica.util.Casing;
+import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.rel.type.RelDataTypeSystem;
 import org.apache.calcite.runtime.CalciteContextException;
 import org.apache.calcite.runtime.PredicateImpl;
 import org.apache.calcite.sql.SqlBinaryOperator;
+import org.apache.calcite.sql.SqlDateLiteral;
 import org.apache.calcite.sql.SqlIntervalLiteral;
 import org.apache.calcite.sql.SqlIntervalQualifier;
 import org.apache.calcite.sql.SqlKind;
@@ -32,9 +34,15 @@ import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlPostfixOperator;
 import org.apache.calcite.sql.SqlPrefixOperator;
 import org.apache.calcite.sql.SqlSpecialOperator;
+import org.apache.calcite.sql.SqlTimeLiteral;
+import org.apache.calcite.sql.SqlTimestampLiteral;
+import org.apache.calcite.sql.SqlUtil;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.util.DateString;
 import org.apache.calcite.util.PrecedenceClimbingParser;
 import org.apache.calcite.util.SaffronProperties;
+import org.apache.calcite.util.TimeString;
+import org.apache.calcite.util.TimestampString;
 import org.apache.calcite.util.Util;
 import org.apache.calcite.util.trace.CalciteTrace;
 
@@ -46,8 +54,10 @@ import org.slf4j.Logger;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.nio.charset.Charset;
+import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.List;
 import java.util.Locale;
 import java.util.StringTokenizer;
@@ -129,6 +139,63 @@ public final class SqlParserUtil {
     return java.sql.Timestamp.valueOf(s);
   }
 
+  public static SqlDateLiteral parseDateLiteral(String s, SqlParserPos pos) {
+    final String dateStr = parseString(s);
+    final Calendar cal =
+        DateTimeUtils.parseDateFormat(dateStr, Format.PER_THREAD.get().date,
+            DateTimeUtils.UTC_ZONE);
+    if (cal == null) {
+      throw SqlUtil.newContextException(pos,
+          RESOURCE.illegalLiteral("DATE", s,
+              RESOURCE.badFormat(DateTimeUtils.DATE_FORMAT_STRING).str()));
+    }
+    final DateString d = DateString.fromCalendarFields(cal);
+    return SqlLiteral.createDate(d, pos);
+  }
+
+  public static SqlTimeLiteral parseTimeLiteral(String s, SqlParserPos pos) {
+    final String dateStr = parseString(s);
+    final DateTimeUtils.PrecisionTime pt =
+        DateTimeUtils.parsePrecisionDateTimeLiteral(dateStr,
+            Format.PER_THREAD.get().time, DateTimeUtils.UTC_ZONE, -1);
+    if (pt == null) {
+      throw SqlUtil.newContextException(pos,
+          RESOURCE.illegalLiteral("TIME", s,
+              RESOURCE.badFormat(DateTimeUtils.TIME_FORMAT_STRING).str()));
+    }
+    final TimeString t = TimeString.fromCalendarFields(pt.getCalendar())
+        .withFraction(pt.getFraction());
+    return SqlLiteral.createTime(t, pt.getPrecision(), pos);
+  }
+
+  public static SqlTimestampLiteral parseTimestampLiteral(String s,
+      SqlParserPos pos) {
+    final String dateStr = parseString(s);
+    final DateTimeUtils.PrecisionTime pt =
+        DateTimeUtils.parsePrecisionDateTimeLiteral(dateStr,
+            Format.PER_THREAD.get().timestamp, DateTimeUtils.UTC_ZONE, -1);
+    if (pt == null) {
+      throw SqlUtil.newContextException(pos,
+          RESOURCE.illegalLiteral("TIMESTAMP", s,
+              RESOURCE.badFormat(DateTimeUtils.TIMESTAMP_FORMAT_STRING).str()));
+    }
+    final TimestampString ts =
+        TimestampString.fromCalendarFields(pt.getCalendar())
+            .withFraction(pt.getFraction());
+    return SqlLiteral.createTimestamp(ts, pt.getPrecision(), pos);
+  }
+
+  public static SqlIntervalLiteral parseIntervalLiteral(SqlParserPos pos,
+      int sign, String s, SqlIntervalQualifier intervalQualifier) {
+    final String intervalStr = parseString(s);
+    if (intervalStr.equals("")) {
+      throw SqlUtil.newContextException(pos,
+          RESOURCE.illegalIntervalLiteral(s + " "
+              + intervalQualifier.toString(), pos.toString()));
+    }
+    return SqlLiteral.createInterval(sign, intervalStr, intervalQualifier, pos);
+  }
+
   /**
    * Checks if the date/time format is valid
    *
@@ -875,6 +942,24 @@ public final class SqlParserUtil {
       SqlParserUtil.replaceSublist(list, start, end, e);
     }
   }
+
+  /** Pre-initialized {@link DateFormat} objects, to be used within the current
+   * thread, because {@code DateFormat} is not thread-safe. */
+  private static class Format {
+    private static final ThreadLocal<Format> PER_THREAD =
+        new ThreadLocal<Format>() {
+          @Override protected Format initialValue() {
+            return new Format();
+          }
+        };
+    final DateFormat timestamp =
+        new SimpleDateFormat(DateTimeUtils.TIMESTAMP_FORMAT_STRING,
+            Locale.ROOT);
+    final DateFormat time =
+        new SimpleDateFormat(DateTimeUtils.TIME_FORMAT_STRING, Locale.ROOT);
+    final DateFormat date =
+        new SimpleDateFormat(DateTimeUtils.DATE_FORMAT_STRING, Locale.ROOT);
+  }
 }
 
 // End SqlParserUtil.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java
index bbe0801..9f7dc51 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeFactoryImpl.java
@@ -56,6 +56,10 @@ public class SqlTypeFactoryImpl extends RelDataTypeFactoryImpl {
   public RelDataType createSqlType(
       SqlTypeName typeName,
       int precision) {
+    final int maxPrecision = typeSystem.getMaxPrecision(typeName);
+    if (maxPrecision >= 0 && precision > maxPrecision) {
+      precision = maxPrecision;
+    }
     if (typeName.allowsScale()) {
       return createSqlType(typeName, precision, typeName.getDefaultScale());
     }
@@ -75,6 +79,10 @@ public class SqlTypeFactoryImpl extends RelDataTypeFactoryImpl {
     assertBasic(typeName);
     assert (precision >= 0)
         || (precision == RelDataType.PRECISION_NOT_SPECIFIED);
+    final int maxPrecision = typeSystem.getMaxPrecision(typeName);
+    if (maxPrecision >= 0 && precision > maxPrecision) {
+      precision = maxPrecision;
+    }
     RelDataType newType =
         new BasicSqlType(typeSystem, typeName, precision, scale);
     newType = SqlTypeUtil.addCharsetAndCollation(newType, this);

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
index f34ea11..f1b4e6a 100644
--- a/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
+++ b/core/src/main/java/org/apache/calcite/sql/type/SqlTypeName.java
@@ -19,6 +19,9 @@ package org.apache.calcite.sql.type;
 import org.apache.calcite.avatica.util.TimeUnit;
 import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.util.DateString;
+import org.apache.calcite.util.TimeString;
+import org.apache.calcite.util.TimestampString;
 import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableList;
@@ -911,11 +914,17 @@ public enum SqlTypeName {
     case BINARY:
       return SqlLiteral.createBinaryString((byte[]) o, pos);
     case DATE:
-      return SqlLiteral.createDate((Calendar) o, pos);
+      return SqlLiteral.createDate(o instanceof Calendar
+          ? DateString.fromCalendarFields((Calendar) o)
+          : (DateString) o, pos);
     case TIME:
-      return SqlLiteral.createTime((Calendar) o, 0 /* todo */, pos);
+      return SqlLiteral.createTime(o instanceof Calendar
+          ? TimeString.fromCalendarFields((Calendar) o)
+          : (TimeString) o, 0 /* todo */, pos);
     case TIMESTAMP:
-      return SqlLiteral.createTimestamp((Calendar) o, 0 /* todo */, pos);
+      return SqlLiteral.createTimestamp(o instanceof Calendar
+          ? TimestampString.fromCalendarFields((Calendar) o)
+          : (TimestampString) o, 0 /* todo */, pos);
     default:
       throw Util.unexpected(this);
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
index b8cddb0..46cd711 100644
--- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java
@@ -2821,7 +2821,7 @@ public class SqlValidatorImpl implements SqlValidatorWithHints {
     case DATE:
     case TIME:
     case TIMESTAMP:
-      Calendar calendar = (Calendar) literal.getValue();
+      Calendar calendar = literal.getValueAs(Calendar.class);
       final int year = calendar.get(Calendar.YEAR);
       final int era = calendar.get(Calendar.ERA);
       if (year < 1 || era == GregorianCalendar.BC || year > 9999) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java
index 3f7b5cb..9f398d6 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java
@@ -31,13 +31,15 @@ import org.apache.calcite.sql.SqlTimestampLiteral;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.util.BitString;
+import org.apache.calcite.util.DateString;
 import org.apache.calcite.util.NlsString;
+import org.apache.calcite.util.TimeString;
+import org.apache.calcite.util.TimestampString;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Preconditions;
 
 import java.math.BigDecimal;
-import java.util.Calendar;
 
 /**
  * Standard implementation of {@link SqlNodeToRexConverter}.
@@ -80,8 +82,7 @@ public class SqlNodeToRexConverterImpl implements SqlNodeToRexConverter {
     RexBuilder rexBuilder = cx.getRexBuilder();
     RelDataTypeFactory typeFactory = cx.getTypeFactory();
     SqlValidator validator = cx.getValidator();
-    final Object value = literal.getValue();
-    if (value == null) {
+    if (literal.getValue() == null) {
       // Since there is no eq. RexLiteral of SqlLiteral.Unknown we
       // treat it as a cast(null as boolean)
       RelDataType type;
@@ -102,23 +103,23 @@ public class SqlNodeToRexConverterImpl implements SqlNodeToRexConverter {
 
     switch (literal.getTypeName()) {
     case DECIMAL:
-
       // exact number
-      BigDecimal bd = (BigDecimal) value;
+      BigDecimal bd = literal.getValueAs(BigDecimal.class);
       return rexBuilder.makeExactLiteral(
           bd,
           literal.createSqlType(typeFactory));
-    case DOUBLE:
 
+    case DOUBLE:
       // approximate type
       // TODO:  preserve fixed-point precision and large integers
-      return rexBuilder.makeApproxLiteral((BigDecimal) value);
+      return rexBuilder.makeApproxLiteral(literal.getValueAs(BigDecimal.class));
+
     case CHAR:
-      return rexBuilder.makeCharLiteral((NlsString) value);
+      return rexBuilder.makeCharLiteral(literal.getValueAs(NlsString.class));
     case BOOLEAN:
-      return rexBuilder.makeLiteral(((Boolean) value).booleanValue());
+      return rexBuilder.makeLiteral(literal.getValueAs(Boolean.class));
     case BINARY:
-      bitString = (BitString) value;
+      bitString = literal.getValueAs(BitString.class);
       Preconditions.checkArgument((bitString.getBitCount() % 8) == 0,
           "incomplete octet");
 
@@ -127,17 +128,17 @@ public class SqlNodeToRexConverterImpl implements SqlNodeToRexConverter {
       ByteString byteString = new ByteString(bitString.getAsByteArray());
       return rexBuilder.makeBinaryLiteral(byteString);
     case SYMBOL:
-      return rexBuilder.makeFlag((Enum) value);
+      return rexBuilder.makeFlag(literal.getValueAs(Enum.class));
     case TIMESTAMP:
       return rexBuilder.makeTimestampLiteral(
-          (Calendar) value,
+          literal.getValueAs(TimestampString.class),
           ((SqlTimestampLiteral) literal).getPrec());
     case TIME:
       return rexBuilder.makeTimeLiteral(
-          (Calendar) value,
+          literal.getValueAs(TimeString.class),
           ((SqlTimeLiteral) literal).getPrec());
     case DATE:
-      return rexBuilder.makeDateLiteral((Calendar) value);
+      return rexBuilder.makeDateLiteral(literal.getValueAs(DateString.class));
 
     case INTERVAL_YEAR:
     case INTERVAL_YEAR_MONTH:
@@ -153,10 +154,10 @@ public class SqlNodeToRexConverterImpl implements SqlNodeToRexConverter {
     case INTERVAL_MINUTE_SECOND:
     case INTERVAL_SECOND:
       SqlIntervalQualifier sqlIntervalQualifier =
-          ((SqlIntervalLiteral.IntervalValue) value).getIntervalQualifier();
-      l = (long) SqlLiteral.value(literal);
+          literal.getValueAs(SqlIntervalLiteral.IntervalValue.class)
+              .getIntervalQualifier();
       return rexBuilder.makeIntervalLiteral(
-          BigDecimal.valueOf(l),
+          literal.getValueAs(BigDecimal.class),
           sqlIntervalQualifier);
     default:
       throw Util.unexpected(literal.getTypeName());

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/util/BasicDatetime.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/BasicDatetime.java b/core/src/main/java/org/apache/calcite/util/BasicDatetime.java
deleted file mode 100644
index 0d38bc0..0000000
--- a/core/src/main/java/org/apache/calcite/util/BasicDatetime.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.util;
-
-import java.util.TimeZone;
-
-/**
- * BasicDatetime is an interface for dates, times, or timestamps that can be
- * assigned from a long value. The value to be assigned may either be a zoneless
- * time, or it may be a zoned time.
- *
- * <p>A zoneless time is based on milliseconds. It may contain date and/or time
- * components as follows:
- *
- * <pre>
- * The time component = value % milliseconds in a day
- * The date component = value / milliseconds in a day
- * </pre>
- *
- * If a date component is specified, it is relative to the epoch (1970-01-01).
- *
- * <p>A zoned time represents a time that was created in a particular time zone.
- * It may contain date and/or time components that are valid when interpreted
- * relative to a specified time zone, according to a
- * {@link java.util.Calendar Calendar}. Jdbc types, such as
- * {@link java.sql.Date} typically contain zoned times.
- */
-public interface BasicDatetime {
-  //~ Methods ----------------------------------------------------------------
-
-  /**
-   * Gets the internal value of this datetime
-   */
-  long getTime();
-
-  /**
-   * Sets this datetime via a zoneless time value. See class comments for more
-   * information.
-   */
-  void setZonelessTime(long value);
-
-  /**
-   * Sets this datetime via a zoned time value. See class comments for more
-   * information.
-   */
-  void setZonedTime(long value, TimeZone zone);
-}
-
-// End BasicDatetime.java