Repository: phoenix Updated Branches: refs/heads/4.0 429acbab7 -> 3969ed5c1
PHOENIX-1485 Add timezone awareness * Add tz-aware methods to DateUtil * Add timezone parameter to TO_DATE * Add a configuration parameter to allow specifying the time zone to be used internally on a connection when parsing dates. Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/ea10e1f7 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/ea10e1f7 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/ea10e1f7 Branch: refs/heads/4.0 Commit: ea10e1f7bd657e0f8b890571f3f1903f07eb43dd Parents: 429acba Author: Gabriel Reid <gr...@apache.org> Authored: Tue Dec 2 19:25:41 2014 +0100 Committer: Gabriel Reid <gabri...@ngdata.com> Committed: Wed Dec 3 17:28:33 2014 +0100 ---------------------------------------------------------------------- .../phoenix/end2end/ToDateFunctionIT.java | 117 +++++++++++++++++++ .../phoenix/compile/StatementContext.java | 44 +++---- .../expression/function/ToDateFunction.java | 16 ++- .../apache/phoenix/parse/ToDateParseNode.java | 15 ++- .../org/apache/phoenix/query/QueryServices.java | 1 + .../phoenix/query/QueryServicesOptions.java | 3 + .../java/org/apache/phoenix/util/DateUtil.java | 37 ++++-- .../expression/SortOrderExpressionTest.java | 3 +- .../org/apache/phoenix/util/DateUtilTest.java | 78 ++++++++++++- 9 files changed, 268 insertions(+), 46 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/ea10e1f7/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 new file mode 100644 index 0000000..19257c1 --- /dev/null +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ToDateFunctionIT.java @@ -0,0 +1,117 @@ +/* + * 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.end2end; + +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.util.Properties; + +import org.apache.phoenix.query.QueryServices; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + + +public class ToDateFunctionIT extends BaseHBaseManagedTimeIT { + + private static final long ONE_HOUR_IN_MILLIS = 1000L * 60L * 60L; + + private Connection conn; + + @Before + public void setUp() throws SQLException { + conn = DriverManager.getConnection(getUrl()); + } + + @After + public void tearDown() throws SQLException { + conn.close(); + } + + private static Date callToDateFunction(Connection conn, String invocation) throws SQLException { + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(String.format("SELECT %s FROM SYSTEM.CATALOG", invocation)); + assertTrue(rs.next()); + Date returnValue = rs.getDate(1); + rs.close(); + stmt.close(); + return returnValue; + } + + private Date callToDateFunction(String invocation) throws SQLException { + return callToDateFunction(conn, invocation); + } + + @Test + public void testToDate_Default() throws SQLException { + // Default time zone is GMT, so this is timestamp 0 + assertEquals(0L, callToDateFunction("TO_DATE('1970-01-01 00:00:00')").getTime()); + } + + @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()); + } + + @Test + public void testToDate_CustomTimeZone() throws SQLException { + // We're using GMT+1, so that's an hour before the Java epoch + assertEquals( + -ONE_HOUR_IN_MILLIS, + callToDateFunction("TO_DATE('1970-01-01', 'yyyy-MM-dd', 'GMT+1')").getTime()); + } + + @Test + public void testToDate_LocalTimeZone() throws SQLException { + assertEquals( + Date.valueOf("1970-01-01"), + callToDateFunction("TO_DATE('1970-01-01', 'yyyy-MM-dd', 'local')")); + } + + @Test + public void testToDate_CustomTimeZoneViaQueryServices() throws SQLException { + Properties props = new Properties(); + props.setProperty(QueryServices.DATE_FORMAT_TIMEZONE_ATTRIB, "GMT+1"); + Connection customTimeZoneConn = DriverManager.getConnection(getUrl(), props); + + assertEquals( + -ONE_HOUR_IN_MILLIS, + callToDateFunction(customTimeZoneConn, "TO_DATE('1970-01-01 00:00:00')").getTime()); + } + + @Test + public void testToDate_CustomTimeZoneViaQueryServicesAndCustomFormat() throws SQLException { + Properties props = new Properties(); + props.setProperty(QueryServices.DATE_FORMAT_TIMEZONE_ATTRIB, "GMT+1"); + Connection customTimeZoneConn = DriverManager.getConnection(getUrl(), props); + + assertEquals( + -ONE_HOUR_IN_MILLIS, + callToDateFunction( + customTimeZoneConn, "TO_DATE('1970-01-01', 'yyyy-MM-dd')").getTime()); + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/ea10e1f7/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 5a36907..f48f613 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 @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TimeZone; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; @@ -49,7 +50,7 @@ import com.google.common.collect.Maps; * Class that keeps common state used across processing the various clauses in a * top level JDBC statement such as SELECT, UPSERT, DELETE, etc. * - * + * * @since 0.1 */ public class StatementContext { @@ -59,27 +60,27 @@ 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 Format dateParser; private final String numberFormat; private final ImmutableBytesWritable tempPtr; private final PhoenixStatement statement; private final Map<PColumn, Integer> dataColumns; - + private long currentTime = QueryConstants.UNSET_TIMESTAMP; private ScanRanges scanRanges = ScanRanges.EVERYTHING; - private final SequenceManager sequences; + private final SequenceManager sequences; private TableRef currentTable; private List<Pair<byte[], byte[]>> whereConditionColumns; private TimeRange scanTimeRange = null; - + private Map<SelectStatement, Object> subqueryResults; - + public StatementContext(PhoenixStatement statement) { this(statement, new Scan()); } - + public StatementContext(PhoenixStatement statement, Scan scan) { this(statement, FromCompiler.EMPTY_TABLE_RESOLVER, new Scan(), new SequenceManager(statement)); } @@ -98,8 +99,9 @@ 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.dateFormatTimeZone = TimeZone.getTimeZone( + connection.getQueryServices().getProps().get(QueryServices.DATE_FORMAT_TIMEZONE_ATTRIB, DateUtil.DEFAULT_TIME_ZONE_ID)); this.dateFormatter = DateUtil.getDateFormatter(dateFormat); - this.dateParser = DateUtil.getDateParser(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; @@ -131,7 +133,7 @@ public class StatementContext { } /** - * @return map of data columns and their positions. + * @return map of data columns and their positions. */ public Map<PColumn, Integer> getDataColumnsMap() { return dataColumns; @@ -141,18 +143,18 @@ public class StatementContext { return dateFormat; } + public TimeZone getDateFormatTimeZone() { + return dateFormatTimeZone; + } + public Format getDateFormatter() { return dateFormatter; } - public Format getDateParser() { - return dateParser; - } - public String getNumberFormat() { return numberFormat; } - + public Scan getScan() { return scan; } @@ -160,11 +162,11 @@ public class StatementContext { public BindManager getBindManager() { return binds; } - + public TableRef getCurrentTable() { return currentTable; } - + public void setCurrentTable(TableRef table) { this.currentTable = table; } @@ -193,12 +195,12 @@ public class StatementContext { public ScanRanges getScanRanges() { return this.scanRanges; } - + public void setScanRanges(ScanRanges scanRanges) { this.scanRanges = scanRanges; scanRanges.initializeScan(scan); } - + public PhoenixConnection getConnection() { return statement.getConnection(); } @@ -243,11 +245,11 @@ public class StatementContext { public void setScanTimeRange(TimeRange value){ this.scanTimeRange = value; } - + public TimeRange getScanTimeRange() { return this.scanTimeRange; } - + public boolean isSubqueryResultAvailable(SelectStatement select) { return subqueryResults.containsKey(select); } @@ -255,7 +257,7 @@ public class StatementContext { public Object getSubqueryResult(SelectStatement select) { return subqueryResults.get(select); } - + public void setSubqueryResult(SelectStatement select, Object result) { subqueryResults.put(select, result); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/ea10e1f7/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 e14cb1d..28d1206 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 @@ -36,15 +36,19 @@ import org.apache.phoenix.util.DateUtil; /** - * - * Implementation of the TO_DATE(<string>,[<format-string>]) built-in function. + * + * Implementation of the {@code TO_DATE(<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. + * 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. * - * * @since 0.1 */ -@BuiltInFunction(name=ToDateFunction.NAME, nodeClass=ToDateParseNode.class, args= {@Argument(allowedTypes={PDataType.VARCHAR}),@Argument(allowedTypes={PDataType.VARCHAR},isConstant=true,defaultValue="null")} ) +@BuiltInFunction(name=ToDateFunction.NAME, nodeClass=ToDateParseNode.class, + args={@Argument(allowedTypes={PDataType.VARCHAR}), + @Argument(allowedTypes={PDataType.VARCHAR},isConstant=true,defaultValue="null"), + @Argument(allowedTypes={PDataType.VARCHAR}, isConstant=true, defaultValue = "null") } ) public class ToDateFunction extends ScalarFunction { public static final String NAME = "TO_DATE"; private Format dateParser; @@ -58,7 +62,7 @@ public class ToDateFunction extends ScalarFunction { this.dateFormat = dateFormat; this.dateParser = dateParser; } - + @Override public int hashCode() { final int prime = 31; http://git-wip-us.apache.org/repos/asf/phoenix/blob/ea10e1f7/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 41f8b43..46bca63 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 @@ -20,6 +20,7 @@ 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; @@ -30,6 +31,7 @@ import org.apache.phoenix.util.DateUtil; public class ToDateParseNode extends FunctionParseNode { + public ToDateParseNode(String name, List<ParseNode> children, BuiltInFunctionInfo info) { super(name, children, info); } @@ -37,13 +39,20 @@ public class ToDateParseNode extends FunctionParseNode { @Override public FunctionExpression create(List<Expression> children, StatementContext context) throws SQLException { Format dateParser; - String dateFormat = (String)((LiteralExpression)children.get(1)).getValue(); + String dateFormat = (String) ((LiteralExpression) children.get(1)).getValue(); + String timeZoneId = (String) ((LiteralExpression) children.get(2)).getValue(); + TimeZone parserTimeZone = context.getDateFormatTimeZone(); if (dateFormat == null) { dateFormat = context.getDateFormat(); - dateParser = context.getDateParser(); + } + if (timeZoneId == null) { + parserTimeZone = context.getDateFormatTimeZone(); + } else if ("LOCAL".equalsIgnoreCase(timeZoneId)) { + parserTimeZone = TimeZone.getDefault(); } else { - dateParser = DateUtil.getDateParser(dateFormat); + parserTimeZone = TimeZone.getTimeZone(timeZoneId); } + dateParser = DateUtil.getDateParser(dateFormat, parserTimeZone); return new ToDateFunction(children, dateFormat, dateParser); } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/ea10e1f7/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 eb72a83..225e5bb 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 @@ -68,6 +68,7 @@ public interface QueryServices extends SQLCloseable { public static final String MAX_MEMORY_WAIT_MS_ATTRIB = "phoenix.query.maxGlobalMemoryWaitMs"; public static final String MAX_TENANT_MEMORY_PERC_ATTRIB = "phoenix.query.maxTenantMemoryPercentage"; 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 NUMBER_FORMAT_ATTRIB = "phoenix.query.numberFormat"; public static final String CALL_QUEUE_ROUND_ROBIN_ATTRIB = "ipc.server.callqueue.roundrobin"; http://git-wip-us.apache.org/repos/asf/phoenix/blob/ea10e1f7/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java index 8088e2d..70824a5 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java @@ -21,6 +21,7 @@ import static org.apache.phoenix.query.QueryServices.ALLOW_ONLINE_TABLE_SCHEMA_U import static org.apache.phoenix.query.QueryServices.CALL_QUEUE_PRODUCER_ATTRIB_NAME; import static org.apache.phoenix.query.QueryServices.CALL_QUEUE_ROUND_ROBIN_ATTRIB; import static org.apache.phoenix.query.QueryServices.DATE_FORMAT_ATTRIB; +import static org.apache.phoenix.query.QueryServices.DATE_FORMAT_TIMEZONE_ATTRIB; import static org.apache.phoenix.query.QueryServices.DELAY_FOR_SCHEMA_UPDATE_CHECK; import static org.apache.phoenix.query.QueryServices.DROP_METADATA_ATTRIB; import static org.apache.phoenix.query.QueryServices.EXPLAIN_CHUNK_COUNT_ATTRIB; @@ -92,6 +93,7 @@ public class QueryServicesOptions { public static final int DEFAULT_TARGET_QUERY_CONCURRENCY = 32; public static final int DEFAULT_MAX_QUERY_CONCURRENCY = 64; public static final String DEFAULT_DATE_FORMAT = DateUtil.DEFAULT_DATE_FORMAT; + public static final String DEFAULT_DATE_FORMAT_TIMEZONE = DateUtil.DEFAULT_TIME_ZONE_ID; public static final boolean DEFAULT_CALL_QUEUE_ROUND_ROBIN = true; public static final int DEFAULT_MAX_MUTATION_SIZE = 500000; public static final boolean DEFAULT_ROW_KEY_ORDER_SALTED_TABLE = true; // Merge sort on client to ensure salted tables are row key ordered @@ -207,6 +209,7 @@ public class QueryServicesOptions { .setIfUnset(MAX_SERVER_CACHE_SIZE_ATTRIB, DEFAULT_MAX_SERVER_CACHE_SIZE) .setIfUnset(SCAN_CACHE_SIZE_ATTRIB, DEFAULT_SCAN_CACHE_SIZE) .setIfUnset(DATE_FORMAT_ATTRIB, DEFAULT_DATE_FORMAT) + .setIfUnset(DATE_FORMAT_TIMEZONE_ATTRIB, DEFAULT_DATE_FORMAT_TIMEZONE) .setIfUnset(STATS_UPDATE_FREQ_MS_ATTRIB, DEFAULT_STATS_UPDATE_FREQ_MS) .setIfUnset(CALL_QUEUE_ROUND_ROBIN_ATTRIB, DEFAULT_CALL_QUEUE_ROUND_ROBIN) .setIfUnset(MAX_MUTATION_SIZE_ATTRIB, DEFAULT_MAX_MUTATION_SIZE) http://git-wip-us.apache.org/repos/asf/phoenix/blob/ea10e1f7/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 62d892f..c940067 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 @@ -35,17 +35,20 @@ import org.apache.phoenix.schema.IllegalDataException; @SuppressWarnings("serial") public class DateUtil { - public static final TimeZone DATE_TIME_ZONE = TimeZone.getTimeZone("GMT"); + public static final String DEFAULT_TIME_ZONE_ID = "GMT"; + 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, DATE_TIME_ZONE); + 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, DATE_TIME_ZONE); + public static final Format DEFAULT_MS_DATE_FORMATTER = FastDateFormat.getInstance( + DEFAULT_MS_DATE_FORMAT, TimeZone.getTimeZone(DEFAULT_TIME_ZONE_ID)); private DateUtil() { } - public static Format getDateParser(String pattern) { + public static Format getDateParser(String pattern, TimeZone timeZone) { SimpleDateFormat format = new SimpleDateFormat(pattern) { @Override public java.util.Date parseObject(String source) throws ParseException { @@ -53,11 +56,15 @@ public class DateUtil { return new java.sql.Date(date.getTime()); } }; - format.setTimeZone(DateUtil.DATE_TIME_ZONE); + format.setTimeZone(timeZone); return format; } - public static Format getTimeParser(String pattern) { + public static Format getDateParser(String pattern) { + return getDateParser(pattern, DEFAULT_TIME_ZONE); + } + + public static Format getTimeParser(String pattern, TimeZone timeZone) { SimpleDateFormat format = new SimpleDateFormat(pattern) { @Override public java.util.Date parseObject(String source) throws ParseException { @@ -65,11 +72,15 @@ public class DateUtil { return new java.sql.Time(date.getTime()); } }; - format.setTimeZone(DateUtil.DATE_TIME_ZONE); + format.setTimeZone(timeZone); return format; } - public static Format getTimestampParser(String pattern) { + public static Format getTimeParser(String pattern) { + return getTimeParser(pattern, DEFAULT_TIME_ZONE); + } + + public static Format getTimestampParser(String pattern, TimeZone timeZone) { SimpleDateFormat format = new SimpleDateFormat(pattern) { @Override public java.util.Date parseObject(String source) throws ParseException { @@ -77,12 +88,18 @@ public class DateUtil { return new java.sql.Timestamp(date.getTime()); } }; - format.setTimeZone(DateUtil.DATE_TIME_ZONE); + format.setTimeZone(timeZone); return format; } + public static Format getTimestampParser(String pattern) { + return getTimestampParser(pattern, DEFAULT_TIME_ZONE); + } + public static Format getDateFormatter(String pattern) { - return DateUtil.DEFAULT_DATE_FORMAT.equals(pattern) ? DateUtil.DEFAULT_DATE_FORMATTER : FastDateFormat.getInstance(pattern, DateUtil.DATE_TIME_ZONE); + return DateUtil.DEFAULT_DATE_FORMAT.equals(pattern) + ? DateUtil.DEFAULT_DATE_FORMATTER + : FastDateFormat.getInstance(pattern, DateUtil.DEFAULT_TIME_ZONE); } private static ThreadLocal<Format> dateFormat = http://git-wip-us.apache.org/repos/asf/phoenix/blob/ea10e1f7/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 2c532aa..d7f4172 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 @@ -26,6 +26,7 @@ import java.sql.Date; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.List; +import java.util.TimeZone; import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; @@ -322,7 +323,7 @@ public class SortOrderExpressionTest { cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); - cal.setTimeZone(DateUtil.DATE_TIME_ZONE); + cal.setTimeZone(TimeZone.getTimeZone(DateUtil.DEFAULT_TIME_ZONE_ID)); Date d = new Date(cal.getTimeInMillis()); return d; } http://git-wip-us.apache.org/repos/asf/phoenix/blob/ea10e1f7/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 7746515..db65884 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 @@ -17,21 +17,26 @@ */ package org.apache.phoenix.util; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - +import java.sql.Date; +import java.sql.Time; import java.sql.Timestamp; +import java.text.ParseException; +import java.util.TimeZone; import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + /** - * * Test class for {@link DateUtil} * - * * @since 2.1.3 */ public class DateUtilTest { + + private static final long ONE_HOUR_IN_MILLIS = 1000L * 60L * 60L; @Test public void testDemonstrateSetNanosOnTimestampLosingMillis() { @@ -59,4 +64,67 @@ public class DateUtilTest { assertFalse(ts1.equals(ts2)); assertTrue(ts2.after(ts1)); } + + @Test + public void testGetDateParser_DefaultTimeZone() throws ParseException { + Date date = (Date) DateUtil.getDateParser("yyyy-MM-dd").parseObject("1970-01-01"); + assertEquals(0, date.getTime()); + } + + @Test + public void testGetDateParser_CustomTimeZone() throws ParseException { + Date date = (Date) DateUtil.getDateParser( + "yyyy-MM-dd", TimeZone.getTimeZone("GMT+1")).parseObject("1970-01-01"); + assertEquals(-ONE_HOUR_IN_MILLIS, date.getTime()); + } + + @Test + public void testGetDateParser_LocalTimeZone() throws ParseException { + Date date = (Date) DateUtil.getDateParser( + "yyyy-MM-dd", TimeZone.getDefault()).parseObject("1970-01-01"); + assertEquals(Date.valueOf("1970-01-01"), date); + } + + @Test + public void testGetTimestampParser_DefaultTimeZone() throws ParseException { + Timestamp ts = (Timestamp) DateUtil.getTimestampParser("yyyy-MM-dd HH:mm:ss") + .parseObject("1970-01-01 00:00:00"); + assertEquals(0, ts.getTime()); + } + + @Test + public void testGetTimestampParser_CustomTimeZone() throws ParseException { + Timestamp ts = (Timestamp) DateUtil.getTimestampParser("yyyy-MM-dd HH:mm:ss", TimeZone.getTimeZone("GMT+1")) + .parseObject("1970-01-01 00:00:00"); + assertEquals(-ONE_HOUR_IN_MILLIS, ts.getTime()); + } + + @Test + public void testGetTimestampParser_LocalTimeZone() throws ParseException { + Timestamp ts = (Timestamp) DateUtil.getTimestampParser( + "yyyy-MM-dd HH:mm:ss", + TimeZone.getDefault()).parseObject("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 = (Time) DateUtil.getTimeParser("HH:mm:ss").parseObject("00:00:00"); + assertEquals(0, time.getTime()); + } + + @Test + public void testGetTimeParser_CustomTimeZone() throws ParseException { + Time time = (Time) DateUtil.getTimeParser( + "HH:mm:ss", + TimeZone.getTimeZone("GMT+1")).parseObject("00:00:00"); + assertEquals(-ONE_HOUR_IN_MILLIS, time.getTime()); + } + + @Test + public void testGetTimeParser_LocalTimeZone() throws ParseException { + Time time = (Time) DateUtil.getTimeParser( + "HH:mm:ss", TimeZone.getDefault()).parseObject("00:00:00"); + assertEquals(Time.valueOf("00:00:00"), time); + } }