PHOENIX-688 Add to_time and to_timestamp built-in functions
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/11a76b29 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/11a76b29 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/11a76b29 Branch: refs/heads/calcite Commit: 11a76b297fad46cd7f51019810ba4d1a7b51b418 Parents: 78d91d1 Author: James Taylor <jtay...@salesforce.com> Authored: Sat Feb 7 23:54:53 2015 -0800 Committer: James Taylor <jtay...@salesforce.com> Committed: Mon Feb 9 18:37:14 2015 -0800 ---------------------------------------------------------------------- .../phoenix/end2end/ProductMetricsIT.java | 4 +- .../phoenix/end2end/ToDateFunctionIT.java | 67 +++++- .../phoenix/end2end/TruncateFunctionIT.java | 5 +- .../apache/phoenix/end2end/UpsertValuesIT.java | 6 +- .../phoenix/end2end/VariableLengthPKIT.java | 3 +- .../phoenix/mapreduce/CsvBulkLoadToolIT.java | 10 +- .../phoenix/compile/StatementContext.java | 28 ++- .../phoenix/expression/ExpressionType.java | 10 +- .../expression/function/ToDateFunction.java | 93 ++++++-- .../expression/function/ToTimeFunction.java | 63 ++++++ .../function/ToTimestampFunction.java | 63 ++++++ .../apache/phoenix/jdbc/PhoenixConnection.java | 20 +- .../apache/phoenix/parse/ToDateParseNode.java | 6 +- .../apache/phoenix/parse/ToTimeParseNode.java | 48 +++++ .../phoenix/parse/ToTimestampParseNode.java | 48 +++++ .../org/apache/phoenix/query/QueryServices.java | 3 + .../org/apache/phoenix/schema/types/PDate.java | 12 +- .../org/apache/phoenix/schema/types/PTime.java | 16 +- .../apache/phoenix/schema/types/PTimestamp.java | 24 +-- .../java/org/apache/phoenix/util/DateUtil.java | 213 +++++++++++++------ .../phoenix/util/csv/CsvUpsertExecutor.java | 52 +++-- .../phoenix/compile/WhereCompilerTest.java | 8 +- .../expression/SortOrderExpressionTest.java | 34 +-- .../org/apache/phoenix/util/DateUtilTest.java | 35 +-- 24 files changed, 656 insertions(+), 215 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/it/java/org/apache/phoenix/end2end/ProductMetricsIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ProductMetricsIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ProductMetricsIT.java index 975541e..ddc5fab 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ProductMetricsIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ProductMetricsIT.java @@ -31,8 +31,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; -import java.text.Format; -import java.text.ParseException; import java.util.Collections; import java.util.List; import java.util.Properties; @@ -87,7 +85,7 @@ public class ProductMetricsIT extends BaseClientManagedTimeIT { } private static Date toDate(String dateString) { - return DateUtil.parseDateTime(dateString); + return DateUtil.parseDate(dateString); } private static void initTable(byte[][] splits, long ts) throws Exception { http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/it/java/org/apache/phoenix/end2end/ToDateFunctionIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ToDateFunctionIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ToDateFunctionIT.java index 984e21b..bda4ea5 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ToDateFunctionIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ToDateFunctionIT.java @@ -18,24 +18,25 @@ package org.apache.phoenix.end2end; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.sql.Connection; import java.sql.Date; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.sql.Time; +import java.sql.Timestamp; import java.util.Properties; import org.apache.phoenix.query.QueryServices; -import org.apache.phoenix.util.DateUtil; import org.junit.After; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - public class ToDateFunctionIT extends BaseHBaseManagedTimeIT { @@ -53,18 +54,26 @@ public class ToDateFunctionIT extends BaseHBaseManagedTimeIT { conn.close(); } - private static Date callToDateFunction(Connection conn, String invocation) throws SQLException { + private static java.util.Date callToDateFunction(Connection conn, String invocation) throws SQLException { Statement stmt = conn.createStatement(); - ResultSet rs = stmt.executeQuery(String.format("SELECT %s FROM SYSTEM.CATALOG", invocation)); + ResultSet rs = stmt.executeQuery(String.format("SELECT %s FROM SYSTEM.CATALOG LIMIT 1", invocation)); assertTrue(rs.next()); - Date returnValue = rs.getDate(1); + java.util.Date returnValue = (java.util.Date)rs.getObject(1); rs.close(); stmt.close(); return returnValue; } private Date callToDateFunction(String invocation) throws SQLException { - return callToDateFunction(conn, invocation); + return (Date)callToDateFunction(conn, invocation); + } + + private Time callToTimeFunction(String invocation) throws SQLException { + return (Time)callToDateFunction(conn, invocation); + } + + private Timestamp callToTimestampFunction(String invocation) throws SQLException { + return (Timestamp)callToDateFunction(conn, invocation); } @Test @@ -87,6 +96,44 @@ public class ToDateFunctionIT extends BaseHBaseManagedTimeIT { } @Test + public void testToTime_Default() throws SQLException { + // Default time zone is GMT, so this is timestamp 0 + assertEquals(0L, callToTimeFunction("TO_TIME('1970-01-01 00:00:00')").getTime()); + assertEquals(0L, callToTimeFunction("TO_TIME('1970-01-01 00:00:00.000')").getTime()); + assertEquals(0L, callToTimeFunction("TO_TIME('1970-01-01')").getTime()); + assertEquals(0L, callToTimeFunction("TO_TIME('1970/01/01','yyyy/MM/dd')").getTime()); + + // Test other ISO 8601 Date Compliant Formats to verify they can be parsed + try { + callToTimeFunction("TO_TIME('2015-01-27T16:17:57+00:00')"); + callToTimeFunction("TO_TIME('2015-01-27T16:17:57Z')"); + callToTimeFunction("TO_TIME('2015-W05')"); + callToTimeFunction("TO_TIME('2015-W05-2')"); + } catch (Exception ex) { + fail("TO_TIME Parse ISO8601 Time Failed due to:" + ex); + } + } + + @Test + public void testToTimestamp_Default() throws SQLException { + // Default time zone is GMT, so this is timestamp 0 + assertEquals(0L, callToTimestampFunction("TO_TIMESTAMP('1970-01-01 00:00:00')").getTime()); + assertEquals(0L, callToTimestampFunction("TO_TIMESTAMP('1970-01-01 00:00:00.000')").getTime()); + assertEquals(0L, callToTimestampFunction("TO_TIMESTAMP('1970-01-01')").getTime()); + assertEquals(0L, callToTimestampFunction("TO_TIMESTAMP('1970/01/01','yyyy/MM/dd')").getTime()); + + // Test other ISO 8601 Date Compliant Formats to verify they can be parsed + try { + callToTimestampFunction("TO_TIMESTAMP('2015-01-27T16:17:57+00:00')"); + callToTimestampFunction("TO_TIMESTAMP('2015-01-27T16:17:57Z')"); + callToTimestampFunction("TO_TIMESTAMP('2015-W05')"); + callToTimestampFunction("TO_TIMESTAMP('2015-W05-2')"); + } catch (Exception ex) { + fail("TO_TIMESTAMP Parse ISO8601 Time Failed due to:" + ex); + } + } + + @Test public void testToDate_CustomDateFormat() throws SQLException { // A date without time component is at midnight assertEquals(0L, callToDateFunction("TO_DATE('1970-01-01', 'yyyy-MM-dd')").getTime()); @@ -115,7 +162,7 @@ public class ToDateFunctionIT extends BaseHBaseManagedTimeIT { assertEquals( -ONE_HOUR_IN_MILLIS, - callToDateFunction(customTimeZoneConn, "TO_DATE('1970-01-01 00:00:00')").getTime()); + callToDateFunction(customTimeZoneConn, "TO_DATE('1970-01-01 00:00:00.000')").getTime()); } @Test http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/it/java/org/apache/phoenix/end2end/TruncateFunctionIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/TruncateFunctionIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/TruncateFunctionIT.java index 59c499d..9e8f2c0 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/TruncateFunctionIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/TruncateFunctionIT.java @@ -32,7 +32,6 @@ import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Timestamp; -import java.text.Format; import java.text.ParseException; import java.util.Properties; @@ -47,11 +46,11 @@ public class TruncateFunctionIT extends BaseClientManagedTimeIT { private static final String DS3 = "1970-01-30 01:30:24.353"; private static Date toDate(String s) throws ParseException { - return DateUtil.parseDateTime(s); + return DateUtil.parseDate(s); } private static Timestamp toTimestamp(String s) throws ParseException { - return new Timestamp((DateUtil.parseDateTime(s)).getTime()); + return DateUtil.parseTimestamp(s); } @Test http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/it/java/org/apache/phoenix/end2end/UpsertValuesIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/UpsertValuesIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/UpsertValuesIT.java index b44fbff..8e07af5 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/UpsertValuesIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/UpsertValuesIT.java @@ -33,8 +33,8 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import java.sql.Timestamp; import java.sql.Time; +import java.sql.Timestamp; import java.util.Properties; import org.apache.phoenix.exception.SQLExceptionCode; @@ -156,7 +156,7 @@ public class UpsertValuesIT extends BaseClientManagedTimeIT { ResultSet rs = conn.createStatement().executeQuery("select k,to_char(date) from UpsertDateTest"); assertTrue(rs.next()); assertEquals("a", rs.getString(1)); - assertEquals("2013-06-08 00:00:00", rs.getString(2)); + assertEquals("2013-06-08 00:00:00.000", rs.getString(2)); } @Test @@ -548,7 +548,7 @@ public class UpsertValuesIT extends BaseClientManagedTimeIT { } private static Date toDate(String dateString) { - return DateUtil.parseDateTime(dateString); + return DateUtil.parseDate(dateString); } @Test http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/it/java/org/apache/phoenix/end2end/VariableLengthPKIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/VariableLengthPKIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/VariableLengthPKIT.java index 0d9aeb2..417d147 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/VariableLengthPKIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/VariableLengthPKIT.java @@ -38,7 +38,6 @@ import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.text.Format; -import java.text.ParseException; import java.util.Properties; import org.apache.phoenix.exception.SQLExceptionCode; @@ -55,7 +54,7 @@ public class VariableLengthPKIT extends BaseClientManagedTimeIT { private static final Date D1 = toDate(DS1); private static Date toDate(String dateString) { - return DateUtil.parseDateTime(dateString); + return DateUtil.parseDate(dateString); } protected static void initGroupByRowKeyColumns(long ts) throws Exception { http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java b/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java index 00968ae..392395d 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java @@ -44,12 +44,6 @@ import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; -import static org.apache.phoenix.query.BaseTest.setUpConfigForMiniCluster; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - @Category(NeedsOwnMiniClusterTest.class) public class CsvBulkLoadToolIT { @@ -119,11 +113,11 @@ public class CsvBulkLoadToolIT { assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); assertEquals("Name 1", rs.getString(2)); - assertEquals(DateUtil.parseDateTime("1970-01-01"), rs.getDate(3)); + assertEquals(DateUtil.parseDate("1970-01-01"), rs.getDate(3)); assertTrue(rs.next()); assertEquals(2, rs.getInt(1)); assertEquals("Name 2", rs.getString(2)); - assertEquals(DateUtil.parseDateTime("1970-01-02"), rs.getDate(3)); + assertEquals(DateUtil.parseDate("1970-01-02"), rs.getDate(3)); assertFalse(rs.next()); rs.close(); http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementContext.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementContext.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementContext.java index f48f613..d726488 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementContext.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementContext.java @@ -60,8 +60,12 @@ public class StatementContext { private final ExpressionManager expressions; private final AggregationManager aggregates; private final String dateFormat; - private final TimeZone dateFormatTimeZone; private final Format dateFormatter; + private final String timeFormat; + private final Format timeFormatter; + private final String timestampFormat; + private final Format timestampFormatter; + private final TimeZone dateFormatTimeZone; private final String numberFormat; private final ImmutableBytesWritable tempPtr; private final PhoenixStatement statement; @@ -99,9 +103,13 @@ public class StatementContext { this.expressions = new ExpressionManager(); PhoenixConnection connection = statement.getConnection(); this.dateFormat = connection.getQueryServices().getProps().get(QueryServices.DATE_FORMAT_ATTRIB, DateUtil.DEFAULT_DATE_FORMAT); + this.dateFormatter = DateUtil.getDateFormatter(dateFormat); + this.timeFormat = connection.getQueryServices().getProps().get(QueryServices.TIME_FORMAT_ATTRIB, DateUtil.DEFAULT_TIME_FORMAT); + this.timeFormatter = DateUtil.getTimeFormatter(timeFormat); + this.timestampFormat = connection.getQueryServices().getProps().get(QueryServices.TIMESTAMP_FORMAT_ATTRIB, DateUtil.DEFAULT_TIMESTAMP_FORMAT); + this.timestampFormatter = DateUtil.getTimestampFormatter(timestampFormat); this.dateFormatTimeZone = TimeZone.getTimeZone( connection.getQueryServices().getProps().get(QueryServices.DATE_FORMAT_TIMEZONE_ATTRIB, DateUtil.DEFAULT_TIME_ZONE_ID)); - this.dateFormatter = DateUtil.getDateFormatter(dateFormat); this.numberFormat = connection.getQueryServices().getProps().get(QueryServices.NUMBER_FORMAT_ATTRIB, NumberUtil.DEFAULT_NUMBER_FORMAT); this.tempPtr = new ImmutableBytesWritable(); this.currentTable = resolver != null && !resolver.getTables().isEmpty() ? resolver.getTables().get(0) : null; @@ -151,6 +159,22 @@ public class StatementContext { return dateFormatter; } + public String getTimeFormat() { + return timeFormat; + } + + public Format getTimeFormatter() { + return timeFormatter; + } + + public String getTimestampFormat() { + return timestampFormat; + } + + public Format getTimestampFormatter() { + return timestampFormatter; + } + public String getNumberFormat() { return numberFormat; } http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java index 706a751..cbbfe4a 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java @@ -21,6 +21,7 @@ import java.util.Map; import org.apache.phoenix.expression.function.ArrayAllComparisonExpression; import org.apache.phoenix.expression.function.ArrayAnyComparisonExpression; +import org.apache.phoenix.expression.function.ArrayElemRefExpression; import org.apache.phoenix.expression.function.ArrayIndexFunction; import org.apache.phoenix.expression.function.ArrayLengthFunction; import org.apache.phoenix.expression.function.CeilDateExpression; @@ -40,7 +41,6 @@ import org.apache.phoenix.expression.function.FloorDateExpression; import org.apache.phoenix.expression.function.FloorDecimalExpression; import org.apache.phoenix.expression.function.FloorFunction; import org.apache.phoenix.expression.function.IndexStateNameFunction; -import org.apache.phoenix.expression.function.ArrayElemRefExpression; import org.apache.phoenix.expression.function.InvertFunction; import org.apache.phoenix.expression.function.LTrimFunction; import org.apache.phoenix.expression.function.LastValueFunction; @@ -76,6 +76,8 @@ import org.apache.phoenix.expression.function.TimezoneOffsetFunction; import org.apache.phoenix.expression.function.ToCharFunction; import org.apache.phoenix.expression.function.ToDateFunction; import org.apache.phoenix.expression.function.ToNumberFunction; +import org.apache.phoenix.expression.function.ToTimeFunction; +import org.apache.phoenix.expression.function.ToTimestampFunction; import org.apache.phoenix.expression.function.TrimFunction; import org.apache.phoenix.expression.function.TruncFunction; import org.apache.phoenix.expression.function.UpperFunction; @@ -187,7 +189,11 @@ public enum ExpressionType { ModulusExpression(ModulusExpression.class), DistinctValueAggregateFunction(DistinctValueAggregateFunction.class), RegexpSplitFunctiond(RegexpSplitFunction.class), - RandomFunction(RandomFunction.class); + RandomFunction(RandomFunction.class), + ToTimeFunction(ToTimeFunction.class), + ToTimestampFunction(ToTimestampFunction.class), + ; + ExpressionType(Class<? extends Expression> clazz) { this.clazz = clazz; } http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java index 73ca3ed..01b0dfd 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java @@ -17,24 +17,23 @@ */ package org.apache.phoenix.expression.function; -import java.io.*; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; import java.sql.SQLException; -import java.text.Format; -import java.text.ParseException; import java.util.List; -import org.apache.commons.lang.StringUtils; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.io.WritableUtils; - import org.apache.phoenix.expression.Expression; -import org.apache.phoenix.parse.*; +import org.apache.phoenix.expression.LiteralExpression; import org.apache.phoenix.parse.FunctionParseNode.Argument; import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction; -import org.apache.phoenix.schema.types.PDate; +import org.apache.phoenix.parse.ToDateParseNode; +import org.apache.phoenix.schema.tuple.Tuple; import org.apache.phoenix.schema.types.PDataType; +import org.apache.phoenix.schema.types.PDate; import org.apache.phoenix.schema.types.PVarchar; -import org.apache.phoenix.schema.tuple.Tuple; import org.apache.phoenix.util.DateUtil; @@ -46,7 +45,6 @@ import org.apache.phoenix.util.DateUtil; * valid (constant) timezone id, or the string "local". The third argument is also optional, and * it defaults to GMT. * - * @since 0.1 */ @BuiltInFunction(name=ToDateFunction.NAME, nodeClass=ToDateParseNode.class, args={@Argument(allowedTypes={PVarchar.class}), @@ -56,33 +54,47 @@ public class ToDateFunction extends ScalarFunction { public static final String NAME = "TO_DATE"; private DateUtil.DateTimeParser dateParser; private String dateFormat; + private String timeZoneId; public ToDateFunction() { } - public ToDateFunction(List<Expression> children, String dateFormat, DateUtil.DateTimeParser dateParser) throws SQLException { - super(children.subList(0, 1)); + public ToDateFunction(List<Expression> children, String dateFormat, String timeZoneId) throws SQLException { + super(children); + init(dateFormat, timeZoneId); + } + + private void init(String dateFormat, String timeZoneId) { this.dateFormat = dateFormat; - this.dateParser = dateParser; + this.dateParser = DateUtil.getDateTimeParser(dateFormat, getDataType(), timeZoneId); + // Store resolved timeZoneId, as if it's LOCAL, we don't want the + // server to evaluate using the local time zone. Instead, we want + // to use the client local time zone. + this.timeZoneId = this.dateParser.getTimeZone().getID(); } @Override public int hashCode() { final int prime = 31; - int result = 1; - result = prime * result + dateFormat.hashCode(); - result = prime * result + getExpression().hashCode(); + int result = super.hashCode(); + result = prime * result + ((dateFormat == null) ? 0 : dateFormat.hashCode()); + result = prime * result + ((timeZoneId == null) ? 0 : timeZoneId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; - if (obj == null) return false; if (getClass() != obj.getClass()) return false; ToDateFunction other = (ToDateFunction)obj; - if (!getExpression().equals(other.getExpression())) return false; - if (!dateFormat.equals(other.dateFormat)) return false; + // Only compare first child, as the other two are potentially resolved on the fly. + if (!this.getChildren().get(0).equals(other.getChildren().get(0))) return false; + if (dateFormat == null) { + if (other.dateFormat != null) return false; + } else if (!dateFormat.equals(other.dateFormat)) return false; + if (timeZoneId == null) { + if (other.timeZoneId != null) return false; + } else if (!timeZoneId.equals(other.timeZoneId)) return false; return true; } @@ -94,8 +106,10 @@ public class ToDateFunction extends ScalarFunction { } PDataType type = expression.getDataType(); String dateStr = (String)type.toObject(ptr, expression.getSortOrder()); - Object value = dateParser.parseDateTime(dateStr); - byte[] byteValue = getDataType().toBytes(value); + long epochTime = dateParser.parseDateTime(dateStr); + PDataType returnType = getDataType(); + byte[] byteValue = new byte[returnType.getByteSize()]; + returnType.getCodec().encodeLong(epochTime, byteValue, 0); ptr.set(byteValue); return true; } @@ -110,17 +124,50 @@ public class ToDateFunction extends ScalarFunction { return getExpression().isNullable(); } + private String getTimeZoneIdArg() { + return children.size() < 3 ? null : (String) ((LiteralExpression) children.get(2)).getValue(); + } + + private String getDateFormatArg() { + return children.size() < 2 ? null : (String) ((LiteralExpression) children.get(1)).getValue(); + } + @Override public void readFields(DataInput input) throws IOException { super.readFields(input); - dateFormat = WritableUtils.readString(input); - dateParser = DateUtil.getDateParser(dateFormat); + String timeZoneId; + String dateFormat = WritableUtils.readString(input); + if (dateFormat.length() != 0) { // pre 4.3 + timeZoneId = DateUtil.DEFAULT_TIME_ZONE_ID; + } else { + int nChildren = children.size(); + if (nChildren == 1) { + dateFormat = WritableUtils.readString(input); + timeZoneId = WritableUtils.readString(input); + } else if (nChildren == 2 || DateUtil.LOCAL_TIME_ZONE_ID.equalsIgnoreCase(getTimeZoneIdArg())) { + dateFormat = getDateFormatArg(); + timeZoneId = WritableUtils.readString(input); + } else { + dateFormat = getDateFormatArg(); + timeZoneId = getTimeZoneIdArg(); + } + } + init(dateFormat, timeZoneId); } @Override public void write(DataOutput output) throws IOException { super.write(output); - WritableUtils.writeString(output, dateFormat); + WritableUtils.writeString(output, ""); // For b/w compat + int nChildren = children.size(); + // If dateFormat and/or timeZoneId are supplied as children, don't write them again, + // except if using LOCAL, in which case we want to write the resolved/actual time zone. + if (nChildren == 1) { + WritableUtils.writeString(output, dateFormat); + WritableUtils.writeString(output, timeZoneId); + } else if (nChildren == 2 || DateUtil.LOCAL_TIME_ZONE_ID.equalsIgnoreCase(getTimeZoneIdArg())) { + WritableUtils.writeString(output, timeZoneId); + } } private Expression getExpression() { http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToTimeFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToTimeFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToTimeFunction.java new file mode 100644 index 0000000..3a26584 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToTimeFunction.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.phoenix.expression.function; + +import java.sql.SQLException; +import java.util.List; + +import org.apache.phoenix.expression.Expression; +import org.apache.phoenix.parse.FunctionParseNode.Argument; +import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction; +import org.apache.phoenix.parse.ToTimeParseNode; +import org.apache.phoenix.schema.types.PDataType; +import org.apache.phoenix.schema.types.PTime; +import org.apache.phoenix.schema.types.PVarchar; + +/** +* +* Implementation of the {@code TO_TIME(<string>,[<format-string>,[<timezone-string>]])} built-in function. +* The second argument is optional and defaults to the phoenix.query.dateFormat value +* from the HBase config. If present it must be a constant string. The third argument is either a +* valid (constant) timezone id, or the string "LOCAL". The third argument is also optional, and +* it defaults to GMT. +* +*/ +@BuiltInFunction(name=ToTimeFunction.NAME, nodeClass=ToTimeParseNode.class, + args={@Argument(allowedTypes={PVarchar.class}), + @Argument(allowedTypes={PVarchar.class},isConstant=true,defaultValue="null"), + @Argument(allowedTypes={PVarchar.class}, isConstant=true, defaultValue = "null") } ) +public class ToTimeFunction extends ToDateFunction { + public static final String NAME = "TO_TIME"; + + public ToTimeFunction() { + } + + public ToTimeFunction(List<Expression> children, String dateFormat, String timeZoneId) throws SQLException { + super(children, dateFormat, timeZoneId); + } + + @Override + public PDataType getDataType() { + return PTime.INSTANCE; + } + + @Override + public String getName() { + return NAME; + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToTimestampFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToTimestampFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToTimestampFunction.java new file mode 100644 index 0000000..17643a2 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToTimestampFunction.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.phoenix.expression.function; + +import java.sql.SQLException; +import java.util.List; + +import org.apache.phoenix.expression.Expression; +import org.apache.phoenix.parse.FunctionParseNode.Argument; +import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction; +import org.apache.phoenix.parse.ToTimestampParseNode; +import org.apache.phoenix.schema.types.PDataType; +import org.apache.phoenix.schema.types.PTimestamp; +import org.apache.phoenix.schema.types.PVarchar; + +/** +* +* Implementation of the {@code TO_TIMESTAMP(<string>,[<format-string>,[<timezone-string>]])} built-in function. +* The second argument is optional and defaults to the phoenix.query.timestampFormat value +* from the HBase config. If present it must be a constant string. The third argument is either a +* valid (constant) timezone id, or the string "local". The third argument is also optional, and +* it defaults to GMT. +* +*/ +@BuiltInFunction(name=ToTimestampFunction.NAME, nodeClass=ToTimestampParseNode.class, + args={@Argument(allowedTypes={PVarchar.class}), + @Argument(allowedTypes={PVarchar.class},isConstant=true,defaultValue="null"), + @Argument(allowedTypes={PVarchar.class}, isConstant=true, defaultValue = "null") } ) +public class ToTimestampFunction extends ToDateFunction { + public static final String NAME = "TO_TIMESTAMP"; + + public ToTimestampFunction() { + } + + public ToTimestampFunction(List<Expression> children, String dateFormat, String timeZoneId) throws SQLException { + super(children, dateFormat, timeZoneId); + } + + @Override + public PDataType getDataType() { + return PTimestamp.INSTANCE; + } + + @Override + public String getName() { + return NAME; + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixConnection.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixConnection.java b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixConnection.java index b778a57..de9e323 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixConnection.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixConnection.java @@ -128,6 +128,8 @@ public class PhoenixConnection implements Connection, org.apache.phoenix.jdbc.Jd private PMetaData metaData; private final PName tenantId; private final String datePattern; + private final String timePattern; + private final String timestampPattern; private boolean isClosed = false; private Sampler<?> sampler; @@ -204,15 +206,19 @@ public class PhoenixConnection implements Connection, org.apache.phoenix.jdbc.Jd this.tenantId = tenantId; this.mutateBatchSize = JDBCUtil.getMutateBatchSize(url, this.info, this.services.getProps()); datePattern = this.services.getProps().get(QueryServices.DATE_FORMAT_ATTRIB, DateUtil.DEFAULT_DATE_FORMAT); + timePattern = this.services.getProps().get(QueryServices.TIME_FORMAT_ATTRIB, DateUtil.DEFAULT_TIME_FORMAT); + timestampPattern = this.services.getProps().get(QueryServices.TIMESTAMP_FORMAT_ATTRIB, DateUtil.DEFAULT_TIMESTAMP_FORMAT); String numberPattern = this.services.getProps().get(QueryServices.NUMBER_FORMAT_ATTRIB, NumberUtil.DEFAULT_NUMBER_FORMAT); int maxSize = this.services.getProps().getInt(QueryServices.MAX_MUTATION_SIZE_ATTRIB,QueryServicesOptions.DEFAULT_MAX_MUTATION_SIZE); - Format dateTimeFormat = DateUtil.getDateFormatter(datePattern); - formatters.put(PDate.INSTANCE, dateTimeFormat); - formatters.put(PTime.INSTANCE, dateTimeFormat); - formatters.put(PTimestamp.INSTANCE, dateTimeFormat); - formatters.put(PUnsignedDate.INSTANCE, dateTimeFormat); - formatters.put(PUnsignedTime.INSTANCE, dateTimeFormat); - formatters.put(PUnsignedTimestamp.INSTANCE, dateTimeFormat); + Format dateFormat = DateUtil.getDateFormatter(datePattern); + Format timeFormat = DateUtil.getDateFormatter(timePattern); + Format timestampFormat = DateUtil.getDateFormatter(timestampPattern); + formatters.put(PDate.INSTANCE, dateFormat); + formatters.put(PTime.INSTANCE, timeFormat); + formatters.put(PTimestamp.INSTANCE, timestampFormat); + formatters.put(PUnsignedDate.INSTANCE, dateFormat); + formatters.put(PUnsignedTime.INSTANCE, timeFormat); + formatters.put(PUnsignedTimestamp.INSTANCE, timestampFormat); formatters.put(PDecimal.INSTANCE, FunctionArgumentType.NUMERIC.getFormatter(numberPattern)); // We do not limit the metaData on a connection less than the global one, // as there's not much that will be cached here. http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/parse/ToDateParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ToDateParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ToDateParseNode.java index 6140dbc..fd4d16a 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ToDateParseNode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ToDateParseNode.java @@ -18,16 +18,13 @@ package org.apache.phoenix.parse; import java.sql.SQLException; -import java.text.Format; import java.util.List; -import java.util.TimeZone; import org.apache.phoenix.compile.StatementContext; import org.apache.phoenix.expression.Expression; import org.apache.phoenix.expression.LiteralExpression; import org.apache.phoenix.expression.function.FunctionExpression; import org.apache.phoenix.expression.function.ToDateFunction; -import org.apache.phoenix.util.DateUtil; public class ToDateParseNode extends FunctionParseNode { @@ -46,7 +43,6 @@ public class ToDateParseNode extends FunctionParseNode { if (timeZoneId == null) { timeZoneId = context.getDateFormatTimeZone().getID(); } - DateUtil.DateTimeParser dateParser = DateUtil.getDateParser(dateFormat, timeZoneId); - return new ToDateFunction(children, dateFormat, dateParser); + return new ToDateFunction(children, dateFormat, timeZoneId); } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/parse/ToTimeParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ToTimeParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ToTimeParseNode.java new file mode 100644 index 0000000..5f0a72d --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ToTimeParseNode.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.phoenix.parse; + +import java.sql.SQLException; +import java.util.List; + +import org.apache.phoenix.compile.StatementContext; +import org.apache.phoenix.expression.Expression; +import org.apache.phoenix.expression.LiteralExpression; +import org.apache.phoenix.expression.function.FunctionExpression; +import org.apache.phoenix.expression.function.ToTimeFunction; + + +public class ToTimeParseNode extends FunctionParseNode { + + public ToTimeParseNode(String name, List<ParseNode> children, BuiltInFunctionInfo info) { + super(name, children, info); + } + + @Override + public FunctionExpression create(List<Expression> children, StatementContext context) throws SQLException { + String dateFormat = (String) ((LiteralExpression) children.get(1)).getValue(); + String timeZoneId = (String) ((LiteralExpression) children.get(2)).getValue(); + if (dateFormat == null) { + dateFormat = context.getTimeFormat(); + } + if (timeZoneId == null) { + timeZoneId = context.getDateFormatTimeZone().getID(); + } + return new ToTimeFunction(children, dateFormat, timeZoneId); + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/parse/ToTimestampParseNode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ToTimestampParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ToTimestampParseNode.java new file mode 100644 index 0000000..2a3f5ec --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ToTimestampParseNode.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.phoenix.parse; + +import java.sql.SQLException; +import java.util.List; + +import org.apache.phoenix.compile.StatementContext; +import org.apache.phoenix.expression.Expression; +import org.apache.phoenix.expression.LiteralExpression; +import org.apache.phoenix.expression.function.FunctionExpression; +import org.apache.phoenix.expression.function.ToTimestampFunction; + + +public class ToTimestampParseNode extends FunctionParseNode { + + public ToTimestampParseNode(String name, List<ParseNode> children, BuiltInFunctionInfo info) { + super(name, children, info); + } + + @Override + public FunctionExpression create(List<Expression> children, StatementContext context) throws SQLException { + String dateFormat = (String) ((LiteralExpression) children.get(1)).getValue(); + String timeZoneId = (String) ((LiteralExpression) children.get(2)).getValue(); + if (dateFormat == null) { + dateFormat = context.getTimestampFormat(); + } + if (timeZoneId == null) { + timeZoneId = context.getDateFormatTimeZone().getID(); + } + return new ToTimestampFunction(children, dateFormat, timeZoneId); + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java index d21695d..e20d5ee 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java @@ -71,6 +71,9 @@ public interface QueryServices extends SQLCloseable { public static final String MAX_SERVER_CACHE_SIZE_ATTRIB = "phoenix.query.maxServerCacheBytes"; public static final String DATE_FORMAT_TIMEZONE_ATTRIB = "phoenix.query.dateFormatTimeZone"; public static final String DATE_FORMAT_ATTRIB = "phoenix.query.dateFormat"; + public static final String TIME_FORMAT_ATTRIB = "phoenix.query.timeFormat"; + public static final String TIMESTAMP_FORMAT_ATTRIB = "phoenix.query.timestampFormat"; + public static final String NUMBER_FORMAT_ATTRIB = "phoenix.query.numberFormat"; public static final String CALL_QUEUE_ROUND_ROBIN_ATTRIB = "ipc.server.callqueue.roundrobin"; public static final String SCAN_CACHE_SIZE_ATTRIB = "hbase.client.scanner.caching"; http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDate.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDate.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDate.java index 13a828f..bbd0a35 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDate.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PDate.java @@ -17,16 +17,16 @@ */ package org.apache.phoenix.schema.types; -import org.apache.hadoop.hbase.io.ImmutableBytesWritable; -import org.apache.hadoop.hbase.util.Bytes; -import org.apache.phoenix.schema.SortOrder; -import org.apache.phoenix.util.DateUtil; - import java.math.BigDecimal; import java.sql.Date; import java.sql.Types; import java.text.Format; +import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.phoenix.schema.SortOrder; +import org.apache.phoenix.util.DateUtil; + public class PDate extends PDataType<Date> { public static final PDate INSTANCE = new PDate(); @@ -71,7 +71,7 @@ public class PDate extends PDataType<Date> { } else if (actualType == PDecimal.INSTANCE) { return new Date(((BigDecimal) object).longValueExact()); } else if (actualType == PVarchar.INSTANCE) { - return DateUtil.parseDateTime((String) object); + return DateUtil.parseDate((String) object); } return throwConstraintViolationException(actualType, this); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTime.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTime.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTime.java index d824885..81cbaff 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTime.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTime.java @@ -17,15 +17,15 @@ */ package org.apache.phoenix.schema.types; -import org.apache.hadoop.hbase.util.Bytes; -import org.apache.phoenix.schema.SortOrder; -import org.apache.phoenix.util.DateUtil; - import java.math.BigDecimal; import java.sql.Time; import java.sql.Types; import java.text.Format; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.phoenix.schema.SortOrder; +import org.apache.phoenix.util.DateUtil; + public class PTime extends PDataType<Time> { public static final PTime INSTANCE = new PTime(); @@ -78,7 +78,7 @@ public class PTime extends PDataType<Time> { } else if (actualType == PDecimal.INSTANCE) { return new java.sql.Time(((BigDecimal) object).longValueExact()); } else if (actualType == PVarchar.INSTANCE) { - return DateUtil.parseDateTime((String) object); + return DateUtil.parseTime((String) object); } return throwConstraintViolationException(actualType, this); } @@ -128,8 +128,10 @@ public class PTime extends PDataType<Time> { @Override public String toStringLiteral(byte[] b, int offset, int length, Format formatter) { - // TODO: different default formatter for TIME? - return PDate.INSTANCE.toStringLiteral(b, offset, length, formatter); + if (formatter == null) { + formatter = DateUtil.DEFAULT_TIME_FORMATTER; + } + return "'" + super.toStringLiteral(b, offset, length, formatter) + "'"; } @Override http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTimestamp.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTimestamp.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTimestamp.java index 4bdcb86..8182e33 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTimestamp.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PTimestamp.java @@ -17,17 +17,17 @@ */ package org.apache.phoenix.schema.types; +import java.math.BigDecimal; +import java.sql.Timestamp; +import java.sql.Types; +import java.text.Format; + import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.util.Bytes; import org.apache.phoenix.query.QueryConstants; import org.apache.phoenix.schema.SortOrder; import org.apache.phoenix.util.DateUtil; -import java.math.BigDecimal; -import java.sql.Timestamp; -import java.sql.Types; -import java.text.Format; - public class PTimestamp extends PDataType<Timestamp> { public static final PTimestamp INSTANCE = new PTimestamp(); @@ -84,7 +84,7 @@ public class PTimestamp extends PDataType<Timestamp> { .intValue(); return DateUtil.getTimestamp(ms, nanos); } else if (actualType == PVarchar.INSTANCE) { - return new Timestamp(DateUtil.parseDateTime((String) object).getTime()); + return DateUtil.parseTimestamp((String) object); } return throwConstraintViolationException(actualType, this); } @@ -181,15 +181,13 @@ public class PTimestamp extends PDataType<Timestamp> { @Override public String toStringLiteral(byte[] b, int offset, int length, Format formatter) { - java.sql.Timestamp value = (java.sql.Timestamp) toObject(b, offset, length); - if (formatter == null || formatter == DateUtil.DEFAULT_DATE_FORMATTER) { - // If default formatter has not been overridden, - // use one that displays milliseconds. - formatter = DateUtil.DEFAULT_MS_DATE_FORMATTER; - } - return "'" + super.toStringLiteral(b, offset, length, formatter) + "." + value.getNanos() + "'"; + if (formatter == null) { + formatter = DateUtil.DEFAULT_TIMESTAMP_FORMATTER; + } + return "'" + super.toStringLiteral(b, offset, length, formatter) + "'"; } + @Override public int getNanos(ImmutableBytesWritable ptr, SortOrder sortOrder) { int nanos = PUnsignedInt.INSTANCE.getCodec() http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/util/DateUtil.java ---------------------------------------------------------------------- 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 fbc74ba..0f4b54a 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 @@ -21,85 +21,122 @@ import java.math.BigDecimal; import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; +import java.sql.Types; import java.text.Format; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.List; import java.util.TimeZone; import org.apache.commons.lang.time.FastDateFormat; import org.apache.phoenix.query.QueryConstants; import org.apache.phoenix.schema.IllegalDataException; +import org.apache.phoenix.schema.types.PDataType; +import org.joda.time.DateTimeZone; import org.joda.time.chrono.ISOChronology; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatterBuilder; import org.joda.time.format.ISODateTimeFormat; +import com.google.common.collect.Lists; -@SuppressWarnings("serial") + +@SuppressWarnings({ "serial", "deprecation" }) public class DateUtil { public static final String DEFAULT_TIME_ZONE_ID = "GMT"; + public static final String LOCAL_TIME_ZONE_ID = "LOCAL"; private static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getTimeZone(DEFAULT_TIME_ZONE_ID); - public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; // This is the format the app sets in NLS settings for every connection. - public static final Format DEFAULT_DATE_FORMATTER = FastDateFormat.getInstance( - DEFAULT_DATE_FORMAT, TimeZone.getTimeZone(DEFAULT_TIME_ZONE_ID)); - + public static final String DEFAULT_MS_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS"; public static final Format DEFAULT_MS_DATE_FORMATTER = FastDateFormat.getInstance( DEFAULT_MS_DATE_FORMAT, TimeZone.getTimeZone(DEFAULT_TIME_ZONE_ID)); - private static final DateTimeFormatter ISO_DATE_TIME_PARSER = new DateTimeFormatterBuilder() - .append(ISODateTimeFormat.dateParser()) - .appendOptional(new DateTimeFormatterBuilder() - .appendLiteral(' ').toParser()) - .appendOptional(new DateTimeFormatterBuilder() - .append(ISODateTimeFormat.timeParser()).toParser()) - .toFormatter() - .withZoneUTC() - .withChronology(ISOChronology.getInstanceUTC()); + public static final String DEFAULT_DATE_FORMAT = DEFAULT_MS_DATE_FORMAT; + public static final Format DEFAULT_DATE_FORMATTER = DEFAULT_MS_DATE_FORMATTER; - private DateUtil() { - } + public static final String DEFAULT_TIME_FORMAT = DEFAULT_MS_DATE_FORMAT; + public static final Format DEFAULT_TIME_FORMATTER = DEFAULT_MS_DATE_FORMATTER; - public static DateTimeParser getDateParser(String pattern, TimeZone timeZone) { - if(DateUtil.DEFAULT_DATE_FORMAT.equals(pattern) && - timeZone.getID().equalsIgnoreCase(DateUtil.DEFAULT_TIME_ZONE_ID)) { - return ISODateFormatParser.getInstance(); - } else { - return new SimpleDateFormatParser(pattern, timeZone); - } + public static final String DEFAULT_TIMESTAMP_FORMAT = DEFAULT_MS_DATE_FORMAT; + public static final Format DEFAULT_TIMESTAMP_FORMATTER = DEFAULT_MS_DATE_FORMATTER; + + private static final DateTimeFormatter ISO_DATE_TIME_FORMATTER = new DateTimeFormatterBuilder() + .append(ISODateTimeFormat.dateParser()) + .appendOptional(new DateTimeFormatterBuilder() + .appendLiteral(' ').toParser()) + .appendOptional(new DateTimeFormatterBuilder() + .append(ISODateTimeFormat.timeParser()).toParser()) + .toFormatter().withChronology(ISOChronology.getInstanceUTC()); + + private DateUtil() { } - public static DateTimeParser getDateParser(String pattern, String timeZoneId) { - if(timeZoneId == null) { - timeZoneId = DateUtil.DEFAULT_TIME_ZONE_ID; - } + private static TimeZone getTimeZone(String timeZoneId) { TimeZone parserTimeZone; - if ("LOCAL".equalsIgnoreCase(timeZoneId)) { + if (timeZoneId == null) { + parserTimeZone = DateUtil.DEFAULT_TIME_ZONE; + } else if (LOCAL_TIME_ZONE_ID.equalsIgnoreCase(timeZoneId)) { parserTimeZone = TimeZone.getDefault(); } else { parserTimeZone = TimeZone.getTimeZone(timeZoneId); } - return getDateParser(pattern, parserTimeZone); + return parserTimeZone; } - - public static DateTimeParser getDateParser(String pattern) { - return getDateParser(pattern, DEFAULT_TIME_ZONE); - } - - public static DateTimeParser getTimeParser(String pattern, TimeZone timeZone) { - return getDateParser(pattern, timeZone); + + private static String[] defaultPattern; + static { + int maxOrdinal = Integer.MIN_VALUE; + List<PDataType> timeDataTypes = Lists.newArrayListWithExpectedSize(6); + for (PDataType type : PDataType.values()) { + if (java.util.Date.class.isAssignableFrom(type.getJavaClass())) { + timeDataTypes.add(type); + if (type.ordinal() > maxOrdinal) { + maxOrdinal = type.ordinal(); + } + } + } + defaultPattern = new String[maxOrdinal+1]; + for (PDataType type : timeDataTypes) { + switch (type.getResultSetSqlType()) { + case Types.TIMESTAMP: + defaultPattern[type.ordinal()] = DateUtil.DEFAULT_TIMESTAMP_FORMAT; + break; + case Types.TIME: + defaultPattern[type.ordinal()] = DateUtil.DEFAULT_TIME_FORMAT; + break; + case Types.DATE: + defaultPattern[type.ordinal()] = DateUtil.DEFAULT_DATE_FORMAT; + break; + } + } } - - public static DateTimeParser getTimeParser(String pattern) { - return getTimeParser(pattern, DEFAULT_TIME_ZONE); + + private static String getDefaultFormat(PDataType type) { + int ordinal = type.ordinal(); + if (ordinal >= 0 || ordinal < defaultPattern.length) { + String format = defaultPattern[ordinal]; + if (format != null) { + return format; + } + } + throw new IllegalArgumentException("Expected a date/time type, but got " + type); } - public static DateTimeParser getTimestampParser(String pattern, TimeZone timeZone) { - return getDateParser(pattern, timeZone); + public static DateTimeParser getDateTimeParser(String pattern, PDataType pDataType, String timeZoneId) { + TimeZone timeZone = getTimeZone(timeZoneId); + String defaultPattern = getDefaultFormat(pDataType); + if (pattern == null || pattern.length() == 0) { + pattern = defaultPattern; + } + if(defaultPattern.equals(pattern)) { + return ISODateFormatParserFactory.getParser(timeZone); + } else { + return new SimpleDateFormatParser(pattern, timeZone); + } } - public static DateTimeParser getTimestampParser(String pattern) { - return getTimestampParser(pattern, DEFAULT_TIME_ZONE); + public static DateTimeParser getDateTimeParser(String pattern, PDataType pDataType) { + return getDateTimeParser(pattern, pDataType, null); } public static Format getDateFormatter(String pattern) { @@ -108,20 +145,32 @@ public class DateUtil { : FastDateFormat.getInstance(pattern, DateUtil.DEFAULT_TIME_ZONE); } - public static Date parseDateTime(String dateTimeValue) { + public static Format getTimeFormatter(String pattern) { + return DateUtil.DEFAULT_TIME_FORMAT.equals(pattern) + ? DateUtil.DEFAULT_TIME_FORMATTER + : FastDateFormat.getInstance(pattern, DateUtil.DEFAULT_TIME_ZONE); + } + + public static Format getTimestampFormatter(String pattern) { + return DateUtil.DEFAULT_TIMESTAMP_FORMAT.equals(pattern) + ? DateUtil.DEFAULT_TIMESTAMP_FORMATTER + : FastDateFormat.getInstance(pattern, DateUtil.DEFAULT_TIME_ZONE); + } + + private static long parseDateTime(String dateTimeValue) { return ISODateFormatParser.getInstance().parseDateTime(dateTimeValue); } public static Date parseDate(String dateValue) { - return parseDateTime(dateValue); + return new Date(parseDateTime(dateValue)); } public static Time parseTime(String timeValue) { - return new Time(parseDateTime(timeValue).getTime()); + return new Time(parseDateTime(timeValue)); } public static Timestamp parseTimestamp(String timestampValue) { - return new Timestamp(parseDateTime(timestampValue).getTime()); + return new Timestamp(parseDateTime(timestampValue)); } /** @@ -145,7 +194,8 @@ public class DateUtil { } public static interface DateTimeParser { - public Date parseDateTime(String dateTimeString) throws IllegalDataException; + public long parseDateTime(String dateTimeString) throws IllegalDataException; + public TimeZone getTimeZone(); } /** @@ -168,41 +218,76 @@ public class DateUtil { } @Override - public Date parseDateTime(String dateTimeString) throws IllegalDataException { + public long parseDateTime(String dateTimeString) throws IllegalDataException { try { java.util.Date date =parser.parse(dateTimeString); - return new java.sql.Date(date.getTime()); + return date.getTime(); } catch (ParseException e) { - throw new IllegalDataException("to_date('" + dateTimeString + "') did not match expected date format of '" + datePattern + "'."); + throw new IllegalDataException("Unable to parse date/time '" + dateTimeString + "' using format string of '" + datePattern + "'."); } } + + @Override + public TimeZone getTimeZone() { + return parser.getTimeZone(); + } } + private static class ISODateFormatParserFactory { + private ISODateFormatParserFactory() {} + + public static DateTimeParser getParser(final TimeZone timeZone) { + // If timeZone matches default, get singleton DateTimeParser + if (timeZone.equals(DEFAULT_TIME_ZONE)) { + return ISODateFormatParser.getInstance(); + } + // Otherwise, create new DateTimeParser + return new DateTimeParser() { + private final DateTimeFormatter formatter = ISO_DATE_TIME_FORMATTER + .withZone(DateTimeZone.forTimeZone(timeZone)); + + @Override + public long parseDateTime(String dateTimeString) throws IllegalDataException { + try { + return formatter.parseDateTime(dateTimeString).getMillis(); + } catch(IllegalArgumentException ex) { + throw new IllegalDataException(ex); + } + } + + @Override + public TimeZone getTimeZone() { + return timeZone; + } + }; + } + } /** * This class is our default DateTime string parser */ private static class ISODateFormatParser implements DateTimeParser { - private static ISODateFormatParser inst = null; - private static Object lock = new Object(); - private ISODateFormatParser() {} + private static final ISODateFormatParser INSTANCE = new ISODateFormatParser(); public static ISODateFormatParser getInstance() { - if(inst != null) return inst; - - synchronized (lock) { - if (inst == null) { - inst = new ISODateFormatParser(); - } - } - return inst; + return INSTANCE; } - public Date parseDateTime(String dateTimeString) throws IllegalDataException { + private final DateTimeFormatter formatter = ISO_DATE_TIME_FORMATTER.withZoneUTC(); + + private ISODateFormatParser() {} + + @Override + public long parseDateTime(String dateTimeString) throws IllegalDataException { try { - return new Date(ISO_DATE_TIME_PARSER.parseDateTime(dateTimeString).getMillis()); + return formatter.parseDateTime(dateTimeString).getMillis(); } catch(IllegalArgumentException ex) { throw new IllegalDataException(ex); } } + + @Override + public TimeZone getTimeZone() { + return formatter.getZone().toTimeZone(); + } } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/main/java/org/apache/phoenix/util/csv/CsvUpsertExecutor.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/csv/CsvUpsertExecutor.java b/phoenix-core/src/main/java/org/apache/phoenix/util/csv/CsvUpsertExecutor.java index 731a13f..b5f6f9f 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/util/csv/CsvUpsertExecutor.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/util/csv/CsvUpsertExecutor.java @@ -17,16 +17,22 @@ */ package org.apache.phoenix.util.csv; -import com.google.common.base.Function; -import com.google.common.collect.Lists; +import java.io.Closeable; +import java.io.IOException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Types; +import java.util.List; +import java.util.Properties; + +import javax.annotation.Nullable; + import org.apache.commons.csv.CSVRecord; -import org.apache.phoenix.expression.LiteralExpression; import org.apache.phoenix.jdbc.PhoenixConnection; import org.apache.phoenix.query.QueryServices; import org.apache.phoenix.query.QueryServicesOptions; import org.apache.phoenix.schema.types.PDataType; -import org.apache.phoenix.schema.types.PDate; -import org.apache.phoenix.schema.types.PTime; import org.apache.phoenix.schema.types.PTimestamp; import org.apache.phoenix.util.ColumnInfo; import org.apache.phoenix.util.DateUtil; @@ -34,16 +40,8 @@ import org.apache.phoenix.util.QueryUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nullable; -import java.io.Closeable; -import java.io.IOException; -import java.sql.Connection; -import java.sql.Date; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.List; -import java.util.Properties; -import java.util.TimeZone; +import com.google.common.base.Function; +import com.google.common.collect.Lists; /** * Executes upsert statements on a provided {@code PreparedStatement} based on incoming CSV records, notifying a @@ -205,12 +203,23 @@ public class CsvUpsertExecutor implements Closeable { throw new RuntimeException(e); } this.dataType = dataType; - if(dataType.equals(PDate.INSTANCE) || dataType.equals(PTime.INSTANCE) || dataType.equals(PTimestamp.INSTANCE)) { - String dateFormat = props.getProperty(QueryServices.DATE_FORMAT_ATTRIB, - QueryServicesOptions.DEFAULT_DATE_FORMAT); + if(dataType.isCoercibleTo(PTimestamp.INSTANCE)) { + // TODO: move to DateUtil + String dateFormat; + int dateSqlType = dataType.getResultSetSqlType(); + if (dateSqlType == Types.DATE) { + dateFormat = props.getProperty(QueryServices.DATE_FORMAT_ATTRIB, + DateUtil.DEFAULT_DATE_FORMAT); + } else if (dateSqlType == Types.TIME) { + dateFormat = props.getProperty(QueryServices.TIME_FORMAT_ATTRIB, + DateUtil.DEFAULT_TIME_FORMAT); + } else { + dateFormat = props.getProperty(QueryServices.TIMESTAMP_FORMAT_ATTRIB, + DateUtil.DEFAULT_TIMESTAMP_FORMAT); + } String timeZoneId = props.getProperty(QueryServices.DATE_FORMAT_TIMEZONE_ATTRIB, QueryServicesOptions.DEFAULT_DATE_FORMAT_TIMEZONE); - this.dateTimeParser = DateUtil.getDateParser(dateFormat, timeZoneId); + this.dateTimeParser = DateUtil.getDateTimeParser(dateFormat, dataType, timeZoneId); } else { this.dateTimeParser = null; } @@ -220,7 +229,10 @@ public class CsvUpsertExecutor implements Closeable { @Override public Object apply(@Nullable String input) { if(dateTimeParser != null) { - return dateTimeParser.parseDateTime(input); + long epochTime = dateTimeParser.parseDateTime(input); + byte[] byteValue = new byte[dataType.getByteSize()]; + dataType.getCodec().encodeLong(epochTime, byteValue, 0); + return dataType.toObject(byteValue); } return dataType.toObject(input); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereCompilerTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereCompilerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereCompilerTest.java index 6dbd303..69c1bbf 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereCompilerTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereCompilerTest.java @@ -37,9 +37,9 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.math.BigDecimal; +import java.sql.Date; import java.sql.DriverManager; import java.sql.SQLException; -import java.text.Format; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -60,11 +60,11 @@ import org.apache.phoenix.query.BaseConnectionlessQueryTest; import org.apache.phoenix.query.KeyRange; import org.apache.phoenix.query.QueryConstants; import org.apache.phoenix.query.QueryServicesOptions; +import org.apache.phoenix.schema.RowKeyValueAccessor; +import org.apache.phoenix.schema.SaltingUtil; import org.apache.phoenix.schema.types.PChar; import org.apache.phoenix.schema.types.PLong; import org.apache.phoenix.schema.types.PVarchar; -import org.apache.phoenix.schema.RowKeyValueAccessor; -import org.apache.phoenix.schema.SaltingUtil; import org.apache.phoenix.util.ByteUtil; import org.apache.phoenix.util.DateUtil; import org.apache.phoenix.util.NumberUtil; @@ -277,7 +277,7 @@ public class WhereCompilerTest extends BaseConnectionlessQueryTest { Scan scan = plan.getContext().getScan(); Filter filter = scan.getFilter(); - Object date = DateUtil.parseDateTime(dateStr); + Date date = DateUtil.parseDate(dateStr); assertEquals( singleKVFilter(constantComparison( http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/test/java/org/apache/phoenix/expression/SortOrderExpressionTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/SortOrderExpressionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/SortOrderExpressionTest.java index f75bb3e..8fb1a6c 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/expression/SortOrderExpressionTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/SortOrderExpressionTest.java @@ -30,22 +30,6 @@ import java.util.TimeZone; import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; -import org.apache.phoenix.schema.types.PChar; -import org.apache.phoenix.schema.types.PDecimal; -import org.apache.phoenix.schema.types.PBoolean; -import org.apache.phoenix.schema.types.PDate; -import org.apache.phoenix.schema.types.PDouble; -import org.apache.phoenix.schema.types.PFloat; -import org.apache.phoenix.schema.types.PInteger; -import org.apache.phoenix.schema.types.PLong; -import org.apache.phoenix.schema.types.PUnsignedDouble; -import org.apache.phoenix.schema.types.PUnsignedFloat; -import org.apache.phoenix.schema.types.PUnsignedInt; -import org.apache.phoenix.schema.types.PUnsignedLong; -import org.apache.phoenix.schema.types.PVarchar; -import org.junit.Test; - -import com.google.common.collect.Lists; import org.apache.phoenix.expression.function.FunctionArgumentType; import org.apache.phoenix.expression.function.LTrimFunction; import org.apache.phoenix.expression.function.LengthFunction; @@ -63,8 +47,24 @@ import org.apache.phoenix.expression.function.ToNumberFunction; import org.apache.phoenix.expression.function.TrimFunction; import org.apache.phoenix.expression.function.UpperFunction; import org.apache.phoenix.schema.SortOrder; +import org.apache.phoenix.schema.types.PBoolean; +import org.apache.phoenix.schema.types.PChar; import org.apache.phoenix.schema.types.PDataType; +import org.apache.phoenix.schema.types.PDate; +import org.apache.phoenix.schema.types.PDecimal; +import org.apache.phoenix.schema.types.PDouble; +import org.apache.phoenix.schema.types.PFloat; +import org.apache.phoenix.schema.types.PInteger; +import org.apache.phoenix.schema.types.PLong; +import org.apache.phoenix.schema.types.PUnsignedDouble; +import org.apache.phoenix.schema.types.PUnsignedFloat; +import org.apache.phoenix.schema.types.PUnsignedInt; +import org.apache.phoenix.schema.types.PUnsignedLong; +import org.apache.phoenix.schema.types.PVarchar; import org.apache.phoenix.util.DateUtil; +import org.junit.Test; + +import com.google.common.collect.Lists; /** * @since 1.2 @@ -148,7 +148,7 @@ public class SortOrderExpressionTest { @Test public void toDate() throws Exception { List<Expression> args = Lists.newArrayList(getInvertedLiteral("2001-11-30 00:00:00:0", PVarchar.INSTANCE)); - evaluateAndAssertResult(new ToDateFunction(args, null, DateUtil.getDateParser("yyyy-MM-dd HH:mm:ss:S")), date(11, 30, 2001)); + evaluateAndAssertResult(new ToDateFunction(args, "yyyy-MM-dd HH:mm:ss:S",DateUtil.DEFAULT_TIME_ZONE_ID), date(11, 30, 2001)); } @Test http://git-wip-us.apache.org/repos/asf/phoenix/blob/11a76b29/phoenix-core/src/test/java/org/apache/phoenix/util/DateUtilTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/util/DateUtilTest.java b/phoenix-core/src/test/java/org/apache/phoenix/util/DateUtilTest.java index 702e556..ec0bc01 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/util/DateUtilTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/util/DateUtilTest.java @@ -28,6 +28,9 @@ import java.text.ParseException; import java.util.TimeZone; import org.apache.phoenix.schema.IllegalDataException; +import org.apache.phoenix.schema.types.PDate; +import org.apache.phoenix.schema.types.PTime; +import org.apache.phoenix.schema.types.PTimestamp; import org.junit.Test; /** @@ -68,64 +71,64 @@ public class DateUtilTest { @Test public void testGetDateParser_DefaultTimeZone() throws ParseException { - Date date = DateUtil.getDateParser("yyyy-MM-dd").parseDateTime("1970-01-01"); + Date date = new Date(DateUtil.getDateTimeParser("yyyy-MM-dd", PDate.INSTANCE).parseDateTime("1970-01-01")); assertEquals(0, date.getTime()); } @Test public void testGetDateParser_CustomTimeZone() throws ParseException { - Date date = DateUtil.getDateParser( - "yyyy-MM-dd", TimeZone.getTimeZone("GMT+1")).parseDateTime("1970-01-01"); + Date date = new Date(DateUtil.getDateTimeParser( + "yyyy-MM-dd", PDate.INSTANCE, TimeZone.getTimeZone("GMT+1").getID()).parseDateTime("1970-01-01")); assertEquals(-ONE_HOUR_IN_MILLIS, date.getTime()); } @Test public void testGetDateParser_LocalTimeZone() throws ParseException { - Date date = DateUtil.getDateParser( - "yyyy-MM-dd", TimeZone.getDefault()).parseDateTime("1970-01-01"); + Date date = new Date(DateUtil.getDateTimeParser( + "yyyy-MM-dd", PDate.INSTANCE, TimeZone.getDefault().getID()).parseDateTime("1970-01-01")); assertEquals(Date.valueOf("1970-01-01"), date); } @Test public void testGetTimestampParser_DefaultTimeZone() throws ParseException { - Timestamp ts = new Timestamp(DateUtil.getTimestampParser("yyyy-MM-dd HH:mm:ss") - .parseDateTime("1970-01-01 00:00:00").getTime()); + Timestamp ts = new Timestamp(DateUtil.getDateTimeParser("yyyy-MM-dd HH:mm:ss", PTimestamp.INSTANCE) + .parseDateTime("1970-01-01 00:00:00")); assertEquals(0, ts.getTime()); } @Test public void testGetTimestampParser_CustomTimeZone() throws ParseException { - Timestamp ts = new Timestamp(DateUtil.getTimestampParser("yyyy-MM-dd HH:mm:ss", TimeZone.getTimeZone("GMT+1")) - .parseDateTime("1970-01-01 00:00:00").getTime()); + Timestamp ts = new Timestamp(DateUtil.getDateTimeParser("yyyy-MM-dd HH:mm:ss", PTimestamp.INSTANCE, TimeZone.getTimeZone("GMT+1").getID()) + .parseDateTime("1970-01-01 00:00:00")); assertEquals(-ONE_HOUR_IN_MILLIS, ts.getTime()); } @Test public void testGetTimestampParser_LocalTimeZone() throws ParseException { - Timestamp ts = new Timestamp(DateUtil.getTimestampParser( + Timestamp ts = new Timestamp(DateUtil.getDateTimeParser( "yyyy-MM-dd HH:mm:ss", - TimeZone.getDefault()).parseDateTime("1970-01-01 00:00:00").getTime()); + PTimestamp.INSTANCE, TimeZone.getDefault().getID()).parseDateTime("1970-01-01 00:00:00")); assertEquals(Timestamp.valueOf("1970-01-01 00:00:00"), ts); } @Test public void testGetTimeParser_DefaultTimeZone() throws ParseException { - Time time = new Time(DateUtil.getTimeParser("HH:mm:ss").parseDateTime("00:00:00").getTime()); + Time time = new Time(DateUtil.getDateTimeParser("HH:mm:ss", PTime.INSTANCE).parseDateTime("00:00:00")); assertEquals(0, time.getTime()); } @Test public void testGetTimeParser_CustomTimeZone() throws ParseException { - Time time = new Time(DateUtil.getTimeParser( + Time time = new Time(DateUtil.getDateTimeParser( "HH:mm:ss", - TimeZone.getTimeZone("GMT+1")).parseDateTime("00:00:00").getTime()); + PTime.INSTANCE, TimeZone.getTimeZone("GMT+1").getID()).parseDateTime("00:00:00")); assertEquals(-ONE_HOUR_IN_MILLIS, time.getTime()); } @Test public void testGetTimeParser_LocalTimeZone() throws ParseException { - Time time = new Time(DateUtil.getTimeParser( - "HH:mm:ss", TimeZone.getDefault()).parseDateTime("00:00:00").getTime()); + Time time = new Time(DateUtil.getDateTimeParser( + "HH:mm:ss", PTime.INSTANCE, TimeZone.getDefault().getID()).parseDateTime("00:00:00")); assertEquals(Time.valueOf("00:00:00"), time); }