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 2018/02/05 19:34:08 UTC

calcite git commit: [CALCITE-2156] In DateRangeRules, compute FLOOR and CEIL of TIMESTAMP WITH LOCAL TIMEZONE in local time zone

Repository: calcite
Updated Branches:
  refs/heads/master e25e74977 -> 96d620be8


[CALCITE-2156] In DateRangeRules, compute FLOOR and CEIL of TIMESTAMP WITH LOCAL TIMEZONE in local time zone

Close apache/calcite#617


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

Branch: refs/heads/master
Commit: 96d620be8054d83aca97d62780cb38cea928a655
Parents: e25e749
Author: Nishant <ni...@gmail.com>
Authored: Tue Jan 30 02:00:05 2018 +0530
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Feb 5 10:36:17 2018 -0800

----------------------------------------------------------------------
 .../calcite/rel/rules/DateRangeRules.java       | 56 +++++++++++++++++---
 .../calcite/rel/rules/DateRangeRulesTest.java   | 42 +++++++++++++--
 .../apache/calcite/test/MockRelOptPlanner.java  |  5 +-
 .../apache/calcite/test/RelOptRulesTest.java    | 18 +++++--
 .../org/apache/calcite/test/RelOptTestBase.java |  9 ++++
 .../calcite/test/RexImplicationCheckerTest.java |  5 ++
 .../apache/calcite/test/SqlToRelTestBase.java   | 37 +++++++++----
 .../org/apache/calcite/test/DruidAdapterIT.java | 19 +++++++
 .../calcite/test/DruidDateRangeRulesTest.java   |  4 +-
 9 files changed, 162 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/96d620be/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 051ff7b..fac9f02 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
@@ -16,7 +16,9 @@
  */
 package org.apache.calcite.rel.rules;
 
+import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.avatica.util.TimeUnitRange;
+import org.apache.calcite.config.CalciteConnectionConfig;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.rel.core.Filter;
@@ -29,6 +31,7 @@ import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.rex.RexVisitorImpl;
 import org.apache.calcite.runtime.PredicateImpl;
+import org.apache.calcite.runtime.SqlFunctions;
 import org.apache.calcite.sql.SqlBinaryOperator;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
@@ -37,6 +40,7 @@ import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.Bug;
 import org.apache.calcite.util.DateString;
 import org.apache.calcite.util.TimestampString;
+import org.apache.calcite.util.TimestampWithTimeZoneString;
 import org.apache.calcite.util.Util;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -61,6 +65,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TimeZone;
 
 /**
  * Collection of planner rules that convert
@@ -145,7 +150,8 @@ public abstract class DateRangeRules {
 
   /** Replaces calls to EXTRACT, FLOOR and CEIL in an expression. */
   @VisibleForTesting
