You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sl...@apache.org on 2014/05/21 17:54:40 UTC

[3/5] 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/trunk
Commit: 2635632270289fbbab2f3e3181f20aa98c34a879
Parents: 484d281
Author: Sylvain Lebresne <sy...@datastax.com>
Authored: Wed May 21 17:29:12 2014 +0200
Committer: Sylvain Lebresne <sy...@datastax.com>
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<Date>
 
     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<Date>
       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<UUID>
 
             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<Date>
 
     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<Date>
       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:<br>
  * - if count of supplied bytes is less than 16, compare counts<br>
@@ -165,8 +164,6 @@ public class UUIDType extends AbstractType<UUID>
         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<UUID>
             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<Date>
 {
-    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<SimpleDateFormat> FORMATTER = new ThreadLocal<SimpleDateFormat>()
+    private static final ThreadLocal<SimpleDateFormat> FORMATTER = new ThreadLocal<SimpleDateFormat>()
     {
         protected SimpleDateFormat initialValue()
         {
@@ -64,6 +83,35 @@ public class TimestampSerializer implements TypeSerializer<Date>
         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<String> 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());
+    }
+}