You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by st...@apache.org on 2022/11/29 13:46:50 UTC
[phoenix] branch master updated: PHOENIX-6823 calling Joda-based round() function on temporal PK field causes division by zero error
This is an automated email from the ASF dual-hosted git repository.
stoty pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/master by this push:
new 66fad95a15 PHOENIX-6823 calling Joda-based round() function on temporal PK field causes division by zero error
66fad95a15 is described below
commit 66fad95a15f55620e9d11b5f4566e9543da30d44
Author: Istvan Toth <st...@apache.org>
AuthorDate: Tue Nov 22 07:22:23 2022 +0100
PHOENIX-6823 calling Joda-based round() function on temporal PK field causes division by zero error
also fix other bugs in the key range pushdown logic for temporals
---
.../phoenix/end2end/RoundFloorCeilFuncIT.java | 437 +++++++
.../expression/function/CeilMonthExpression.java | 13 +
.../expression/function/CeilWeekExpression.java | 13 +
.../expression/function/CeilYearExpression.java | 13 +
.../expression/function/FloorMonthExpression.java | 13 +
.../expression/function/FloorWeekExpression.java | 13 +
.../expression/function/FloorYearExpression.java | 13 +
.../expression/function/RoundDateExpression.java | 82 +-
.../function/RoundJodaDateExpression.java | 10 +-
.../expression/function/RoundMonthExpression.java | 21 +
.../expression/function/RoundWeekExpression.java | 22 +
.../expression/function/RoundYearExpression.java | 21 +
.../java/org/apache/phoenix/util/DateUtil.java | 55 +-
.../apache/phoenix/compile/WhereOptimizerTest.java | 251 +++-
.../expression/RoundFloorCeilExpressionsTest.java | 1235 ++++++++++++++++++++
15 files changed, 2165 insertions(+), 47 deletions(-)
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/RoundFloorCeilFuncIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/RoundFloorCeilFuncIT.java
index 2eba6e08b6..f7facaf253 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/RoundFloorCeilFuncIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/RoundFloorCeilFuncIT.java
@@ -29,8 +29,11 @@ import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
import java.util.Properties;
import org.apache.phoenix.expression.function.CeilFunction;
@@ -669,4 +672,438 @@ public class RoundFloorCeilFuncIT extends ParallelStatsDisabledIT {
assertEquals(1380603, rs.getLong(1));
}
+ @Test
+ public void testRoundFunctionsRowKey() throws SQLException {
+ // Exercise the newKeyPart push down logic in RoundDateExpression
+
+ java.time.LocalDateTime LD_PAST = java.time.LocalDateTime.of(2000, 6, 6, 12, 0, 30, 0);
+ java.time.Instant INSTANT_LD_PAST = LD_PAST.toInstant(ZoneOffset.UTC);
+
+ java.time.LocalDateTime LD_FUTURE = java.time.LocalDateTime.of(2040, 6, 6, 12, 0, 30, 0);
+ java.time.Instant INSTANT_LD_FUTURE = LD_FUTURE.toInstant(ZoneOffset.UTC);
+
+ java.time.LocalDateTime LD_MID_MIN = java.time.LocalDateTime.of(2022, 6, 6, 12, 0, 30, 0);
+ java.time.Instant INSTANT_MID_MIN = LD_MID_MIN.toInstant(ZoneOffset.UTC);
+ Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+ try (Connection conn = DriverManager.getConnection(getUrl(), props);
+ Statement stmt = conn.createStatement();) {
+
+ String tableName = generateUniqueName();
+ stmt.executeUpdate(
+ "CREATE TABLE " + tableName + " ( " + " df DATE primary key, dfv DATE) ");
+
+ PreparedStatement ps =
+ conn.prepareStatement("UPSERT INTO " + tableName + " VALUES (?, ?)");
+
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_LD_PAST));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_LD_PAST));
+ ps.executeUpdate();
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_MID_MIN.minusMillis(1)));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_MID_MIN.minusMillis(1)));
+ ps.executeUpdate();
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_MID_MIN));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_MID_MIN));
+ ps.executeUpdate();
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_MID_MIN.plusMillis(1)));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_MID_MIN.plusMillis(1)));
+ ps.executeUpdate();
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_LD_FUTURE));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_LD_FUTURE));
+ ps.executeUpdate();
+ conn.commit();
+
+ ResultSet rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where round(df, 'MINUTE', 1) = DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // MID_MIN, MID_MIN +1
+ assertEquals(2, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where round(df, 'MINUTE', 1) = DATE '2022-06-06 12:00:00'");
+ assertTrue(rs.next());
+ // MID_MIN -1
+ assertEquals(1, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where round(df, 'MINUTE', 1) > DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // FUTURE
+ assertEquals(1, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where round(df, 'MINUTE', 1) >= DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // MID_MIN, MID_MIN +1, FUTURE
+ assertEquals(3, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where round(df, 'MINUTE', 1) < DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1
+ assertEquals(2, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where round(df, 'MINUTE', 1) <= DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1, MID_MIN, MID_MIN +1
+ assertEquals(4, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where round(df, 'MINUTE', 1) <= DATE '2022-06-06 12:00:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1
+ assertEquals(2, rs.getInt(1));
+
+ //
+ // The same, but without range scan:
+ //
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where round(dfv, 'MINUTE', 1) = DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // MID_MIN, MID_MIN +1
+ assertEquals(2, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where round(dfv, 'MINUTE', 1) = DATE '2022-06-06 12:00:00'");
+ assertTrue(rs.next());
+ // MID_MIN -1
+ assertEquals(1, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where round(dfv, 'MINUTE', 1) > DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // FUTURE
+ assertEquals(1, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where round(dfv, 'MINUTE', 1) >= DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // MID_MIN, MID_MIN +1, FUTURE
+ assertEquals(3, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where round(dfv, 'MINUTE', 1) < DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1
+ assertEquals(2, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where round(dfv, 'MINUTE', 1) <= DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1, MID_MIN, MID_MIN +1
+ assertEquals(4, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where round(dfv, 'MINUTE', 1) <= DATE '2022-06-06 12:00:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1
+ assertEquals(2, rs.getInt(1));
+ }
+ }
+
+ @Test
+ public void testFloorFunctionsRowKey() throws SQLException {
+ // Exercise the newKeyPart push down logic in RoundDateExpression
+
+ java.time.LocalDateTime LD_PAST = java.time.LocalDateTime.of(2000, 6, 6, 12, 1, 0, 0);
+ java.time.Instant INSTANT_LD_PAST = LD_PAST.toInstant(ZoneOffset.UTC);
+
+ java.time.LocalDateTime LD_FUTURE = java.time.LocalDateTime.of(2040, 6, 6, 12, 1, 0, 0);
+ java.time.Instant INSTANT_LD_FUTURE = LD_FUTURE.toInstant(ZoneOffset.UTC);
+
+ java.time.LocalDateTime LD_MID_MIN = java.time.LocalDateTime.of(2022, 6, 6, 12, 1, 0, 0);
+ java.time.Instant INSTANT_MID_MIN = LD_MID_MIN.toInstant(ZoneOffset.UTC);
+
+ Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+ try (Connection conn = DriverManager.getConnection(getUrl(), props);
+ Statement stmt = conn.createStatement();) {
+
+ String tableName = generateUniqueName();
+ stmt.executeUpdate(
+ "CREATE TABLE " + tableName + " ( " + " df DATE primary key, dfv DATE) ");
+
+ PreparedStatement ps =
+ conn.prepareStatement("UPSERT INTO " + tableName + " VALUES (?, ?)");
+
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_LD_PAST));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_LD_PAST));
+ ps.executeUpdate();
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_MID_MIN.minusMillis(1)));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_MID_MIN.minusMillis(1)));
+ ps.executeUpdate();
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_MID_MIN));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_MID_MIN));
+ ps.executeUpdate();
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_MID_MIN.plusMillis(1)));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_MID_MIN.plusMillis(1)));
+ ps.executeUpdate();
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_LD_FUTURE));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_LD_FUTURE));
+ ps.executeUpdate();
+ conn.commit();
+
+ ResultSet rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where floor(df, 'MINUTE', 1) = DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // MID_MIN, MID_MIN +1
+ assertEquals(2, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where floor(df, 'MINUTE', 1) = DATE '2022-06-06 12:00:00'");
+ assertTrue(rs.next());
+ // MID_MIN -1
+ assertEquals(1, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where floor(df, 'MINUTE', 1) > DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // FUTURE
+ assertEquals(1, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where floor(df, 'MINUTE', 1) >= DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // MID_MIN, MID_MIN +1, FUTURE
+ assertEquals(3, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where floor(df, 'MINUTE', 1) < DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1
+ assertEquals(2, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where floor(df, 'MINUTE', 1) <= DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1, MID_MIN, MID_MIN +1
+ assertEquals(4, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where floor(df, 'MINUTE', 1) <= DATE '2022-06-06 12:00:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1
+ assertEquals(2, rs.getInt(1));
+
+ //
+ // The same, but without range scan:
+ //
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where floor(dfv, 'MINUTE', 1) = DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // MID_MIN, MID_MIN +1
+ assertEquals(2, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where floor(dfv, 'MINUTE', 1) = DATE '2022-06-06 12:00:00'");
+ assertTrue(rs.next());
+ // MID_MIN -1
+ assertEquals(1, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where floor(dfv, 'MINUTE', 1) > DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // FUTURE
+ assertEquals(1, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where floor(dfv, 'MINUTE', 1) >= DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // MID_MIN, MID_MIN +1, FUTURE
+ assertEquals(3, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where floor(dfv, 'MINUTE', 1) < DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1
+ assertEquals(2, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where floor(dfv, 'MINUTE', 1) <= DATE '2022-06-06 12:01:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1, MID_MIN, MID_MIN +1
+ assertEquals(4, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where floor(dfv, 'MINUTE', 1) <= DATE '2022-06-06 12:00:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1
+ assertEquals(2, rs.getInt(1));
+ }
+ }
+
+ @Test
+ public void testCeilFunctionsRowKey() throws SQLException {
+ // Exercise the newKeyPart push down logic in RoundDateExpression and children
+
+ java.time.LocalDateTime LD_PAST = java.time.LocalDateTime.of(2000, 6, 6, 12, 1, 0, 0);
+ java.time.Instant INSTANT_LD_PAST = LD_PAST.toInstant(ZoneOffset.UTC);
+
+ java.time.LocalDateTime LD_FUTURE = java.time.LocalDateTime.of(2040, 6, 6, 12, 0, 0, 0);
+ java.time.Instant INSTANT_LD_FUTURE = LD_FUTURE.toInstant(ZoneOffset.UTC);
+
+ java.time.LocalDateTime LD_MID_MIN = java.time.LocalDateTime.of(2022, 6, 1, 0, 0, 0, 0);
+ java.time.Instant INSTANT_MID_MIN = LD_MID_MIN.toInstant(ZoneOffset.UTC);
+
+ Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+ try (Connection conn = DriverManager.getConnection(getUrl(), props);
+ Statement stmt = conn.createStatement();) {
+
+ String tableName = generateUniqueName();
+ stmt.executeUpdate(
+ "CREATE TABLE " + tableName + " ( " + " df DATE primary key, dfv DATE) ");
+
+ PreparedStatement ps =
+ conn.prepareStatement("UPSERT INTO " + tableName + " VALUES (?, ?)");
+
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_LD_PAST));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_LD_PAST));
+ ps.executeUpdate();
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_MID_MIN.minusMillis(1)));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_MID_MIN.minusMillis(1)));
+ ps.executeUpdate();
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_MID_MIN));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_MID_MIN));
+ ps.executeUpdate();
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_MID_MIN.plusMillis(1)));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_MID_MIN.plusMillis(1)));
+ ps.executeUpdate();
+ ps.setTimestamp(1, java.sql.Timestamp.from(INSTANT_LD_FUTURE));
+ ps.setTimestamp(2, java.sql.Timestamp.from(INSTANT_LD_FUTURE));
+ ps.executeUpdate();
+ conn.commit();
+
+ ResultSet rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where ceil(df, 'MONTH', 1) = DATE '2022-06-01 00:00:00'");
+ assertTrue(rs.next());
+ // MID_MIN-1, MID_MIN
+ assertEquals(2, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where ceil(df, 'MONTH', 1) = DATE '2022-07-01 00:00:00'");
+ assertTrue(rs.next());
+ // MID_MIN +1
+ assertEquals(1, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where ceil(df, 'MONTH', 1) > DATE '2022-07-01 00:00:00'");
+ assertTrue(rs.next());
+ // FUTURE
+ assertEquals(1, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where ceil(df, 'MONTH', 1) >= DATE '2022-07-01 00:00:00'");
+ assertTrue(rs.next());
+ // MID_MIN +1, FUTURE
+ assertEquals(2, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where ceil(df, 'MONTH', 1) < DATE '2022-07-01 00:00:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1, MID_MIN
+ assertEquals(3, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where ceil(df, 'MONTH', 1) <= DATE '2022-07-01 00:00:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1, MID_MIN, MID_MIN +1
+ assertEquals(4, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where ceil(df, 'MONTH', 1) <= DATE '2022-06-01 00:00:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1, MID_MIN
+ assertEquals(3, rs.getInt(1));
+
+ //
+ // The same, but without range scan:
+ //
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where ceil(dfv, 'MONTH', 1) = DATE '2022-06-01 00:00:00'");
+ assertTrue(rs.next());
+ // MID_MIN-1, MID_MIN
+ assertEquals(2, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where ceil(dfv, 'MONTH', 1) = DATE '2022-07-01 00:00:00'");
+ assertTrue(rs.next());
+ // MID_MIN +1
+ assertEquals(1, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where ceil(dfv, 'MONTH', 1) > DATE '2022-07-01 00:00:00'");
+ assertTrue(rs.next());
+ // FUTURE
+ assertEquals(1, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where ceil(dfv, 'MONTH', 1) >= DATE '2022-07-01 00:00:00'");
+ assertTrue(rs.next());
+ // MID_MIN +1, FUTURE
+ assertEquals(2, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where ceil(dfv, 'MONTH', 1) < DATE '2022-07-01 00:00:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1, MID_MIN
+ assertEquals(3, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where ceil(dfv, 'MONTH', 1) <= DATE '2022-07-01 00:00:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1, MID_MIN, MID_MIN +1
+ assertEquals(4, rs.getInt(1));
+
+ rs =
+ stmt.executeQuery("select count(*) " + " from " + tableName
+ + " where ceil(dfv, 'MONTH', 1) <= DATE '2022-06-01 00:00:00'");
+ assertTrue(rs.next());
+ // PAST, MID_MIN-1, MID_MIN
+ assertEquals(3, rs.getInt(1));
+ }
+ }
+
}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilMonthExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilMonthExpression.java
index 22daeb551b..e35a0f348b 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilMonthExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilMonthExpression.java
@@ -21,6 +21,7 @@ import java.util.List;
import org.apache.phoenix.expression.Expression;
import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
/**
*
@@ -41,4 +42,16 @@ public class CeilMonthExpression extends RoundJodaDateExpression {
return dateTime.monthOfYear().roundCeilingCopy().getMillis();
}
+ @Override
+ public long rangeLower(long time) {
+ // floor(time - 1) + 1
+ return (new DateTime(time - 1, GJChronology.getInstanceUTC())).monthOfYear()
+ .roundFloorCopy().getMillis() + 1;
+ }
+
+ @Override
+ public long rangeUpper(long time) {
+ // ceil
+ return roundDateTime(new DateTime(time, GJChronology.getInstanceUTC()));
+ }
}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilWeekExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilWeekExpression.java
index 28da94f4f1..658eb402bb 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilWeekExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilWeekExpression.java
@@ -21,6 +21,7 @@ import java.util.List;
import org.apache.phoenix.expression.Expression;
import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
/**
*
@@ -41,4 +42,16 @@ public class CeilWeekExpression extends RoundJodaDateExpression {
return dateTime.weekOfWeekyear().roundCeilingCopy().getMillis();
}
+ @Override
+ public long rangeLower(long time) {
+ // floor(time - 1) + 1
+ return (new DateTime(time - 1, GJChronology.getInstanceUTC())).weekOfWeekyear()
+ .roundFloorCopy().getMillis() + 1;
+ }
+
+ @Override
+ public long rangeUpper(long time) {
+ // ceil
+ return roundDateTime(new DateTime(time, GJChronology.getInstanceUTC()));
+ }
}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilYearExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilYearExpression.java
index b6e6b63a31..c09e56a31b 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilYearExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/CeilYearExpression.java
@@ -21,6 +21,7 @@ import java.util.List;
import org.apache.phoenix.expression.Expression;
import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
/**
*
@@ -41,4 +42,16 @@ public class CeilYearExpression extends RoundJodaDateExpression {
return dateTime.year().roundCeilingCopy().getMillis();
}
+ @Override
+ public long rangeLower(long time) {
+ // floor(time - 1) + 1
+ return (new DateTime(time - 1, GJChronology.getInstanceUTC())).year().roundFloorCopy()
+ .getMillis() + 1;
+ }
+
+ @Override
+ public long rangeUpper(long time) {
+ // ceil
+ return roundDateTime(new DateTime(time, GJChronology.getInstanceUTC()));
+ }
}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorMonthExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorMonthExpression.java
index cf802055ba..1d5733d876 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorMonthExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorMonthExpression.java
@@ -21,6 +21,7 @@ import java.util.List;
import org.apache.phoenix.expression.Expression;
import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
/**
*
@@ -41,4 +42,16 @@ public class FloorMonthExpression extends RoundJodaDateExpression {
return datetime.monthOfYear().roundFloorCopy().getMillis();
}
+ @Override
+ public long rangeLower(long time) {
+ // floor
+ return roundDateTime(new DateTime(time, GJChronology.getInstanceUTC()));
+ }
+
+ @Override
+ public long rangeUpper(long time) {
+ // ceil(time + 1) -1
+ return (new DateTime(time + 1, GJChronology.getInstanceUTC())).monthOfYear()
+ .roundCeilingCopy().getMillis() - 1;
+ }
}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorWeekExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorWeekExpression.java
index b6596c9f20..73cd048ae7 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorWeekExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorWeekExpression.java
@@ -21,6 +21,7 @@ import java.util.List;
import org.apache.phoenix.expression.Expression;
import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
/**
* Floor function that rounds up the {@link DateTime} to start of week.
@@ -40,4 +41,16 @@ public class FloorWeekExpression extends RoundJodaDateExpression {
return datetime.weekOfWeekyear().roundFloorCopy().getMillis();
}
+ @Override
+ public long rangeLower(long time) {
+ // floor
+ return roundDateTime(new DateTime(time, GJChronology.getInstanceUTC()));
+ }
+
+ @Override
+ public long rangeUpper(long time) {
+ // ceil(time + 1) -1
+ return (new DateTime(time + 1, GJChronology.getInstanceUTC())).weekOfWeekyear()
+ .roundCeilingCopy().getMillis() - 1;
+ }
}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorYearExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorYearExpression.java
index 4ac8792b5f..77c926dfdc 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorYearExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/FloorYearExpression.java
@@ -21,6 +21,7 @@ import java.util.List;
import org.apache.phoenix.expression.Expression;
import org.joda.time.DateTime;
+import org.joda.time.chrono.GJChronology;
/**
*
@@ -41,4 +42,16 @@ public class FloorYearExpression extends RoundJodaDateExpression {
return datetime.year().roundFloorCopy().getMillis();
}
+ @Override
+ public long rangeLower(long time) {
+ // floor
+ return roundDateTime(new DateTime(time, GJChronology.getInstanceUTC()));
+ }
+
+ @Override
+ public long rangeUpper(long time) {
+ // ceil(time + 1) -1
+ return (new DateTime(time + 1, GJChronology.getInstanceUTC())).year().roundCeilingCopy()
+ .getMillis() - 1;
+ }
}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDateExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDateExpression.java
index fb2c624211..3d628e08c1 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDateExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundDateExpression.java
@@ -45,9 +45,9 @@ import org.apache.phoenix.schema.types.PDataType.PDataCodec;
import org.apache.phoenix.schema.types.PDate;
import org.apache.phoenix.schema.types.PInteger;
import org.apache.phoenix.schema.types.PVarchar;
-import org.apache.phoenix.util.ByteUtil;
-
+import org.apache.phoenix.thirdparty.com.google.common.annotations.VisibleForTesting;
import org.apache.phoenix.thirdparty.com.google.common.collect.Lists;
+import org.apache.phoenix.util.ByteUtil;
/**
* Function used to bucketize date/time values by rounding them to
@@ -105,7 +105,7 @@ public class RoundDateExpression extends ScalarFunction {
public static Expression create(List<Expression> children) throws SQLException {
int numChildren = children.size();
- if(numChildren < 2 || numChildren > 3) {
+ if (numChildren < 2 || numChildren > 3) {
throw new IllegalArgumentException("Wrong number of arguments : " + numChildren);
}
Object timeUnitValue = ((LiteralExpression)children.get(1)).getValue();
@@ -138,7 +138,7 @@ public class RoundDateExpression extends ScalarFunction {
Object multiplierValue = numChildren > 2 ? ((LiteralExpression)children.get(2)).getValue() : null;
int multiplier = multiplierValue == null ? 1 :((Number)multiplierValue).intValue();
TimeUnit timeUnit = TimeUnit.getTimeUnit(timeUnitValue != null ? timeUnitValue.toString() : null);
- if(timeUnit.ordinal() < TIME_UNIT_MS.length) {
+ if (timeUnit.ordinal() < TIME_UNIT_MS.length) {
divBy = multiplier * TIME_UNIT_MS[timeUnit.ordinal()];
}
}
@@ -148,8 +148,8 @@ public class RoundDateExpression extends ScalarFunction {
return divBy/2;
}
-
- protected long roundTime(long time) {
+ @VisibleForTesting
+ public long roundTime(long time) {
long value;
long roundUpAmount = getRoundUpAmount();
if (time <= Long.MAX_VALUE - roundUpAmount) { // If no overflow, add
@@ -159,7 +159,21 @@ public class RoundDateExpression extends ScalarFunction {
}
return value * divBy;
}
-
+
+ @VisibleForTesting
+ public long rangeLower(long time) {
+ // This is for the ms based intervals. This needs to be separately implemented for the
+ // joda based intervals
+ return roundTime(time) - getRoundUpAmount();
+ }
+
+ @VisibleForTesting
+ public long rangeUpper(long time) {
+ // This is for the ms based intervals. This needs to be separately implemented for the
+ // joda based intervals
+ return roundTime(time) + (divBy - getRoundUpAmount()) - 1;
+ }
+
@Override
public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
if (children.get(0).evaluate(tuple, ptr)) {
@@ -260,7 +274,8 @@ public class RoundDateExpression extends ScalarFunction {
PDataCodec codec = getKeyRangeCodec(type);
int offset = ByteUtil.isInclusive(op) ? 1 : 0;
long value = codec.decodeLong(key, 0, SortOrder.getDefault());
- byte[] nextKey = new byte[type.getByteSize()];
+ byte[] lowerKey = new byte[type.getByteSize()];
+ byte[] upperKey = new byte[type.getByteSize()];
KeyRange range;
switch (op) {
case EQUAL:
@@ -269,21 +284,58 @@ public class RoundDateExpression extends ScalarFunction {
// had ROUND(dateCol,'DAY') = TO_DATE('2013-01-01 23:00:00')
// it could never be equal, since date constant isn't at a day
// boundary.
- if (value % divBy != 0) {
+ if (value != roundTime(value)) {
return KeyRange.EMPTY_RANGE;
}
- codec.encodeLong(value + divBy, nextKey, 0);
- range = type.getKeyRange(key, true, nextKey, false);
+ codec.encodeLong(rangeLower(value), lowerKey, 0);
+ codec.encodeLong(rangeUpper(value), upperKey, 0);
+ range = type.getKeyRange(lowerKey, true, upperKey, true);
break;
+ // a simple number example (with half up rounding):
+ // round(x) = 10 ==> [9.5, 10.5)
+ // round(x) <= 10 ==> [-inf, 10.5)
+ // round(x) <= 10.1 === round(x) <= 10 => [-inf, 10.5)
+ // round(x) <= 9.9 === round(x) <= 9 => [-inf, 9.5)
+ // round(x) < 10 ==> round(x) <= 9 ==> [-inf, 9.5)
case GREATER:
+ if (value == roundTime(value)) {
+ codec.encodeLong(rangeUpper(value), lowerKey, 0);
+ range = type.getKeyRange(lowerKey, false, KeyRange.UNBOUND, false);
+ break;
+ }
+ //fallthrough intended
case GREATER_OR_EQUAL:
- codec.encodeLong((value + divBy - offset)/divBy*divBy, nextKey, 0);
- range = type.getKeyRange(nextKey, true, KeyRange.UNBOUND, false);
+ codec.encodeLong(rangeLower(value), lowerKey, 0);
+ range = type.getKeyRange(lowerKey, true, KeyRange.UNBOUND, false);
+ if (value <= roundTime(value)) {
+ //always true for ceil
+ codec.encodeLong(rangeLower(value), lowerKey, 0);
+ range = type.getKeyRange(lowerKey, true, KeyRange.UNBOUND, false);
+ } else {
+ //always true for floor, except when exact
+ codec.encodeLong(rangeUpper(value), lowerKey, 0);
+ range = type.getKeyRange(lowerKey, false, KeyRange.UNBOUND, false);
+ }
break;
case LESS:
+ if (value == roundTime(value)) {
+ codec.encodeLong(rangeLower(value), upperKey, 0);
+ range = type.getKeyRange(KeyRange.UNBOUND, false, upperKey, false);
+ break;
+ }
+ //fallthrough intended
case LESS_OR_EQUAL:
- codec.encodeLong((value + divBy - (1 -offset))/divBy*divBy, nextKey, 0);
- range = type.getKeyRange(KeyRange.UNBOUND, false, nextKey, false);
+ codec.encodeLong(rangeUpper(value), upperKey, 0);
+ range = type.getKeyRange(KeyRange.UNBOUND, false, upperKey, true);
+ if (value >= roundTime(value)) {
+ //always true for floor
+ codec.encodeLong(rangeUpper(value), upperKey, 0);
+ range = type.getKeyRange(KeyRange.UNBOUND, false, upperKey, true);
+ } else {
+ //always true for ceil, except when exact
+ codec.encodeLong(rangeLower(value), upperKey, 0);
+ range = type.getKeyRange(KeyRange.UNBOUND, false, upperKey, false);
+ }
break;
default:
return childPart.getKeyRange(op, rhs);
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundJodaDateExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundJodaDateExpression.java
index aa9ef070a8..0a8ee678cf 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundJodaDateExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundJodaDateExpression.java
@@ -25,7 +25,7 @@ import org.apache.phoenix.expression.Expression;
import org.apache.phoenix.schema.tuple.Tuple;
import org.apache.phoenix.schema.types.PDataType;
import org.joda.time.DateTime;
-import org.joda.time.chrono.ISOChronology;
+import org.joda.time.chrono.GJChronology;
/**
*
@@ -48,7 +48,7 @@ public abstract class RoundJodaDateExpression extends RoundDateExpression{
}
PDataType dataType = getDataType();
long time = dataType.getCodec().decodeLong(ptr, children.get(0).getSortOrder());
- DateTime dt = new DateTime(time, ISOChronology.getInstanceUTC());
+ DateTime dt = new DateTime(time, GJChronology.getInstanceUTC());
long value = roundDateTime(dt);
Date d = new Date(value);
byte[] byteValue = dataType.toBytes(d);
@@ -63,4 +63,10 @@ public abstract class RoundJodaDateExpression extends RoundDateExpression{
* @return Time in millis.
*/
public abstract long roundDateTime(DateTime dateTime);
+
+ @Override
+ // We need a working roundTime() for the RowKey pushdown logic.
+ public long roundTime(long time) {
+ return roundDateTime(new DateTime(time, GJChronology.getInstanceUTC()));
+ }
}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundMonthExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundMonthExpression.java
index 5ca21da5de..e333dcdd9e 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundMonthExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundMonthExpression.java
@@ -20,7 +20,10 @@ package org.apache.phoenix.expression.function;
import java.util.List;
import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.util.DateUtil;
import org.joda.time.DateTime;
+import org.joda.time.DateTimeFieldType;
+import org.joda.time.chrono.GJChronology;
/**
*
@@ -39,4 +42,22 @@ public class RoundMonthExpression extends RoundJodaDateExpression {
return dateTime.monthOfYear().roundHalfEvenCopy().getMillis();
}
+ @Override
+ public long rangeLower(long epochMs) {
+ // We're doing unnecessary conversions here, but this is not perf sensitive
+ DateTime rounded =
+ new DateTime(roundDateTime(new DateTime(epochMs, GJChronology.getInstanceUTC())),
+ GJChronology.getInstanceUTC());
+ DateTime prev = rounded.minusMonths(1);
+ return DateUtil.rangeJodaHalfEven(rounded, prev, DateTimeFieldType.monthOfYear());
+ }
+
+ @Override
+ public long rangeUpper(long epochMs) {
+ DateTime rounded =
+ new DateTime(roundDateTime(new DateTime(epochMs, GJChronology.getInstanceUTC())),
+ GJChronology.getInstanceUTC());
+ DateTime next = rounded.plusMonths(1);
+ return DateUtil.rangeJodaHalfEven(rounded, next, DateTimeFieldType.monthOfYear());
+ }
}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundWeekExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundWeekExpression.java
index 0572e19f7e..e66f580cf0 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundWeekExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundWeekExpression.java
@@ -20,7 +20,10 @@ package org.apache.phoenix.expression.function;
import java.util.List;
import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.util.DateUtil;
import org.joda.time.DateTime;
+import org.joda.time.DateTimeFieldType;
+import org.joda.time.chrono.GJChronology;
/**
*
@@ -38,4 +41,23 @@ public class RoundWeekExpression extends RoundJodaDateExpression {
public long roundDateTime(DateTime dateTime) {
return dateTime.weekOfWeekyear().roundHalfEvenCopy().getMillis();
}
+
+ @Override
+ public long rangeLower(long epochMs) {
+ // We're doing unnecessary conversions here, but this is NOT perf sensitive
+ DateTime rounded =
+ new DateTime(roundDateTime(new DateTime(epochMs, GJChronology.getInstanceUTC())),
+ GJChronology.getInstanceUTC());
+ DateTime prev = rounded.minusWeeks(1);
+ return DateUtil.rangeJodaHalfEven(rounded, prev, DateTimeFieldType.weekOfWeekyear());
+ }
+
+ @Override
+ public long rangeUpper(long epochMs) {
+ DateTime rounded =
+ new DateTime(roundDateTime(new DateTime(epochMs, GJChronology.getInstanceUTC())),
+ GJChronology.getInstanceUTC());
+ DateTime next = rounded.plusWeeks(1);
+ return DateUtil.rangeJodaHalfEven(rounded, next, DateTimeFieldType.weekOfWeekyear());
+ }
}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundYearExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundYearExpression.java
index b73d05ac76..8a99d7b20d 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundYearExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RoundYearExpression.java
@@ -20,7 +20,10 @@ package org.apache.phoenix.expression.function;
import java.util.List;
import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.util.DateUtil;
import org.joda.time.DateTime;
+import org.joda.time.DateTimeFieldType;
+import org.joda.time.chrono.GJChronology;
/**
*
@@ -39,4 +42,22 @@ public class RoundYearExpression extends RoundJodaDateExpression {
return dateTime.year().roundHalfEvenCopy().getMillis();
}
+ @Override
+ public long rangeLower(long epochMs) {
+ // We're doing unnecessary conversions here, but this is NOT perf sensitive
+ DateTime rounded =
+ new DateTime(roundDateTime(new DateTime(epochMs, GJChronology.getInstanceUTC())),
+ GJChronology.getInstanceUTC());
+ DateTime prev = rounded.minusYears(1);
+ return DateUtil.rangeJodaHalfEven(rounded, prev, DateTimeFieldType.year());
+ }
+
+ @Override
+ public long rangeUpper(long epochMs) {
+ DateTime rounded =
+ new DateTime(roundDateTime(new DateTime(epochMs, GJChronology.getInstanceUTC())),
+ GJChronology.getInstanceUTC());
+ DateTime next = rounded.plusYears(1);
+ return DateUtil.rangeJodaHalfEven(rounded, next, DateTimeFieldType.year());
+ }
}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/DateUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/DateUtil.java
index cc16eb6c30..9122f6195b 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/DateUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/DateUtil.java
@@ -40,16 +40,15 @@ import org.apache.phoenix.schema.types.PDate;
import org.apache.phoenix.schema.types.PTimestamp;
import org.apache.phoenix.schema.types.PUnsignedDate;
import org.apache.phoenix.schema.types.PUnsignedTimestamp;
+import org.apache.phoenix.thirdparty.com.google.common.collect.Lists;
import org.joda.time.DateTime;
+import org.joda.time.DateTimeFieldType;
import org.joda.time.DateTimeZone;
-import org.joda.time.chrono.ISOChronology;
import org.joda.time.chrono.GJChronology;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;
import org.joda.time.format.ISODateTimeFormat;
-import org.apache.phoenix.thirdparty.com.google.common.collect.Lists;
-
import edu.umd.cs.findbugs.annotations.NonNull;
@@ -155,7 +154,7 @@ public class DateUtil {
if (pattern == null || pattern.length() == 0) {
pattern = defaultPattern;
}
- if(defaultPattern.equals(pattern)) {
+ if (defaultPattern.equals(pattern)) {
return JulianDateFormatParserFactory.getParser(timeZone);
} else {
return new SimpleDateFormatParser(pattern, timeZone);
@@ -207,7 +206,7 @@ public class DateUtil {
String nanosStr = timestampValue.substring(period + 1);
if (nanosStr.length() > 9)
throw new IllegalDataException("nanos > 999999999 or < 0");
- if(nanosStr.length() > 3 ) {
+ if (nanosStr.length() > 3) {
int nanos = Integer.parseInt(nanosStr);
for (int i = 0; i < 9 - nanosStr.length(); i++) {
nanos *= 10;
@@ -347,4 +346,50 @@ public class DateUtil {
return formatter.getZone().toTimeZone();
}
}
+
+ public static long rangeJodaHalfEven(DateTime roundedDT, DateTime otherDT,
+ DateTimeFieldType type) {
+ // It's OK if this is slow, as it's only called O(1) times per query
+ //
+ // We need to reverse engineer what roundHalfEvenCopy() does
+ // and return the lower/upper (inclusive) range here
+ // Joda simply works on milliseconds between the floor and ceil values.
+ // We could avoid the period call for units less than a day, but this is not a perf
+ // critical function.
+ long roundedMs = roundedDT.getMillis();
+ long otherMs = otherDT.getMillis();
+ long midMs = (roundedMs + otherMs) / 2;
+ long remainder = (roundedMs + otherMs) % 2;
+ if (remainder == 0) {
+ int roundedUnits = roundedDT.get(type);
+ if (otherMs > roundedMs) {
+ // Upper range, other is bigger.
+ if ((roundedUnits & 1) == 0) {
+ // This unit is even, the next second is odd, so we get the mid point
+ return midMs;
+ } else {
+ // This unit is odd, the next second is even and takes the midpoint.
+ return midMs - 1;
+ }
+ } else {
+ // Lower range, other is smaller.
+ if ((roundedUnits & 1) == 0) {
+ // This unit is even, the next second is odd, so we get the mid point
+ return midMs;
+ } else {
+ // This unit is odd, the next second is even and takes the midpoint.
+ return midMs + 1;
+ }
+ }
+ } else {
+ // probably never happens
+ if (otherMs > roundedMs) {
+ // Upper range, return the rounded down value
+ return midMs;
+ } else {
+ // Lower range, the mid value belongs to the previous unit.
+ return midMs + 1;
+ }
+ }
+ }
}
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java
index 0b9c1ee76b..e9aca1a3f5 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java
@@ -409,10 +409,11 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
public void testEqualRound() throws Exception {
String inst = "a";
String host = "b";
- Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
- Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
+ Date roundDate = DateUtil.parseDate("2012-01-01 00:00:00");
+ Date startDate = DateUtil.parseDate("2011-12-31 12:00:00");
+ Date endDate = DateUtil.parseDate("2012-01-01 12:00:00"); //Hbase normalizes scans to left closed
String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')=?";
- List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+ List<Object> binds = Arrays.<Object>asList(inst,host,roundDate);
Scan scan = compileStatement(query, binds).getScan();
assertNull(scan.getFilter());
@@ -420,10 +421,12 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
PDate.INSTANCE.toBytes(startDate));
assertArrayEquals(startRow, scan.getStartRow());
+ assertTrue(scan.includeStartRow());
byte[] stopRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
PDate.INSTANCE.toBytes(endDate));
assertArrayEquals(stopRow, scan.getStopRow());
+ assertFalse(scan.includeStopRow());
}
@Test
@@ -441,17 +444,18 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
public void testBoundaryGreaterThanRound() throws Exception {
String inst = "a";
String host = "b";
- Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
- Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
+ Date roundDate = DateUtil.parseDate("2012-01-01 00:00:00");
+ Date startDate = DateUtil.parseDate("2012-01-01 12:00:00");
String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')>?";
- List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+ List<Object> binds = Arrays.<Object>asList(inst,host,roundDate);
Scan scan = compileStatement(query, binds).getScan();
assertNull(scan.getFilter());
byte[] startRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
- PDate.INSTANCE.toBytes(endDate));
+ PDate.INSTANCE.toBytes(startDate));
assertArrayEquals(startRow, scan.getStartRow());
+ assertTrue(scan.includeStartRow());
byte[] stopRow = ByteUtil.nextKey(ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY));
assertArrayEquals(stopRow, scan.getStopRow());
@@ -462,7 +466,7 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
String inst = "a";
String host = "b";
Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
- Date endDate = DateUtil.parseDate("2012-01-01 00:00:00");
+ Date startDateHalfRange = DateUtil.parseDate("2011-12-31 12:00:00.000");
String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')>=?";
List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
Scan scan = compileStatement(query, binds).getScan();
@@ -470,7 +474,7 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
byte[] startRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
- PDate.INSTANCE.toBytes(endDate));
+ PDate.INSTANCE.toBytes(startDateHalfRange));
assertArrayEquals(startRow, scan.getStartRow());
byte[] stopRow = ByteUtil.nextKey(ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY));
@@ -481,17 +485,19 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
public void testGreaterThanRound() throws Exception {
String inst = "a";
String host = "b";
- Date startDate = DateUtil.parseDate("2012-01-01 01:00:00");
- Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
+ Date roundDate = DateUtil.parseDate("2012-01-01 01:00:00");
+ Date startDate = DateUtil.parseDate("2012-01-01 12:00:00"); //Hbase normalizes scans to left closed
String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')>?";
- List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+ List<Object> binds = Arrays.<Object>asList(inst,host,roundDate);
+
Scan scan = compileStatement(query, binds).getScan();
assertNull(scan.getFilter());
byte[] startRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
- PDate.INSTANCE.toBytes(endDate));
+ PDate.INSTANCE.toBytes(startDate));
assertArrayEquals(startRow, scan.getStartRow());
+ assertTrue(scan.includeStartRow());
byte[] stopRow = ByteUtil.nextKey(ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY));
assertArrayEquals(stopRow, scan.getStopRow());
@@ -501,10 +507,10 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
public void testLessThanRound() throws Exception {
String inst = "a";
String host = "b";
- Date startDate = DateUtil.parseDate("2012-01-01 01:00:00");
- Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
+ Date roundDate = DateUtil.parseDate("2012-01-01 01:00:00");
+ Date endDate = DateUtil.parseDate("2012-01-01 12:00:00"); //Hbase normalizes scans to left closed
String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')<?";
- List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+ List<Object> binds = Arrays.<Object>asList(inst,host,roundDate);
Scan scan = compileStatement(query, binds).getScan();
assertNull(scan.getFilter());
@@ -515,16 +521,18 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
PDate.INSTANCE.toBytes(endDate));
assertArrayEquals(stopRow, scan.getStopRow());
+ assertTrue(scan.includeStartRow());
}
@Test
public void testBoundaryLessThanRound() throws Exception {
String inst = "a";
String host = "b";
- Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
- Date endDate = DateUtil.parseDate("2012-01-01 00:00:00");
+ Date roundDate = DateUtil.parseDate("2012-01-01 00:00:00");
+ Date endDate = DateUtil.parseDate("2011-12-31 12:00:00"); //Hbase normalizes scans to left closed
String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')<?";
- List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+ List<Object> binds = Arrays.<Object>asList(inst,host,roundDate);
+
Scan scan = compileStatement(query, binds).getScan();
assertNull(scan.getFilter());
@@ -535,16 +543,17 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
PDate.INSTANCE.toBytes(endDate));
assertArrayEquals(stopRow, scan.getStopRow());
+ assertFalse(scan.includeStopRow());
}
@Test
public void testLessThanOrEqualRound() throws Exception {
String inst = "a";
String host = "b";
- Date startDate = DateUtil.parseDate("2012-01-01 01:00:00");
- Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
+ Date roundDate = DateUtil.parseDate("2012-01-01 01:00:00");
+ Date endDate = DateUtil.parseDate("2012-01-01 12:00:00"); //Hbase normalizes scans to left closed
String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')<=?";
- List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+ List<Object> binds = Arrays.<Object>asList(inst,host,roundDate);
Scan scan = compileStatement(query, binds).getScan();
assertNull(scan.getFilter());
@@ -555,19 +564,147 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
PDate.INSTANCE.toBytes(endDate));
assertArrayEquals(stopRow, scan.getStopRow());
+ assertFalse(scan.includeStopRow());
+ }
+
+ @Test
+ public void testLessThanOrEqualRound2() throws Exception {
+ String inst = "a";
+ String host = "b";
+ Date roundDate = DateUtil.parseDate("2011-12-31 23:00:00");
+ Date endDate = DateUtil.parseDate("2011-12-31 12:00:00"); //Hbase normalizes scans to left closed
+ String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')<=?";
+ List<Object> binds = Arrays.<Object>asList(inst,host,roundDate);
+ Scan scan = compileStatement(query, binds).getScan();
+ assertNull(scan.getFilter());
+
+ byte[] startRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host)/*,QueryConstants.SEPARATOR_BYTE_ARRAY*/);
+ assertArrayEquals(startRow, scan.getStartRow());
+ byte[] stopRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PDate.INSTANCE.toBytes(endDate));
+ assertArrayEquals(stopRow, scan.getStopRow());
+ assertFalse(scan.includeStopRow());
}
@Test
public void testBoundaryLessThanOrEqualRound() throws Exception {
String inst = "a";
String host = "b";
- Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
- Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
+ Date roundDate = DateUtil.parseDate("2012-01-01 00:00:00");
+ Date endDate = DateUtil.parseDate("2012-01-01 12:00:00"); //Hbase normalizes scans to left closed
String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')<=?";
- List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+ List<Object> binds = Arrays.<Object>asList(inst,host,roundDate);
+ Scan scan = compileStatement(query, binds).getScan();
+
+ assertNull(scan.getFilter());
+ byte[] startRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host)/*,QueryConstants.SEPARATOR_BYTE_ARRAY*/);
+ assertArrayEquals(startRow, scan.getStartRow());
+ assertTrue(scan.includeStartRow());
+ byte[] stopRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PDate.INSTANCE.toBytes(endDate));
+ assertArrayEquals(stopRow, scan.getStopRow());
+ assertFalse(scan.includeStopRow());
+ }
+
+ @Test
+ public void testLessThanOrEqualFloor() throws Exception {
+ String inst = "a";
+ String host = "b";
+ Date floorDate = DateUtil.parseDate("2012-01-01 01:00:00");
+ Date endDate = DateUtil.parseDate("2012-01-02 00:00:00"); //Hbase normalizes scans to left closed
+ String query = "select * from ptsdb where inst=? and host=? and floor(date,'DAY')<=?";
+ List<Object> binds = Arrays.<Object>asList(inst,host,floorDate);
+ Scan scan = compileStatement(query, binds).getScan();
+ assertNull(scan.getFilter());
+
+ byte[] startRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host)/*,QueryConstants.SEPARATOR_BYTE_ARRAY*/);
+ assertArrayEquals(startRow, scan.getStartRow());
+ byte[] stopRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PDate.INSTANCE.toBytes(endDate));
+ assertArrayEquals(stopRow, scan.getStopRow());
+ assertFalse(scan.includeStopRow());
+ }
+
+ @Test
+ public void testLessThanOrEqualFloorBoundary() throws Exception {
+ String inst = "a";
+ String host = "b";
+ Date floorDate = DateUtil.parseDate("2012-01-01 00:00:00");
+ Date endDate = DateUtil.parseDate("2012-01-02 00:00:00"); //Hbase normalizes scans to left closed
+ String query = "select * from ptsdb where inst=? and host=? and floor(date,'DAY')<=?";
+ List<Object> binds = Arrays.<Object>asList(inst,host,floorDate);
+ Scan scan = compileStatement(query, binds).getScan();
+ assertNull(scan.getFilter());
+
+ byte[] startRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host)/*,QueryConstants.SEPARATOR_BYTE_ARRAY*/);
+ assertArrayEquals(startRow, scan.getStartRow());
+ byte[] stopRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PDate.INSTANCE.toBytes(endDate));
+ assertArrayEquals(stopRow, scan.getStopRow());
+ assertFalse(scan.includeStopRow());
+ }
+
+ @Test
+ public void testGreaterThanOrEqualFloor() throws Exception {
+ String inst = "a";
+ String host = "b";
+ Date floorDate = DateUtil.parseDate("2012-01-01 01:00:00");
+ Date startDate = DateUtil.parseDate("2012-01-02 00:00:00");
+ String query = "select * from ptsdb where inst=? and host=? and floor(date,'DAY')>=?";
+ List<Object> binds = Arrays.<Object>asList(inst,host,floorDate);
Scan scan = compileStatement(query, binds).getScan();
+ assertNull(scan.getFilter());
+
+ byte[] startRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PDate.INSTANCE.toBytes(startDate));
+ assertArrayEquals(startRow, scan.getStartRow());
+ byte[] stopRow = ByteUtil.nextKey(ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY));
+ assertArrayEquals(stopRow, scan.getStopRow());
+ assertFalse(scan.includeStopRow());
+ }
+ @Test
+ public void testGreaterThanOrEqualFloorBoundary() throws Exception {
+ String inst = "a";
+ String host = "b";
+ Date floorDate = DateUtil.parseDate("2012-01-01 00:00:00");
+ Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
+ String query = "select * from ptsdb where inst=? and host=? and floor(date,'DAY')>=?";
+ List<Object> binds = Arrays.<Object>asList(inst,host,floorDate);
+ Scan scan = compileStatement(query, binds).getScan();
assertNull(scan.getFilter());
+
+ byte[] startRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PDate.INSTANCE.toBytes(startDate));
+ assertArrayEquals(startRow, scan.getStartRow());
+ byte[] stopRow = ByteUtil.nextKey(ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY));
+ assertArrayEquals(stopRow, scan.getStopRow());
+ assertFalse(scan.includeStopRow());
+ }
+
+ @Test
+ public void testLessThanOrEqualCeil() throws Exception {
+ String inst = "a";
+ String host = "b";
+ Date ceilDate = DateUtil.parseDate("2012-01-01 01:00:00");
+ Date endDate = DateUtil.parseDate("2012-01-01 00:00:00.001"); //Hbase normalizes scans to left closed
+ String query = "select * from ptsdb where inst=? and host=? and ceil(date,'DAY')<=?";
+ List<Object> binds = Arrays.<Object>asList(inst,host,ceilDate);
+ Scan scan = compileStatement(query, binds).getScan();
+ assertNull(scan.getFilter());
+
byte[] startRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
PVarchar.INSTANCE.toBytes(host)/*,QueryConstants.SEPARATOR_BYTE_ARRAY*/);
assertArrayEquals(startRow, scan.getStartRow());
@@ -575,6 +712,70 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
PDate.INSTANCE.toBytes(endDate));
assertArrayEquals(stopRow, scan.getStopRow());
+ assertFalse(scan.includeStopRow());
+ }
+
+ @Test
+ public void testLessThanOrEqualCeilBoundary() throws Exception {
+ String inst = "a";
+ String host = "b";
+ Date ceilDate = DateUtil.parseDate("2012-01-01 00:00:00");
+ Date endDate = DateUtil.parseDate("2012-01-01 00:00:00.001"); //Hbase normalizes scans to left closed
+ String query = "select * from ptsdb where inst=? and host=? and ceil(date,'DAY')<=?";
+ List<Object> binds = Arrays.<Object>asList(inst,host,ceilDate);
+ Scan scan = compileStatement(query, binds).getScan();
+ assertNull(scan.getFilter());
+
+ byte[] startRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host)/*,QueryConstants.SEPARATOR_BYTE_ARRAY*/);
+ assertArrayEquals(startRow, scan.getStartRow());
+ byte[] stopRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PDate.INSTANCE.toBytes(endDate));
+ assertArrayEquals(stopRow, scan.getStopRow());
+ assertFalse(scan.includeStopRow());
+ }
+
+ @Test
+ public void testGreaterThanOrEqualCeil() throws Exception {
+ String inst = "a";
+ String host = "b";
+ Date ceilDate = DateUtil.parseDate("2012-01-01 01:00:00");
+ Date startDate = DateUtil.parseDate("2012-01-01 00:00:00.001");
+ String query = "select * from ptsdb where inst=? and host=? and ceil(date,'DAY')>=?";
+ List<Object> binds = Arrays.<Object>asList(inst,host,ceilDate);
+ Scan scan = compileStatement(query, binds).getScan();
+ assertNull(scan.getFilter());
+
+ byte[] startRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PDate.INSTANCE.toBytes(startDate));
+ assertArrayEquals(startRow, scan.getStartRow());
+ byte[] stopRow = ByteUtil.nextKey(ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY));
+ assertArrayEquals(stopRow, scan.getStopRow());
+ assertFalse(scan.includeStopRow());
+ }
+
+ @Test
+ public void testGreaterThanOrEqualCeilBoundary() throws Exception {
+ String inst = "a";
+ String host = "b";
+ Date ceilDate = DateUtil.parseDate("2012-01-01 00:00:00");
+ Date startDate = DateUtil.parseDate("2011-12-31 00:00:00.001");
+ String query = "select * from ptsdb where inst=? and host=? and ceil(date,'DAY')>=?";
+ List<Object> binds = Arrays.<Object>asList(inst,host,ceilDate);
+ Scan scan = compileStatement(query, binds).getScan();
+ assertNull(scan.getFilter());
+
+ byte[] startRow = ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PDate.INSTANCE.toBytes(startDate));
+ assertArrayEquals(startRow, scan.getStartRow());
+ byte[] stopRow = ByteUtil.nextKey(ByteUtil.concat(PVarchar.INSTANCE.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+ PVarchar.INSTANCE.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY));
+ assertArrayEquals(stopRow, scan.getStopRow());
+ assertFalse(scan.includeStopRow());
}
@Test
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/RoundFloorCeilExpressionsTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/RoundFloorCeilExpressionsTest.java
index e652c69c25..4c81ab3fd9 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/expression/RoundFloorCeilExpressionsTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/RoundFloorCeilExpressionsTest.java
@@ -20,6 +20,7 @@ package org.apache.phoenix.expression;
import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -37,10 +38,19 @@ import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.phoenix.compile.KeyPart;
import org.apache.phoenix.expression.function.CeilDateExpression;
import org.apache.phoenix.expression.function.CeilDecimalExpression;
+import org.apache.phoenix.expression.function.CeilMonthExpression;
+import org.apache.phoenix.expression.function.CeilWeekExpression;
+import org.apache.phoenix.expression.function.CeilYearExpression;
import org.apache.phoenix.expression.function.FloorDateExpression;
import org.apache.phoenix.expression.function.FloorDecimalExpression;
+import org.apache.phoenix.expression.function.FloorMonthExpression;
+import org.apache.phoenix.expression.function.FloorWeekExpression;
+import org.apache.phoenix.expression.function.FloorYearExpression;
import org.apache.phoenix.expression.function.RoundDateExpression;
import org.apache.phoenix.expression.function.RoundDecimalExpression;
+import org.apache.phoenix.expression.function.RoundMonthExpression;
+import org.apache.phoenix.expression.function.RoundWeekExpression;
+import org.apache.phoenix.expression.function.RoundYearExpression;
import org.apache.phoenix.expression.function.ScalarFunction;
import org.apache.phoenix.expression.function.TimeUnit;
import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr;
@@ -58,6 +68,8 @@ import org.apache.phoenix.schema.types.PInteger;
import org.apache.phoenix.schema.types.PVarchar;
import org.apache.phoenix.util.DateUtil;
import org.apache.phoenix.util.PropertiesUtil;
+import org.joda.time.Chronology;
+import org.joda.time.chrono.GJChronology;
import org.junit.Test;
/**
@@ -70,6 +82,26 @@ import org.junit.Test;
*/
public class RoundFloorCeilExpressionsTest extends BaseConnectionlessQueryTest {
+
+ private static long HALF_SEC = 500;
+ private static long SEC = 2 * HALF_SEC;
+
+ private static long HALF_MIN = 30 * 1000;
+ private static long MIN = 2 * HALF_MIN;
+
+ private static long HALF_HOUR = 30 * 60 * 1000;
+ private static long HOUR = 2 * HALF_HOUR;
+
+ private static long HALF_DAY = 12 * 60 * 60 * 1000;
+ private static long DAY = 2 * HALF_DAY;
+
+ private static long HALF_WEEK = 7 * 12 * 60 * 60 * 1000;
+ private static long WEEK = 2 * HALF_WEEK;
+
+ // Note that without the "l" the integer arithmetic below would overflow
+ private static long HALF_YEAR = 365l * 12 * 60 * 60 * 1000;
+ private static long YEAR = 2l * HALF_YEAR;
+
// Decimal Expression Tests
@Test
@@ -688,4 +720,1207 @@ public class RoundFloorCeilExpressionsTest extends BaseConnectionlessQueryTest {
Date resultDate = (Date)result;
assertEquals(DateUtil.parseDate("2016-01-04 00:00:00"), resultDate);
}
+
+ private RoundDateExpression getRoundMsExpression(String s, TimeUnit u, int m) throws SQLException {
+ return (RoundDateExpression)RoundDateExpression.create(LiteralExpression.newConstant(s), u, m );
+ }
+
+ // The three tests below are backported from PHOENIX-5066.
+ // When PHOENIX-5066 lands, these can be removed as redundant.
+
+ @Test
+ public void testRoundingGMT() throws SQLException {
+ // We operate on Instants for time units up to Days, simply counting millis
+
+ RoundDateExpression oddWholeSecondExp =
+ getRoundMsExpression("2022-11-11 11:11:11", TimeUnit.SECOND, 1);
+ java.sql.Timestamp oddWholeSecond =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:11:11").getTime());
+ long lowerBoundaryOddWholeSecond = oddWholeSecond.getTime() - HALF_SEC;
+ long upperBoundaryOddWholeSecond = oddWholeSecond.getTime() + HALF_SEC - 1;
+ assertEquals(lowerBoundaryOddWholeSecond,
+ oddWholeSecondExp.rangeLower(oddWholeSecond.getTime()));
+ assertEquals(upperBoundaryOddWholeSecond,
+ oddWholeSecondExp.rangeUpper(oddWholeSecond.getTime()));
+ assertEquals(oddWholeSecond,
+ new java.sql.Timestamp(oddWholeSecondExp.roundTime(lowerBoundaryOddWholeSecond)));
+ assertNotEquals(oddWholeSecond,
+ new java.sql.Timestamp(oddWholeSecondExp.roundTime(lowerBoundaryOddWholeSecond - 1)));
+ assertEquals(oddWholeSecond,
+ new java.sql.Timestamp(oddWholeSecondExp.roundTime(upperBoundaryOddWholeSecond)));
+ assertNotEquals(oddWholeSecond,
+ new java.sql.Timestamp(oddWholeSecondExp.roundTime(upperBoundaryOddWholeSecond + 1)));
+
+ // 10 sec range
+ RoundDateExpression oddWholeSecondRound10Exp =
+ getRoundMsExpression("2022-11-11 11:11:10", TimeUnit.SECOND, 10);
+ java.sql.Timestamp oddWholeSecondRound10 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:11:10").getTime());
+ long lowerBoundaryOddWholeSecondRound10 = oddWholeSecondRound10.getTime() - 5 * SEC;
+ long upperBoundaryOddWholeSecondRound10 = oddWholeSecondRound10.getTime() + 5 * SEC - 1;
+ assertEquals(lowerBoundaryOddWholeSecondRound10,
+ oddWholeSecondRound10Exp.rangeLower(oddWholeSecond.getTime()));
+ assertEquals(upperBoundaryOddWholeSecondRound10,
+ oddWholeSecondRound10Exp.rangeUpper(oddWholeSecond.getTime()));
+ assertEquals(oddWholeSecondRound10, new java.sql.Timestamp(
+ oddWholeSecondRound10Exp.roundTime(lowerBoundaryOddWholeSecondRound10)));
+ assertNotEquals(oddWholeSecondRound10, new java.sql.Timestamp(
+ oddWholeSecondRound10Exp.roundTime(lowerBoundaryOddWholeSecondRound10 - 1)));
+ assertEquals(oddWholeSecondRound10, new java.sql.Timestamp(
+ oddWholeSecondRound10Exp.roundTime(upperBoundaryOddWholeSecondRound10)));
+ assertNotEquals(oddWholeSecondRound10, new java.sql.Timestamp(
+ oddWholeSecondRound10Exp.roundTime(upperBoundaryOddWholeSecondRound10 + 1)));
+
+ // 15 sec range
+ RoundDateExpression oddWholeSecondRound15Exp =
+ getRoundMsExpression("2022-11-11 11:11:15", TimeUnit.SECOND, 15);
+ java.sql.Timestamp oddWholeSecondRound15 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:11:15").getTime());
+ long lowerBoundaryOddWholeSecondRound15 = oddWholeSecondRound15.getTime() - 15 * HALF_SEC;
+ long upperBoundaryOddWholeSecondRound15 =
+ oddWholeSecondRound15.getTime() + 15 * HALF_SEC - 1;
+ assertEquals(lowerBoundaryOddWholeSecondRound15,
+ oddWholeSecondRound15Exp.rangeLower(oddWholeSecond.getTime()));
+ assertEquals(upperBoundaryOddWholeSecondRound15,
+ oddWholeSecondRound15Exp.rangeUpper(oddWholeSecond.getTime()));
+ assertEquals(oddWholeSecondRound15, new java.sql.Timestamp(
+ oddWholeSecondRound15Exp.roundTime(lowerBoundaryOddWholeSecondRound15)));
+ assertNotEquals(oddWholeSecondRound15, new java.sql.Timestamp(
+ oddWholeSecondRound15Exp.roundTime(lowerBoundaryOddWholeSecondRound15 - 1)));
+ assertEquals(oddWholeSecondRound15, new java.sql.Timestamp(
+ oddWholeSecondRound15Exp.roundTime(upperBoundaryOddWholeSecondRound15)));
+ assertNotEquals(oddWholeSecondRound15, new java.sql.Timestamp(
+ oddWholeSecondRound15Exp.roundTime(upperBoundaryOddWholeSecondRound15 + 1)));
+
+ RoundDateExpression evenWholeSecondExp =
+ getRoundMsExpression("2022-11-11 11:11:12", TimeUnit.SECOND, 1);
+ java.sql.Timestamp evenWholeSecond =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:11:12").getTime());
+ long lowerBoundaryEvenWholeSecond = evenWholeSecond.getTime() - HALF_SEC;
+ long upperBoundaryEvenWholeSecond = evenWholeSecond.getTime() + HALF_SEC - 1;
+ assertEquals(lowerBoundaryEvenWholeSecond,
+ evenWholeSecondExp.rangeLower(evenWholeSecond.getTime()));
+ assertEquals(upperBoundaryEvenWholeSecond,
+ evenWholeSecondExp.rangeUpper(evenWholeSecond.getTime()));
+ assertEquals(evenWholeSecond,
+ new java.sql.Timestamp(evenWholeSecondExp.roundTime(lowerBoundaryEvenWholeSecond)));
+ assertNotEquals(evenWholeSecond,
+ new java.sql.Timestamp(evenWholeSecondExp.roundTime(lowerBoundaryEvenWholeSecond - 1)));
+ assertEquals(evenWholeSecond,
+ new java.sql.Timestamp(evenWholeSecondExp.roundTime(upperBoundaryEvenWholeSecond)));
+ assertNotEquals(evenWholeSecond,
+ new java.sql.Timestamp(evenWholeSecondExp.roundTime(upperBoundaryEvenWholeSecond + 1)));
+
+ RoundDateExpression oddWholeMinuteExp =
+ getRoundMsExpression("2022-11-11 11:11:0", TimeUnit.MINUTE, 1);
+ java.sql.Timestamp oddWholeMinute =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:11:0").getTime());
+ long lowerBoundaryOddWholeMinute = oddWholeMinute.getTime() - HALF_MIN;
+ long upperBoundaryOddWholeMinute = oddWholeMinute.getTime() + HALF_MIN - 1;
+ assertEquals(lowerBoundaryOddWholeMinute,
+ oddWholeMinuteExp.rangeLower(oddWholeMinute.getTime()));
+ assertEquals(upperBoundaryOddWholeMinute,
+ oddWholeMinuteExp.rangeUpper(oddWholeMinute.getTime()));
+ assertEquals(oddWholeMinute,
+ new java.sql.Timestamp(oddWholeMinuteExp.roundTime(lowerBoundaryOddWholeMinute)));
+ assertNotEquals(oddWholeMinute,
+ new java.sql.Timestamp(oddWholeMinuteExp.roundTime(lowerBoundaryOddWholeMinute - 1)));
+ assertEquals(oddWholeMinute,
+ new java.sql.Timestamp(oddWholeMinuteExp.roundTime(upperBoundaryOddWholeMinute)));
+ assertNotEquals(oddWholeMinute,
+ new java.sql.Timestamp(oddWholeMinuteExp.roundTime(upperBoundaryOddWholeMinute + 1)));
+
+ RoundDateExpression oddWholeMinuteRound20Exp =
+ getRoundMsExpression("2022-11-11 11:20:0", TimeUnit.MINUTE, 20);
+ java.sql.Timestamp oddWholeMinuteRound20 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:20:0").getTime());
+ long lowerBoundaryOddWholeMinute20 = oddWholeMinuteRound20.getTime() - 10 * MIN;
+ long upperBoundaryOddWholeMinute20 = oddWholeMinuteRound20.getTime() + 10 * MIN - 1;
+ assertEquals(lowerBoundaryOddWholeMinute20,
+ oddWholeMinuteRound20Exp.rangeLower(oddWholeMinute.getTime()));
+ assertEquals(upperBoundaryOddWholeMinute20,
+ oddWholeMinuteRound20Exp.rangeUpper(oddWholeMinute.getTime()));
+ assertEquals(oddWholeMinuteRound20, new java.sql.Timestamp(
+ oddWholeMinuteRound20Exp.roundTime(lowerBoundaryOddWholeMinute20)));
+ assertNotEquals(oddWholeMinuteRound20, new java.sql.Timestamp(
+ oddWholeMinuteRound20Exp.roundTime(lowerBoundaryOddWholeMinute20 - 1)));
+ assertEquals(oddWholeMinuteRound20, new java.sql.Timestamp(
+ oddWholeMinuteRound20Exp.roundTime(upperBoundaryOddWholeMinute20)));
+ assertNotEquals(oddWholeMinuteRound20, new java.sql.Timestamp(
+ oddWholeMinuteRound20Exp.roundTime(upperBoundaryOddWholeMinute20 + 1)));
+
+ // Minutes since epoch, don't expect the rounded value to be "round"
+
+ RoundDateExpression oddWholeMinuteRound17Exp =
+ getRoundMsExpression("2022-11-11 11:12:0", TimeUnit.MINUTE, 17);
+ java.sql.Timestamp oddWholeMinuteRound17 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:12:00").getTime());
+ long lowerBoundaryOddWholeMinute17 = oddWholeMinuteRound17.getTime() - 17 * HALF_MIN;
+ long upperBoundaryOddWholeMinute17 = oddWholeMinuteRound17.getTime() + 17 * HALF_MIN - 1;
+ assertEquals(lowerBoundaryOddWholeMinute17,
+ oddWholeMinuteRound17Exp.rangeLower(oddWholeMinute.getTime()));
+ assertEquals(upperBoundaryOddWholeMinute17,
+ oddWholeMinuteRound17Exp.rangeUpper(oddWholeMinute.getTime()));
+ assertEquals(oddWholeMinuteRound17, new java.sql.Timestamp(
+ oddWholeMinuteRound17Exp.roundTime(lowerBoundaryOddWholeMinute17)));
+ assertNotEquals(oddWholeMinuteRound17, new java.sql.Timestamp(
+ oddWholeMinuteRound17Exp.roundTime(lowerBoundaryOddWholeMinute17 - 1)));
+ assertEquals(oddWholeMinuteRound17, new java.sql.Timestamp(
+ oddWholeMinuteRound17Exp.roundTime(upperBoundaryOddWholeMinute17)));
+ assertNotEquals(oddWholeMinuteRound17, new java.sql.Timestamp(
+ oddWholeMinuteRound17Exp.roundTime(upperBoundaryOddWholeMinute17 + 1)));
+
+ RoundDateExpression evenWholeMinuteExp =
+ getRoundMsExpression("2022-11-11 11:12:0", TimeUnit.MINUTE, 1);
+ java.sql.Timestamp evenWholeMinute =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:12:0").getTime());
+ long lowerBoundaryEvenWholeMinute = evenWholeMinute.getTime() - HALF_MIN;
+ long upperBoundaryEvenWholeMinute = evenWholeMinute.getTime() + HALF_MIN - 1;
+ assertEquals(lowerBoundaryEvenWholeMinute,
+ evenWholeMinuteExp.rangeLower(evenWholeMinute.getTime()));
+ assertEquals(upperBoundaryEvenWholeMinute,
+ evenWholeMinuteExp.rangeUpper(evenWholeMinute.getTime()));
+ assertEquals(evenWholeMinute,
+ new java.sql.Timestamp(evenWholeMinuteExp.roundTime(lowerBoundaryEvenWholeMinute)));
+ assertNotEquals(evenWholeMinute,
+ new java.sql.Timestamp(evenWholeMinuteExp.roundTime(lowerBoundaryEvenWholeMinute - 1)));
+ assertEquals(evenWholeMinute,
+ new java.sql.Timestamp(evenWholeMinuteExp.roundTime(upperBoundaryEvenWholeMinute)));
+ assertNotEquals(evenWholeMinute,
+ new java.sql.Timestamp(evenWholeMinuteExp.roundTime(upperBoundaryEvenWholeMinute + 1)));
+
+ RoundDateExpression oddWholeHourExp =
+ getRoundMsExpression("2022-11-11 11:0:0", TimeUnit.HOUR, 1);
+ java.sql.Timestamp oddWholeHour =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:0:0").getTime());
+ long lowerBoundaryOddWholeHour = oddWholeHour.getTime() - HALF_HOUR;
+ long upperBoundaryOddWholeHour = oddWholeHour.getTime() + HALF_HOUR - 1;
+ assertEquals(lowerBoundaryOddWholeHour, oddWholeHourExp.rangeLower(oddWholeHour.getTime()));
+ assertEquals(upperBoundaryOddWholeHour, oddWholeHourExp.rangeUpper(oddWholeHour.getTime()));
+ assertEquals(oddWholeHour,
+ new java.sql.Timestamp(oddWholeHourExp.roundTime(lowerBoundaryOddWholeHour)));
+ assertNotEquals(oddWholeHour,
+ new java.sql.Timestamp(oddWholeHourExp.roundTime(lowerBoundaryOddWholeHour - 1)));
+ assertEquals(oddWholeHour,
+ new java.sql.Timestamp(oddWholeHourExp.roundTime(upperBoundaryOddWholeHour)));
+ assertNotEquals(oddWholeHour,
+ new java.sql.Timestamp(oddWholeHourExp.roundTime(upperBoundaryOddWholeHour + 1)));
+
+ // Not rounding to hourOfDay
+ RoundDateExpression oddWholeHour10Exp =
+ getRoundMsExpression("2022-11-11 12:0:0", TimeUnit.HOUR, 10);
+ java.sql.Timestamp oddWholeHour10 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 12:0:0").getTime());
+ long lowerBoundaryOddWholeHour10 = oddWholeHour10.getTime() - HALF_HOUR * 10;
+ long upperBoundaryOddWholeHour10 = oddWholeHour10.getTime() + HALF_HOUR * 10 - 1;
+ assertEquals(lowerBoundaryOddWholeHour10,
+ oddWholeHour10Exp.rangeLower(oddWholeHour.getTime()));
+ assertEquals(upperBoundaryOddWholeHour10,
+ oddWholeHour10Exp.rangeUpper(oddWholeHour.getTime()));
+ assertEquals(oddWholeHour10,
+ new java.sql.Timestamp(oddWholeHour10Exp.roundTime(lowerBoundaryOddWholeHour10)));
+ assertNotEquals(oddWholeHour10,
+ new java.sql.Timestamp(oddWholeHour10Exp.roundTime(lowerBoundaryOddWholeHour10 - 1)));
+ assertEquals(oddWholeHour10,
+ new java.sql.Timestamp(oddWholeHour10Exp.roundTime(upperBoundaryOddWholeHour10)));
+ assertNotEquals(oddWholeHour10,
+ new java.sql.Timestamp(oddWholeHour10Exp.roundTime(upperBoundaryOddWholeHour10 + 1)));
+
+ // Not rounding to hourOfDay
+ RoundDateExpression oddWholeHour11Exp =
+ getRoundMsExpression("2022-11-11 07:0:0", TimeUnit.HOUR, 11);
+ java.sql.Timestamp oddWholeHour11 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 07:0:0").getTime());
+ long lowerBoundaryOddWholeHour11 = oddWholeHour11.getTime() - HALF_HOUR * 11;
+ long upperBoundaryOddWholeHour11 = oddWholeHour11.getTime() + HALF_HOUR * 11 - 1;
+ assertEquals(lowerBoundaryOddWholeHour11,
+ oddWholeHour11Exp.rangeLower(oddWholeHour.getTime()));
+ assertEquals(upperBoundaryOddWholeHour11,
+ oddWholeHour11Exp.rangeUpper(oddWholeHour.getTime()));
+ assertEquals(oddWholeHour11,
+ new java.sql.Timestamp(oddWholeHour11Exp.roundTime(lowerBoundaryOddWholeHour11)));
+ assertNotEquals(oddWholeHour11,
+ new java.sql.Timestamp(oddWholeHour11Exp.roundTime(lowerBoundaryOddWholeHour11 - 1)));
+ assertEquals(oddWholeHour11,
+ new java.sql.Timestamp(oddWholeHour11Exp.roundTime(upperBoundaryOddWholeHour11)));
+ assertNotEquals(oddWholeHour11,
+ new java.sql.Timestamp(oddWholeHour11Exp.roundTime(upperBoundaryOddWholeHour11 + 1)));
+
+ RoundDateExpression evenwholeHourExp =
+ getRoundMsExpression("2022-11-11 12:0:0", TimeUnit.HOUR, 1);
+ java.sql.Timestamp evenwholeHour =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 12:0:0").getTime());
+ long lowerBoundaryEvenWholeHour = evenwholeHour.getTime() - HALF_HOUR;
+ long upperBoundaryEvenWholeHour = evenwholeHour.getTime() + HALF_HOUR - 1;
+ assertEquals(lowerBoundaryEvenWholeHour,
+ evenwholeHourExp.rangeLower(evenwholeHour.getTime()));
+ assertEquals(upperBoundaryEvenWholeHour,
+ evenwholeHourExp.rangeUpper(evenwholeHour.getTime()));
+ assertEquals(evenwholeHour,
+ new java.sql.Timestamp(evenwholeHourExp.roundTime(lowerBoundaryEvenWholeHour)));
+ assertNotEquals(evenwholeHour,
+ new java.sql.Timestamp(evenwholeHourExp.roundTime(lowerBoundaryEvenWholeHour - 1)));
+ assertEquals(evenwholeHour,
+ new java.sql.Timestamp(evenwholeHourExp.roundTime(upperBoundaryEvenWholeHour)));
+ assertNotEquals(evenwholeHour,
+ new java.sql.Timestamp(evenwholeHourExp.roundTime(upperBoundaryEvenWholeHour + 1)));
+
+ // No DST switchover
+ RoundDateExpression oddWholeDayExp =
+ getRoundMsExpression("2022-11-11 0:0:0", TimeUnit.DAY, 1);
+ java.sql.Timestamp oddWholeDay =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 0:0:0").getTime());
+ long lowerBoundaryOddWholeDay = oddWholeDay.getTime() - HALF_DAY;
+ long upperBoundaryOddWholeDay = oddWholeDay.getTime() + HALF_DAY - 1;
+ assertEquals(lowerBoundaryOddWholeDay, oddWholeDayExp.rangeLower(oddWholeDay.getTime()));
+ assertEquals(upperBoundaryOddWholeDay, oddWholeDayExp.rangeUpper(oddWholeDay.getTime()));
+ assertEquals(oddWholeDay,
+ new java.sql.Timestamp(oddWholeDayExp.roundTime(lowerBoundaryOddWholeDay)));
+ assertNotEquals(oddWholeDay,
+ new java.sql.Timestamp(oddWholeDayExp.roundTime(lowerBoundaryOddWholeDay - 1)));
+ assertEquals(oddWholeDay,
+ new java.sql.Timestamp(oddWholeDayExp.roundTime(upperBoundaryOddWholeDay)));
+ assertNotEquals(oddWholeDay,
+ new java.sql.Timestamp(oddWholeDayExp.roundTime(upperBoundaryOddWholeDay + 1)));
+
+ RoundDateExpression oddWholeDay10Exp =
+ getRoundMsExpression("2022-11-14 0:0:0", TimeUnit.DAY, 10);
+ java.sql.Timestamp oddWholeDay10 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-14 0:0:0").getTime());
+ long lowerBoundaryOddWholeDay10 = oddWholeDay10.getTime() - 10 * HALF_DAY;
+ long upperBoundaryOddWholeDay10 = oddWholeDay10.getTime() + 10 * HALF_DAY - 1;
+ assertEquals(lowerBoundaryOddWholeDay10,
+ oddWholeDay10Exp.rangeLower(oddWholeDay.getTime()));
+ assertEquals(upperBoundaryOddWholeDay10,
+ oddWholeDay10Exp.rangeUpper(oddWholeDay.getTime()));
+ assertEquals(oddWholeDay10,
+ new java.sql.Timestamp(oddWholeDay10Exp.roundTime(lowerBoundaryOddWholeDay10)));
+ assertNotEquals(oddWholeDay10,
+ new java.sql.Timestamp(oddWholeDay10Exp.roundTime(lowerBoundaryOddWholeDay10 - 1)));
+ assertEquals(oddWholeDay10,
+ new java.sql.Timestamp(oddWholeDay10Exp.roundTime(upperBoundaryOddWholeDay10)));
+ assertNotEquals(oddWholeDay10,
+ new java.sql.Timestamp(oddWholeDay10Exp.roundTime(upperBoundaryOddWholeDay10 + 1)));
+
+ RoundDateExpression oddWholeDay3Exp =
+ getRoundMsExpression("2022-11-12 0:0:0", TimeUnit.DAY, 3);
+ java.sql.Timestamp oddWholeDay3 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-12 0:0:0").getTime());
+ long lowerBoundaryOddWholeDay3 = oddWholeDay3.getTime() - 3 * HALF_DAY;
+ long upperBoundaryOddWholeDay3 = oddWholeDay3.getTime() + 3 * HALF_DAY - 1;
+ assertEquals(lowerBoundaryOddWholeDay3, oddWholeDay3Exp.rangeLower(oddWholeDay.getTime()));
+ assertEquals(upperBoundaryOddWholeDay3, oddWholeDay3Exp.rangeUpper(oddWholeDay.getTime()));
+ assertEquals(oddWholeDay3,
+ new java.sql.Timestamp(oddWholeDay3Exp.roundTime(lowerBoundaryOddWholeDay3)));
+ assertNotEquals(oddWholeDay3,
+ new java.sql.Timestamp(oddWholeDay3Exp.roundTime(lowerBoundaryOddWholeDay3 - 1)));
+ assertEquals(oddWholeDay3,
+ new java.sql.Timestamp(oddWholeDay3Exp.roundTime(upperBoundaryOddWholeDay3)));
+ assertNotEquals(oddWholeDay3,
+ new java.sql.Timestamp(oddWholeDay3Exp.roundTime(upperBoundaryOddWholeDay3 + 1)));
+
+ RoundDateExpression evenWholeDayExp =
+ getRoundMsExpression("2022-11-12 0:0:0", TimeUnit.DAY, 1);
+ java.sql.Timestamp evenWholeDay =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-12 0:0:0").getTime());
+ long lowerBoundaryEvenWholeDay = evenWholeDay.getTime() - HALF_DAY;
+ long upperBoundaryEvenWholeDay = evenWholeDay.getTime() + HALF_DAY - 1;
+ assertEquals(lowerBoundaryEvenWholeDay, evenWholeDayExp.rangeLower(evenWholeDay.getTime()));
+ assertEquals(upperBoundaryEvenWholeDay, evenWholeDayExp.rangeUpper(evenWholeDay.getTime()));
+ assertEquals(evenWholeDay,
+ new java.sql.Timestamp(evenWholeDayExp.roundTime(lowerBoundaryEvenWholeDay)));
+ assertNotEquals(evenWholeDay,
+ new java.sql.Timestamp(evenWholeDayExp.roundTime(lowerBoundaryEvenWholeDay - 1)));
+ assertEquals(evenWholeDay,
+ new java.sql.Timestamp(evenWholeDayExp.roundTime(upperBoundaryEvenWholeDay)));
+ assertNotEquals(evenWholeDay,
+ new java.sql.Timestamp(evenWholeDayExp.roundTime(upperBoundaryEvenWholeDay + 1)));
+
+ // Stateless, we can reuse it for every week test
+ RoundWeekExpression roundWeekExpression = new RoundWeekExpression();
+ java.sql.Timestamp wholeWeekOdd =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-10-10 0:0:0").getTime());
+ long lowerBoundaryWholeWeekOdd = wholeWeekOdd.getTime() - (HALF_WEEK - 1);
+ long upperBoundaryWholeWeekOdd = wholeWeekOdd.getTime() + HALF_WEEK - 1;
+ assertEquals(lowerBoundaryWholeWeekOdd,
+ roundWeekExpression.rangeLower(wholeWeekOdd.getTime()));
+ assertEquals(upperBoundaryWholeWeekOdd,
+ roundWeekExpression.rangeUpper(wholeWeekOdd.getTime()));
+ assertEquals(wholeWeekOdd,
+ new java.sql.Timestamp(roundWeekExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeWeekOdd, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeWeekOdd,
+ new java.sql.Timestamp(roundWeekExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeWeekOdd - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeWeekOdd,
+ new java.sql.Timestamp(roundWeekExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeWeekOdd, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeWeekOdd,
+ new java.sql.Timestamp(roundWeekExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeWeekOdd + 1, GJChronology.getInstanceUTC()))));
+
+ java.sql.Timestamp wholeWeekEven =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-10-17 0:0:0").getTime());
+ long lowerBoundaryWholeWeekEven = wholeWeekEven.getTime() - HALF_WEEK;
+ long upperBoundaryWholeWeekEven = wholeWeekEven.getTime() + HALF_WEEK;
+ assertEquals(lowerBoundaryWholeWeekEven,
+ roundWeekExpression.rangeLower(wholeWeekEven.getTime()));
+ assertEquals(upperBoundaryWholeWeekEven,
+ roundWeekExpression.rangeUpper(wholeWeekEven.getTime()));
+ assertEquals(wholeWeekEven,
+ new java.sql.Timestamp(roundWeekExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeWeekEven, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeWeekEven,
+ new java.sql.Timestamp(roundWeekExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeWeekEven - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeWeekEven,
+ new java.sql.Timestamp(roundWeekExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeWeekEven, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeWeekEven,
+ new java.sql.Timestamp(roundWeekExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeWeekEven + 1, GJChronology.getInstanceUTC()))));
+
+ RoundMonthExpression roundMonthExpression = new RoundMonthExpression();
+ // We're still using roundHalfEven here for backwards compatibility
+ java.sql.Timestamp wholeMonthEven =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-06-1 0:0:0").getTime());
+ // May is 31 days
+ long lowerBoundaryWholeMonthEven = wholeMonthEven.getTime() - 31 * HALF_DAY;
+ // June is 30 days
+ long upperBoundaryWholeMonthEven = wholeMonthEven.getTime() + 30 * HALF_DAY;
+ assertEquals(lowerBoundaryWholeMonthEven,
+ roundMonthExpression.rangeLower(wholeMonthEven.getTime()));
+ assertEquals(upperBoundaryWholeMonthEven,
+ roundMonthExpression.rangeUpper(wholeMonthEven.getTime()));
+ assertEquals(wholeMonthEven,
+ new java.sql.Timestamp(roundMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeMonthEven, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeMonthEven,
+ new java.sql.Timestamp(roundMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeMonthEven - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeMonthEven,
+ new java.sql.Timestamp(roundMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeMonthEven, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeMonthEven,
+ new java.sql.Timestamp(roundMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeMonthEven + 1, GJChronology.getInstanceUTC()))));
+
+ // We're still using roundHalfEven here for backwards compatibility
+ java.sql.Timestamp wholeMonthOdd =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-07-1 0:0:0").getTime());
+ // June is 30 days
+ long lowerBoundaryWholeMonthOdd = wholeMonthOdd.getTime() - 30 * HALF_DAY + 1;
+ // July is 31 days
+ long upperBoundaryWholeMonthOdd = wholeMonthOdd.getTime() + 31 * HALF_DAY - 1;
+ assertEquals(lowerBoundaryWholeMonthOdd,
+ roundMonthExpression.rangeLower(wholeMonthOdd.getTime()));
+ assertEquals(upperBoundaryWholeMonthOdd,
+ roundMonthExpression.rangeUpper(wholeMonthOdd.getTime()));
+ assertEquals(wholeMonthOdd,
+ new java.sql.Timestamp(roundMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeMonthOdd, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeMonthOdd,
+ new java.sql.Timestamp(roundMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeMonthOdd - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeMonthOdd,
+ new java.sql.Timestamp(roundMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeMonthOdd, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeMonthOdd,
+ new java.sql.Timestamp(roundMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeMonthOdd + 1, GJChronology.getInstanceUTC()))));
+
+ // We're still using roundHalfEven here for backwards compatibility
+ java.sql.Timestamp wholeMonthLeap =
+ new java.sql.Timestamp(DateUtil.parseDate("2024-02-1 0:0:0").getTime());
+ // January is 31 days
+ long lowerBoundaryWholeMonthLeap = wholeMonthLeap.getTime() - 31 * HALF_DAY;
+ // February is 29 days
+ long upperBoundaryWholeMonthLeap = wholeMonthLeap.getTime() + 29 * HALF_DAY;
+ assertEquals(lowerBoundaryWholeMonthLeap,
+ roundMonthExpression.rangeLower(wholeMonthLeap.getTime()));
+ assertEquals(upperBoundaryWholeMonthLeap,
+ roundMonthExpression.rangeUpper(wholeMonthLeap.getTime()));
+ assertEquals(wholeMonthLeap,
+ new java.sql.Timestamp(roundMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeMonthLeap, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeMonthLeap,
+ new java.sql.Timestamp(roundMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeMonthLeap - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeMonthLeap,
+ new java.sql.Timestamp(roundMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeMonthLeap, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeMonthLeap,
+ new java.sql.Timestamp(roundMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeMonthLeap + 1, GJChronology.getInstanceUTC()))));
+
+ // We're still using roundHalfEven here for backwards compatibility
+ RoundYearExpression roundYearExpression = new RoundYearExpression();
+ java.sql.Timestamp wholeYearEven =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-1-1 0:0:0").getTime());
+ long lowerBoundaryWholeYearEven = wholeYearEven.getTime() - HALF_YEAR;
+ long upperBoundaryWholeYearEven = wholeYearEven.getTime() + HALF_YEAR;
+ assertEquals(lowerBoundaryWholeYearEven,
+ roundYearExpression.rangeLower(wholeYearEven.getTime()));
+ assertEquals(upperBoundaryWholeYearEven,
+ roundYearExpression.rangeUpper(wholeYearEven.getTime()));
+ assertEquals(wholeYearEven,
+ new java.sql.Timestamp(roundYearExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeYearEven, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeYearEven,
+ new java.sql.Timestamp(roundYearExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeYearEven - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeYearEven,
+ new java.sql.Timestamp(roundYearExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeYearEven, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeYearEven,
+ new java.sql.Timestamp(roundYearExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeYearEven + 1, GJChronology.getInstanceUTC()))));
+
+ // We're still using roundHalfEven here for backwards compatibility
+ java.sql.Timestamp wholeYearOdd =
+ new java.sql.Timestamp(DateUtil.parseDate("2023-1-1 0:0:0").getTime());
+ long lowerBoundaryWholeYearOdd = wholeYearOdd.getTime() - HALF_YEAR + 1;
+ long upperBoundaryWholeYearOdd = wholeYearOdd.getTime() + HALF_YEAR - 1;
+ assertEquals(lowerBoundaryWholeYearOdd,
+ roundYearExpression.rangeLower(wholeYearOdd.getTime()));
+ assertEquals(upperBoundaryWholeYearOdd,
+ roundYearExpression.rangeUpper(wholeYearOdd.getTime()));
+ assertEquals(wholeYearOdd,
+ new java.sql.Timestamp(roundYearExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeYearOdd, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeYearOdd,
+ new java.sql.Timestamp(roundYearExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeYearOdd - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeYearOdd,
+ new java.sql.Timestamp(roundYearExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeYearOdd, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeYearOdd,
+ new java.sql.Timestamp(roundYearExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeYearOdd + 1, GJChronology.getInstanceUTC()))));
+
+ // We're still using roundHalfEven here for backwards compatibility
+ java.sql.Timestamp wholeYearLeapEven =
+ new java.sql.Timestamp(DateUtil.parseDate("2024-1-1 0:0:0").getTime());
+ long lowerBoundaryWholeYearLeapEven = wholeYearLeapEven.getTime() - HALF_YEAR;
+ long upperBoundaryWholeYearLeapEven = wholeYearLeapEven.getTime() + HALF_YEAR + HALF_DAY;
+ assertEquals(lowerBoundaryWholeYearLeapEven,
+ roundYearExpression.rangeLower(wholeYearLeapEven.getTime()));
+ assertEquals(upperBoundaryWholeYearLeapEven,
+ roundYearExpression.rangeUpper(wholeYearLeapEven.getTime()));
+ assertEquals(wholeYearLeapEven,
+ new java.sql.Timestamp(roundYearExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeYearLeapEven, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeYearLeapEven,
+ new java.sql.Timestamp(roundYearExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeYearLeapEven - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeYearLeapEven,
+ new java.sql.Timestamp(roundYearExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeYearLeapEven, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeYearLeapEven,
+ new java.sql.Timestamp(roundYearExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeYearLeapEven + 1, GJChronology.getInstanceUTC()))));
+ }
+
+ private FloorDateExpression getFloorMsExpression(String s, TimeUnit u, int m)
+ throws SQLException {
+ return (FloorDateExpression) FloorDateExpression.create(LiteralExpression.newConstant(s), u,
+ m);
+ }
+
+ @Test
+ public void testFloorGMT() throws SQLException {
+
+ // No need to repeat odd / even cases
+ // The logic for upper and lower scan ranges is always
+ // [floor(ts), ceil(ts+1)-1]
+
+ RoundDateExpression oddWholeSecondExp =
+ getFloorMsExpression("2022-11-11 11:11:11", TimeUnit.SECOND, 1);
+ java.sql.Timestamp oddWholeSecond =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:11:11").getTime());
+ long lowerBoundaryOddWholeSecond = oddWholeSecond.getTime();
+ long upperBoundaryOddWholeSecond = oddWholeSecond.getTime() + SEC - 1;
+ assertEquals(lowerBoundaryOddWholeSecond,
+ oddWholeSecondExp.rangeLower(oddWholeSecond.getTime()));
+ assertEquals(upperBoundaryOddWholeSecond,
+ oddWholeSecondExp.rangeUpper(oddWholeSecond.getTime()));
+ assertEquals(oddWholeSecond,
+ new java.sql.Timestamp(oddWholeSecondExp.roundTime(lowerBoundaryOddWholeSecond)));
+ assertNotEquals(oddWholeSecond,
+ new java.sql.Timestamp(oddWholeSecondExp.roundTime(lowerBoundaryOddWholeSecond - 1)));
+ assertEquals(oddWholeSecond,
+ new java.sql.Timestamp(oddWholeSecondExp.roundTime(upperBoundaryOddWholeSecond)));
+ assertNotEquals(oddWholeSecond,
+ new java.sql.Timestamp(oddWholeSecondExp.roundTime(upperBoundaryOddWholeSecond + 1)));
+
+ // 10 sec range
+ RoundDateExpression oddWholeSecondFloor10Exp =
+ getFloorMsExpression("2022-11-11 11:11:10", TimeUnit.SECOND, 10);
+ java.sql.Timestamp oddWholeSecondFloor10 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:11:10").getTime());
+ long lowerBoundaryOddWholeSecondFloor10 = oddWholeSecondFloor10.getTime();
+ long upperBoundaryOddWholeSecondFloor10 = oddWholeSecondFloor10.getTime() + 10 * SEC - 1;
+ assertEquals(lowerBoundaryOddWholeSecondFloor10,
+ oddWholeSecondFloor10Exp.rangeLower(oddWholeSecond.getTime()));
+ assertEquals(upperBoundaryOddWholeSecondFloor10,
+ oddWholeSecondFloor10Exp.rangeUpper(oddWholeSecond.getTime()));
+ assertEquals(oddWholeSecondFloor10, new java.sql.Timestamp(
+ oddWholeSecondFloor10Exp.roundTime(lowerBoundaryOddWholeSecondFloor10)));
+ assertNotEquals(oddWholeSecondFloor10, new java.sql.Timestamp(
+ oddWholeSecondFloor10Exp.roundTime(lowerBoundaryOddWholeSecondFloor10 - 1)));
+ assertEquals(oddWholeSecondFloor10, new java.sql.Timestamp(
+ oddWholeSecondFloor10Exp.roundTime(upperBoundaryOddWholeSecondFloor10)));
+ assertNotEquals(oddWholeSecondFloor10, new java.sql.Timestamp(
+ oddWholeSecondFloor10Exp.roundTime(upperBoundaryOddWholeSecondFloor10 + 1)));
+
+ // 15 sec range
+ RoundDateExpression oddWholeSecondFloor15Exp =
+ getFloorMsExpression("2022-11-11 11:11:0", TimeUnit.SECOND, 15);
+ java.sql.Timestamp oddWholeSecondFloor15 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:11:0").getTime());
+ long lowerBoundaryOddWholeSecondFloor15 = oddWholeSecondFloor15.getTime();
+ long upperBoundaryOddWholeSecondFloor15 = oddWholeSecondFloor15.getTime() + 15 * SEC - 1;
+ assertEquals(lowerBoundaryOddWholeSecondFloor15,
+ oddWholeSecondFloor15Exp.rangeLower(oddWholeSecond.getTime()));
+ assertEquals(upperBoundaryOddWholeSecondFloor15,
+ oddWholeSecondFloor15Exp.rangeUpper(oddWholeSecond.getTime()));
+ assertEquals(oddWholeSecondFloor15, new java.sql.Timestamp(
+ oddWholeSecondFloor15Exp.roundTime(lowerBoundaryOddWholeSecondFloor15)));
+ assertNotEquals(oddWholeSecondFloor15, new java.sql.Timestamp(
+ oddWholeSecondFloor15Exp.roundTime(lowerBoundaryOddWholeSecondFloor15 - 1)));
+ assertEquals(oddWholeSecondFloor15, new java.sql.Timestamp(
+ oddWholeSecondFloor15Exp.roundTime(upperBoundaryOddWholeSecondFloor15)));
+ assertNotEquals(oddWholeSecondFloor15, new java.sql.Timestamp(
+ oddWholeSecondFloor15Exp.roundTime(upperBoundaryOddWholeSecondFloor15 + 1)));
+
+ RoundDateExpression evenWholeMinuteExp =
+ getFloorMsExpression("2022-11-11 11:12:0", TimeUnit.MINUTE, 1);
+ java.sql.Timestamp evenWholeMinute =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:12:0").getTime());
+ long lowerBoundaryEvenWholeMinute = evenWholeMinute.getTime();
+ long upperBoundaryEvenWholeMinute = evenWholeMinute.getTime() + MIN - 1;
+ assertEquals(lowerBoundaryEvenWholeMinute,
+ evenWholeMinuteExp.rangeLower(evenWholeMinute.getTime()));
+ assertEquals(upperBoundaryEvenWholeMinute,
+ evenWholeMinuteExp.rangeUpper(evenWholeMinute.getTime()));
+ assertEquals(evenWholeMinute,
+ new java.sql.Timestamp(evenWholeMinuteExp.roundTime(lowerBoundaryEvenWholeMinute)));
+ assertNotEquals(evenWholeMinute,
+ new java.sql.Timestamp(evenWholeMinuteExp.roundTime(lowerBoundaryEvenWholeMinute - 1)));
+ assertEquals(evenWholeMinute,
+ new java.sql.Timestamp(evenWholeMinuteExp.roundTime(upperBoundaryEvenWholeMinute)));
+ assertNotEquals(evenWholeMinute,
+ new java.sql.Timestamp(evenWholeMinuteExp.roundTime(upperBoundaryEvenWholeMinute + 1)));
+
+ RoundDateExpression evenWholeMinuteFloor20Exp =
+ getFloorMsExpression("2022-11-11 11:00:0", TimeUnit.MINUTE, 20);
+ java.sql.Timestamp evenWholeMinuteFloor20 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:00:0").getTime());
+ long lowerBoundaryEvenWholeMinuteFloor20 = evenWholeMinuteFloor20.getTime();
+ long upperBoundaryEvenWholeMinuteFloor20 = evenWholeMinuteFloor20.getTime() + 20 * MIN - 1;
+ assertEquals(lowerBoundaryEvenWholeMinuteFloor20,
+ evenWholeMinuteFloor20Exp.rangeLower(evenWholeMinute.getTime()));
+ assertEquals(upperBoundaryEvenWholeMinuteFloor20,
+ evenWholeMinuteFloor20Exp.rangeUpper(evenWholeMinute.getTime()));
+ assertEquals(evenWholeMinuteFloor20, new java.sql.Timestamp(
+ evenWholeMinuteFloor20Exp.roundTime(lowerBoundaryEvenWholeMinuteFloor20)));
+ assertNotEquals(evenWholeMinuteFloor20, new java.sql.Timestamp(
+ evenWholeMinuteFloor20Exp.roundTime(lowerBoundaryEvenWholeMinuteFloor20 - 1)));
+ assertEquals(evenWholeMinuteFloor20, new java.sql.Timestamp(
+ evenWholeMinuteFloor20Exp.roundTime(upperBoundaryEvenWholeMinuteFloor20)));
+ assertNotEquals(evenWholeMinuteFloor20, new java.sql.Timestamp(
+ evenWholeMinuteFloor20Exp.roundTime(upperBoundaryEvenWholeMinuteFloor20 + 1)));
+
+ // Minutes since epoch, don't expect the rounded value to be "round"
+ RoundDateExpression evenWholeMinuteFloor17Exp =
+ getFloorMsExpression("2022-11-11 11:12:00", TimeUnit.MINUTE, 17);
+ java.sql.Timestamp evenWholeMinuteFloor17 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:12:00").getTime());
+ long lowerBoundaryEvenWholeMinute17 = evenWholeMinuteFloor17.getTime();
+ long upperBoundaryEvenWholeMinute17 = evenWholeMinuteFloor17.getTime() + 17 * MIN - 1;
+ assertEquals(lowerBoundaryEvenWholeMinute17,
+ evenWholeMinuteFloor17Exp.rangeLower(evenWholeMinute.getTime()));
+ assertEquals(upperBoundaryEvenWholeMinute17,
+ evenWholeMinuteFloor17Exp.rangeUpper(evenWholeMinute.getTime()));
+ assertEquals(evenWholeMinuteFloor17, new java.sql.Timestamp(
+ evenWholeMinuteFloor17Exp.roundTime(lowerBoundaryEvenWholeMinute17)));
+ assertNotEquals(evenWholeMinuteFloor17, new java.sql.Timestamp(
+ evenWholeMinuteFloor17Exp.roundTime(lowerBoundaryEvenWholeMinute17 - 1)));
+ assertEquals(evenWholeMinuteFloor17, new java.sql.Timestamp(
+ evenWholeMinuteFloor17Exp.roundTime(upperBoundaryEvenWholeMinute17)));
+ assertNotEquals(evenWholeMinuteFloor17, new java.sql.Timestamp(
+ evenWholeMinuteFloor17Exp.roundTime(upperBoundaryEvenWholeMinute17 + 1)));
+
+ RoundDateExpression oddWholeHourExp =
+ getFloorMsExpression("2022-11-11 11:0:0", TimeUnit.HOUR, 1);
+ java.sql.Timestamp oddWholeHour =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:0:0").getTime());
+ long lowerBoundaryOddWholeHour = oddWholeHour.getTime();
+ long upperBoundaryOddWholeHour = oddWholeHour.getTime() + HOUR - 1;
+ assertEquals(lowerBoundaryOddWholeHour, oddWholeHourExp.rangeLower(oddWholeHour.getTime()));
+ assertEquals(upperBoundaryOddWholeHour, oddWholeHourExp.rangeUpper(oddWholeHour.getTime()));
+ assertEquals(oddWholeHour,
+ new java.sql.Timestamp(oddWholeHourExp.roundTime(lowerBoundaryOddWholeHour)));
+ assertNotEquals(oddWholeHour,
+ new java.sql.Timestamp(oddWholeHourExp.roundTime(lowerBoundaryOddWholeHour - 1)));
+ assertEquals(oddWholeHour,
+ new java.sql.Timestamp(oddWholeHourExp.roundTime(upperBoundaryOddWholeHour)));
+ assertNotEquals(oddWholeHour,
+ new java.sql.Timestamp(oddWholeHourExp.roundTime(upperBoundaryOddWholeHour + 1)));
+
+ // Not rounding to hourOfDay
+ RoundDateExpression oddWholeHour10Exp =
+ getFloorMsExpression("2022-11-11 02:0:0", TimeUnit.HOUR, 10);
+ java.sql.Timestamp oddWholeHour10 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 02:0:0").getTime());
+ long lowerBoundaryOddWholeHour10 = oddWholeHour10.getTime();
+ long upperBoundaryOddWholeHour10 = oddWholeHour10.getTime() + HOUR * 10 - 1;
+ assertEquals(lowerBoundaryOddWholeHour10,
+ oddWholeHour10Exp.rangeLower(oddWholeHour.getTime()));
+ assertEquals(upperBoundaryOddWholeHour10,
+ oddWholeHour10Exp.rangeUpper(oddWholeHour.getTime()));
+ assertEquals(oddWholeHour10,
+ new java.sql.Timestamp(oddWholeHour10Exp.roundTime(lowerBoundaryOddWholeHour10)));
+ assertNotEquals(oddWholeHour10,
+ new java.sql.Timestamp(oddWholeHour10Exp.roundTime(lowerBoundaryOddWholeHour10 - 1)));
+ assertEquals(oddWholeHour10,
+ new java.sql.Timestamp(oddWholeHour10Exp.roundTime(upperBoundaryOddWholeHour10)));
+ assertNotEquals(oddWholeHour10,
+ new java.sql.Timestamp(oddWholeHour10Exp.roundTime(upperBoundaryOddWholeHour10 + 1)));
+
+ // Not rounding to hourOfDay
+ RoundDateExpression oddWholeHour11Exp =
+ getFloorMsExpression("2022-11-11 07:0:0", TimeUnit.HOUR, 11);
+ java.sql.Timestamp oddWholeHour11 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 07:0:0").getTime());
+ long lowerBoundaryOddWholeHour11 = oddWholeHour11.getTime();
+ long upperBoundaryOddWholeHour11 = oddWholeHour11.getTime() + HOUR * 11 - 1;
+ assertEquals(lowerBoundaryOddWholeHour11,
+ oddWholeHour11Exp.rangeLower(oddWholeHour.getTime()));
+ assertEquals(upperBoundaryOddWholeHour11,
+ oddWholeHour11Exp.rangeUpper(oddWholeHour.getTime()));
+ assertEquals(oddWholeHour11,
+ new java.sql.Timestamp(oddWholeHour11Exp.roundTime(lowerBoundaryOddWholeHour11)));
+ assertNotEquals(oddWholeHour11,
+ new java.sql.Timestamp(oddWholeHour11Exp.roundTime(lowerBoundaryOddWholeHour11 - 1)));
+ assertEquals(oddWholeHour11,
+ new java.sql.Timestamp(oddWholeHour11Exp.roundTime(upperBoundaryOddWholeHour11)));
+ assertNotEquals(oddWholeHour11,
+ new java.sql.Timestamp(oddWholeHour11Exp.roundTime(upperBoundaryOddWholeHour11 + 1)));
+
+ // No DST switchover
+ RoundDateExpression evenWholeDayExp =
+ getFloorMsExpression("2022-11-12 0:0:0", TimeUnit.DAY, 1);
+ java.sql.Timestamp evenWholeDay =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-12 0:0:0").getTime());
+ long lowerBoundaryEvenWholeDay = evenWholeDay.getTime();
+ long upperBoundaryEvenWholeDay = evenWholeDay.getTime() + DAY - 1;
+ assertEquals(lowerBoundaryEvenWholeDay, evenWholeDayExp.rangeLower(evenWholeDay.getTime()));
+ assertEquals(upperBoundaryEvenWholeDay, evenWholeDayExp.rangeUpper(evenWholeDay.getTime()));
+ assertEquals(evenWholeDay,
+ new java.sql.Timestamp(evenWholeDayExp.roundTime(lowerBoundaryEvenWholeDay)));
+ assertNotEquals(evenWholeDay,
+ new java.sql.Timestamp(evenWholeDayExp.roundTime(lowerBoundaryEvenWholeDay - 1)));
+ assertEquals(evenWholeDay,
+ new java.sql.Timestamp(evenWholeDayExp.roundTime(upperBoundaryEvenWholeDay)));
+ assertNotEquals(evenWholeDay,
+ new java.sql.Timestamp(evenWholeDayExp.roundTime(upperBoundaryEvenWholeDay + 1)));
+
+ RoundDateExpression evenWholeDay2Exp =
+ getFloorMsExpression("2022-11-12 0:0:0", TimeUnit.DAY, 2);
+ java.sql.Timestamp evenWholeDay2 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-12 0:0:0").getTime());
+ long lowerBoundaryEvenWholeDay2 = evenWholeDay2.getTime();
+ long upperBoundaryEvenWholeDay2 = evenWholeDay2.getTime() + 2 * DAY - 1;
+ assertEquals(lowerBoundaryEvenWholeDay2,
+ evenWholeDay2Exp.rangeLower(evenWholeDay.getTime()));
+ assertEquals(upperBoundaryEvenWholeDay2,
+ evenWholeDay2Exp.rangeUpper(evenWholeDay.getTime()));
+ assertEquals(evenWholeDay2,
+ new java.sql.Timestamp(evenWholeDay2Exp.roundTime(lowerBoundaryEvenWholeDay2)));
+ assertNotEquals(evenWholeDay2,
+ new java.sql.Timestamp(evenWholeDay2Exp.roundTime(lowerBoundaryEvenWholeDay2 - 1)));
+ assertEquals(evenWholeDay2,
+ new java.sql.Timestamp(evenWholeDay2Exp.roundTime(upperBoundaryEvenWholeDay2)));
+ assertNotEquals(evenWholeDay2,
+ new java.sql.Timestamp(evenWholeDay2Exp.roundTime(upperBoundaryEvenWholeDay2 + 1)));
+
+ RoundDateExpression evenWholeDay3Exp =
+ getFloorMsExpression("2022-11-12 0:0:0", TimeUnit.DAY, 3);
+ java.sql.Timestamp evenWholeDay3 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-12 0:0:0").getTime());
+ long lowerBoundaryEvenWholeDay3 = evenWholeDay3.getTime();
+ long upperBoundaryEvenWholeDay3 = evenWholeDay3.getTime() + 3 * DAY - 1;
+ assertEquals(lowerBoundaryEvenWholeDay3,
+ evenWholeDay3Exp.rangeLower(evenWholeDay.getTime()));
+ assertEquals(upperBoundaryEvenWholeDay3,
+ evenWholeDay3Exp.rangeUpper(evenWholeDay.getTime()));
+ assertEquals(evenWholeDay3,
+ new java.sql.Timestamp(evenWholeDay3Exp.roundTime(lowerBoundaryEvenWholeDay3)));
+ assertNotEquals(evenWholeDay3,
+ new java.sql.Timestamp(evenWholeDay3Exp.roundTime(lowerBoundaryEvenWholeDay3 - 1)));
+ assertEquals(evenWholeDay3,
+ new java.sql.Timestamp(evenWholeDay3Exp.roundTime(upperBoundaryEvenWholeDay3)));
+ assertNotEquals(evenWholeDay3,
+ new java.sql.Timestamp(evenWholeDay3Exp.roundTime(upperBoundaryEvenWholeDay3 + 1)));
+
+ FloorWeekExpression floorWeekExpression = new FloorWeekExpression();
+ java.sql.Timestamp wholeWeekOdd =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-10-10 0:0:0").getTime());
+ long lowerBoundaryWholeWeekOdd = wholeWeekOdd.getTime();
+ long upperBoundaryWholeWeekOdd = wholeWeekOdd.getTime() + WEEK - 1;
+ assertEquals(lowerBoundaryWholeWeekOdd,
+ floorWeekExpression.rangeLower(wholeWeekOdd.getTime()));
+ assertEquals(upperBoundaryWholeWeekOdd,
+ floorWeekExpression.rangeUpper(wholeWeekOdd.getTime()));
+ assertEquals(wholeWeekOdd,
+ new java.sql.Timestamp(floorWeekExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeWeekOdd, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeWeekOdd,
+ new java.sql.Timestamp(floorWeekExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeWeekOdd - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeWeekOdd,
+ new java.sql.Timestamp(floorWeekExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeWeekOdd, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeWeekOdd,
+ new java.sql.Timestamp(floorWeekExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeWeekOdd + 1, GJChronology.getInstanceUTC()))));
+
+ FloorMonthExpression floorMonthExpression = new FloorMonthExpression();
+ java.sql.Timestamp wholeMonthOdd =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-07-1 0:0:0").getTime());
+ long lowerBoundaryWholeMonthOdd = wholeMonthOdd.getTime();
+ // July is 31 days
+ long upperBoundaryWholeMonthOdd = wholeMonthOdd.getTime() + 31 * DAY - 1;
+ assertEquals(lowerBoundaryWholeMonthOdd,
+ floorMonthExpression.rangeLower(wholeMonthOdd.getTime()));
+ assertEquals(upperBoundaryWholeMonthOdd,
+ floorMonthExpression.rangeUpper(wholeMonthOdd.getTime()));
+ assertEquals(wholeMonthOdd,
+ new java.sql.Timestamp(floorMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeMonthOdd, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeMonthOdd,
+ new java.sql.Timestamp(floorMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeMonthOdd - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeMonthOdd,
+ new java.sql.Timestamp(floorMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeMonthOdd, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeMonthOdd,
+ new java.sql.Timestamp(floorMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeMonthOdd + 1, GJChronology.getInstanceUTC()))));
+
+ java.sql.Timestamp wholeMonthLeap =
+ new java.sql.Timestamp(DateUtil.parseDate("2024-02-1 0:0:0").getTime());
+ long lowerBoundaryWholeMonthLeap = wholeMonthLeap.getTime();
+ // February is 29 days
+ long upperBoundaryWholeMonthLeap = wholeMonthLeap.getTime() + 29 * DAY - 1;
+ assertEquals(lowerBoundaryWholeMonthLeap,
+ floorMonthExpression.rangeLower(wholeMonthLeap.getTime()));
+ assertEquals(upperBoundaryWholeMonthLeap,
+ floorMonthExpression.rangeUpper(wholeMonthLeap.getTime()));
+ assertEquals(wholeMonthLeap,
+ new java.sql.Timestamp(floorMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeMonthLeap, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeMonthLeap,
+ new java.sql.Timestamp(floorMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeMonthLeap - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeMonthLeap,
+ new java.sql.Timestamp(floorMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeMonthLeap, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeMonthLeap,
+ new java.sql.Timestamp(floorMonthExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeMonthLeap + 1, GJChronology.getInstanceUTC()))));
+
+ FloorYearExpression floorYearExpression = new FloorYearExpression();
+ java.sql.Timestamp wholeYearEven =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-1-1 0:0:0").getTime());
+ long lowerBoundaryWholeYearEven = wholeYearEven.getTime();
+ long upperBoundaryWholeYearEven = wholeYearEven.getTime() + YEAR - 1;
+ assertEquals(lowerBoundaryWholeYearEven,
+ floorYearExpression.rangeLower(wholeYearEven.getTime()));
+ assertEquals(upperBoundaryWholeYearEven,
+ floorYearExpression.rangeUpper(wholeYearEven.getTime()));
+ assertEquals(wholeYearEven,
+ new java.sql.Timestamp(floorYearExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeYearEven, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeYearEven,
+ new java.sql.Timestamp(floorYearExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeYearEven - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeYearEven,
+ new java.sql.Timestamp(floorYearExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeYearEven, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeYearEven,
+ new java.sql.Timestamp(floorYearExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeYearEven + 1, GJChronology.getInstanceUTC()))));
+
+ java.sql.Timestamp wholeYearLeapEven =
+ new java.sql.Timestamp(DateUtil.parseDate("2024-1-1 0:0:0").getTime());
+ long lowerBoundaryWholeYearLeapEven = wholeYearLeapEven.getTime();
+ long upperBoundaryWholeYearLeapEven = wholeYearLeapEven.getTime() + YEAR + DAY - 1;
+ assertEquals(lowerBoundaryWholeYearLeapEven,
+ floorYearExpression.rangeLower(wholeYearLeapEven.getTime()));
+ assertEquals(upperBoundaryWholeYearLeapEven,
+ floorYearExpression.rangeUpper(wholeYearLeapEven.getTime()));
+ assertEquals(wholeYearLeapEven,
+ new java.sql.Timestamp(floorYearExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeYearLeapEven, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeYearLeapEven,
+ new java.sql.Timestamp(floorYearExpression.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeYearLeapEven - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeYearLeapEven,
+ new java.sql.Timestamp(floorYearExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeYearLeapEven, GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeYearLeapEven,
+ new java.sql.Timestamp(floorYearExpression.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeYearLeapEven + 1, GJChronology.getInstanceUTC()))));
+ }
+
+ private CeilDateExpression getCeilMsExpression(String s, TimeUnit u, int m)
+ throws SQLException {
+ return (CeilDateExpression) CeilDateExpression.create(LiteralExpression.newConstant(s), u,
+ m);
+ }
+
+ @Test
+ public void testCeilGMT() throws SQLException {
+
+ // No need to repeat odd / even cases
+ // The logic for upper and lower scan ranges is always
+ // [floor(ts-1)+1, ceil(ts)]
+
+ RoundDateExpression oddWholeSecondExp =
+ getCeilMsExpression("2022-11-11 11:11:11", TimeUnit.SECOND, 1);
+ java.sql.Timestamp oddWholeSecond =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:11:11").getTime());
+ long lowerBoundaryOddWholeSecond = oddWholeSecond.getTime() - SEC + 1;
+ long upperBoundaryOddWholeSecond = oddWholeSecond.getTime();
+ assertEquals(lowerBoundaryOddWholeSecond,
+ oddWholeSecondExp.rangeLower(oddWholeSecond.getTime()));
+ assertEquals(upperBoundaryOddWholeSecond,
+ oddWholeSecondExp.rangeUpper(oddWholeSecond.getTime()));
+ assertEquals(oddWholeSecond,
+ new java.sql.Timestamp(oddWholeSecondExp.roundTime(lowerBoundaryOddWholeSecond)));
+ assertNotEquals(oddWholeSecond,
+ new java.sql.Timestamp(oddWholeSecondExp.roundTime(lowerBoundaryOddWholeSecond - 1)));
+ assertEquals(oddWholeSecond,
+ new java.sql.Timestamp(oddWholeSecondExp.roundTime(upperBoundaryOddWholeSecond)));
+ assertNotEquals(oddWholeSecond,
+ new java.sql.Timestamp(oddWholeSecondExp.roundTime(upperBoundaryOddWholeSecond + 1)));
+
+ // 10 sec range
+ RoundDateExpression oddWholeSecondCeil10Exp =
+ getCeilMsExpression("2022-11-11 11:11:20", TimeUnit.SECOND, 10);
+ java.sql.Timestamp oddWholeSecondCeil10 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:11:20").getTime());
+ long lowerBoundaryOddWholeSecondCeil10 = oddWholeSecondCeil10.getTime() - 10 * SEC + 1;
+ long upperBoundaryOddWholeSecondCeil10 = oddWholeSecondCeil10.getTime();
+ assertEquals(lowerBoundaryOddWholeSecondCeil10,
+ oddWholeSecondCeil10Exp.rangeLower(oddWholeSecond.getTime()));
+ assertEquals(upperBoundaryOddWholeSecondCeil10,
+ oddWholeSecondCeil10Exp.rangeUpper(oddWholeSecond.getTime()));
+ assertEquals(oddWholeSecondCeil10, new java.sql.Timestamp(
+ oddWholeSecondCeil10Exp.roundTime(lowerBoundaryOddWholeSecondCeil10)));
+ assertNotEquals(oddWholeSecondCeil10, new java.sql.Timestamp(
+ oddWholeSecondCeil10Exp.roundTime(lowerBoundaryOddWholeSecondCeil10 - 1)));
+ assertEquals(oddWholeSecondCeil10, new java.sql.Timestamp(
+ oddWholeSecondCeil10Exp.roundTime(upperBoundaryOddWholeSecondCeil10)));
+ assertNotEquals(oddWholeSecondCeil10, new java.sql.Timestamp(
+ oddWholeSecondCeil10Exp.roundTime(upperBoundaryOddWholeSecondCeil10 + 1)));
+
+ // 15 sec range
+ RoundDateExpression oddWholeSecondCeil15Exp =
+ getCeilMsExpression("2022-11-11 11:11:15", TimeUnit.SECOND, 15);
+ java.sql.Timestamp oddWholeSecondCeil15 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:11:15").getTime());
+ long lowerBoundaryOddWholeSecondFloor15 = oddWholeSecondCeil15.getTime() - 15 * SEC + 1;
+ long upperBoundaryOddWholeSecondFloor15 = oddWholeSecondCeil15.getTime();
+ assertEquals(lowerBoundaryOddWholeSecondFloor15,
+ oddWholeSecondCeil15Exp.rangeLower(oddWholeSecond.getTime()));
+ assertEquals(upperBoundaryOddWholeSecondFloor15,
+ oddWholeSecondCeil15Exp.rangeUpper(oddWholeSecond.getTime()));
+ assertEquals(oddWholeSecondCeil15, new java.sql.Timestamp(
+ oddWholeSecondCeil15Exp.roundTime(lowerBoundaryOddWholeSecondFloor15)));
+ assertNotEquals(oddWholeSecondCeil15, new java.sql.Timestamp(
+ oddWholeSecondCeil15Exp.roundTime(lowerBoundaryOddWholeSecondFloor15 - 1)));
+ assertEquals(oddWholeSecondCeil15, new java.sql.Timestamp(
+ oddWholeSecondCeil15Exp.roundTime(upperBoundaryOddWholeSecondFloor15)));
+ assertNotEquals(oddWholeSecondCeil15, new java.sql.Timestamp(
+ oddWholeSecondCeil15Exp.roundTime(upperBoundaryOddWholeSecondFloor15 + 1)));
+
+ RoundDateExpression evenWholeMinuteExp =
+ getCeilMsExpression("2022-11-11 11:12:0", TimeUnit.MINUTE, 1);
+ java.sql.Timestamp evenWholeMinute =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:12:0").getTime());
+ long lowerBoundaryEvenWholeMinute = evenWholeMinute.getTime() - MIN + 1;
+ long upperBoundaryEvenWholeMinute = evenWholeMinute.getTime();
+ assertEquals(lowerBoundaryEvenWholeMinute,
+ evenWholeMinuteExp.rangeLower(evenWholeMinute.getTime()));
+ assertEquals(upperBoundaryEvenWholeMinute,
+ evenWholeMinuteExp.rangeUpper(evenWholeMinute.getTime()));
+ assertEquals(evenWholeMinute,
+ new java.sql.Timestamp(evenWholeMinuteExp.roundTime(lowerBoundaryEvenWholeMinute)));
+ assertNotEquals(evenWholeMinute,
+ new java.sql.Timestamp(evenWholeMinuteExp.roundTime(lowerBoundaryEvenWholeMinute - 1)));
+ assertEquals(evenWholeMinute,
+ new java.sql.Timestamp(evenWholeMinuteExp.roundTime(upperBoundaryEvenWholeMinute)));
+ assertNotEquals(evenWholeMinute,
+ new java.sql.Timestamp(evenWholeMinuteExp.roundTime(upperBoundaryEvenWholeMinute + 1)));
+
+ RoundDateExpression evenWholeMinuteCeil20Exp =
+ getCeilMsExpression("2022-11-11 11:20:0", TimeUnit.MINUTE, 20);
+ java.sql.Timestamp evenWholeMinuteCeil20 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:20:0").getTime());
+ long lowerBoundaryEvenWholeMinuteCeil20 = evenWholeMinuteCeil20.getTime() - 20 * MIN + 1;
+ long upperBoundaryEvenWholeMinuteCeil20 = evenWholeMinuteCeil20.getTime();
+ assertEquals(lowerBoundaryEvenWholeMinuteCeil20,
+ evenWholeMinuteCeil20Exp.rangeLower(evenWholeMinute.getTime()));
+ assertEquals(upperBoundaryEvenWholeMinuteCeil20,
+ evenWholeMinuteCeil20Exp.rangeUpper(evenWholeMinute.getTime()));
+ assertEquals(evenWholeMinuteCeil20, new java.sql.Timestamp(
+ evenWholeMinuteCeil20Exp.roundTime(lowerBoundaryEvenWholeMinuteCeil20)));
+ assertNotEquals(evenWholeMinuteCeil20, new java.sql.Timestamp(
+ evenWholeMinuteCeil20Exp.roundTime(lowerBoundaryEvenWholeMinuteCeil20 - 1)));
+ assertEquals(evenWholeMinuteCeil20, new java.sql.Timestamp(
+ evenWholeMinuteCeil20Exp.roundTime(upperBoundaryEvenWholeMinuteCeil20)));
+ assertNotEquals(evenWholeMinuteCeil20, new java.sql.Timestamp(
+ evenWholeMinuteCeil20Exp.roundTime(upperBoundaryEvenWholeMinuteCeil20 + 1)));
+
+ // Minutes since epoch, don't expect the rounded value to be "round"
+ RoundDateExpression evenWholeMinuteCeil17Exp =
+ getCeilMsExpression("2022-11-11 11:12:00", TimeUnit.MINUTE, 17);
+ java.sql.Timestamp evenWholeMinuteCeil17 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:12:00").getTime());
+ long lowerBoundaryEvenWholeMinute17 = evenWholeMinuteCeil17.getTime() - 17 * MIN + 1;
+ long upperBoundaryEvenWholeMinute17 = evenWholeMinuteCeil17.getTime();
+ assertEquals(lowerBoundaryEvenWholeMinute17,
+ evenWholeMinuteCeil17Exp.rangeLower(evenWholeMinute.getTime()));
+ assertEquals(upperBoundaryEvenWholeMinute17,
+ evenWholeMinuteCeil17Exp.rangeUpper(evenWholeMinute.getTime()));
+ assertEquals(evenWholeMinuteCeil17, new java.sql.Timestamp(
+ evenWholeMinuteCeil17Exp.roundTime(lowerBoundaryEvenWholeMinute17)));
+ assertNotEquals(evenWholeMinuteCeil17, new java.sql.Timestamp(
+ evenWholeMinuteCeil17Exp.roundTime(lowerBoundaryEvenWholeMinute17 - 1)));
+ assertEquals(evenWholeMinuteCeil17, new java.sql.Timestamp(
+ evenWholeMinuteCeil17Exp.roundTime(upperBoundaryEvenWholeMinute17)));
+ assertNotEquals(evenWholeMinuteCeil17, new java.sql.Timestamp(
+ evenWholeMinuteCeil17Exp.roundTime(upperBoundaryEvenWholeMinute17 + 1)));
+
+ RoundDateExpression oddWholeHourExp =
+ getCeilMsExpression("2022-11-11 11:0:0", TimeUnit.HOUR, 1);
+ java.sql.Timestamp oddWholeHour =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 11:0:0").getTime());
+ long lowerBoundaryOddWholeHour = oddWholeHour.getTime() - HOUR + 1;
+ long upperBoundaryOddWholeHour = oddWholeHour.getTime();
+ assertEquals(lowerBoundaryOddWholeHour,
+ oddWholeHourExp.rangeLower(oddWholeHour.getTime() - 1));
+ assertEquals(upperBoundaryOddWholeHour, oddWholeHourExp.rangeUpper(oddWholeHour.getTime()));
+ assertEquals(oddWholeHour,
+ new java.sql.Timestamp(oddWholeHourExp.roundTime(lowerBoundaryOddWholeHour)));
+ assertNotEquals(oddWholeHour,
+ new java.sql.Timestamp(oddWholeHourExp.roundTime(lowerBoundaryOddWholeHour - 1)));
+ assertEquals(oddWholeHour,
+ new java.sql.Timestamp(oddWholeHourExp.roundTime(upperBoundaryOddWholeHour)));
+ assertNotEquals(oddWholeHour,
+ new java.sql.Timestamp(oddWholeHourExp.roundTime(upperBoundaryOddWholeHour + 1)));
+
+ // Not rounding to hourOfDay
+ RoundDateExpression oddWholeHour10Exp =
+ getCeilMsExpression("2022-11-11 12:0:0", TimeUnit.HOUR, 10);
+ java.sql.Timestamp oddWholeHour10 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 12:0:0").getTime());
+ long lowerBoundaryOddWholeHour10 = oddWholeHour10.getTime() - 10 * HOUR + 1;
+ long upperBoundaryOddWholeHour10 = oddWholeHour10.getTime();
+ assertEquals(lowerBoundaryOddWholeHour10,
+ oddWholeHour10Exp.rangeLower(oddWholeHour.getTime()));
+ assertEquals(upperBoundaryOddWholeHour10,
+ oddWholeHour10Exp.rangeUpper(oddWholeHour.getTime()));
+ assertEquals(oddWholeHour10,
+ new java.sql.Timestamp(oddWholeHour10Exp.roundTime(lowerBoundaryOddWholeHour10)));
+ assertNotEquals(oddWholeHour10,
+ new java.sql.Timestamp(oddWholeHour10Exp.roundTime(lowerBoundaryOddWholeHour10 - 1)));
+ assertEquals(oddWholeHour10,
+ new java.sql.Timestamp(oddWholeHour10Exp.roundTime(upperBoundaryOddWholeHour10)));
+ assertNotEquals(oddWholeHour10,
+ new java.sql.Timestamp(oddWholeHour10Exp.roundTime(upperBoundaryOddWholeHour10 + 1)));
+
+ // Not rounding to hourOfDay
+ RoundDateExpression oddWholeHour11Exp =
+ getCeilMsExpression("2022-11-11 12:0:0", TimeUnit.HOUR, 11);
+ java.sql.Timestamp oddWholeHour11 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-11 18:0:0").getTime());
+ long lowerBoundaryOddWholeHour11 = oddWholeHour11.getTime() - 11 * HOUR + 1;
+ long upperBoundaryOddWholeHour11 = oddWholeHour11.getTime();
+ assertEquals(lowerBoundaryOddWholeHour11,
+ oddWholeHour11Exp.rangeLower(oddWholeHour.getTime()));
+ assertEquals(upperBoundaryOddWholeHour11,
+ oddWholeHour11Exp.rangeUpper(oddWholeHour.getTime()));
+ assertEquals(oddWholeHour11,
+ new java.sql.Timestamp(oddWholeHour11Exp.roundTime(lowerBoundaryOddWholeHour11)));
+ assertNotEquals(oddWholeHour11,
+ new java.sql.Timestamp(oddWholeHour11Exp.roundTime(lowerBoundaryOddWholeHour11 - 1)));
+ assertEquals(oddWholeHour11,
+ new java.sql.Timestamp(oddWholeHour11Exp.roundTime(upperBoundaryOddWholeHour11)));
+ assertNotEquals(oddWholeHour11,
+ new java.sql.Timestamp(oddWholeHour11Exp.roundTime(upperBoundaryOddWholeHour11 + 1)));
+
+ RoundDateExpression evenWholeDayExp =
+ getCeilMsExpression("2022-11-12 0:0:0", TimeUnit.DAY, 1);
+ java.sql.Timestamp evenWholeDay =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-12 0:0:0").getTime());
+ long lowerBoundaryEvenWholeDay = evenWholeDay.getTime() - DAY + 1;
+ long upperBoundaryEvenWholeDay = evenWholeDay.getTime();
+ assertEquals(lowerBoundaryEvenWholeDay, evenWholeDayExp.rangeLower(evenWholeDay.getTime()));
+ assertEquals(upperBoundaryEvenWholeDay, evenWholeDayExp.rangeUpper(evenWholeDay.getTime()));
+ assertEquals(evenWholeDay,
+ new java.sql.Timestamp(evenWholeDayExp.roundTime(lowerBoundaryEvenWholeDay)));
+ assertNotEquals(evenWholeDay,
+ new java.sql.Timestamp(evenWholeDayExp.roundTime(lowerBoundaryEvenWholeDay - 1)));
+ assertEquals(evenWholeDay,
+ new java.sql.Timestamp(evenWholeDayExp.roundTime(upperBoundaryEvenWholeDay)));
+ assertNotEquals(evenWholeDay,
+ new java.sql.Timestamp(evenWholeDayExp.roundTime(upperBoundaryEvenWholeDay + 1)));
+
+ RoundDateExpression evenWholeDay2Exp =
+ getCeilMsExpression("2022-11-12 0:0:0", TimeUnit.DAY, 2);
+ java.sql.Timestamp evenWholeDay2 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-12 0:0:0").getTime());
+ long lowerBoundaryEvenWholeDay2 = evenWholeDay2.getTime() - 2 * DAY + 1;
+ long upperBoundaryEvenWholeDay2 = evenWholeDay2.getTime();
+ assertEquals(lowerBoundaryEvenWholeDay2,
+ evenWholeDay2Exp.rangeLower(evenWholeDay.getTime()));
+ assertEquals(upperBoundaryEvenWholeDay2,
+ evenWholeDay2Exp.rangeUpper(evenWholeDay.getTime()));
+ assertEquals(evenWholeDay2,
+ new java.sql.Timestamp(evenWholeDay2Exp.roundTime(lowerBoundaryEvenWholeDay2)));
+ assertNotEquals(evenWholeDay2,
+ new java.sql.Timestamp(evenWholeDay2Exp.roundTime(lowerBoundaryEvenWholeDay2 - 1)));
+ assertEquals(evenWholeDay2,
+ new java.sql.Timestamp(evenWholeDay2Exp.roundTime(upperBoundaryEvenWholeDay2)));
+ assertNotEquals(evenWholeDay2,
+ new java.sql.Timestamp(evenWholeDay2Exp.roundTime(upperBoundaryEvenWholeDay2 + 1)));
+
+ RoundDateExpression evenWholeDay3Exp =
+ getCeilMsExpression("2022-11-12 0:0:0", TimeUnit.DAY, 3);
+ java.sql.Timestamp evenWholeDay3 =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-11-12 0:0:0").getTime());
+ long lowerBoundaryEvenWholeDay3 = evenWholeDay3.getTime() - 3 * DAY + 1;
+ long upperBoundaryEvenWholeDay3 = evenWholeDay3.getTime();
+ assertEquals(lowerBoundaryEvenWholeDay3,
+ evenWholeDay3Exp.rangeLower(evenWholeDay.getTime()));
+ assertEquals(upperBoundaryEvenWholeDay3,
+ evenWholeDay3Exp.rangeUpper(evenWholeDay.getTime()));
+ assertEquals(evenWholeDay3,
+ new java.sql.Timestamp(evenWholeDay3Exp.roundTime(lowerBoundaryEvenWholeDay3)));
+ assertNotEquals(evenWholeDay3,
+ new java.sql.Timestamp(evenWholeDay3Exp.roundTime(lowerBoundaryEvenWholeDay3 - 1)));
+ assertEquals(evenWholeDay3,
+ new java.sql.Timestamp(evenWholeDay3Exp.roundTime(upperBoundaryEvenWholeDay3)));
+ assertNotEquals(evenWholeDay3,
+ new java.sql.Timestamp(evenWholeDay3Exp.roundTime(upperBoundaryEvenWholeDay3 + 1)));
+
+ CeilWeekExpression ceilWeekExp = new CeilWeekExpression();
+ java.sql.Timestamp wholeWeekOdd =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-10-10 0:0:0").getTime());
+ long lowerBoundaryWholeWeekOdd = wholeWeekOdd.getTime() - WEEK + 1;
+ long upperBoundaryWholeWeekOdd = wholeWeekOdd.getTime();
+ assertEquals(lowerBoundaryWholeWeekOdd, ceilWeekExp.rangeLower(wholeWeekOdd.getTime()));
+ assertEquals(upperBoundaryWholeWeekOdd, ceilWeekExp.rangeUpper(wholeWeekOdd.getTime()));
+ assertEquals(wholeWeekOdd, new java.sql.Timestamp(
+ ceilWeekExp.roundDateTime(new org.joda.time.DateTime(lowerBoundaryWholeWeekOdd,
+ GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeWeekOdd, new java.sql.Timestamp(
+ ceilWeekExp.roundDateTime(new org.joda.time.DateTime(lowerBoundaryWholeWeekOdd - 1,
+ GJChronology.getInstanceUTC()))));
+ assertEquals(wholeWeekOdd, new java.sql.Timestamp(
+ ceilWeekExp.roundDateTime(new org.joda.time.DateTime(upperBoundaryWholeWeekOdd,
+ GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeWeekOdd, new java.sql.Timestamp(
+ ceilWeekExp.roundDateTime(new org.joda.time.DateTime(upperBoundaryWholeWeekOdd + 1,
+ GJChronology.getInstanceUTC()))));
+
+ CeilMonthExpression ceilMonthExp = new CeilMonthExpression();
+ java.sql.Timestamp wholeMonthOdd =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-08-1 0:0:0").getTime());
+ // July is 31 days
+ long lowerBoundaryWholeMonthOdd = wholeMonthOdd.getTime() - 31 * DAY + 1;
+ long upperBoundaryWholeMonthOdd = wholeMonthOdd.getTime();
+ assertEquals(lowerBoundaryWholeMonthOdd, ceilMonthExp.rangeLower(wholeMonthOdd.getTime()));
+ assertEquals(upperBoundaryWholeMonthOdd, ceilMonthExp.rangeUpper(wholeMonthOdd.getTime()));
+ assertEquals(wholeMonthOdd, new java.sql.Timestamp(
+ ceilMonthExp.roundDateTime(new org.joda.time.DateTime(lowerBoundaryWholeMonthOdd,
+ GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeMonthOdd,
+ new java.sql.Timestamp(ceilMonthExp.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeMonthOdd - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeMonthOdd, new java.sql.Timestamp(
+ ceilMonthExp.roundDateTime(new org.joda.time.DateTime(upperBoundaryWholeMonthOdd,
+ GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeMonthOdd,
+ new java.sql.Timestamp(ceilMonthExp.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeMonthOdd + 1, GJChronology.getInstanceUTC()))));
+
+ java.sql.Timestamp wholeMonthLeap =
+ new java.sql.Timestamp(DateUtil.parseDate("2024-03-1 0:0:0").getTime());
+ // February is 29 days
+ long lowerBoundaryWholeMonthLeap = wholeMonthLeap.getTime() - 29 * DAY + 1;
+ long upperBoundaryWholeMonthLeap = wholeMonthLeap.getTime();
+ assertEquals(lowerBoundaryWholeMonthLeap,
+ ceilMonthExp.rangeLower(wholeMonthLeap.getTime()));
+ assertEquals(upperBoundaryWholeMonthLeap,
+ ceilMonthExp.rangeUpper(wholeMonthLeap.getTime()));
+ assertEquals(wholeMonthLeap, new java.sql.Timestamp(
+ ceilMonthExp.roundDateTime(new org.joda.time.DateTime(lowerBoundaryWholeMonthLeap,
+ GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeMonthLeap,
+ new java.sql.Timestamp(ceilMonthExp.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeMonthLeap - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeMonthLeap, new java.sql.Timestamp(
+ ceilMonthExp.roundDateTime(new org.joda.time.DateTime(upperBoundaryWholeMonthLeap,
+ GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeMonthLeap,
+ new java.sql.Timestamp(ceilMonthExp.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeMonthLeap + 1, GJChronology.getInstanceUTC()))));
+
+ CeilYearExpression ceilYearExp = new CeilYearExpression();
+ java.sql.Timestamp wholeYearEven =
+ new java.sql.Timestamp(DateUtil.parseDate("2022-1-1 0:0:0").getTime());
+ long lowerBoundaryWholeYearEven = wholeYearEven.getTime() - YEAR + 1;
+ long upperBoundaryWholeYearEven = wholeYearEven.getTime();
+ assertEquals(lowerBoundaryWholeYearEven, ceilYearExp.rangeLower(wholeYearEven.getTime()));
+ assertEquals(upperBoundaryWholeYearEven, ceilYearExp.rangeUpper(wholeYearEven.getTime()));
+ assertEquals(wholeYearEven, new java.sql.Timestamp(
+ ceilYearExp.roundDateTime(new org.joda.time.DateTime(lowerBoundaryWholeYearEven,
+ GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeYearEven, new java.sql.Timestamp(
+ ceilYearExp.roundDateTime(new org.joda.time.DateTime(lowerBoundaryWholeYearEven - 1,
+ GJChronology.getInstanceUTC()))));
+ assertEquals(wholeYearEven, new java.sql.Timestamp(
+ ceilYearExp.roundDateTime(new org.joda.time.DateTime(upperBoundaryWholeYearEven,
+ GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeYearEven, new java.sql.Timestamp(
+ ceilYearExp.roundDateTime(new org.joda.time.DateTime(upperBoundaryWholeYearEven + 1,
+ GJChronology.getInstanceUTC()))));
+
+ java.sql.Timestamp wholeYearLeapEven =
+ new java.sql.Timestamp(DateUtil.parseDate("2025-1-1 0:0:0").getTime());
+ long lowerBoundaryWholeYearLeapEven = wholeYearLeapEven.getTime() - (YEAR + DAY) + 1;
+ long upperBoundaryWholeYearLeapEven = wholeYearLeapEven.getTime();
+ assertEquals(lowerBoundaryWholeYearLeapEven,
+ ceilYearExp.rangeLower(wholeYearLeapEven.getTime()));
+ assertEquals(upperBoundaryWholeYearLeapEven,
+ ceilYearExp.rangeUpper(wholeYearLeapEven.getTime()));
+ assertEquals(wholeYearLeapEven, new java.sql.Timestamp(
+ ceilYearExp.roundDateTime(new org.joda.time.DateTime(lowerBoundaryWholeYearLeapEven,
+ GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeYearLeapEven,
+ new java.sql.Timestamp(ceilYearExp.roundDateTime(new org.joda.time.DateTime(
+ lowerBoundaryWholeYearLeapEven - 1, GJChronology.getInstanceUTC()))));
+ assertEquals(wholeYearLeapEven, new java.sql.Timestamp(
+ ceilYearExp.roundDateTime(new org.joda.time.DateTime(upperBoundaryWholeYearLeapEven,
+ GJChronology.getInstanceUTC()))));
+ assertNotEquals(wholeYearLeapEven,
+ new java.sql.Timestamp(ceilYearExp.roundDateTime(new org.joda.time.DateTime(
+ upperBoundaryWholeYearLeapEven + 1, GJChronology.getInstanceUTC()))));
+ }
+
}