Repository: phoenix Updated Branches: refs/heads/3.0 9cd65bf0a -> ddeacbf78
PHOENIX-1127 Support milliseconds in timestamp parsing Use Joda time for (implicit) date parsing, allowing date-time values to contain an optional time component, as well as supporting optional millisecond parsing. Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/ddeacbf7 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/ddeacbf7 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/ddeacbf7 Branch: refs/heads/3.0 Commit: ddeacbf78fbed11ddd7409e01920d9d198d40404 Parents: 9cd65bf Author: Gabriel Reid <gr...@apache.org> Authored: Sat Dec 20 18:03:58 2014 +0100 Committer: Gabriel Reid <gr...@apache.org> Committed: Sun Dec 21 09:34:19 2014 +0100 ---------------------------------------------------------------------- .../src/build/components-major-client.xml | 1 + phoenix-core/pom.xml | 4 ++ .../phoenix/end2end/CSVCommonsLoaderIT.java | 41 ++++++++++++++ .../java/org/apache/phoenix/util/DateUtil.java | 57 ++++++++------------ .../org/apache/phoenix/util/DateUtilTest.java | 42 +++++++++++++++ 5 files changed, 110 insertions(+), 35 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/ddeacbf7/phoenix-assembly/src/build/components-major-client.xml ---------------------------------------------------------------------- diff --git a/phoenix-assembly/src/build/components-major-client.xml b/phoenix-assembly/src/build/components-major-client.xml index c3980cd..ca6e9db 100644 --- a/phoenix-assembly/src/build/components-major-client.xml +++ b/phoenix-assembly/src/build/components-major-client.xml @@ -49,6 +49,7 @@ <include>org.codehaus.jackson:jackson-mapper-asl</include> <include>org.codehaus.jackson:jackson-core-asl</include> <include>org.xerial.snappy:snappy-java</include> + <include>joda-time:joda-time</include> </includes> </dependencySet> </dependencySets> http://git-wip-us.apache.org/repos/asf/phoenix/blob/ddeacbf7/phoenix-core/pom.xml ---------------------------------------------------------------------- diff --git a/phoenix-core/pom.xml b/phoenix-core/pom.xml index fceb6c7..6098443 100644 --- a/phoenix-core/pom.xml +++ b/phoenix-core/pom.xml @@ -237,6 +237,10 @@ <groupId>org.apache.hbase</groupId> <artifactId>hbase</artifactId> </dependency> + <dependency> + <groupId>joda-time</groupId> + <artifactId>joda-time</artifactId> + </dependency> <!-- Findbugs Annotation --> <dependency> <groupId>net.sourceforge.findbugs</groupId> http://git-wip-us.apache.org/repos/asf/phoenix/blob/ddeacbf7/phoenix-core/src/it/java/org/apache/phoenix/end2end/CSVCommonsLoaderIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CSVCommonsLoaderIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CSVCommonsLoaderIT.java index e98d5f3..1cc5ff6 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CSVCommonsLoaderIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CSVCommonsLoaderIT.java @@ -651,6 +651,47 @@ public class CSVCommonsLoaderIT extends BaseHBaseManagedTimeIT { } @Test + public void testCSVCommonsUpsert_WithTimestamp() throws Exception { + CSVParser parser = null; + PhoenixConnection conn = null; + try { + + // Create table + String statements = "CREATE TABLE IF NOT EXISTS TS_TABLE " + + "(ID BIGINT NOT NULL PRIMARY KEY, TS TIMESTAMP);"; + conn = DriverManager.getConnection(getUrl()).unwrap( + PhoenixConnection.class); + PhoenixRuntime.executeStatements(conn, + new StringReader(statements), null); + + // Upsert CSV file + CSVCommonsLoader csvUtil = new CSVCommonsLoader(conn, "TS_TABLE", + null, true, ',', '"', null, "!"); + csvUtil.upsert( + new StringReader("ID,TS\n" + + "1,1970-01-01 00:00:10\n" + + "2,1970-01-01 00:00:10.123\n")); + + // Compare Phoenix ResultSet with CSV file content + PreparedStatement statement = conn + .prepareStatement("SELECT ID, TS FROM TS_TABLE ORDER BY ID"); + ResultSet phoenixResultSet = statement.executeQuery(); + assertTrue(phoenixResultSet.next()); + assertEquals(1L, phoenixResultSet.getLong(1)); + assertEquals(10000L, phoenixResultSet.getTimestamp(2).getTime()); + assertTrue(phoenixResultSet.next()); + assertEquals(2L, phoenixResultSet.getLong(1)); + assertEquals(10123L, phoenixResultSet.getTimestamp(2).getTime()); + assertFalse(phoenixResultSet.next()); + } finally { + if (parser != null) + parser.close(); + if (conn != null) + conn.close(); + } + } + + @Test public void testCSVCommonsUpsert_NonExistentTable() throws Exception { PhoenixConnection conn = null; try { http://git-wip-us.apache.org/repos/asf/phoenix/blob/ddeacbf7/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 c940067..8952708 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 @@ -30,7 +30,11 @@ import org.apache.commons.lang.time.FastDateFormat; import org.apache.phoenix.query.QueryConstants; import org.apache.phoenix.schema.IllegalDataException; - +import org.joda.time.DateTime; +import org.joda.time.chrono.ISOChronology; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.DateTimeFormatterBuilder; +import org.joda.time.format.ISODateTimeFormat; @SuppressWarnings("serial") @@ -45,6 +49,14 @@ public class DateUtil { public static final Format DEFAULT_MS_DATE_FORMATTER = FastDateFormat.getInstance( DEFAULT_MS_DATE_FORMAT, TimeZone.getTimeZone(DEFAULT_TIME_ZONE_ID)); + private static final DateTimeFormatter DATE_TIME_PARSER = new DateTimeFormatterBuilder() + .append(ISODateTimeFormat.dateParser()) + .appendOptional(new DateTimeFormatterBuilder() + .appendLiteral(' ') + .append(ISODateTimeFormat.timeParser()).toParser()) + .toFormatter() + .withChronology(ISOChronology.getInstanceUTC()); + private DateUtil() { } @@ -102,49 +114,24 @@ public class DateUtil { : FastDateFormat.getInstance(pattern, DateUtil.DEFAULT_TIME_ZONE); } - private static ThreadLocal<Format> dateFormat = - new ThreadLocal < Format > () { - @Override protected Format initialValue() { - return getDateParser(DEFAULT_DATE_FORMAT); - } - }; - - public static Date parseDate(String dateValue) { + private static DateTime parseDateTime(String dateTimeValue) { try { - return (Date)dateFormat.get().parseObject(dateValue); - } catch (ParseException e) { + return DATE_TIME_PARSER.parseDateTime(dateTimeValue); + } catch (IllegalArgumentException e) { throw new IllegalDataException(e); } } - private static ThreadLocal<Format> timeFormat = - new ThreadLocal < Format > () { - @Override protected Format initialValue() { - return getTimeParser(DEFAULT_DATE_FORMAT); - } - }; + public static Date parseDate(String dateValue) { + return new Date(parseDateTime(dateValue).getMillis()); + } public static Time parseTime(String timeValue) { - try { - return (Time)timeFormat.get().parseObject(timeValue); - } catch (ParseException e) { - throw new IllegalDataException(e); - } + return new Time(parseDateTime(timeValue).getMillis()); } - private static ThreadLocal<Format> timestampFormat = - new ThreadLocal < Format > () { - @Override protected Format initialValue() { - return getTimestampParser(DEFAULT_DATE_FORMAT); - } - }; - - public static Timestamp parseTimestamp(String timeValue) { - try { - return (Timestamp)timestampFormat.get().parseObject(timeValue); - } catch (ParseException e) { - throw new IllegalDataException(e); - } + public static Timestamp parseTimestamp(String timestampValue) { + return new Timestamp(parseDateTime(timestampValue).getMillis()); } /** http://git-wip-us.apache.org/repos/asf/phoenix/blob/ddeacbf7/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 36acf70..e5d4dfa 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 @@ -23,11 +23,13 @@ import java.sql.Timestamp; import java.text.ParseException; import java.util.TimeZone; +import org.apache.phoenix.schema.IllegalDataException; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * Test class for {@link DateUtil} @@ -127,4 +129,44 @@ public class DateUtilTest { "HH:mm:ss", TimeZone.getDefault()).parseObject("00:00:00"); assertEquals(Time.valueOf("00:00:00"), time); } + + @Test + public void testParseDate() { + assertEquals(10000L, DateUtil.parseDate("1970-01-01 00:00:10").getTime()); + } + + @Test + public void testParseDate_PureDate() { + assertEquals(0L, DateUtil.parseDate("1970-01-01").getTime()); + } + + @Test(expected = IllegalDataException.class) + public void testParseDate_InvalidDate() { + DateUtil.parseDate("not-a-date"); + } + + @Test + public void testParseTime() { + assertEquals(10000L, DateUtil.parseTime("1970-01-01 00:00:10").getTime()); + } + + @Test(expected=IllegalDataException.class) + public void testParseTime_InvalidTime() { + DateUtil.parseDate("not-a-time"); + } + + @Test + public void testParseTimestamp() { + assertEquals(10000L, DateUtil.parseTimestamp("1970-01-01 00:00:10").getTime()); + } + + @Test + public void testParseTimestamp_WithMillis() { + assertEquals(10123L, DateUtil.parseTimestamp("1970-01-01 00:00:10.123").getTime()); + } + + @Test(expected=IllegalDataException.class) + public void testParseTimestamp_InvalidTimestamp() { + DateUtil.parseTimestamp("not-a-timestamp"); + } }