http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/util/DateString.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/DateString.java 
b/core/src/main/java/org/apache/calcite/util/DateString.java
new file mode 100644
index 0000000..cea9df3
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/util/DateString.java
@@ -0,0 +1,98 @@
+/*
+ * 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 org.apache.calcite.avatica.util.DateTimeUtils;
+
+import com.google.common.base.Preconditions;
+
+import java.util.Calendar;
+import java.util.regex.Pattern;
+
+/**
+ * Date literal.
+ *
+ * <p>Immutable, internally represented as a string (in ISO format).
+ */
+public class DateString implements Comparable<DateString> {
+  private static final Pattern PATTERN =
+      Pattern.compile("[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]");
+
+  final String v;
+
+  /** Creates a DateString. */
+  public DateString(String v) {
+    this.v = v;
+    Preconditions.checkArgument(PATTERN.matcher(v).matches(), v);
+  }
+
+  /** Creates a DateString for year, month, day values. */
+  public DateString(int year, int month, int day) {
+    this(TimestampString.ymd(new StringBuilder(), year, month, 
day).toString());
+  }
+
+  @Override public String toString() {
+    return v;
+  }
+
+  @Override public boolean equals(Object o) {
+    // The value is in canonical form.
+    return o == this
+        || o instanceof DateString
+        && ((DateString) o).v.equals(v);
+  }
+
+  @Override public int hashCode() {
+    return v.hashCode();
+  }
+
+  @Override public int compareTo(DateString o) {
+    return v.compareTo(o.v);
+  }
+
+  /** Creates a DateString from a Calendar. */
+  public static DateString fromCalendarFields(Calendar calendar) {
+    return new DateString(calendar.get(Calendar.YEAR),
+        calendar.get(Calendar.MONTH) + 1,
+        calendar.get(Calendar.DAY_OF_MONTH));
+  }
+
+  /** Returns the number of days since the epoch. */
+  public int getDaysSinceEpoch() {
+    int year = Integer.valueOf(v.substring(0, 4));
+    int month = Integer.valueOf(v.substring(5, 7));
+    int day = Integer.valueOf(v.substring(8, 10));
+    return DateTimeUtils.ymdToUnixDate(year, month, day);
+  }
+
+  /** Creates a DateString that is a given number of days since the epoch. */
+  public static DateString fromDaysSinceEpoch(int days) {
+    return new DateString(DateTimeUtils.unixDateToString(days));
+  }
+
+  /** Returns the number of milliseconds since the epoch. Always a multiple of
+   * 86,400,000 (the number of milliseconds in a day). */
+  public long getMillisSinceEpoch() {
+    return getDaysSinceEpoch() * DateTimeUtils.MILLIS_PER_DAY;
+  }
+
+  public Calendar toCalendar() {
+    return Util.calendar(getMillisSinceEpoch());
+  }
+}
+
+// End DateString.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/util/TimeString.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/TimeString.java 
b/core/src/main/java/org/apache/calcite/util/TimeString.java
new file mode 100644
index 0000000..75aa96b
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/util/TimeString.java
@@ -0,0 +1,192 @@
+/*
+ * 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 org.apache.calcite.avatica.util.DateTimeUtils;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
+import java.util.Calendar;
+import java.util.regex.Pattern;
+
+/**
+ * Time literal.
+ *
+ * <p>Immutable, internally represented as a string (in ISO format),
+ * and can support unlimited precision (milliseconds, nanoseconds).
+ */
+public class TimeString implements Comparable<TimeString> {
+  private static final Pattern PATTERN =
+      Pattern.compile("[0-9][0-9]:[0-9][0-9]:[0-9][0-9](\\.[0-9]*[1-9])?");
+
+  final String v;
+
+  /** Creates a TimeString. */
+  public TimeString(String v) {
+    this.v = v;
+    Preconditions.checkArgument(PATTERN.matcher(v).matches(), v);
+  }
+
+  /** Creates a TimeString for hour, minute, second and millisecond values. */
+  public TimeString(int h, int m, int s) {
+    this(TimestampString.hms(new StringBuilder(), h, m, s).toString());
+  }
+
+  /** Sets the fraction field of a {@code TimeString} to a given number
+   * of milliseconds. Nukes the value set via {@link #withNanos}.
+   *
+   * <p>For example,
+   * {@code new TimeString(1970, 1, 1, 2, 3, 4).withMillis(56)}
+   * yields {@code TIME '1970-01-01 02:03:04.056'}. */
+  public TimeString withMillis(int millis) {
+    Preconditions.checkArgument(millis >= 0 && millis < 1000);
+    return withFraction(TimestampString.pad(3, millis));
+  }
+
+  /** Sets the fraction field of a {@code TimeString} to a given number
+   * of nanoseconds. Nukes the value set via {@link #withMillis(int)}.
+   *
+   * <p>For example,
+   * {@code new TimeString(1970, 1, 1, 2, 3, 4).withNanos(56789)}
+   * yields {@code TIME '1970-01-01 02:03:04.000056789'}. */
+  public TimeString withNanos(int nanos) {
+    Preconditions.checkArgument(nanos >= 0 && nanos < 1000000000);
+    return withFraction(TimestampString.pad(9, nanos));
+  }
+
+  /** Sets the fraction field of a {@code TimeString}.
+   * The precision is determined by the number of leading zeros.
+   * Trailing zeros are stripped.
+   *
+   * <p>For example,
+   * {@code new TimeString(1970, 1, 1, 2, 3, 4).withFraction("00506000")}
+   * yields {@code TIME '1970-01-01 02:03:04.00506'}. */
+  public TimeString withFraction(String fraction) {
+    String v = this.v;
+    int i = v.indexOf('.');
+    if (i >= 0) {
+      v = v.substring(0, i);
+    }
+    while (fraction.endsWith("0")) {
+      fraction = fraction.substring(0, fraction.length() - 1);
+    }
+    if (fraction.length() > 0) {
+      v = v + "." + fraction;
+    }
+    return new TimeString(v);
+  }
+
+  @Override public String toString() {
+    return v;
+  }
+
+  @Override public boolean equals(Object o) {
+    // The value is in canonical form (no trailing zeros).
+    return o == this
+        || o instanceof TimeString
+        && ((TimeString) o).v.equals(v);
+  }
+
+  @Override public int hashCode() {
+    return v.hashCode();
+  }
+
+  @Override public int compareTo(TimeString o) {
+    return v.compareTo(o.v);
+  }
+
+  /** Creates a TimeString from a Calendar. */
+  public static TimeString fromCalendarFields(Calendar calendar) {
+    return new TimeString(
+        calendar.get(Calendar.HOUR_OF_DAY),
+        calendar.get(Calendar.MINUTE),
+        calendar.get(Calendar.SECOND))
+        .withMillis(calendar.get(Calendar.MILLISECOND));
+  }
+
+  public static TimeString fromMillisOfDay(int i) {
+    return new TimeString(DateTimeUtils.unixTimeToString(i))
+        .withMillis((int) DateTimeUtils.floorMod(i, 1000));
+  }
+
+  public TimeString round(int precision) {
+    Preconditions.checkArgument(precision >= 0);
+    int targetLength = 9 + precision;
+    if (v.length() <= targetLength) {
+      return this;
+    }
+    String v = this.v.substring(0, targetLength);
+    while (v.length() >= 9 && (v.endsWith("0") || v.endsWith("."))) {
+      v = v.substring(0, v.length() - 1);
+    }
+    return new TimeString(v);
+  }
+
+  public int getMillisOfDay() {
+    int h = Integer.valueOf(v.substring(0, 2));
+    int m = Integer.valueOf(v.substring(3, 5));
+    int s = Integer.valueOf(v.substring(6, 8));
+    int ms = getMillisInSecond();
+    return (int) (h * DateTimeUtils.MILLIS_PER_HOUR
+        + m * DateTimeUtils.MILLIS_PER_MINUTE
+        + s * DateTimeUtils.MILLIS_PER_SECOND
+        + ms);
+  }
+
+  private int getMillisInSecond() {
+    switch (v.length()) {
+    case 8: // "12:34:56"
+      return 0;
+    case 10: // "12:34:56.7"
+      return Integer.valueOf(v.substring(9)) * 100;
+    case 11: // "12:34:56.78"
+      return Integer.valueOf(v.substring(9)) * 10;
+    case 12: // "12:34:56.789"
+    default: // "12:34:56.7890000012345"
+      return Integer.valueOf(v.substring(9, 12));
+    }
+  }
+
+  public Calendar toCalendar() {
+    return Util.calendar(getMillisOfDay());
+  }
+
+  /** Converts this TimestampString to a string, truncated or padded with
+   * zeroes to a given precision. */
+  public String toString(int precision) {
+    Preconditions.checkArgument(precision >= 0);
+    final int p = precision();
+    if (precision < p) {
+      return round(precision).toString(precision);
+    }
+    if (precision > p) {
+      String s = v;
+      if (p == 0) {
+        s += ".";
+      }
+      return s + Strings.repeat("0", precision - p);
+    }
+    return v;
+  }
+
+  private int precision() {
+    return v.length() < 9 ? 0 : (v.length() - 9);
+  }
+}
+
+// End TimeString.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/util/TimestampString.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/TimestampString.java 
b/core/src/main/java/org/apache/calcite/util/TimestampString.java
new file mode 100644
index 0000000..4e392f0
--- /dev/null
+++ b/core/src/main/java/org/apache/calcite/util/TimestampString.java
@@ -0,0 +1,252 @@
+/*
+ * 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 org.apache.calcite.avatica.util.DateTimeUtils;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
+import java.util.Calendar;
+import java.util.regex.Pattern;
+
+/**
+ * Timestamp literal.
+ *
+ * <p>Immutable, internally represented as a string (in ISO format),
+ * and can support unlimited precision (milliseconds, nanoseconds).
+ */
+public class TimestampString implements Comparable<TimestampString> {
+  private static final Pattern PATTERN =
+      Pattern.compile("[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]"
+          + " "
+          + "[0-9][0-9]:[0-9][0-9]:[0-9][0-9](\\.[0-9]*[1-9])?");
+
+  final String v;
+
+  /** Creates a TimeString. */
+  public TimestampString(String v) {
+    this.v = v;
+    Preconditions.checkArgument(PATTERN.matcher(v).matches(), v);
+  }
+
+  /** Creates a TimestampString for year, month, day, hour, minute, second,
+   *  millisecond values. */
+  public TimestampString(int year, int month, int day, int h, int m, int s) {
+    this(ymdhms(new StringBuilder(), year, month, day, h, m, s).toString());
+  }
+
+  /** Sets the fraction field of a {@code TimestampString} to a given number
+   * of milliseconds. Nukes the value set via {@link #withNanos}.
+   *
+   * <p>For example,
+   * {@code new TimestampString(1970, 1, 1, 2, 3, 4).withMillis(56)}
+   * yields {@code TIMESTAMP '1970-01-01 02:03:04.056'}. */
+  public TimestampString withMillis(int millis) {
+    Preconditions.checkArgument(millis >= 0 && millis < 1000);
+    return withFraction(pad(3, millis));
+  }
+
+  /** Sets the fraction field of a {@code TimestampString} to a given number
+   * of nanoseconds. Nukes the value set via {@link #withMillis(int)}.
+   *
+   * <p>For example,
+   * {@code new TimestampString(1970, 1, 1, 2, 3, 4).withNanos(56789)}
+   * yields {@code TIMESTAMP '1970-01-01 02:03:04.000056789'}. */
+  public TimestampString withNanos(int nanos) {
+    Preconditions.checkArgument(nanos >= 0 && nanos < 1000000000);
+    return withFraction(pad(9, nanos));
+  }
+
+  /** Sets the fraction field of a {@code TimestampString}.
+   * The precision is determined by the number of leading zeros.
+   * Trailing zeros are stripped.
+   *
+   * <p>For example,
+   * {@code new TimestampString(1970, 1, 1, 2, 3, 4).withFraction("00506000")}
+   * yields {@code TIMESTAMP '1970-01-01 02:03:04.00506'}. */
+  public TimestampString withFraction(String fraction) {
+    String v = this.v;
+    int i = v.indexOf('.');
+    if (i >= 0) {
+      v = v.substring(0, i);
+    }
+    while (fraction.endsWith("0")) {
+      fraction = fraction.substring(0, fraction.length() - 1);
+    }
+    if (fraction.length() > 0) {
+      v = v + "." + fraction;
+    }
+    return new TimestampString(v);
+  }
+
+  @Override public String toString() {
+    return v;
+  }
+
+  @Override public boolean equals(Object o) {
+    // The value is in canonical form (no trailing zeros).
+    return o == this
+        || o instanceof TimestampString
+        && ((TimestampString) o).v.equals(v);
+  }
+
+  @Override public int hashCode() {
+    return v.hashCode();
+  }
+
+  @Override public int compareTo(TimestampString o) {
+    return v.compareTo(o.v);
+  }
+
+  static StringBuilder hms(StringBuilder b, int h, int m, int s) {
+    int2(b, h);
+    b.append(':');
+    int2(b, m);
+    b.append(':');
+    int2(b, s);
+    return b;
+  }
+
+  static StringBuilder ymdhms(StringBuilder b, int year, int month, int day,
+      int h, int m, int s) {
+    ymd(b, year, month, day);
+    b.append(' ');
+    hms(b, h, m, s);
+    return b;
+  }
+
+  static StringBuilder ymd(StringBuilder b, int year, int month, int day) {
+    int4(b, year);
+    b.append('-');
+    int2(b, month);
+    b.append('-');
+    int2(b, day);
+    return b;
+  }
+
+  private static void int4(StringBuilder buf, int i) {
+    buf.append((char) ('0' + (i / 1000) % 10));
+    buf.append((char) ('0' + (i / 100) % 10));
+    buf.append((char) ('0' + (i / 10) % 10));
+    buf.append((char) ('0' + i % 10));
+  }
+
+  private static void int2(StringBuilder buf, int i) {
+    buf.append((char) ('0' + (i / 10) % 10));
+    buf.append((char) ('0' + i % 10));
+  }
+
+  /** Creates a TimestampString from a Calendar. */
+  public static TimestampString fromCalendarFields(Calendar calendar) {
+    return new TimestampString(
+        calendar.get(Calendar.YEAR),
+        calendar.get(Calendar.MONTH) + 1,
+        calendar.get(Calendar.DAY_OF_MONTH),
+        calendar.get(Calendar.HOUR_OF_DAY),
+        calendar.get(Calendar.MINUTE),
+        calendar.get(Calendar.SECOND))
+        .withMillis(calendar.get(Calendar.MILLISECOND));
+  }
+
+  public TimestampString round(int precision) {
+    Preconditions.checkArgument(precision >= 0);
+    int targetLength = 20 + precision;
+    if (v.length() <= targetLength) {
+      return this;
+    }
+    String v = this.v.substring(0, targetLength);
+    while (v.length() >= 20 && (v.endsWith("0") || v.endsWith("."))) {
+      v = v.substring(0, v.length() - 1);
+    }
+    return new TimestampString(v);
+  }
+
+  /** Returns the number of milliseconds since the epoch. */
+  public long getMillisSinceEpoch() {
+    final int year = Integer.valueOf(v.substring(0, 4));
+    final int month = Integer.valueOf(v.substring(5, 7));
+    final int day = Integer.valueOf(v.substring(8, 10));
+    final int h = Integer.valueOf(v.substring(11, 13));
+    final int m = Integer.valueOf(v.substring(14, 16));
+    final int s = Integer.valueOf(v.substring(17, 19));
+    final int ms = getMillisInSecond();
+    final int d = DateTimeUtils.ymdToUnixDate(year, month, day);
+    return d * DateTimeUtils.MILLIS_PER_DAY
+        + h * DateTimeUtils.MILLIS_PER_HOUR
+        + m * DateTimeUtils.MILLIS_PER_MINUTE
+        + s * DateTimeUtils.MILLIS_PER_SECOND
+        + ms;
+  }
+
+  private int getMillisInSecond() {
+    switch (v.length()) {
+    case 19: // "1999-12-31 12:34:56"
+      return 0;
+    case 21: // "1999-12-31 12:34:56.7"
+      return Integer.valueOf(v.substring(20)) * 100;
+    case 22: // "1999-12-31 12:34:56.78"
+      return Integer.valueOf(v.substring(20)) * 10;
+    case 23: // "1999-12-31 12:34:56.789"
+    default:  // "1999-12-31 12:34:56.789123456"
+      return Integer.valueOf(v.substring(20, 23));
+    }
+  }
+
+  /** Creates a TimestampString that is a given number of milliseconds since
+   * the epoch. */
+  public static TimestampString fromMillisSinceEpoch(long millis) {
+    return new TimestampString(DateTimeUtils.unixTimestampToString(millis))
+        .withMillis((int) DateTimeUtils.floorMod(millis, 1000));
+  }
+
+  static String pad(int length, long v) {
+    StringBuilder s = new StringBuilder(Long.toString(v));
+    while (s.length() < length) {
+      s.insert(0, "0");
+    }
+    return s.toString();
+  }
+
+  public Calendar toCalendar() {
+    return Util.calendar(getMillisSinceEpoch());
+  }
+
+  /** Converts this TimestampString to a string, truncated or padded with
+   * zeroes to a given precision. */
+  public String toString(int precision) {
+    Preconditions.checkArgument(precision >= 0);
+    final int p = precision();
+    if (precision < p) {
+      return round(precision).toString(precision);
+    }
+    if (precision > p) {
+      String s = v;
+      if (p == 0) {
+        s += ".";
+      }
+      return s + Strings.repeat("0", precision - p);
+    }
+    return v;
+  }
+
+  private int precision() {
+    return v.length() < 20 ? 0 : (v.length() - 20);
+  }
+}
+
+// End TimestampString.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/util/Util.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Util.java 
b/core/src/main/java/org/apache/calcite/util/Util.java
index 5e26fd7..e0746e2 100644
--- a/core/src/main/java/org/apache/calcite/util/Util.java
+++ b/core/src/main/java/org/apache/calcite/util/Util.java
@@ -665,7 +665,7 @@ public class Util {
    * underscore followed by the hex code of the character; and underscores are
    * doubled.</p>
    *
-   * Examples:
+   * <p>Examples:
    *
    * <ul>
    * <li><code>toJavaId("foo")</code> returns <code>"foo"</code>
@@ -740,7 +740,7 @@ public class Util {
   /**
    * Converts a list of a string, with commas between elements.
    *
-   * For example,
+   * <p>For example,
    * <code>commaList(Arrays.asList({"a", "b"}))</code>
    * returns "a, b".
    *
@@ -944,7 +944,7 @@ public class Util {
    * <pre><code>int x = Util.deprecated(0, false);</code></pre>
    * </blockquote>
    *
-   * but the usual usage is to pass in a descriptive string.
+   * <p>but the usual usage is to pass in a descriptive string.
    *
    * <h3>Examples</h3>
    *
@@ -1265,7 +1265,7 @@ public class Util {
    * <blockquote>"std offset dst [offset],start[/time],end[/time]"
    * </blockquote>
    *
-   * where:
+   * <p>where:
    *
    * <ul>
    * <li>'std' specifies the abbrev of the time zone.
@@ -1736,7 +1736,7 @@ public class Util {
    * &nbsp;&nbsp;&nbsp;&nbsp;print(i);<br>
    * }</code></blockquote>
    *
-   * will print 1, 2, 4.
+   * <p>will print 1, 2, 4.
    *
    * @param iterable      Iterable
    * @param includeFilter Class whose instances to include
@@ -2414,12 +2414,20 @@ public class Util {
     return reader(new FileInputStream(file));
   }
 
-  /** Creates a {@link Calendar} in the GMT time zone and root locale.
+  /** Creates a {@link Calendar} in the UTC time zone and root locale.
    * Does not use the time zone or locale. */
   public static Calendar calendar() {
     return Calendar.getInstance(DateTimeUtils.UTC_ZONE, Locale.ROOT);
   }
 
+  /** Creates a {@link Calendar} in the UTC time zone and root locale
+   * with a given time. */
+  public static Calendar calendar(long millis) {
+    Calendar calendar = calendar();
+    calendar.setTimeInMillis(millis);
+    return calendar;
+  }
+
   //~ Inner Classes ----------------------------------------------------------
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/util/ZonelessDate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/ZonelessDate.java 
b/core/src/main/java/org/apache/calcite/util/ZonelessDate.java
deleted file mode 100644
index 0d5fc16..0000000
--- a/core/src/main/java/org/apache/calcite/util/ZonelessDate.java
+++ /dev/null
@@ -1,135 +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 org.apache.calcite.avatica.util.DateTimeUtils;
-
-import java.sql.Date;
-import java.text.DateFormat;
-import java.util.Calendar;
-import java.util.TimeZone;
-
-/**
- * ZonelessDate is a date value without a time zone.
- */
-public class ZonelessDate extends ZonelessDatetime {
-  //~ Static fields/initializers ---------------------------------------------
-
-  /**
-   * SerialVersionUID created with JDK 1.5 serialver tool.
-   */
-  private static final long serialVersionUID = -6385775986251759394L;
-
-  //~ Instance fields --------------------------------------------------------
-
-  protected transient Date tempDate;
-
-  //~ Constructors -----------------------------------------------------------
-
-  /**
-   * Constructs a ZonelessDate.
-   */
-  public ZonelessDate() {
-  }
-
-  //~ Methods ----------------------------------------------------------------
-
-  // override ZonelessDatetime
-  public void setZonelessTime(long value) {
-    super.setZonelessTime(value);
-    clearTime();
-  }
-
-  // override ZonelessDatetime
-  public void setZonedTime(long value, TimeZone zone) {
-    super.setZonedTime(value, zone);
-    clearTime();
-  }
-
-  // implement ZonelessDatetime
-  public Object toJdbcObject() {
-    return new Date(getJdbcDate(DateTimeUtils.DEFAULT_ZONE));
-  }
-
-  /**
-   * Converts this ZonelessDate to a java.sql.Date and formats it via the
-   * {@link java.sql.Date#toString() toString()} method of that class.
-   *
-   * @return the formatted date string
-   */
-  public String toString() {
-    Date jdbcDate = getTempDate(getJdbcDate(DateTimeUtils.DEFAULT_ZONE));
-    return jdbcDate.toString();
-  }
-
-  /**
-   * Formats this ZonelessDate via a SimpleDateFormat.
-   *
-   * @param format Format string, as required by
-   *     {@link java.text.SimpleDateFormat}
-   * @return the formatted date string
-   */
-  public String toString(String format) {
-    DateFormat formatter = getFormatter(format);
-    Date jdbcDate = getTempDate(getTime());
-    return formatter.format(jdbcDate);
-  }
-
-  /**
-   * Parses a string as a ZonelessDate.
-   *
-   * @param s a string representing a date in ISO format, i.e. according to
-   *          the SimpleDateFormat string "yyyy-MM-dd"
-   * @return the parsed date, or null if parsing failed
-   */
-  public static ZonelessDate parse(String s) {
-    return parse(s, DateTimeUtils.DATE_FORMAT_STRING);
-  }
-
-  /**
-   * Parses a string as a ZonelessDate with a given format string.
-   *
-   * @param s      a string representing a date in ISO format, i.e. according 
to
-   *               the SimpleDateFormat string "yyyy-MM-dd"
-   * @param format Format string as per {@link java.text.SimpleDateFormat}
-   * @return the parsed date, or null if parsing failed
-   */
-  public static ZonelessDate parse(String s, String format) {
-    Calendar cal =
-        DateTimeUtils.parseDateFormat(s, format, DateTimeUtils.GMT_ZONE);
-    if (cal == null) {
-      return null;
-    }
-    ZonelessDate zd = new ZonelessDate();
-    zd.setZonelessTime(cal.getTimeInMillis());
-    return zd;
-  }
-
-  /**
-   * Gets a temporary Date object. The same object is returned every time.
-   */
-  protected Date getTempDate(long value) {
-    if (tempDate == null) {
-      tempDate = new Date(value);
-    } else {
-      tempDate.setTime(value);
-    }
-    return tempDate;
-  }
-}
-
-// End ZonelessDate.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/util/ZonelessDatetime.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/ZonelessDatetime.java 
b/core/src/main/java/org/apache/calcite/util/ZonelessDatetime.java
deleted file mode 100644
index ab311e7..0000000
--- a/core/src/main/java/org/apache/calcite/util/ZonelessDatetime.java
+++ /dev/null
@@ -1,199 +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 org.apache.calcite.avatica.util.DateTimeUtils;
-
-import java.io.Serializable;
-import java.text.DateFormat;
-import java.util.Calendar;
-import java.util.Locale;
-import java.util.TimeZone;
-
-/**
- * ZonelessDatetime is an abstract class for dates, times, or timestamps that
- * contain a zoneless time value.
- */
-public abstract class ZonelessDatetime implements BasicDatetime, Serializable {
-  //~ Static fields/initializers ---------------------------------------------
-
-  /**
-   * SerialVersionUID created with JDK 1.5 serialver tool.
-   */
-  private static final long serialVersionUID = -1274713852537224763L;
-
-  //~ Instance fields --------------------------------------------------------
-
-  /**
-   * Treat this as a protected field. It is only made public to simplify Java
-   * code generation.
-   */
-  public long internalTime;
-
-  // The following fields are workspace and are not serialized.
-
-  protected transient Calendar tempCal;
-  protected transient DateFormat tempFormatter;
-  protected transient String lastFormat;
-
-  //~ Methods ----------------------------------------------------------------
-
-  // implement BasicDatetime
-  public long getTime() {
-    return internalTime;
-  }
-
-  // implement BasicDatetime
-  public void setZonelessTime(long value) {
-    this.internalTime = value;
-  }
-
-  // implement BasicDatetime
-  public void setZonedTime(long value, TimeZone zone) {
-    this.internalTime = value + zone.getOffset(value);
-  }
-
-  /**
-   * Gets the time portion of this zoneless datetime.
-   */
-  public long getTimeValue() {
-    // Value must be non-negative, even for negative timestamps, and
-    // unfortunately the '%' operator returns a negative value if its LHS
-    // is negative.
-    long timePart = internalTime % DateTimeUtils.MILLIS_PER_DAY;
-    if (timePart < 0) {
-      timePart += DateTimeUtils.MILLIS_PER_DAY;
-    }
-    return timePart;
-  }
-
-  /**
-   * Gets the date portion of this zoneless datetime.
-   */
-  public long getDateValue() {
-    return internalTime - getTimeValue();
-  }
-
-  /**
-   * Clears the date component of this datetime
-   */
-  public void clearDate() {
-    internalTime = getTimeValue();
-  }
-
-  /**
-   * Clears the time component of this datetime
-   */
-  public void clearTime() {
-    internalTime = getDateValue();
-  }
-
-  /**
-   * Gets the value of this datetime as a milliseconds value for
-   * {@link java.sql.Time}.
-   *
-   * @param zone time zone in which to generate a time value for
-   */
-  public long getJdbcTime(TimeZone zone) {
-    long timeValue = getTimeValue();
-    return timeValue - zone.getOffset(timeValue);
-  }
-
-  /**
-   * Gets the value of this datetime as a milliseconds value for
-   * {@link java.sql.Date}.
-   *
-   * @param zone time zone in which to generate a time value for
-   */
-  public long getJdbcDate(TimeZone zone) {
-    Calendar cal = getCalendar(DateTimeUtils.GMT_ZONE);
-    cal.setTimeInMillis(getDateValue());
-
-    int year = cal.get(Calendar.YEAR);
-    int doy = cal.get(Calendar.DAY_OF_YEAR);
-
-    cal.clear();
-    cal.setTimeZone(zone);
-    cal.set(Calendar.YEAR, year);
-    cal.set(Calendar.DAY_OF_YEAR, doy);
-    return cal.getTimeInMillis();
-  }
-
-  /**
-   * Gets the value of this datetime as a milliseconds value for
-   * {@link java.sql.Timestamp}.
-   *
-   * @param zone time zone in which to generate a time value for
-   */
-  public long getJdbcTimestamp(TimeZone zone) {
-    Calendar cal = getCalendar(DateTimeUtils.GMT_ZONE);
-    cal.setTimeInMillis(internalTime);
-
-    int year = cal.get(Calendar.YEAR);
-    int doy = cal.get(Calendar.DAY_OF_YEAR);
-    int hour = cal.get(Calendar.HOUR_OF_DAY);
-    int minute = cal.get(Calendar.MINUTE);
-    int second = cal.get(Calendar.SECOND);
-    int millis = cal.get(Calendar.MILLISECOND);
-
-    cal.clear();
-    cal.setTimeZone(zone);
-    cal.set(Calendar.YEAR, year);
-    cal.set(Calendar.DAY_OF_YEAR, doy);
-    cal.set(Calendar.HOUR_OF_DAY, hour);
-    cal.set(Calendar.MINUTE, minute);
-    cal.set(Calendar.SECOND, second);
-    cal.set(Calendar.MILLISECOND, millis);
-    return cal.getTimeInMillis();
-  }
-
-  /**
-   * Returns this datetime as a Jdbc object
-   */
-  public abstract Object toJdbcObject();
-
-  /**
-   * Gets a temporary Calendar set to the specified time zone. The same
-   * Calendar is returned on subsequent calls.
-   */
-  protected Calendar getCalendar(TimeZone zone) {
-    if (tempCal == null) {
-      tempCal = Calendar.getInstance(zone, Locale.ROOT);
-    } else {
-      tempCal.setTimeZone(zone);
-    }
-    return tempCal;
-  }
-
-  /**
-   * Gets a temporary formatter for a zoneless date time. The same formatter
-   * is returned on subsequent calls.
-   *
-   * @param format a {@link java.text.SimpleDateFormat} format string
-   */
-  protected DateFormat getFormatter(String format) {
-    if ((tempFormatter != null) && lastFormat.equals(format)) {
-      return tempFormatter;
-    }
-    tempFormatter = DateTimeUtils.newDateFormat(format);
-    tempFormatter.setTimeZone(DateTimeUtils.GMT_ZONE);
-    lastFormat = format;
-    return tempFormatter;
-  }
-}
-
-// End ZonelessDatetime.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/util/ZonelessTime.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/ZonelessTime.java 
b/core/src/main/java/org/apache/calcite/util/ZonelessTime.java
deleted file mode 100644
index 28a788c..0000000
--- a/core/src/main/java/org/apache/calcite/util/ZonelessTime.java
+++ /dev/null
@@ -1,175 +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 org.apache.calcite.avatica.util.DateTimeUtils;
-
-import java.sql.Time;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.TimeZone;
-
-/**
- * ZonelessTime is a time value without a time zone.
- */
-public class ZonelessTime extends ZonelessDatetime {
-  //~ Static fields/initializers ---------------------------------------------
-
-  /**
-   * SerialVersionUID created with JDK 1.5 serialver tool.
-   */
-  private static final long serialVersionUID = 906156904798141861L;
-
-  //~ Instance fields --------------------------------------------------------
-
-  protected final int precision;
-  protected transient Time tempTime;
-
-  //~ Constructors -----------------------------------------------------------
-
-  /**
-   * Constructs a ZonelessTime
-   */
-  public ZonelessTime() {
-    precision = 0;
-  }
-
-  /**
-   * Constructs a ZonelessTime with precision.
-   *
-   * <p>The precision is the number of digits to the right of the decimal
-   * point in the seconds value. For example, a <code>TIME(6)</code> has a
-   * precision to microseconds.
-   *
-   * @param precision Number of digits of precision
-   */
-  public ZonelessTime(int precision) {
-    this.precision = precision;
-  }
-
-  //~ Methods ----------------------------------------------------------------
-
-  // override ZonelessDatetime
-  public void setZonelessTime(long value) {
-    super.setZonelessTime(value);
-    clearDate();
-  }
-
-  // override ZonelessDatetime
-  public void setZonedTime(long value, TimeZone zone) {
-    super.setZonedTime(value, zone);
-    clearDate();
-  }
-
-  // implement ZonelessDatetime
-  public Object toJdbcObject() {
-    return new Time(getJdbcTime(DateTimeUtils.DEFAULT_ZONE));
-  }
-
-  /**
-   * Override ZonelessDatetime.
-   *
-   * <p>NOTE: the returned timestamp is based on the current date of the
-   * specified time zone, rather than the context variable for current_date,
-   * as specified by the SQL standard.
-   */
-  public long getJdbcTimestamp(TimeZone zone) {
-    Calendar cal = getCalendar(DateTimeUtils.GMT_ZONE);
-    cal.setTimeInMillis(getTime());
-    int hour = cal.get(Calendar.HOUR_OF_DAY);
-    int minute = cal.get(Calendar.MINUTE);
-    int second = cal.get(Calendar.SECOND);
-    int millis = cal.get(Calendar.MILLISECOND);
-
-    cal.setTimeZone(zone);
-    cal.setTimeInMillis(System.currentTimeMillis());
-    cal.set(Calendar.HOUR_OF_DAY, hour);
-    cal.set(Calendar.MINUTE, minute);
-    cal.set(Calendar.SECOND, second);
-    cal.set(Calendar.MILLISECOND, millis);
-    return cal.getTimeInMillis();
-  }
-
-  /**
-   * Converts this ZonelessTime to a java.sql.Time and formats it via the
-   * {@link java.sql.Time#toString() toString()} method of that class.
-   *
-   * @return the formatted time string
-   */
-  public String toString() {
-    Time jdbcTime = getTempTime(getJdbcTime(DateTimeUtils.DEFAULT_ZONE));
-    return jdbcTime.toString();
-  }
-
-  /**
-   * Formats this ZonelessTime via a SimpleDateFormat
-   *
-   * @param format format string, as required by SimpleDateFormat
-   * @return the formatted time string
-   */
-  public String toString(String format) {
-    DateFormat formatter = getFormatter(format);
-    Time jdbcTime = getTempTime(getTime());
-    return formatter.format(jdbcTime);
-  }
-
-  /**
-   * Parses a string as a ZonelessTime.
-   *
-   * @param s a string representing a time in ISO format, i.e. according to
-   *          the {@link SimpleDateFormat} string "HH:mm:ss"
-   * @return the parsed time, or null if parsing failed
-   */
-  public static ZonelessTime parse(String s) {
-    return parse(s, DateTimeUtils.TIME_FORMAT_STRING);
-  }
-
-  /**
-   * Parses a string as a ZonelessTime using a given format string.
-   *
-   * @param s      a string representing a time the given format
-   * @param format format string as per {@link SimpleDateFormat}
-   * @return the parsed time, or null if parsing failed
-   */
-  public static ZonelessTime parse(String s, String format) {
-    DateTimeUtils.PrecisionTime pt =
-        DateTimeUtils.parsePrecisionDateTimeLiteral(s,
-            format,
-            DateTimeUtils.GMT_ZONE);
-    if (pt == null) {
-      return null;
-    }
-    ZonelessTime zt = new ZonelessTime(pt.getPrecision());
-    zt.setZonelessTime(pt.getCalendar().getTime().getTime());
-    return zt;
-  }
-
-  /**
-   * Gets a temporary Time object. The same object is returned every time.
-   */
-  protected Time getTempTime(long value) {
-    if (tempTime == null) {
-      tempTime = new Time(value);
-    } else {
-      tempTime.setTime(value);
-    }
-    return tempTime;
-  }
-}
-
-// End ZonelessTime.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/main/java/org/apache/calcite/util/ZonelessTimestamp.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/ZonelessTimestamp.java 
b/core/src/main/java/org/apache/calcite/util/ZonelessTimestamp.java
deleted file mode 100644
index e58f687..0000000
--- a/core/src/main/java/org/apache/calcite/util/ZonelessTimestamp.java
+++ /dev/null
@@ -1,160 +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 org.apache.calcite.avatica.util.DateTimeUtils;
-
-import java.sql.Timestamp;
-import java.text.DateFormat;
-
-/**
- * ZonelessTimestamp is a timestamp value without a time zone.
- */
-public class ZonelessTimestamp extends ZonelessDatetime {
-  //~ Static fields/initializers ---------------------------------------------
-
-  /**
-   * SerialVersionUID created with JDK 1.5 serialver tool.
-   */
-  private static final long serialVersionUID = -6829714640541648394L;
-
-  //~ Instance fields --------------------------------------------------------
-
-  protected final int precision;
-
-  protected transient Timestamp tempTimestamp;
-
-  //~ Constructors -----------------------------------------------------------
-
-  /**
-   * Constructs a ZonelessTimestamp.
-   */
-  public ZonelessTimestamp() {
-    this.precision = 0;
-  }
-
-  /**
-   * Constructs a ZonelessTimestamp with precision.
-   *
-   * <p>The precision is the number of digits to the right of the decimal
-   * point in the seconds value. For example, a <code>TIMESTAMP(3)</code> has
-   * a precision to milliseconds.
-   *
-   * @param precision Number of digits of precision
-   */
-  public ZonelessTimestamp(int precision) {
-    this.precision = precision;
-  }
-
-  //~ Methods ----------------------------------------------------------------
-
-  // implement ZonelessDatetime
-  public Object toJdbcObject() {
-    return new Timestamp(getJdbcTimestamp(DateTimeUtils.DEFAULT_ZONE));
-  }
-
-  /**
-   * Converts this ZonelessTimestamp to a java.sql.Timestamp and formats it
-   * via the {@link java.sql.Timestamp#toString() toString()} method of that
-   * class.
-   *
-   * <p>Note: Jdbc formatting always includes a decimal point and at least one
-   * digit of milliseconds precision. Trailing zeros, except for the first one
-   * after the decimal point, do not appear in the output.
-   *
-   * @return the formatted time string
-   */
-  public String toString() {
-    Timestamp ts =
-        getTempTimestamp(getJdbcTimestamp(DateTimeUtils.DEFAULT_ZONE));
-
-    // Remove trailing '.0' so that format is consistent with SQL spec for
-    // CAST(TIMESTAMP(0) TO VARCHAR). E.g. "1969-12-31 16:00:00.0"
-    // becomes "1969-12-31 16:00:00"
-    String sts = ts.toString();
-    if (sts.length() > 19 && ts.getNanos() == 0) {
-      sts = sts.substring(0, 19);
-    }
-    return sts;
-  }
-
-  /**
-   * Formats this ZonelessTimestamp via a SimpleDateFormat. This method does
-   * not display milliseconds precision.
-   *
-   * @param format format string, as required by SimpleDateFormat
-   * @return the formatted timestamp string
-   */
-  public String toString(String format) {
-    DateFormat formatter = getFormatter(format);
-    Timestamp ts = getTempTimestamp(getTime());
-    return formatter.format(ts);
-  }
-
-  /**
-   * Parses a string as a ZonelessTimestamp.
-   *
-   * <p>This method's parsing is strict and may parse fractional seconds (as
-   * opposed to just milliseconds.)
-   *
-   * @param s a string representing a time in ISO format, i.e. according to
-   *          the SimpleDateFormat string "yyyy-MM-dd HH:mm:ss"
-   * @return the parsed time, or null if parsing failed
-   */
-  public static ZonelessTimestamp parse(String s) {
-    return parse(s, DateTimeUtils.TIMESTAMP_FORMAT_STRING);
-  }
-
-  /**
-   * Parses a string as a ZonelessTimestamp using a given format string.
-   *
-   * <p>This method's parsing is strict and may parse fractional seconds (as
-   * opposed to just milliseconds.)
-   *
-   * @param s      a string representing a time in ISO format, i.e. according 
to
-   *               the SimpleDateFormat string "yyyy-MM-dd HH:mm:ss"
-   * @param format Format string as per {@link java.text.SimpleDateFormat}
-   * @return the parsed timestamp, or null if parsing failed
-   */
-  public static ZonelessTimestamp parse(String s, String format) {
-    DateTimeUtils.PrecisionTime pt =
-        DateTimeUtils.parsePrecisionDateTimeLiteral(s,
-            format,
-            DateTimeUtils.GMT_ZONE);
-    if (pt == null) {
-      return null;
-    }
-    ZonelessTimestamp zt = new ZonelessTimestamp(pt.getPrecision());
-    zt.setZonelessTime(pt.getCalendar().getTime().getTime());
-    return zt;
-  }
-
-  /**
-   * Gets a temporary Timestamp object. The same object is returned every
-   * time.
-   */
-  protected Timestamp getTempTimestamp(long value) {
-    if (tempTimestamp == null) {
-      tempTimestamp = new Timestamp(value);
-    } else {
-      tempTimestamp.setTime(value);
-    }
-    return tempTimestamp;
-  }
-}
-
-// End ZonelessTimestamp.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index 8f5015c..4e4db08 100644
--- 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++ 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -659,6 +659,26 @@ public class RelToSqlConverterTest {
     sql(query).ok(expected);
   }
 
+  @Test public void testLiteral() {
+    checkLiteral("DATE '1978-05-02'");
+    checkLiteral("TIME '12:34:56'");
+    checkLiteral("TIME '12:34:56.78'");
+    checkLiteral("TIMESTAMP '1978-05-02 12:34:56.78'");
+    checkLiteral("'I can''t explain'");
+    checkLiteral("''");
+    checkLiteral("TRUE");
+    checkLiteral("123");
+    checkLiteral("123.45");
+    checkLiteral("-123.45");
+  }
+
+  private void checkLiteral(String s) {
+    sql("VALUES " + s)
+        .dialect(DatabaseProduct.HSQLDB.getDialect())
+        .ok("SELECT *\n"
+            + "FROM (VALUES  (" + s + "))");
+  }
+
   /** Test case for
    * <a 
href="https://issues.apache.org/jira/browse/CALCITE-1798";>[CALCITE-1798]
    * Generate dialect-specific SQL for FLOOR operator</a>. */

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java 
b/core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java
index bbf95f0..0fd99f8 100644
--- a/core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/rex/RexBuilderTest.java
@@ -16,18 +16,28 @@
  */
 package org.apache.calcite.rex;
 
+import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeSystem;
 import org.apache.calcite.sql.type.SqlTypeFactoryImpl;
 import org.apache.calcite.sql.type.SqlTypeName;
+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 org.junit.Test;
 
+import java.util.Calendar;
+
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
 
 /**
- * Test for {@link RexBuilder}
+ * Test for {@link RexBuilder}.
  */
 public class RexBuilderTest {
 
@@ -80,6 +90,203 @@ public class RexBuilderTest {
     assertEquals(ensuredNode.getType(), 
typeFactory.createSqlType(SqlTypeName.INTEGER));
   }
 
+  private static final long MOON = -14159025000L;
+
+  private static final int MOON_DAY = -164;
+
+  private static final int MOON_TIME = 10575000;
+
+  /** Tests {@link RexBuilder#makeTimestampLiteral(TimestampString, int)}. */
+  @Test public void testTimestampLiteral() {
+    final RelDataTypeFactory typeFactory =
+        new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
+    final RelDataType timestampType =
+        typeFactory.createSqlType(SqlTypeName.TIMESTAMP);
+    final RelDataType timestampType3 =
+        typeFactory.createSqlType(SqlTypeName.TIMESTAMP, 3);
+    final RelDataType timestampType9 =
+        typeFactory.createSqlType(SqlTypeName.TIMESTAMP, 9);
+    final RelDataType timestampType18 =
+        typeFactory.createSqlType(SqlTypeName.TIMESTAMP, 18);
+    final RexBuilder builder = new RexBuilder(typeFactory);
+
+    // Old way: provide a Calendar
+    final Calendar calendar = Util.calendar();
+    calendar.set(1969, Calendar.JULY, 21, 2, 56, 15); // one small step
+    calendar.set(Calendar.MILLISECOND, 0);
+    checkTimestamp(builder.makeLiteral(calendar, timestampType, false));
+
+    // Old way #2: Provide a Long
+    checkTimestamp(builder.makeLiteral(MOON, timestampType, false));
+
+    // The new way
+    final TimestampString ts = new TimestampString(1969, 7, 21, 2, 56, 15);
+    checkTimestamp(builder.makeLiteral(ts, timestampType, false));
+
+    // Now with milliseconds
+    final TimestampString ts2 = ts.withMillis(56);
+    assertThat(ts2.toString(), is("1969-07-21 02:56:15.056"));
+    final RexNode literal2 = builder.makeLiteral(ts2, timestampType3, false);
+    assertThat(((RexLiteral) literal2).getValueAs(TimestampString.class)
+            .toString(), is("1969-07-21 02:56:15.056"));
+
+    // Now with nanoseconds
+    final TimestampString ts3 = ts.withNanos(56);
+    final RexNode literal3 = builder.makeLiteral(ts3, timestampType9, false);
+    assertThat(((RexLiteral) literal3).getValueAs(TimestampString.class)
+            .toString(), is("1969-07-21 02:56:15"));
+    final TimestampString ts3b = ts.withNanos(2345678);
+    final RexNode literal3b = builder.makeLiteral(ts3b, timestampType9, false);
+    assertThat(((RexLiteral) literal3b).getValueAs(TimestampString.class)
+            .toString(), is("1969-07-21 02:56:15.002"));
+
+    // Now with a very long fraction
+    final TimestampString ts4 = ts.withFraction("102030405060708090102");
+    final RexNode literal4 = builder.makeLiteral(ts4, timestampType18, false);
+    assertThat(((RexLiteral) literal4).getValueAs(TimestampString.class)
+            .toString(), is("1969-07-21 02:56:15.102"));
+
+    // toString
+    assertThat(ts2.round(1).toString(), is("1969-07-21 02:56:15"));
+    assertThat(ts2.round(2).toString(), is("1969-07-21 02:56:15.05"));
+    assertThat(ts2.round(3).toString(), is("1969-07-21 02:56:15.056"));
+    assertThat(ts2.round(4).toString(), is("1969-07-21 02:56:15.056"));
+
+    assertThat(ts2.toString(6), is("1969-07-21 02:56:15.056000"));
+    assertThat(ts2.toString(1), is("1969-07-21 02:56:15.0"));
+    assertThat(ts2.toString(0), is("1969-07-21 02:56:15"));
+
+    assertThat(ts2.round(0).toString(), is("1969-07-21 02:56:15"));
+    assertThat(ts2.round(0).toString(0), is("1969-07-21 02:56:15"));
+    assertThat(ts2.round(0).toString(1), is("1969-07-21 02:56:15.0"));
+    assertThat(ts2.round(0).toString(2), is("1969-07-21 02:56:15.00"));
+
+    assertThat(TimestampString.fromMillisSinceEpoch(1456513560123L).toString(),
+        is("2016-02-26 19:06:00.123"));
+  }
+
+  private void checkTimestamp(RexNode node) {
+    assertThat(node.toString(), is("1969-07-21 02:56:15"));
+    RexLiteral literal = (RexLiteral) node;
+    assertThat(literal.getValue() instanceof Calendar, is(true));
+    assertThat(literal.getValue2() instanceof Long, is(true));
+    assertThat(literal.getValue3() instanceof Long, is(true));
+    assertThat((Long) literal.getValue2(), is(MOON));
+    assertThat(literal.getValueAs(Calendar.class), notNullValue());
+    assertThat(literal.getValueAs(TimestampString.class), notNullValue());
+  }
+
+  /** Tests {@link RexBuilder#makeTimeLiteral(TimeString, int)}. */
+  @Test public void testTimeLiteral() {
+    final RelDataTypeFactory typeFactory =
+        new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
+    RelDataType timeType = typeFactory.createSqlType(SqlTypeName.TIME);
+    final RelDataType timeType3 =
+        typeFactory.createSqlType(SqlTypeName.TIME, 3);
+    final RelDataType timeType9 =
+        typeFactory.createSqlType(SqlTypeName.TIME, 9);
+    final RelDataType timeType18 =
+        typeFactory.createSqlType(SqlTypeName.TIME, 18);
+    final RexBuilder builder = new RexBuilder(typeFactory);
+
+    // Old way: provide a Calendar
+    final Calendar calendar = Util.calendar();
+    calendar.set(1969, Calendar.JULY, 21, 2, 56, 15); // one small step
+    calendar.set(Calendar.MILLISECOND, 0);
+    checkTime(builder.makeLiteral(calendar, timeType, false));
+
+    // Old way #2: Provide a Long
+    checkTime(builder.makeLiteral(MOON_TIME, timeType, false));
+
+    // The new way
+    final TimeString t = new TimeString(2, 56, 15);
+    assertThat(t.getMillisOfDay(), is(10575000));
+    checkTime(builder.makeLiteral(t, timeType, false));
+
+    // Now with milliseconds
+    final TimeString t2 = t.withMillis(56);
+    assertThat(t2.getMillisOfDay(), is(10575056));
+    assertThat(t2.toString(), is("02:56:15.056"));
+    final RexNode literal2 = builder.makeLiteral(t2, timeType3, false);
+    assertThat(((RexLiteral) literal2).getValueAs(TimeString.class)
+        .toString(), is("02:56:15.056"));
+
+    // Now with nanoseconds
+    final TimeString t3 = t.withNanos(2345678);
+    assertThat(t3.getMillisOfDay(), is(10575002));
+    final RexNode literal3 = builder.makeLiteral(t3, timeType9, false);
+    assertThat(((RexLiteral) literal3).getValueAs(TimeString.class)
+        .toString(), is("02:56:15.002"));
+
+    // Now with a very long fraction
+    final TimeString t4 = t.withFraction("102030405060708090102");
+    assertThat(t4.getMillisOfDay(), is(10575102));
+    final RexNode literal4 = builder.makeLiteral(t4, timeType18, false);
+    assertThat(((RexLiteral) literal4).getValueAs(TimeString.class)
+        .toString(), is("02:56:15.102"));
+
+    // toString
+    assertThat(t2.round(1).toString(), is("02:56:15"));
+    assertThat(t2.round(2).toString(), is("02:56:15.05"));
+    assertThat(t2.round(3).toString(), is("02:56:15.056"));
+    assertThat(t2.round(4).toString(), is("02:56:15.056"));
+
+    assertThat(t2.toString(6), is("02:56:15.056000"));
+    assertThat(t2.toString(1), is("02:56:15.0"));
+    assertThat(t2.toString(0), is("02:56:15"));
+
+    assertThat(t2.round(0).toString(), is("02:56:15"));
+    assertThat(t2.round(0).toString(0), is("02:56:15"));
+    assertThat(t2.round(0).toString(1), is("02:56:15.0"));
+    assertThat(t2.round(0).toString(2), is("02:56:15.00"));
+
+    assertThat(TimeString.fromMillisOfDay(53560123).toString(),
+        is("14:52:40.123"));
+  }
+
+  private void checkTime(RexNode node) {
+    assertThat(node.toString(), is("02:56:15"));
+    RexLiteral literal = (RexLiteral) node;
+    assertThat(literal.getValue() instanceof Calendar, is(true));
+    assertThat(literal.getValue2() instanceof Integer, is(true));
+    assertThat(literal.getValue3() instanceof Integer, is(true));
+    assertThat((Integer) literal.getValue2(), is(MOON_TIME));
+    assertThat(literal.getValueAs(Calendar.class), notNullValue());
+    assertThat(literal.getValueAs(TimeString.class), notNullValue());
+  }
+
+  /** Tests {@link RexBuilder#makeDateLiteral(DateString)}. */
+  @Test public void testDateLiteral() {
+    final RelDataTypeFactory typeFactory =
+        new SqlTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
+    RelDataType dateType = typeFactory.createSqlType(SqlTypeName.DATE);
+    final RexBuilder builder = new RexBuilder(typeFactory);
+
+    // Old way: provide a Calendar
+    final Calendar calendar = Util.calendar();
+    calendar.set(1969, Calendar.JULY, 21); // one small step
+    calendar.set(Calendar.MILLISECOND, 0);
+    checkDate(builder.makeLiteral(calendar, dateType, false));
+
+    // Old way #2: Provide in Integer
+    checkDate(builder.makeLiteral(MOON_DAY, dateType, false));
+
+    // The new way
+    final DateString d = new DateString(1969, 7, 21);
+    checkDate(builder.makeLiteral(d, dateType, false));
+  }
+
+  private void checkDate(RexNode node) {
+    assertThat(node.toString(), is("1969-07-21"));
+    RexLiteral literal = (RexLiteral) node;
+    assertThat(literal.getValue() instanceof Calendar, is(true));
+    assertThat(literal.getValue2() instanceof Integer, is(true));
+    assertThat(literal.getValue3() instanceof Integer, is(true));
+    assertThat((Integer) literal.getValue2(), is(MOON_DAY));
+    assertThat(literal.getValueAs(Calendar.class), notNullValue());
+    assertThat(literal.getValueAs(DateString.class), notNullValue());
+  }
+
 }
 
 // End RexBuilderTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java 
b/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java
index 46190df..d421033 100644
--- a/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java
+++ b/core/src/test/java/org/apache/calcite/rex/RexExecutorTest.java
@@ -36,6 +36,7 @@ import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.tools.Frameworks;
+import org.apache.calcite.util.DateString;
 import org.apache.calcite.util.NlsString;
 import org.apache.calcite.util.Util;
 
@@ -47,7 +48,6 @@ import org.junit.Test;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.List;
 import java.util.Random;
 
@@ -159,20 +159,22 @@ public class RexExecutorTest {
     checkConstant(true,
         new Function<RexBuilder, RexNode>() {
           public RexNode apply(RexBuilder rexBuilder) {
-            Calendar calendar = Util.calendar();
+            final DateString d =
+                DateString.fromCalendarFields(Util.calendar());
             return rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN_OR_EQUAL,
-                rexBuilder.makeDateLiteral(calendar),
-                rexBuilder.makeDateLiteral(calendar));
+                rexBuilder.makeDateLiteral(d),
+                rexBuilder.makeDateLiteral(d));
           }
         });
     // date 'today' < date 'today' -> false
     checkConstant(false,
         new Function<RexBuilder, RexNode>() {
           public RexNode apply(RexBuilder rexBuilder) {
-            Calendar calendar = Util.calendar();
+            final DateString d =
+                DateString.fromCalendarFields(Util.calendar());
             return rexBuilder.makeCall(SqlStdOperatorTable.LESS_THAN,
-                rexBuilder.makeDateLiteral(calendar),
-                rexBuilder.makeDateLiteral(calendar));
+                rexBuilder.makeDateLiteral(d),
+                rexBuilder.makeDateLiteral(d));
           }
         });
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java 
b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
index f4baa86..95d70d3 100644
--- a/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/parser/SqlParserTest.java
@@ -2230,13 +2230,13 @@ public class SqlParserTest {
     checkExpSame("TIMESTAMP '2004-06-01 15:55:55.900'");
     checkExp(
         "TIMESTAMP '2004-06-01 15:55:55.1234'",
-        "TIMESTAMP '2004-06-01 15:55:55.123'");
+        "TIMESTAMP '2004-06-01 15:55:55.1234'");
     checkExp(
         "TIMESTAMP '2004-06-01 15:55:55.1236'",
-        "TIMESTAMP '2004-06-01 15:55:55.123'");
+        "TIMESTAMP '2004-06-01 15:55:55.1236'");
     checkExp(
         "TIMESTAMP '2004-06-01 15:55:55.9999'",
-        "TIMESTAMP '2004-06-01 15:55:55.999'");
+        "TIMESTAMP '2004-06-01 15:55:55.9999'");
     checkExpSame("NULL");
   }
 
