Return-Path: X-Original-To: apmail-cassandra-commits-archive@www.apache.org Delivered-To: apmail-cassandra-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 0279D11993 for ; Wed, 21 May 2014 15:49:53 +0000 (UTC) Received: (qmail 51565 invoked by uid 500); 21 May 2014 15:49:52 -0000 Delivered-To: apmail-cassandra-commits-archive@cassandra.apache.org Received: (qmail 51464 invoked by uid 500); 21 May 2014 15:49:52 -0000 Mailing-List: contact commits-help@cassandra.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cassandra.apache.org Delivered-To: mailing list commits@cassandra.apache.org Received: (qmail 51334 invoked by uid 99); 21 May 2014 15:49:52 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 21 May 2014 15:49:52 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 895D899CC84; Wed, 21 May 2014 15:49:52 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: slebresne@apache.org To: commits@cassandra.apache.org Date: Wed, 21 May 2014 15:49:54 -0000 Message-Id: In-Reply-To: <12fd956555d1440a84eac0c0cb032411@git.apache.org> References: <12fd956555d1440a84eac0c0cb032411@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [3/4] git commit: Add missing iso8601 patterns for date strings Add missing iso8601 patterns for date strings patch by chander; reviewed by slebresne for CASSANDRA-6973 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/26356322 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/26356322 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/26356322 Branch: refs/heads/cassandra-2.1 Commit: 2635632270289fbbab2f3e3181f20aa98c34a879 Parents: 484d281 Author: Sylvain Lebresne Authored: Wed May 21 17:29:12 2014 +0200 Committer: Sylvain Lebresne Committed: Wed May 21 17:29:12 2014 +0200 ---------------------------------------------------------------------- CHANGES.txt | 4 + .../apache/cassandra/db/marshal/DateType.java | 41 +---------- .../cassandra/db/marshal/TimeUUIDType.java | 6 +- .../cassandra/db/marshal/TimestampType.java | 43 +---------- .../apache/cassandra/db/marshal/UUIDType.java | 38 ++-------- .../serializers/TimestampSerializer.java | 68 ++++++++++++++--- .../serializers/TimestampSerializerTest.java | 77 ++++++++++++++++++++ 7 files changed, 152 insertions(+), 125 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/26356322/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 3f8e3d0..bddb1d1 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,7 @@ +2.0.9 + * Add missing iso8601 patterns for date strings (6973) + + 2.0.8 * Always reallocate buffers in HSHA (CASSANDRA-6285) * (Hadoop) support authentication in CqlRecordReader (CASSANDRA-7221) http://git-wip-us.apache.org/repos/asf/cassandra/blob/26356322/src/java/org/apache/cassandra/db/marshal/DateType.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/marshal/DateType.java b/src/java/org/apache/cassandra/db/marshal/DateType.java index 8e28bd4..0c97688 100644 --- a/src/java/org/apache/cassandra/db/marshal/DateType.java +++ b/src/java/org/apache/cassandra/db/marshal/DateType.java @@ -38,9 +38,6 @@ public class DateType extends AbstractType public static final DateType instance = new DateType(); - static final String DEFAULT_FORMAT = TimestampSerializer.iso8601Patterns[3]; - static final SimpleDateFormat FORMATTER = new SimpleDateFormat(DEFAULT_FORMAT); - DateType() {} // singleton public int compare(ByteBuffer o1, ByteBuffer o2) @@ -63,43 +60,7 @@ public class DateType extends AbstractType if (source.isEmpty()) return ByteBufferUtil.EMPTY_BYTE_BUFFER; - return ByteBufferUtil.bytes(dateStringToTimestamp(source)); - } - - public static long dateStringToTimestamp(String source) throws MarshalException - { - long millis; - - if (source.toLowerCase().equals("now")) - { - millis = System.currentTimeMillis(); - } - // Milliseconds since epoch? - else if (source.matches("^-?\\d+$")) - { - try - { - millis = Long.parseLong(source); - } - catch (NumberFormatException e) - { - throw new MarshalException(String.format("unable to make long (for date) from: '%s'", source), e); - } - } - // Last chance, attempt to parse as date-time string - else - { - try - { - millis = DateUtils.parseDateStrictly(source, TimestampSerializer.iso8601Patterns).getTime(); - } - catch (ParseException e1) - { - throw new MarshalException(String.format("unable to coerce '%s' to a formatted date (long)", source), e1); - } - } - - return millis; + return ByteBufferUtil.bytes(TimestampSerializer.dateStringToTimestamp(source)); } @Override http://git-wip-us.apache.org/repos/asf/cassandra/blob/26356322/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java b/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java index 51cf47a..fa82f06 100644 --- a/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java +++ b/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java @@ -25,6 +25,7 @@ import org.apache.cassandra.cql3.CQL3Type; import org.apache.cassandra.serializers.TypeSerializer; import org.apache.cassandra.serializers.MarshalException; import org.apache.cassandra.serializers.TimeUUIDSerializer; +import org.apache.cassandra.serializers.TimestampSerializer; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.UUIDGen; @@ -110,9 +111,10 @@ public class TimeUUIDType extends AbstractType if (uuid.version() != 1) throw new MarshalException("TimeUUID supports only version 1 UUIDs"); - } else + } + else { - idBytes = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(DateType.dateStringToTimestamp(source))); + idBytes = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(TimestampSerializer.dateStringToTimestamp(source))); } return idBytes; http://git-wip-us.apache.org/repos/asf/cassandra/blob/26356322/src/java/org/apache/cassandra/db/marshal/TimestampType.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/marshal/TimestampType.java b/src/java/org/apache/cassandra/db/marshal/TimestampType.java index cf1ea41..69ead8e 100644 --- a/src/java/org/apache/cassandra/db/marshal/TimestampType.java +++ b/src/java/org/apache/cassandra/db/marshal/TimestampType.java @@ -18,9 +18,7 @@ package org.apache.cassandra.db.marshal; import java.nio.ByteBuffer; -import java.text.ParseException; import java.util.Date; -import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,7 +27,6 @@ import org.apache.cassandra.serializers.TypeSerializer; import org.apache.cassandra.serializers.MarshalException; import org.apache.cassandra.serializers.TimestampSerializer; import org.apache.cassandra.utils.ByteBufferUtil; -import org.apache.commons.lang3.time.DateUtils; /** * Type for date-time values. @@ -44,8 +41,6 @@ public class TimestampType extends AbstractType public static final TimestampType instance = new TimestampType(); - private static final Pattern timestampPattern = Pattern.compile("^-?\\d+$"); - private TimestampType() {} // singleton public int compare(ByteBuffer o1, ByteBuffer o2) @@ -59,43 +54,7 @@ public class TimestampType extends AbstractType if (source.isEmpty()) return ByteBufferUtil.EMPTY_BYTE_BUFFER; - return ByteBufferUtil.bytes(dateStringToTimestamp(source)); - } - - public static long dateStringToTimestamp(String source) throws MarshalException - { - long millis; - - if (source.toLowerCase().equals("now")) - { - millis = System.currentTimeMillis(); - } - // Milliseconds since epoch? - else if (timestampPattern.matcher(source).matches()) - { - try - { - millis = Long.parseLong(source); - } - catch (NumberFormatException e) - { - throw new MarshalException(String.format("unable to make long (for date) from: '%s'", source), e); - } - } - // Last chance, attempt to parse as date-time string - else - { - try - { - millis = DateUtils.parseDateStrictly(source, TimestampSerializer.iso8601Patterns).getTime(); - } - catch (ParseException e1) - { - throw new MarshalException(String.format("unable to coerce '%s' to a formatted date (long)", source), e1); - } - } - - return millis; + return ByteBufferUtil.bytes(TimestampSerializer.dateStringToTimestamp(source)); } @Override http://git-wip-us.apache.org/repos/asf/cassandra/blob/26356322/src/java/org/apache/cassandra/db/marshal/UUIDType.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/marshal/UUIDType.java b/src/java/org/apache/cassandra/db/marshal/UUIDType.java index 4b0751e..969ff17 100644 --- a/src/java/org/apache/cassandra/db/marshal/UUIDType.java +++ b/src/java/org/apache/cassandra/db/marshal/UUIDType.java @@ -26,12 +26,11 @@ import org.apache.cassandra.cql3.CQL3Type; import org.apache.cassandra.serializers.TypeSerializer; import org.apache.cassandra.serializers.MarshalException; import org.apache.cassandra.serializers.UUIDSerializer; +import org.apache.cassandra.serializers.TimestampSerializer; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.UUIDGen; import org.apache.commons.lang3.time.DateUtils; -import static org.apache.cassandra.serializers.TimestampSerializer.iso8601Patterns; - /** * Compares UUIDs using the following criteria:
* - if count of supplied bytes is less than 16, compare counts
@@ -165,8 +164,6 @@ public class UUIDType extends AbstractType if (source.isEmpty()) return ByteBufferUtil.EMPTY_BYTE_BUFFER; - ByteBuffer idBytes = null; - // ffffffff-ffff-ffff-ffff-ffffffffff if (TimeUUIDType.regexPattern.matcher(source).matches()) { @@ -174,43 +171,22 @@ public class UUIDType extends AbstractType try { uuid = UUID.fromString(source); - idBytes = ByteBuffer.wrap(UUIDGen.decompose(uuid)); + return ByteBuffer.wrap(UUIDGen.decompose(uuid)); } catch (IllegalArgumentException e) { throw new MarshalException(String.format("unable to make UUID from '%s'", source), e); } - } else if (source.toLowerCase().equals("now")) - { - idBytes = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes()); } - // Milliseconds since epoch? - else if (source.matches("^\\d+$")) + + try { - try - { - idBytes = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(Long.parseLong(source))); - } - catch (NumberFormatException e) - { - throw new MarshalException(String.format("unable to make version 1 UUID from '%s'", source), e); - } + return ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(TimestampSerializer.dateStringToTimestamp(source))); } - // Last chance, attempt to parse as date-time string - else + catch (MarshalException e) { - try - { - long timestamp = DateUtils.parseDate(source, iso8601Patterns).getTime(); - idBytes = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(timestamp)); - } - catch (ParseException e1) - { - throw new MarshalException(String.format("unable to coerce '%s' to version 1 UUID", source), e1); - } + throw new MarshalException(String.format("unable to make version 1 UUID from '%s'", source), e); } - - return idBytes; } public CQL3Type asCQL3Type() http://git-wip-us.apache.org/repos/asf/cassandra/blob/26356322/src/java/org/apache/cassandra/serializers/TimestampSerializer.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/serializers/TimestampSerializer.java b/src/java/org/apache/cassandra/serializers/TimestampSerializer.java index f2a40f1..5cb9586 100644 --- a/src/java/org/apache/cassandra/serializers/TimestampSerializer.java +++ b/src/java/org/apache/cassandra/serializers/TimestampSerializer.java @@ -21,30 +21,49 @@ import org.apache.cassandra.utils.ByteBufferUtil; import java.nio.ByteBuffer; import java.text.SimpleDateFormat; +import java.text.ParseException; import java.util.Date; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.time.DateUtils; public class TimestampSerializer implements TypeSerializer { - public static final String[] iso8601Patterns = new String[] { + private static final String[] dateStringPatterns = new String[] { "yyyy-MM-dd HH:mm", "yyyy-MM-dd HH:mm:ss", - "yyyy-MM-dd HH:mmZ", - "yyyy-MM-dd HH:mm:ssZ", + "yyyy-MM-dd HH:mmX", + "yyyy-MM-dd HH:mmXX", + "yyyy-MM-dd HH:mmXXX", + "yyyy-MM-dd HH:mm:ssX", + "yyyy-MM-dd HH:mm:ssXX", + "yyyy-MM-dd HH:mm:ssXXX", "yyyy-MM-dd HH:mm:ss.SSS", - "yyyy-MM-dd HH:mm:ss.SSSZ", + "yyyy-MM-dd HH:mm:ss.SSSX", + "yyyy-MM-dd HH:mm:ss.SSSXX", + "yyyy-MM-dd HH:mm:ss.SSSXXX", "yyyy-MM-dd'T'HH:mm", - "yyyy-MM-dd'T'HH:mmZ", + "yyyy-MM-dd'T'HH:mmX", + "yyyy-MM-dd'T'HH:mmXX", + "yyyy-MM-dd'T'HH:mmXXX", "yyyy-MM-dd'T'HH:mm:ss", - "yyyy-MM-dd'T'HH:mm:ssZ", + "yyyy-MM-dd'T'HH:mm:ssX", + "yyyy-MM-dd'T'HH:mm:ssXX", + "yyyy-MM-dd'T'HH:mm:ssXXX", "yyyy-MM-dd'T'HH:mm:ss.SSS", - "yyyy-MM-dd'T'HH:mm:ss.SSSZ", + "yyyy-MM-dd'T'HH:mm:ss.SSSX", + "yyyy-MM-dd'T'HH:mm:ss.SSSXX", + "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", "yyyy-MM-dd", - "yyyy-MM-ddZ" + "yyyy-MM-ddX", + "yyyy-MM-ddXX", + "yyyy-MM-ddXXX" }; - static final String DEFAULT_FORMAT = iso8601Patterns[3]; + private static final String DEFAULT_FORMAT = dateStringPatterns[3]; + private static final Pattern timestampPattern = Pattern.compile("^-?\\d+$"); - static final ThreadLocal FORMATTER = new ThreadLocal() + private static final ThreadLocal FORMATTER = new ThreadLocal() { protected SimpleDateFormat initialValue() { @@ -64,6 +83,35 @@ public class TimestampSerializer implements TypeSerializer return value == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBufferUtil.bytes(value.getTime()); } + public static long dateStringToTimestamp(String source) throws MarshalException + { + if (source.equalsIgnoreCase("now")) + return System.currentTimeMillis(); + + // Milliseconds since epoch? + if (timestampPattern.matcher(source).matches()) + { + try + { + return Long.parseLong(source); + } + catch (NumberFormatException e) + { + throw new MarshalException(String.format("unable to make long (for date) from: '%s'", source), e); + } + } + + // Last chance, attempt to parse as date-time string + try + { + return DateUtils.parseDateStrictly(source, dateStringPatterns).getTime(); + } + catch (ParseException e1) + { + throw new MarshalException(String.format("unable to coerce '%s' to a formatted date (long)", source), e1); + } + } + public void validate(ByteBuffer bytes) throws MarshalException { if (bytes.remaining() != 8 && bytes.remaining() != 0) http://git-wip-us.apache.org/repos/asf/cassandra/blob/26356322/test/unit/org/apache/cassandra/serializers/TimestampSerializerTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/serializers/TimestampSerializerTest.java b/test/unit/org/apache/cassandra/serializers/TimestampSerializerTest.java new file mode 100644 index 0000000..d991845 --- /dev/null +++ b/test/unit/org/apache/cassandra/serializers/TimestampSerializerTest.java @@ -0,0 +1,77 @@ +/** + * 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.cassandra.serializers; + +import java.util.List; +import java.util.ArrayList; + +import org.junit.Test; +import static org.junit.Assert.assertTrue; + +import org.apache.cassandra.serializers.MarshalException; +import org.apache.cassandra.serializers.TimestampSerializer; + +public class TimestampSerializerTest +{ + private String dates[] = new String[] + { + "2014-04-01", + "2014-04-01+0000", + "2014-04-01 20:30", + "2014-04-01 20:30:35", + "2014-04-01 20:30:35Z", + "2014-04-01 20:30+07", + "2014-04-01 20:30+0700", + "2014-04-01 20:30+07:00", + "2014-04-01 20:30:35+07", + "2014-04-01 20:30:35+0700", + "2014-04-01 20:30:35+07:00", + "2014-04-01 20:30:35.898", + "2014-04-01 20:30:35.898Z", + "2014-04-01 20:30:35.898+07", + "2014-04-01 20:30:35.898+0700", + "2014-04-01 20:30:35.898+07:00", + "2014-04-01T20:30", + "2014-04-01T20:30:25", + "2014-04-01T20:30:35Z", + "2014-04-01T20:30:35+00:00", + "2014-04-01T20:30:35+0700", + "2014-04-01T20:30:35+07:00", + "2014-04-01T20:30:35.898", + "2014-04-01T20:30:35.898+00:00" + }; + + @Test + public void testDateStringToTimestamp() + { + List unparsedDates = new ArrayList<>(); + for (String date: dates) + { + try + { + long millis = TimestampSerializer.dateStringToTimestamp(date); + } + catch (MarshalException e) + { + unparsedDates.add(date); + } + } + assertTrue("Unable to parse: " + unparsedDates, unparsedDates.isEmpty()); + } +}