-  public static RexNode replaceTimeUnits(RexBuilder rexBuilder, RexNode e) {
+  public static RexNode replaceTimeUnits(RexBuilder rexBuilder, RexNode e,
+      String timeZone) {
     ImmutableSortedSet<TimeUnitRange> timeUnits = extractTimeUnits(e);
     if (!timeUnits.contains(TimeUnitRange.YEAR)) {
       // Case when we have FLOOR or CEIL but no extract on YEAR.
@@ -157,7 +163,8 @@ public abstract class DateRangeRules {
     final Map<String, RangeSet<Calendar>> operandRanges = new HashMap<>();
     for (TimeUnitRange timeUnit : timeUnits) {
       e = e.accept(
-          new ExtractShuttle(rexBuilder, timeUnit, operandRanges, timeUnits));
+          new ExtractShuttle(rexBuilder, timeUnit, operandRanges, timeUnits,
+              timeZone));
     }
     return e;
   }
@@ -174,8 +181,10 @@ public abstract class DateRangeRules {
     @Override public void onMatch(RelOptRuleCall call) {
       final Filter filter = call.rel(0);
       final RexBuilder rexBuilder = filter.getCluster().getRexBuilder();
+      final String timeZone = filter.getCluster().getPlanner().getContext()
+          .unwrap(CalciteConnectionConfig.class).timeZone();
       final RexNode condition =
-          replaceTimeUnits(rexBuilder, filter.getCondition());
+          replaceTimeUnits(rexBuilder, filter.getCondition(), timeZone);
       if (RexUtil.eq(condition, filter.getCondition())) {
         return;
       }
@@ -238,17 +247,19 @@ public abstract class DateRangeRules {
     private final Map<String, RangeSet<Calendar>> operandRanges;
     private final Deque<RexCall> calls = new ArrayDeque<>();
     private final ImmutableSortedSet<TimeUnitRange> timeUnitRanges;
+    private final String timeZone;
 
     @VisibleForTesting
     ExtractShuttle(RexBuilder rexBuilder, TimeUnitRange timeUnit,
         Map<String, RangeSet<Calendar>> operandRanges,
-        ImmutableSortedSet<TimeUnitRange> timeUnitRanges) {
+        ImmutableSortedSet<TimeUnitRange> timeUnitRanges, String timeZone) {
       this.rexBuilder = Preconditions.checkNotNull(rexBuilder);
       this.timeUnit = Preconditions.checkNotNull(timeUnit);
       Bug.upgrade("Change type to Map<RexNode, RangeSet<Calendar>> when"
           + " [CALCITE-1367] is fixed");
       this.operandRanges = Preconditions.checkNotNull(operandRanges);
       this.timeUnitRanges = Preconditions.checkNotNull(timeUnitRanges);
+      this.timeZone = timeZone;
     }
 
     @Override public RexNode visitCall(RexCall call) {
@@ -365,7 +376,7 @@ public abstract class DateRangeRules {
           for (TimeUnitRange timeUnit : timeUnitRanges) {
             clonedOperand = clonedOperand.accept(
                 new ExtractShuttle(rexBuilder, timeUnit, operandRanges,
-                    timeUnitRanges));
+                    timeUnitRanges, timeZone));
           }
           if ((clonedOperand != operand) && (update != null)) {
             update[0] = true;
@@ -507,11 +518,22 @@ public abstract class DateRangeRules {
 
     private RexLiteral dateTimeLiteral(RexBuilder rexBuilder, Calendar calendar,
         RexNode operand) {
+      final TimestampString ts;
+      final int p;
       switch (operand.getType().getSqlTypeName()) {
       case TIMESTAMP:
+        ts = TimestampString.fromCalendarFields(calendar);
+        p = operand.getType().getPrecision();
+        return rexBuilder.makeTimestampLiteral(ts, p);
       case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
-        final TimestampString ts = TimestampString.fromCalendarFields(calendar);
-        return rexBuilder.makeTimestampLiteral(ts, operand.getType().getPrecision());
+        ts = TimestampString.fromCalendarFields(calendar);
+        final TimeZone tz = TimeZone.getTimeZone(this.timeZone);
+        final TimestampString localTs =
+            new TimestampWithTimeZoneString(ts, tz)
+                .withTimeZone(DateTimeUtils.UTC_ZONE)
+                .getLocalTimestampString();
+        p = operand.getType().getPrecision();
+        return rexBuilder.makeTimestampWithLocalTimeZoneLiteral(localTs, p);
       case DATE:
         final DateString d = DateString.fromCalendarFields(calendar);
         return rexBuilder.makeDateLiteral(d);
@@ -558,7 +580,7 @@ public abstract class DateRangeRules {
         rangeSet = ImmutableRangeSet.<Calendar>of().complement();
       }
       final RangeSet<Calendar> s2 = TreeRangeSet.create();
-      final Calendar c = timeLiteral.getValueAs(Calendar.class);
+      final Calendar c = timestampValue(timeLiteral);
       final Range<Calendar> range = floor
           ? floorRange(timeUnit, comparison, c)
           : ceilRange(timeUnit, comparison, c);
@@ -572,6 +594,24 @@ public abstract class DateRangeRules {
       return toRex(operand, range);
     }
 
+    private Calendar timestampValue(RexLiteral timeLiteral) {
+      switch (timeLiteral.getTypeName()) {
+      case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+        final TimeZone tz = TimeZone.getTimeZone(this.timeZone);
+        return Util.calendar(
+            SqlFunctions.timestampWithLocalTimeZoneToTimestamp(
+                timeLiteral.getValueAs(Long.class), tz));
+      case TIMESTAMP:
+        return Util.calendar(timeLiteral.getValueAs(Long.class));
+      case DATE:
+        // Cast date to timestamp with local time zone
+        final DateString d = timeLiteral.getValueAs(DateString.class);
+        return Util.calendar(d.getMillisSinceEpoch());
+      default:
+        throw Util.unexpected(timeLiteral.getTypeName());
+      }
+    }
+
     private Range<Calendar> floorRange(TimeUnitRange timeUnit, SqlKind comparison,
         Calendar c) {
       Calendar floor = floor(c, timeUnit);

http://git-wip-us.apache.org/repos/asf/calcite/blob/96d620be/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java b/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java
index f0439ab..01fe9bc 100644
--- a/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java
@@ -20,6 +20,7 @@ import org.apache.calcite.avatica.util.TimeUnitRange;
 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.DateString;
 import org.apache.calcite.util.TimestampString;
 import org.apache.calcite.util.Util;
 
@@ -84,6 +85,7 @@ public class DateRangeRulesTest {
     final Fixture2 f = new Fixture2();
     checkDateRange(f,
         f.and(f.eq(f.exYearD, f.literal(2014)), f.eq(f.exMonthD, f.literal(6))),
+        "UTC",
         is("AND(AND(>=($8, 2014-01-01), <($8, 2015-01-01)),"
             + " AND(>=($8, 2014-06-01), <($8, 2014-07-01)))"),
         is("AND(>=($8, 2014-01-01), <($8, 2015-01-01),"
@@ -111,7 +113,7 @@ public class DateRangeRulesTest {
             f.or(f.eq(f.exMonthD, f.literal(2)),
                 f.eq(f.exMonthD, f.literal(3)),
                 f.eq(f.exMonthD, f.literal(5))));
-    checkDateRange(f, e, is(s1), is(s2));
+    checkDateRange(f, e, "UTC", is(s1), is(s2));
   }
 
   @Test public void testExtractYearAndDayFromDateColumn() {
@@ -657,17 +659,47 @@ public class DateRangeRulesTest {
         is(">($9, 2009-01-01 00:00:00)"));
   }
 
+  @Test public void testFloorRewriteWithTimezone() {
+    final Calendar c = Util.calendar();
+    c.clear();
+    c.set(2010, Calendar.FEBRUARY, 1, 11, 30, 0);
+    final Fixture2 f = new Fixture2();
+    checkDateRange(f,
+        f.eq(f.floorHour,
+            f.timestampLocalTzLiteral(TimestampString.fromCalendarFields(c))),
+        "IST",
+        is("AND(>=($9, 2010-02-01 17:00:00), <($9, 2010-02-01 18:00:00))"),
+        CoreMatchers.any(String.class));
+
+    c.clear();
+    c.set(2010, Calendar.FEBRUARY, 1, 11, 00, 0);
+    checkDateRange(f,
+        f.eq(f.floorHour,
+            f.timestampLiteral(TimestampString.fromCalendarFields(c))),
+        "IST",
+        is("AND(>=($9, 2010-02-01 11:00:00), <($9, 2010-02-01 12:00:00))"),
+        CoreMatchers.any(String.class));
+
+    c.clear();
+    c.set(2010, Calendar.FEBRUARY, 1, 00, 00, 0);
+    checkDateRange(f,
+        f.eq(f.floorHour, f.dateLiteral(DateString.fromCalendarFields(c))),
+        "IST",
+        is("AND(>=($9, 2010-02-01 00:00:00), <($9, 2010-02-01 01:00:00))"),
+        CoreMatchers.any(String.class));
+  }
+
   private static Set<TimeUnitRange> set(TimeUnitRange... es) {
     return ImmutableSet.copyOf(es);
   }
 
   private void checkDateRange(Fixture f, RexNode e, Matcher<String> matcher) {
-    checkDateRange(f, e, matcher, CoreMatchers.any(String.class));
+    checkDateRange(f, e, "UTC", matcher, CoreMatchers.any(String.class));
   }
 
-  private void checkDateRange(Fixture f, RexNode e, Matcher<String> matcher,
-      Matcher<String> simplifyMatcher) {
-    e = DateRangeRules.replaceTimeUnits(f.rexBuilder, e);
+  private void checkDateRange(Fixture f, RexNode e, String timeZone,
+      Matcher<String> matcher, Matcher<String> simplifyMatcher) {
+    e = DateRangeRules.replaceTimeUnits(f.rexBuilder, e, timeZone);
     assertThat(e.toString(), matcher);
     final RexNode e2 = f.simplify.simplify(e);
     assertThat(e2.toString(), simplifyMatcher);

http://git-wip-us.apache.org/repos/asf/calcite/blob/96d620be/core/src/test/java/org/apache/calcite/test/MockRelOptPlanner.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/MockRelOptPlanner.java b/core/src/test/java/org/apache/calcite/test/MockRelOptPlanner.java
index adce9a9..d35c019 100644
--- a/core/src/test/java/org/apache/calcite/test/MockRelOptPlanner.java
+++ b/core/src/test/java/org/apache/calcite/test/MockRelOptPlanner.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.test;
 
 import org.apache.calcite.plan.AbstractRelOptPlanner;
+import org.apache.calcite.plan.Context;
 import org.apache.calcite.plan.RelOptCostImpl;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptRule;
@@ -53,8 +54,8 @@ public class MockRelOptPlanner extends AbstractRelOptPlanner {
   //~ Methods ----------------------------------------------------------------
 
   /** Creates MockRelOptPlanner. */
-  public MockRelOptPlanner() {
-    super(RelOptCostImpl.FACTORY, null);
+  public MockRelOptPlanner(Context context) {
+    super(RelOptCostImpl.FACTORY, context);
     setExecutor(new RexExecutorImpl(Schemas.createDataContext(null, null)));
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/96d620be/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 2873531..2e2a5f6 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -16,6 +16,9 @@
  */
 package org.apache.calcite.test;
 
+import org.apache.calcite.config.CalciteConnectionConfigImpl;
+import org.apache.calcite.plan.Context;
+import org.apache.calcite.plan.Contexts;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptUtil;
@@ -119,6 +122,7 @@ import org.junit.Test;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Properties;
 
 import javax.annotation.Nullable;
 
@@ -3178,7 +3182,7 @@ public class RelOptRulesTest extends RelOptTestBase {
     Tester tester = new TesterImpl(getDiffRepos(), true, true, false, false,
         null, null) {
       @Override public RelOptPlanner createPlanner() {
-        return new MockRelOptPlanner() {
+        return new MockRelOptPlanner(Contexts.empty()) {
           @Override public List<RelTraitDef> getRelTraitDefs() {
             return ImmutableList.<RelTraitDef>of(RelCollationTraitDef.INSTANCE);
           }
@@ -3704,17 +3708,19 @@ public class RelOptRulesTest extends RelOptTestBase {
    * Converting predicates on date dimension columns into date ranges</a>,
    * specifically a rule that converts {@code EXTRACT(YEAR FROM ...) = constant}
    * to a range. */
-  @Test public void testExtractYearToRange() throws Exception {
+  @Test public void testExtractYearToRange() {
     final String sql = "select *\n"
         + "from sales.emp_b as e\n"
         + "where extract(year from birthdate) = 2014";
     HepProgram program = new HepProgramBuilder()
         .addRuleInstance(DateRangeRules.FILTER_INSTANCE)
         .build();
-    sql(sql).with(program).check();
+    final Context context =
+        Contexts.of(new CalciteConnectionConfigImpl(new Properties()));
+    sql(sql).with(program).withContext(context).check();
   }
 
-  @Test public void testExtractYearMonthToRange() throws Exception {
+  @Test public void testExtractYearMonthToRange() {
     final String sql = "select *\n"
         + "from sales.emp_b as e\n"
         + "where extract(year from birthdate) = 2014"
@@ -3722,7 +3728,9 @@ public class RelOptRulesTest extends RelOptTestBase {
     HepProgram program = new HepProgramBuilder()
         .addRuleInstance(DateRangeRules.FILTER_INSTANCE)
         .build();
-    sql(sql).with(program).check();
+    final Context context =
+        Contexts.of(new CalciteConnectionConfigImpl(new Properties()));
+    sql(sql).with(program).withContext(context).check();
   }
 
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/96d620be/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java b/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
index 848918e..114463f 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptTestBase.java
@@ -16,6 +16,7 @@
  */
 package org.apache.calcite.test;
 
+import org.apache.calcite.plan.Context;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptUtil;
@@ -279,6 +280,14 @@ abstract class RelOptTestBase extends SqlToRelTestBase {
           });
     }
 
+    public Sql withContext(final Context context) {
+      return withTransform(
+          new Function<Tester, Tester>() {
+            public Tester apply(Tester tester) {
+              return tester.withContext(context);
+            }
+          });
+    }
 
     public void check() {
       check(false);

http://git-wip-us.apache.org/repos/asf/calcite/blob/96d620be/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 0a2d74b..296b497 100644
--- a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
@@ -553,6 +553,11 @@ public class RexImplicationCheckerTest {
           timestampDataType.getPrecision());
     }
 
+    public RexNode timestampLocalTzLiteral(TimestampString ts) {
+      return rexBuilder.makeTimestampWithLocalTimeZoneLiteral(ts,
+          timestampDataType.getPrecision());
+    }
+
     public RexNode timeLiteral(TimeString t) {
       return rexBuilder.makeTimeLiteral(t, timeDataType.getPrecision());
     }

http://git-wip-us.apache.org/repos/asf/calcite/blob/96d620be/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
index c8ece76..1b9581d 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelTestBase.java
@@ -17,6 +17,8 @@
 package org.apache.calcite.test;
 
 import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.plan.Context;
+import org.apache.calcite.plan.Contexts;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptSchema;
@@ -240,6 +242,9 @@ public abstract class SqlToRelTestBase {
     Tester withClusterFactory(Function<RelOptCluster, RelOptCluster> function);
 
     boolean isLateDecorrelate();
+
+    /** Returns a tester that uses a given context. */
+    Tester withContext(Context context);
   }
 
   //~ Inner Classes ----------------------------------------------------------
@@ -504,6 +509,7 @@ public abstract class SqlToRelTestBase {
     private final Function<RelOptCluster, RelOptCluster> clusterFactory;
     private RelDataTypeFactory typeFactory;
     public final SqlToRelConverter.Config config;
+    private final Context context;
 
     /**
      * Creates a TesterImpl.
@@ -526,7 +532,8 @@ public abstract class SqlToRelTestBase {
           catalogReaderFactory,
           clusterFactory,
           SqlToRelConverter.Config.DEFAULT,
-          SqlConformanceEnum.DEFAULT);
+          SqlConformanceEnum.DEFAULT,
+          Contexts.empty());
     }
 
     protected TesterImpl(DiffRepository diffRepos, boolean enableDecorrelate,
@@ -534,7 +541,8 @@ public abstract class SqlToRelTestBase {
         Function<RelDataTypeFactory, Prepare.CatalogReader>
             catalogReaderFactory,
         Function<RelOptCluster, RelOptCluster> clusterFactory,
-        SqlToRelConverter.Config config, SqlConformance conformance) {
+        SqlToRelConverter.Config config, SqlConformance conformance,
+        Context context) {
       this.diffRepos = diffRepos;
       this.enableDecorrelate = enableDecorrelate;
       this.enableTrim = enableTrim;
@@ -544,6 +552,7 @@ public abstract class SqlToRelTestBase {
       this.clusterFactory = clusterFactory;
       this.config = config;
       this.conformance = conformance;
+      this.context = context;
     }
 
     public RelRoot convertSqlToRel(String sql) {
@@ -673,7 +682,7 @@ public abstract class SqlToRelTestBase {
     }
 
     public RelOptPlanner createPlanner() {
-      return new MockRelOptPlanner();
+      return new MockRelOptPlanner(context);
     }
 
     public void assertConvertsTo(
@@ -734,7 +743,7 @@ public abstract class SqlToRelTestBase {
           ? this
           : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
               enableExpand, enableLateDecorrelate, catalogReaderFactory,
-              clusterFactory, config, conformance);
+              clusterFactory, config, conformance, context);
     }
 
     public Tester withLateDecorrelation(boolean enableLateDecorrelate) {
@@ -742,7 +751,7 @@ public abstract class SqlToRelTestBase {
           ? this
           : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
               enableExpand, enableLateDecorrelate, catalogReaderFactory,
-              clusterFactory, config, conformance);
+              clusterFactory, config, conformance, context);
     }
 
     public TesterImpl withConfig(SqlToRelConverter.Config config) {
@@ -750,7 +759,7 @@ public abstract class SqlToRelTestBase {
           ? this
           : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
               enableExpand, enableLateDecorrelate, catalogReaderFactory,
-              clusterFactory, config, conformance);
+              clusterFactory, config, conformance, context);
     }
 
     public Tester withTrim(boolean enableTrim) {
@@ -758,7 +767,7 @@ public abstract class SqlToRelTestBase {
           ? this
           : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
               enableExpand, enableLateDecorrelate, catalogReaderFactory,
-              clusterFactory, config, conformance);
+              clusterFactory, config, conformance, context);
     }
 
     public Tester withExpand(boolean enableExpand) {
@@ -766,27 +775,33 @@ public abstract class SqlToRelTestBase {
           ? this
           : new TesterImpl(diffRepos, enableDecorrelate, enableTrim,
               enableExpand, enableLateDecorrelate, catalogReaderFactory,
-              clusterFactory, config, conformance);
+              clusterFactory, config, conformance, context);
     }
 
     public Tester withConformance(SqlConformance conformance) {
       return new TesterImpl(diffRepos, enableDecorrelate, false,
           enableExpand, enableLateDecorrelate, catalogReaderFactory,
-          clusterFactory, config, conformance);
+          clusterFactory, config, conformance, context);
     }
 
     public Tester withCatalogReaderFactory(
         Function<RelDataTypeFactory, Prepare.CatalogReader> factory) {
       return new TesterImpl(diffRepos, enableDecorrelate, false,
           enableExpand, enableLateDecorrelate, factory,
-          clusterFactory, config, conformance);
+          clusterFactory, config, conformance, context);
     }
 
     public Tester withClusterFactory(
         Function<RelOptCluster, RelOptCluster> clusterFactory) {
       return new TesterImpl(diffRepos, enableDecorrelate, false,
           enableExpand, enableLateDecorrelate, catalogReaderFactory,
-          clusterFactory, config, conformance);
+          clusterFactory, config, conformance, context);
+    }
+
+    public Tester withContext(Context context) {
+      return new TesterImpl(diffRepos, enableDecorrelate, false,
+          enableExpand, enableLateDecorrelate, catalogReaderFactory,
+          clusterFactory, config, conformance, context);
     }
 
     public boolean isLateDecorrelate() {

http://git-wip-us.apache.org/repos/asf/calcite/blob/96d620be/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
----------------------------------------------------------------------
diff --git a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
index e2cbab8..9d3191c 100644
--- a/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
+++ b/druid/src/test/java/org/apache/calcite/test/DruidAdapterIT.java
@@ -3487,6 +3487,25 @@ public class DruidAdapterIT {
         .runs()
         .queryContains(druidChecker("{\"queryType\":\"timeseries\""));
   }
+
+  @Test public void testFloorToDateRangeWithTimeZone() {
+    final String sql = "Select cast(floor(\"timestamp\" to MONTH) as timestamp) as t from "
+        + "\"foodmart\" where floor(\"timestamp\" to MONTH) >= '1997-05-01 00:00:00 IST' "
+        + "and floor(\"timestamp\" to MONTH) < '1997-05-02 00:00:00 IST' order by t"
+        + " limit 1";
+    final String druidQuery = "{\"queryType\":\"scan\",\"dataSource\":\"foodmart\",\"intervals\":"
+        + "[\"1997-04-30T18:30:00.000Z/1997-05-31T18:30:00.000Z\"],\"columns\":[\"__time\"],"
+        + "\"granularity\":{\"type\":\"all\"},\"resultFormat\":\"compactedList\"}";
+    CalciteAssert.that()
+        .enable(enabled())
+        .with(ImmutableMap.of("model", FOODMART.getPath()))
+        .with(CalciteConnectionProperty.TIME_ZONE.camelName(), "IST")
+        .query(sql)
+        .runs()
+        .queryContains(druidChecker(druidQuery))
+        .returnsOrdered("T=1997-05-01 05:30:00");
+  }
+
 }
 
 // End DruidAdapterIT.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/96d620be/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 ceb2d5e..1b20b32 100644
--- a/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
+++ b/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
@@ -141,7 +141,7 @@ public class DruidDateRangeRulesTest {
   // HiveRexExecutorImpl is used in Hive
   private void checkDateRangeNoSimplify(Fixture f, RexNode e,
       Matcher<String> intervalMatcher) {
-    e = DateRangeRules.replaceTimeUnits(f.rexBuilder, e);
+    e = DateRangeRules.replaceTimeUnits(f.rexBuilder, e, "UTC");
     final List<Interval> intervals =
         DruidDateTimeUtils.createInterval(e, "UTC");
     assertThat(intervals, notNullValue());
@@ -149,7 +149,7 @@ public class DruidDateRangeRulesTest {
   }
 
   private void checkDateRange(Fixture f, RexNode e, Matcher<String> intervalMatcher) {
-    e = DateRangeRules.replaceTimeUnits(f.rexBuilder, e);
+    e = DateRangeRules.replaceTimeUnits(f.rexBuilder, e, "UTC");
     final RexNode e2 = f.simplify.simplify(e);
     List<Interval> intervals =
         DruidDateTimeUtils.createInterval(e2, "UTC");