This is an automated email from the ASF dual-hosted git repository. tdsilva pushed a commit to branch 4.14-HBase-1.2 in repository https://gitbox.apache.org/repos/asf/phoenix.git
commit 7a6daf0fcb88214f1273aa3e160f13db84036ffe Author: Josh Elser <els...@apache.org> AuthorDate: Tue Jul 31 15:53:11 2018 -0400 PHOENIX-4822 Ensure the provided timezone is used client-side (Jaanai Zhang) --- .../org/apache/phoenix/end2end/DateTimeIT.java | 77 ++++++++++++++++++++++ .../apache/phoenix/compile/StatementContext.java | 11 ++-- .../org/apache/phoenix/jdbc/PhoenixConnection.java | 8 ++- .../java/org/apache/phoenix/util/DateUtil.java | 22 ++++--- 4 files changed, 101 insertions(+), 17 deletions(-) diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/DateTimeIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DateTimeIT.java index c976114..cc7c7a7 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/DateTimeIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/DateTimeIT.java @@ -54,12 +54,19 @@ import java.text.Format; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Properties; +import java.util.TimeZone; +import org.apache.commons.lang.time.FastDateFormat; import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.util.Bytes; +import org.apache.phoenix.compile.StatementContext; +import org.apache.phoenix.jdbc.PhoenixConnection; +import org.apache.phoenix.jdbc.PhoenixStatement; import org.apache.phoenix.query.QueryConstants; +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.ByteUtil; import org.apache.phoenix.util.DateUtil; @@ -1880,4 +1887,74 @@ public class DateTimeIT extends ParallelStatsDisabledIT { conn.close(); } } + + @Test + public void testDateFormatTimeZone()throws Exception { + String[] timeZoneIDs = {DateUtil.DEFAULT_TIME_ZONE_ID, "Asia/Yerevan", "Australia/Adelaide", "Asia/Tokyo"}; + for (String timeZoneID : timeZoneIDs) { + testDateFormatTimeZone(timeZoneID); + } + } + + public void testDateFormatTimeZone(String timeZoneId) throws Exception { + Properties props = new Properties(); + props.setProperty("phoenix.query.dateFormatTimeZone", timeZoneId); + Connection conn1 = DriverManager.getConnection(getUrl(), props); + + String tableName = generateUniqueName(); + String ddl = "CREATE TABLE IF NOT EXISTS " + tableName + + " (k1 INTEGER PRIMARY KEY," + + " v_date DATE," + + " v_time TIME," + + " v_timestamp TIMESTAMP)"; + try { + conn1.createStatement().execute(ddl); + + PhoenixConnection pConn = conn1.unwrap(PhoenixConnection.class); + verifyTimeZoneIDWithConn(pConn, PDate.INSTANCE, timeZoneId); + verifyTimeZoneIDWithConn(pConn, PTime.INSTANCE, timeZoneId); + verifyTimeZoneIDWithConn(pConn, PTimestamp.INSTANCE, timeZoneId); + + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(timeZoneId)); + cal.setTime(date); + String dateStr = DateUtil.getDateFormatter(DateUtil.DEFAULT_MS_DATE_FORMAT).format(date); + + String dml = "UPSERT INTO " + tableName + " VALUES (" + + "1," + + "'" + dateStr + "'," + + "'" + dateStr + "'," + + "'" + dateStr + "'" + + ")"; + conn1.createStatement().execute(dml); + conn1.commit(); + + PhoenixStatement stmt = conn1.createStatement().unwrap(PhoenixStatement.class); + ResultSet rs = stmt.executeQuery("SELECT v_date, v_time, v_timestamp FROM " + tableName); + + assertTrue(rs.next()); + assertEquals(rs.getDate(1).toString(), new Date(cal.getTimeInMillis()).toString()); + assertEquals(rs.getTime(2).toString(), new Time(cal.getTimeInMillis()).toString()); + assertEquals(rs.getTimestamp(3).getTime(), cal.getTimeInMillis()); + assertFalse(rs.next()); + + StatementContext stmtContext = stmt.getQueryPlan().getContext(); + verifyTimeZoneIDWithFormatter(stmtContext.getDateFormatter(), timeZoneId); + verifyTimeZoneIDWithFormatter(stmtContext.getTimeFormatter(), timeZoneId); + verifyTimeZoneIDWithFormatter(stmtContext.getTimestampFormatter(), timeZoneId); + + stmt.close(); + } finally { + conn1.close(); + } + } + + private void verifyTimeZoneIDWithConn(PhoenixConnection conn, PDataType dataType, String timeZoneId) { + Format formatter = conn.getFormatter(dataType); + verifyTimeZoneIDWithFormatter(formatter, timeZoneId); + } + + private void verifyTimeZoneIDWithFormatter(Format formatter, String timeZoneId) { + assertTrue(formatter instanceof FastDateFormat); + assertEquals(((FastDateFormat)formatter).getTimeZone().getID(), timeZoneId); + } } 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 fe60bb9..eb195c2 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 @@ -120,14 +120,15 @@ public class StatementContext { this.expressions = new ExpressionManager(); PhoenixConnection connection = statement.getConnection(); ReadOnlyProps props = connection.getQueryServices().getProps(); + String timeZoneID = props.get(QueryServices.DATE_FORMAT_TIMEZONE_ATTRIB, + DateUtil.DEFAULT_TIME_ZONE_ID); this.dateFormat = props.get(QueryServices.DATE_FORMAT_ATTRIB, DateUtil.DEFAULT_DATE_FORMAT); - this.dateFormatter = DateUtil.getDateFormatter(dateFormat); + this.dateFormatter = DateUtil.getDateFormatter(dateFormat, timeZoneID); this.timeFormat = props.get(QueryServices.TIME_FORMAT_ATTRIB, DateUtil.DEFAULT_TIME_FORMAT); - this.timeFormatter = DateUtil.getTimeFormatter(timeFormat); + this.timeFormatter = DateUtil.getTimeFormatter(timeFormat, timeZoneID); this.timestampFormat = props.get(QueryServices.TIMESTAMP_FORMAT_ATTRIB, DateUtil.DEFAULT_TIMESTAMP_FORMAT); - this.timestampFormatter = DateUtil.getTimestampFormatter(timestampFormat); - this.dateFormatTimeZone = DateUtil.getTimeZone(props.get(QueryServices.DATE_FORMAT_TIMEZONE_ATTRIB, - DateUtil.DEFAULT_TIME_ZONE_ID)); + this.timestampFormatter = DateUtil.getTimestampFormatter(timestampFormat, timeZoneID); + this.dateFormatTimeZone = DateUtil.getTimeZone(timeZoneID); this.numberFormat = props.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; 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 43b7ca9..a66cd54 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 @@ -332,9 +332,11 @@ public class PhoenixConnection implements Connection, MetaDataMutated, SQLClosea int maxSizeBytes = this.services.getProps().getInt( QueryServices.MAX_MUTATION_SIZE_BYTES_ATTRIB, QueryServicesOptions.DEFAULT_MAX_MUTATION_SIZE_BYTES); - Format dateFormat = DateUtil.getDateFormatter(datePattern); - Format timeFormat = DateUtil.getDateFormatter(timePattern); - Format timestampFormat = DateUtil.getDateFormatter(timestampPattern); + String timeZoneID = this.services.getProps().get(QueryServices.DATE_FORMAT_TIMEZONE_ATTRIB, + DateUtil.DEFAULT_TIME_ZONE_ID); + Format dateFormat = DateUtil.getDateFormatter(datePattern, timeZoneID); + Format timeFormat = DateUtil.getDateFormatter(timePattern, timeZoneID); + Format timestampFormat = DateUtil.getDateFormatter(timestampPattern, timeZoneID); formatters.put(PDate.INSTANCE, dateFormat); formatters.put(PTime.INSTANCE, timeFormat); formatters.put(PTimestamp.INSTANCE, timestampFormat); 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 9e37eca..f67f152 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 @@ -97,7 +97,7 @@ public class DateUtil { public static TimeZone getTimeZone(String timeZoneId) { TimeZone parserTimeZone; - if (timeZoneId == null) { + if (timeZoneId == null || timeZoneId.equals(DateUtil.DEFAULT_TIME_ZONE_ID)) { parserTimeZone = DateUtil.DEFAULT_TIME_ZONE; } else if (LOCAL_TIME_ZONE_ID.equalsIgnoreCase(timeZoneId)) { parserTimeZone = TimeZone.getDefault(); @@ -164,21 +164,25 @@ public class DateUtil { } public static Format getDateFormatter(String pattern) { - return DateUtil.DEFAULT_DATE_FORMAT.equals(pattern) + return getDateFormatter(pattern, DateUtil.DEFAULT_TIME_ZONE_ID); + } + + public static Format getDateFormatter(String pattern, String timeZoneID) { + return DateUtil.DEFAULT_DATE_FORMAT.equals(pattern) && DateUtil.DEFAULT_TIME_ZONE_ID.equals(timeZoneID) ? DateUtil.DEFAULT_DATE_FORMATTER - : FastDateFormat.getInstance(pattern, DateUtil.DEFAULT_TIME_ZONE); + : FastDateFormat.getInstance(pattern, getTimeZone(timeZoneID)); } - public static Format getTimeFormatter(String pattern) { - return DateUtil.DEFAULT_TIME_FORMAT.equals(pattern) + public static Format getTimeFormatter(String pattern, String timeZoneID) { + return DateUtil.DEFAULT_TIME_FORMAT.equals(pattern) && DateUtil.DEFAULT_TIME_ZONE_ID.equals(timeZoneID) ? DateUtil.DEFAULT_TIME_FORMATTER - : FastDateFormat.getInstance(pattern, DateUtil.DEFAULT_TIME_ZONE); + : FastDateFormat.getInstance(pattern, getTimeZone(timeZoneID)); } - public static Format getTimestampFormatter(String pattern) { - return DateUtil.DEFAULT_TIMESTAMP_FORMAT.equals(pattern) + public static Format getTimestampFormatter(String pattern, String timeZoneID) { + return DateUtil.DEFAULT_TIMESTAMP_FORMAT.equals(pattern) && DateUtil.DEFAULT_TIME_ZONE_ID.equals(timeZoneID) ? DateUtil.DEFAULT_TIMESTAMP_FORMATTER - : FastDateFormat.getInstance(pattern, DateUtil.DEFAULT_TIME_ZONE); + : FastDateFormat.getInstance(pattern, getTimeZone(timeZoneID)); } private static long parseDateTime(String dateTimeValue) {