@@ -3690,6 +3690,7 @@ public class SqlParserTest {
     checkExp("TIME '12:01:01.'", "TIME '12:01:01'");
     checkExp("TIME '12:01:01.000'", "TIME '12:01:01.000'");
     checkExp("TIME '12:01:01.001'", "TIME '12:01:01.001'");
+    checkExp("TIME '12:01:01.01023456789'", "TIME '12:01:01.01023456789'");
 
     // Timestamp literals
     checkExp(
@@ -3701,6 +3702,10 @@ public class SqlParserTest {
     checkExp(
         "TIMESTAMP '2004-12-01 12:01:01.'",
         "TIMESTAMP '2004-12-01 12:01:01'");
+    checkExp(
+        "TIMESTAMP  '2004-12-01 12:01:01.010234567890'",
+        "TIMESTAMP '2004-12-01 12:01:01.010234567890'");
+    checkExpSame("TIMESTAMP '2004-12-01 12:01:01.01023456789'");
 
     // Failures.
     checkFails("^DATE '12/21/99'^", "(?s).*Illegal DATE literal.*");

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java 
b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
index 63443cb..d3e19dc 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
@@ -51,6 +51,7 @@ import org.apache.calcite.test.SqlLimitsTest;
 import org.apache.calcite.util.Bug;
 import org.apache.calcite.util.Holder;
 import org.apache.calcite.util.Pair;
+import org.apache.calcite.util.TimestampString;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Function;
@@ -6883,9 +6884,8 @@ public abstract class SqlOperatorBaseTest {
       case VARCHAR:
         return SqlLiteral.createCharString(value.toString(), 
SqlParserPos.ZERO);
       case TIMESTAMP:
-        Calendar calendar = Util.calendar();
-        calendar.setTimeInMillis((Long) value);
-        return SqlLiteral.createTimestamp(calendar, type.getPrecision(),
+        TimestampString ts = TimestampString.fromMillisSinceEpoch((Long) 
value);
+        return SqlLiteral.createTimestamp(ts, type.getPrecision(),
             SqlParserPos.ZERO);
       default:
         throw new AssertionError(type);

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java 
b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
index ee2511d..f089170 100644
--- a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
@@ -36,8 +36,11 @@ import org.apache.calcite.server.CalciteServerStatement;
 import org.apache.calcite.sql.SqlCollation;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.tools.Frameworks;
+import org.apache.calcite.util.DateString;
 import org.apache.calcite.util.Holder;
 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 org.junit.Ignore;
@@ -50,7 +53,6 @@ import java.math.BigDecimal;
 import java.sql.Date;
 import java.sql.Time;
 import java.sql.Timestamp;
-import java.util.Calendar;
 
 /**
  * Unit tests for {@link RexImplicationChecker}.
@@ -179,9 +181,9 @@ public class RexImplicationCheckerTest {
   @Ignore("work in progress")
   @Test public void testSimpleDate() {
     final Fixture f = new Fixture();
-    final Calendar instance = Util.calendar();
-    final RexNode node1 = f.ge(f.dt, f.rexBuilder.makeDateLiteral(instance));
-    final RexNode node2 = f.eq(f.dt, f.rexBuilder.makeDateLiteral(instance));
+    final DateString d = DateString.fromCalendarFields(Util.calendar());
+    final RexNode node1 = f.ge(f.dt, f.rexBuilder.makeDateLiteral(d));
+    final RexNode node2 = f.eq(f.dt, f.rexBuilder.makeDateLiteral(d));
 
     f.checkImplies(node2, node1);
     f.checkNotImplies(node1, node2);
@@ -190,9 +192,10 @@ public class RexImplicationCheckerTest {
   @Ignore("work in progress")
   @Test public void testSimpleTimeStamp() {
     final Fixture f = new Fixture();
-    final Calendar calendar = Util.calendar();
-    final RexNode node1 = f.le(f.ts, f.timestampLiteral(calendar));
-    final RexNode node2 = f.le(f.ts, f.timestampLiteral(calendar));
+    final TimestampString ts =
+        TimestampString.fromCalendarFields(Util.calendar());
+    final RexNode node1 = f.le(f.ts, f.timestampLiteral(ts));
+    final RexNode node2 = f.le(f.ts, f.timestampLiteral(ts));
 
     f.checkImplies(node1, node2);
     f.checkNotImplies(node2, node1);
@@ -201,9 +204,9 @@ public class RexImplicationCheckerTest {
   @Ignore("work in progress")
   @Test public void testSimpleTime() {
     final Fixture f = new Fixture();
-    final Calendar calendar = Util.calendar();
-    final RexNode node1 = f.le(f.ts, f.timeLiteral(calendar));
-    final RexNode node2 = f.le(f.ts, f.timeLiteral(calendar));
+    final TimeString t = TimeString.fromCalendarFields(Util.calendar());
+    final RexNode node1 = f.le(f.ts, f.timeLiteral(t));
+    final RexNode node2 = f.le(f.ts, f.timeLiteral(t));
 
     f.checkImplies(node1, node2);
     f.checkNotImplies(node2, node1);
@@ -491,14 +494,13 @@ public class RexImplicationCheckerTest {
           new NlsString(z, null, SqlCollation.COERCIBLE));
     }
 
-    public RexNode timestampLiteral(Calendar calendar) {
-      return rexBuilder.makeTimestampLiteral(
-          calendar, timeStampDataType.getPrecision());
+    public RexNode timestampLiteral(TimestampString ts) {
+      return rexBuilder.makeTimestampLiteral(ts,
+          timeStampDataType.getPrecision());
     }
 
-    public RexNode timeLiteral(Calendar calendar) {
-      return rexBuilder.makeTimestampLiteral(
-          calendar, timeDataType.getPrecision());
+    public RexNode timeLiteral(TimeString t) {
+      return rexBuilder.makeTimeLiteral(t, timeDataType.getPrecision());
     }
 
     public RexNode cast(RelDataType type, RexNode exp) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java 
b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
index 408cb73..f889347 100644
--- a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
@@ -38,9 +38,12 @@ import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.SqlTypeAssignmentRules;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.util.DateString;
 import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.NlsString;
 import org.apache.calcite.util.TestUtil;
+import org.apache.calcite.util.TimeString;
+import org.apache.calcite.util.TimestampString;
 import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableList;
@@ -1397,12 +1400,11 @@ public class RexProgramTest {
     literals.add((RexLiteral)
         rexBuilder.makeLiteral(new ByteString(new byte[] {1, 2, -34, 0, -128}),
             typeFactory.createSqlType(SqlTypeName.BINARY, 5), false));
-    literals.add(
-        rexBuilder.makeDateLiteral(cal(1974, Calendar.AUGUST, 9, 0, 0, 0)));
-    literals.add(rexBuilder.makeTimeLiteral(cal(0, 0, 0, 1, 23, 45), 0));
+    literals.add(rexBuilder.makeDateLiteral(new DateString(1974, 8, 9)));
+    literals.add(rexBuilder.makeTimeLiteral(new TimeString(1, 23, 45), 0));
     literals.add(
         rexBuilder.makeTimestampLiteral(
-            cal(1974, Calendar.AUGUST, 9, 1, 23, 45), 0));
+            new TimestampString(1974, 8, 9, 1, 23, 45), 0));
 
     final Multimap<SqlTypeName, RexLiteral> map = LinkedHashMultimap.create();
     for (RexLiteral literal : literals) {

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/core/src/test/resources/sql/misc.iq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/misc.iq 
b/core/src/test/resources/sql/misc.iq
index cbf12fe..9ecd55d 100644
--- a/core/src/test/resources/sql/misc.iq
+++ b/core/src/test/resources/sql/misc.iq
@@ -1910,7 +1910,7 @@ select TIMESTAMP '2016-02-26 19:06:00.123456789',
 (1 row)
 
 !ok
-EnumerableCalc(expr#0=[{inputs}], expr#1=[2016-02-26 19:06:00.123], 
expr#2=[2016-02-26 19:06:00], expr#3=[2016-02-26 19:06:00.1], 
expr#4=[2016-02-26 19:06:00.12], expr#5=[2016-02-26 19:06:00.123], 
expr#6=[2016-02-26 19:06:00.123], EXPR$0=[$t1], EXPR$1=[$t2], EXPR$2=[$t2], 
EXPR$3=[$t3], EXPR$4=[$t4], EXPR$5=[$t1], EXPR$6=[$t5], EXPR$7=[$t6])
+EnumerableCalc(expr#0=[{inputs}], expr#1=[2016-02-26 19:06:00.123], 
expr#2=[2016-02-26 19:06:00], expr#3=[2016-02-26 19:06:00.1], 
expr#4=[2016-02-26 19:06:00.12], EXPR$0=[$t1], EXPR$1=[$t2], EXPR$2=[$t2], 
EXPR$3=[$t3], EXPR$4=[$t4], EXPR$5=[$t1], EXPR$6=[$t1], EXPR$7=[$t1])
   EnumerableValues(tuples=[[{ 0 }]])
 !plan
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java
----------------------------------------------------------------------
diff --git 
a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java 
b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java
index 0e2b3d3..d6065e2 100644
--- 
a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java
+++ 
b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidDateTimeUtils.java
@@ -24,6 +24,8 @@ import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.util.DateString;
+import org.apache.calcite.util.TimestampString;
 import org.apache.calcite.util.Util;
 import org.apache.calcite.util.trace.CalciteTrace;
 
@@ -37,9 +39,7 @@ import com.google.common.collect.TreeRangeSet;
 import org.slf4j.Logger;
 
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.List;
-import java.util.regex.Pattern;
 
 /**
  * Utilities for generating intervals from RexNode.
@@ -49,10 +49,6 @@ public class DruidDateTimeUtils {
 
   protected static final Logger LOGGER = CalciteTrace.getPlannerTracer();
 
-  private static final Pattern TIMESTAMP_PATTERN =
-      Pattern.compile("[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]"
-          + " [0-9][0-9]:[0-9][0-9]:[0-9][0-9]");
-
   private DruidDateTimeUtils() {
   }
 
@@ -63,7 +59,7 @@ public class DruidDateTimeUtils {
    */
   public static List<LocalInterval> createInterval(RelDataType type,
       RexNode e) {
-    final List<Range<Calendar>> ranges = extractRanges(e, false);
+    final List<Range<TimestampString>> ranges = extractRanges(e, false);
     if (ranges == null) {
       // We did not succeed, bail out
       return null;
@@ -78,18 +74,18 @@ public class DruidDateTimeUtils {
     return toInterval(ImmutableList.<Range>copyOf(condensedRanges.asRanges()));
   }
 
-  protected static List<LocalInterval> toInterval(List<Range<Calendar>> 
ranges) {
+  protected static List<LocalInterval> toInterval(List<Range<TimestampString>> 
ranges) {
     List<LocalInterval> intervals = Lists.transform(ranges,
-        new Function<Range<Calendar>, LocalInterval>() {
-          public LocalInterval apply(Range<Calendar> range) {
+        new Function<Range<TimestampString>, LocalInterval>() {
+          public LocalInterval apply(Range<TimestampString> range) {
             if (!range.hasLowerBound() && !range.hasUpperBound()) {
               return DruidTable.DEFAULT_INTERVAL;
             }
             long start = range.hasLowerBound()
-                ? range.lowerEndpoint().getTime().getTime()
+                ? range.lowerEndpoint().getMillisSinceEpoch()
                 : DruidTable.DEFAULT_INTERVAL.getStartMillis();
             long end = range.hasUpperBound()
-                ? range.upperEndpoint().getTime().getTime()
+                ? range.upperEndpoint().getMillisSinceEpoch()
                 : DruidTable.DEFAULT_INTERVAL.getEndMillis();
             if (range.hasLowerBound()
                 && range.lowerBoundType() == BoundType.OPEN) {
@@ -108,7 +104,7 @@ public class DruidDateTimeUtils {
     return intervals;
   }
 
-  protected static List<Range<Calendar>> extractRanges(RexNode node,
+  protected static List<Range<TimestampString>> extractRanges(RexNode node,
       boolean withNot) {
     switch (node.getKind()) {
     case EQUALS:
@@ -125,9 +121,9 @@ public class DruidDateTimeUtils {
 
     case OR: {
       RexCall call = (RexCall) node;
-      List<Range<Calendar>> intervals = Lists.newArrayList();
+      List<Range<TimestampString>> intervals = Lists.newArrayList();
       for (RexNode child : call.getOperands()) {
-        List<Range<Calendar>> extracted = extractRanges(child, withNot);
+        List<Range<TimestampString>> extracted = extractRanges(child, withNot);
         if (extracted != null) {
           intervals.addAll(extracted);
         }
@@ -137,9 +133,9 @@ public class DruidDateTimeUtils {
 
     case AND: {
       RexCall call = (RexCall) node;
-      List<Range<Calendar>> ranges = new ArrayList<>();
+      List<Range<TimestampString>> ranges = new ArrayList<>();
       for (RexNode child : call.getOperands()) {
-        List<Range<Calendar>> extractedRanges = extractRanges(child, false);
+        List<Range<TimestampString>> extractedRanges = extractRanges(child, 
false);
         if (extractedRanges == null || extractedRanges.isEmpty()) {
           // We could not extract, we bail out
           return null;
@@ -148,7 +144,7 @@ public class DruidDateTimeUtils {
           ranges.addAll(extractedRanges);
           continue;
         }
-        List<Range<Calendar>> overlapped = new ArrayList<>();
+        List<Range<TimestampString>> overlapped = new ArrayList<>();
         for (Range current : ranges) {
           for (Range interval : extractedRanges) {
             if (current.isConnected(interval)) {
@@ -166,7 +162,7 @@ public class DruidDateTimeUtils {
     }
   }
 
-  protected static List<Range<Calendar>> leafToRanges(RexCall call,
+  protected static List<Range<TimestampString>> leafToRanges(RexCall call,
       boolean withNot) {
     switch (call.getKind()) {
     case EQUALS:
@@ -175,7 +171,7 @@ public class DruidDateTimeUtils {
     case GREATER_THAN:
     case GREATER_THAN_OR_EQUAL:
     {
-      final Calendar value;
+      final TimestampString value;
       if (call.getOperands().get(0) instanceof RexInputRef
           && literalValue(call.getOperands().get(1)) != null) {
         value = literalValue(call.getOperands().get(1));
@@ -203,8 +199,8 @@ public class DruidDateTimeUtils {
     }
     case BETWEEN:
     {
-      final Calendar value1;
-      final Calendar value2;
+      final TimestampString value1;
+      final TimestampString value2;
       if (literalValue(call.getOperands().get(2)) != null
           && literalValue(call.getOperands().get(3)) != null) {
         value1 = literalValue(call.getOperands().get(2));
@@ -223,9 +219,9 @@ public class DruidDateTimeUtils {
     }
     case IN:
     {
-      ImmutableList.Builder<Range<Calendar>> ranges = ImmutableList.builder();
+      ImmutableList.Builder<Range<TimestampString>> ranges = 
ImmutableList.builder();
       for (RexNode operand : Util.skip(call.operands)) {
-        final Calendar element = literalValue(operand);
+        final TimestampString element = literalValue(operand);
         if (element == null) {
           return null;
         }
@@ -243,13 +239,16 @@ public class DruidDateTimeUtils {
     }
   }
 
-  private static Calendar literalValue(RexNode node) {
+  private static TimestampString literalValue(RexNode node) {
     switch (node.getKind()) {
     case LITERAL:
-      assert node instanceof RexLiteral;
-      Object value = ((RexLiteral) node).getValue();
-      if (value instanceof  Calendar) {
-        return (Calendar) value;
+      switch (((RexLiteral) node).getTypeName()) {
+      case TIMESTAMP:
+        return ((RexLiteral) node).getValueAs(TimestampString.class);
+      case DATE:
+        // For uniformity, treat dates as timestamps
+        final DateString d = ((RexLiteral) node).getValueAs(DateString.class);
+        return TimestampString.fromMillisSinceEpoch(d.getMillisSinceEpoch());
       }
       break;
     case CAST:

http://git-wip-us.apache.org/repos/asf/calcite/blob/205af813/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
----------------------------------------------------------------------
diff --git 
a/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java 
b/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
index b2cf321..74ce10c 100644
--- a/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
+++ b/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
@@ -23,6 +23,7 @@ import org.apache.calcite.rel.rules.DateRangeRules;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.test.RexImplicationCheckerTest.Fixture;
+import org.apache.calcite.util.TimestampString;
 import org.apache.calcite.util.Util;
 
 import com.google.common.collect.ImmutableList;
@@ -123,12 +124,13 @@ public class DruidDateRangeRulesTest {
    * Push CAST of literals to Druid</a>. */
   @Test public void testFilterWithCast() {
     final Fixture2 f = new Fixture2();
-    Calendar from = Util.calendar();
-    from.clear();
-    from.set(2010, Calendar.JANUARY, 1);
-    Calendar to = Util.calendar();
-    to.clear();
-    to.set(2011, Calendar.JANUARY, 1);
+    final Calendar c = Util.calendar();
+    c.clear();
+    c.set(2010, Calendar.JANUARY, 1);
+    final TimestampString from = TimestampString.fromCalendarFields(c);
+    c.clear();
+    c.set(2011, Calendar.JANUARY, 1);
+    final TimestampString to = TimestampString.fromCalendarFields(c);
 
     // dt >= 2010-01-01 AND dt < 2011-01-01
     checkDateRangeNoSimplify(f,

Reply via email to