You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by re...@apache.org on 2019/12/10 13:39:21 UTC

svn commit: r1871135 - in /jackrabbit/branches/2.18: ./ jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/ jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/ jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/com...

Author: reschke
Date: Tue Dec 10 13:39:21 2019
New Revision: 1871135

URL: http://svn.apache.org/viewvc?rev=1871135&view=rev
Log:
JCR-4502: ISO8601: add convenience methods that do not require passing a Calendar, also support short format without ms information (merged r1869804, r1870503, and r1870756 into 2.18)

Modified:
    jackrabbit/branches/2.18/   (props changed)
    jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/ISO8601.java
    jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/package-info.java
    jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/ISO8601Test.java
    jackrabbit/branches/2.18/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql/QueryFormat.java
    jackrabbit/branches/2.18/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/xpath/QueryFormat.java

Propchange: jackrabbit/branches/2.18/
------------------------------------------------------------------------------
  Merged /jackrabbit/trunk:r1869804,1870503,1870756

Modified: jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/ISO8601.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/ISO8601.java?rev=1871135&r1=1871134&r2=1871135&view=diff
==============================================================================
--- jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/ISO8601.java (original)
+++ jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/ISO8601.java Tue Dec 10 13:39:21 2019
@@ -16,10 +16,13 @@
  */
 package org.apache.jackrabbit.util;
 
+import java.time.Clock;
 import java.util.Calendar;
+import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.SimpleTimeZone;
 import java.util.TimeZone;
 
 /**
@@ -75,6 +78,8 @@ public final class ISO8601 {
         }
     }
 
+    private static TimeZone UTC = TimeZone.getTimeZone("UTC");
+
     /**
      * Parses an ISO8601-compliant date/time string.
      *
@@ -226,6 +231,91 @@ public final class ISO8601 {
     }
 
     /**
+     * Formats a time instant into an ISO8601-compliant date/time string using
+     * the UTC timezone.
+     *
+     * @param date
+     *            date to be formatted
+     * @return the formatted date/time string.
+     * @throws IllegalArgumentException
+     *             if the calendar cannot be represented as defined by ISO 8601
+     *             (i.e. year with more than four digits).
+     */
+    public static String format(Date date) throws IllegalArgumentException {
+        return format(date, 0);
+    }
+
+    /**
+     * Formats a clock time instant into an ISO8601-compliant date/time string.
+     * 
+     * @param clock
+     *            clock to obtain time and time zone from
+     * @return the formatted date/time string.
+     * @throws IllegalArgumentException
+     *             if the calendar cannot be represented as defined by ISO 8601
+     *             (i.e. year with more than four digits).
+     */
+    public static String format(Clock clock) throws IllegalArgumentException {
+        return format(clock.millis(), clock.getZone().getRules().getOffset(clock.instant()).getTotalSeconds());
+    }
+
+    /**
+     * Formats a time instant into an ISO8601-compliant date/time string using
+     * the UTC timezone.
+     *
+     * @param millisSinceEpoch
+     *            milliseconds since the epoch
+     * @return the formatted date/time string.
+     * @throws IllegalArgumentException
+     *             if the calendar cannot be represented as defined by ISO 8601
+     *             (i.e. year with more than four digits).
+     */
+    public static String format(long millisSinceEpoch) throws IllegalArgumentException {
+        return format(millisSinceEpoch, 0);
+    }
+
+    /**
+     * Formats a time instant and a timezone offset into an ISO8601-compliant
+     * date/time string.
+     *
+     * @param date
+     *            date to be formatted
+     * @param tzOffsetInSeconds
+     *            timezone offset from UTC in seconds
+     * @return the formatted date/time string.
+     * @throws IllegalArgumentException
+     *             if the calendar cannot be represented as defined by ISO 8601
+     *             (i.e. year with more than four digits).
+     */
+    public static String format(Date date, int tzOffsetInSeconds) throws IllegalArgumentException {
+        if (date == null) {
+            throw new IllegalArgumentException("argument can not be null");
+        }
+        return format(date.getTime(), tzOffsetInSeconds);
+    }
+
+    /**
+     * Formats a time instant and a timezone offset into an ISO8601-compliant
+     * date/time string.
+     *
+     * @param millisSinceEpoch
+     *            milliseconds since the epoch
+     * @param tzOffsetInSeconds
+     *            timezone offset from UTC in seconds
+     * @return the formatted date/time string.
+     * @throws IllegalArgumentException
+     *             if a <code>null</code> argument is passed the calendar cannot
+     *             be represented as defined by ISO 8601 (i.e. year with more
+     *             than four digits).
+     */
+    public static String format(long millisSinceEpoch, int tzOffsetInSeconds) throws IllegalArgumentException {
+        Calendar cal = Calendar.getInstance();
+        cal.setTimeZone(tzOffsetInSeconds == 0 ? UTC : new SimpleTimeZone(tzOffsetInSeconds * 1000, ""));
+        cal.setTimeInMillis(millisSinceEpoch);
+        return format(cal);
+    }
+
+    /**
      * Formats a <code>Calendar</code> value into an ISO8601-compliant
      * date/time string.
      *
@@ -236,6 +326,10 @@ public final class ISO8601 {
      * with more than four digits).
      */
     public static String format(Calendar cal) throws IllegalArgumentException {
+        return format(cal, true);
+    }
+
+    private static String format(Calendar cal, boolean includeMs) throws IllegalArgumentException {
         if (cal == null) {
             throw new IllegalArgumentException("argument can not be null");
         }
@@ -265,9 +359,11 @@ public final class ISO8601 {
         buf.append(':');
         // second (ss)
         appendZeroPaddedInt(buf, cal.get(Calendar.SECOND), 2);
-        buf.append('.');
-        // millisecond (SSS)
-        appendZeroPaddedInt(buf, cal.get(Calendar.MILLISECOND), 3);
+        if (includeMs) {
+            buf.append('.');
+            // millisecond (SSS)
+            appendZeroPaddedInt(buf, cal.get(Calendar.MILLISECOND), 3);
+        }
         // time zone designator (Z or +00:00 or -00:00)
         TimeZone tz = cal.getTimeZone();
         // determine offset of timezone from UTC (incl. daylight saving)
@@ -313,6 +409,62 @@ public final class ISO8601 {
         return year;
     }
 
+
+    /**
+     * Variants that exclude the milliseconds from the formatted string.
+     *
+     */
+    public static class SHORT {
+
+        /**
+         * @see ISO8601#format(Date)
+         */
+        public static String format(Date date) throws IllegalArgumentException {
+            return format(date, 0);
+        }
+
+        /**
+         * @see ISO8601#format(Clock)
+         */
+        public static String format(Clock clock) throws IllegalArgumentException {
+            return format(clock.millis(), clock.getZone().getRules().getOffset(clock.instant()).getTotalSeconds());
+        }
+
+        /**
+         * @see ISO8601#format(long)
+         */
+        public static String format(long millisSinceEpoch) throws IllegalArgumentException {
+            return format(millisSinceEpoch, 0);
+        }
+
+        /**
+         * @see ISO8601#format(Date, int)
+         */
+        public static String format(Date date, int tzOffsetInSeconds) throws IllegalArgumentException {
+            if (date == null) {
+                throw new IllegalArgumentException("argument can not be null");
+            }
+            return format(date.getTime(), tzOffsetInSeconds);
+        }
+
+        /**
+         * @see ISO8601#format(long, int)
+         */
+        public static String format(long millisSinceEpoch, int tzOffsetInSeconds) throws IllegalArgumentException {
+            Calendar cal = Calendar.getInstance();
+            cal.setTimeZone(tzOffsetInSeconds == 0 ? UTC : new SimpleTimeZone(tzOffsetInSeconds * 1000, ""));
+            cal.setTimeInMillis(millisSinceEpoch);
+            return format(cal);
+        }
+
+        /**
+         * @see ISO8601#format(Calendar)
+         */
+        public static String format(Calendar cal) throws IllegalArgumentException {
+            return ISO8601.format(cal, false);
+        }
+    }
+
     /**
      * Appends a zero-padded number to the given string buffer.
      * <p>

Modified: jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/package-info.java?rev=1871135&r1=1871134&r2=1871135&view=diff
==============================================================================
--- jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/package-info.java (original)
+++ jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/util/package-info.java Tue Dec 10 13:39:21 2019
@@ -14,5 +14,5 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@org.osgi.annotation.versioning.Version("2.4")
+@org.osgi.annotation.versioning.Version("2.5.0")
 package org.apache.jackrabbit.util;

Modified: jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/ISO8601Test.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/ISO8601Test.java?rev=1871135&r1=1871134&r2=1871135&view=diff
==============================================================================
--- jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/ISO8601Test.java (original)
+++ jackrabbit/branches/2.18/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/ISO8601Test.java Tue Dec 10 13:39:21 2019
@@ -16,7 +16,11 @@
  */
 package org.apache.jackrabbit.util;
 
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
 import java.util.Calendar;
+import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.SimpleTimeZone;
 import java.util.TimeZone;
@@ -26,11 +30,17 @@ import junit.framework.TestCase;
 public class ISO8601Test extends TestCase {
 
     private TimeZone customPlus = new SimpleTimeZone(83 * 60 * 1000, "test");
-    private TimeZone customMinus = new SimpleTimeZone(-1202 * 60 * 1000, "test");
+    private TimeZone customMinus = new SimpleTimeZone(-122 * 60 * 1000, "test");
+    private ZoneId customPlusZI = ZoneId.of("+01:23");
+    private ZoneId customMinusZI = ZoneId.of("-02:02");
 
     public void testFormatThrowsIllegalArgumentException() {
         try {
-            ISO8601.format(null);
+            ISO8601.format((Calendar) null);
+        } catch (IllegalArgumentException expected) {
+        }
+        try {
+            ISO8601.format((Date) null);
         } catch (IllegalArgumentException expected) {
         }
     }
@@ -45,31 +55,85 @@ public class ISO8601Test extends TestCas
     public void testFormatUTC() {
         Calendar c = Calendar.getInstance();
         c.setTimeZone(TimeZone.getTimeZone("UTC"));
+        Clock clock;
 
         c.setTimeInMillis(0);
+        clock = Clock.fixed(Instant.ofEpochMilli(0), ZoneId.of("Z"));
         assertEquals("1970-01-01T00:00:00.000Z", ISO8601.format(c));
+        assertEquals("1970-01-01T00:00:00.000Z", ISO8601.format(clock));
+        assertEquals("1970-01-01T00:00:00.000Z", ISO8601.format(0));
+        assertEquals("1970-01-01T00:00:00.000Z", ISO8601.format(new Date(0)));
+        assertEquals("1970-01-01T00:00:00.000Z", ISO8601.format(0, 0));
+        assertEquals("1970-01-01T00:00:00.000Z", ISO8601.format(new Date(0), 0));
 
         c.setTimeInMillis(123456789012L);
+        clock = Clock.fixed(Instant.ofEpochMilli(123456789012L), ZoneId.of("Z"));
         assertEquals("1973-11-29T21:33:09.012Z", ISO8601.format(c));
+        assertEquals("1973-11-29T21:33:09.012Z", ISO8601.format(clock));
+        assertEquals("1973-11-29T21:33:09.012Z", ISO8601.format(123456789012L));
+        assertEquals("1973-11-29T21:33:09.012Z", ISO8601.format(new Date(123456789012L)));
+        assertEquals("1973-11-29T21:33:09.012Z", ISO8601.format(123456789012L, 0));
+        assertEquals("1973-11-29T21:33:09.012Z", ISO8601.format(new Date(123456789012L), 0));
+    }
+
+    public void testFormatUTCShort() {
+        Calendar c = Calendar.getInstance();
+        c.setTimeZone(TimeZone.getTimeZone("UTC"));
+        Clock clock;
+
+        c.setTimeInMillis(0);
+        clock = Clock.fixed(Instant.ofEpochMilli(0), ZoneId.of("Z"));
+        assertEquals("1970-01-01T00:00:00Z", ISO8601.SHORT.format(c));
+        assertEquals("1970-01-01T00:00:00Z", ISO8601.SHORT.format(clock));
+        assertEquals("1970-01-01T00:00:00Z", ISO8601.SHORT.format(0));
+        assertEquals("1970-01-01T00:00:00Z", ISO8601.SHORT.format(new Date(0)));
+        assertEquals("1970-01-01T00:00:00Z", ISO8601.SHORT.format(0, 0));
+        assertEquals("1970-01-01T00:00:00Z", ISO8601.SHORT.format(new Date(0), 0));
+
+        c.setTimeInMillis(123456789012L);
+        clock = Clock.fixed(Instant.ofEpochMilli(123456789012L), ZoneId.of("Z"));
+        assertEquals("1973-11-29T21:33:09Z", ISO8601.SHORT.format(c));
+        assertEquals("1973-11-29T21:33:09Z", ISO8601.SHORT.format(clock));
+        assertEquals("1973-11-29T21:33:09Z", ISO8601.SHORT.format(123456789012L));
+        assertEquals("1973-11-29T21:33:09Z", ISO8601.SHORT.format(new Date(123456789012L)));
+        assertEquals("1973-11-29T21:33:09Z", ISO8601.SHORT.format(123456789012L, 0));
+        assertEquals("1973-11-29T21:33:09Z", ISO8601.SHORT.format(new Date(123456789012L), 0));
     }
 
     public void testFormatCustomTz() {
         Calendar c = Calendar.getInstance();
         c.setTimeZone(customPlus);
+        Clock clock;
 
         c.setTimeInMillis(0);
+        clock = Clock.fixed(Instant.ofEpochMilli(0), customPlusZI);
         assertEquals("1970-01-01T01:23:00.000+01:23", ISO8601.format(c));
+        assertEquals("1970-01-01T01:23:00.000+01:23", ISO8601.format(clock));
+        assertEquals("1970-01-01T01:23:00.000+01:23", ISO8601.format(0, customPlus.getRawOffset() / 1000));
+        assertEquals("1970-01-01T01:23:00.000+01:23", ISO8601.format(new Date(0), customPlus.getRawOffset() / 1000));
 
         c.setTimeInMillis(123456789012L);
+        clock = Clock.fixed(Instant.ofEpochMilli(123456789012L), customPlusZI);
         assertEquals("1973-11-29T22:56:09.012+01:23", ISO8601.format(c));
+        assertEquals("1973-11-29T22:56:09.012+01:23", ISO8601.format(clock));
+        assertEquals("1973-11-29T22:56:09.012+01:23", ISO8601.format(123456789012L, customPlus.getRawOffset() / 1000));
+        assertEquals("1973-11-29T22:56:09.012+01:23", ISO8601.format(new Date(123456789012L), customPlus.getRawOffset() / 1000));
 
         c.setTimeZone(customMinus);
 
         c.setTimeInMillis(0);
-        assertEquals("1969-12-31T03:58:00.000-20:02", ISO8601.format(c));
+        clock = Clock.fixed(Instant.ofEpochMilli(0), customMinusZI);
+        assertEquals("1969-12-31T21:58:00.000-02:02", ISO8601.format(c));
+        assertEquals("1969-12-31T21:58:00.000-02:02", ISO8601.format(clock));
+        assertEquals("1969-12-31T21:58:00.000-02:02", ISO8601.format(0, customMinus.getRawOffset() / 1000));
+        assertEquals("1969-12-31T21:58:00.000-02:02", ISO8601.format(new Date(0), customMinus.getRawOffset() / 1000));
 
         c.setTimeInMillis(123456789012L);
-        assertEquals("1973-11-29T01:31:09.012-20:02", ISO8601.format(c));
+        clock = Clock.fixed(Instant.ofEpochMilli(123456789012L), customMinusZI);
+        assertEquals("1973-11-29T19:31:09.012-02:02", ISO8601.format(c));
+        assertEquals("1973-11-29T19:31:09.012-02:02", ISO8601.format(clock));
+        assertEquals("1973-11-29T19:31:09.012-02:02", ISO8601.format(123456789012L, customMinus.getRawOffset() / 1000));
+        assertEquals("1973-11-29T19:31:09.012-02:02", ISO8601.format(new Date(123456789012L), customMinus.getRawOffset() / 1000));
     }
 
     public void testParseUTC() {
@@ -91,11 +155,11 @@ public class ISO8601Test extends TestCas
         assertEquals(123456789012L, c.getTimeInMillis());
         assertEquals(customPlus.getRawOffset(), c.getTimeZone().getRawOffset());
 
-        c = ISO8601.parse("1969-12-31T03:58:00.000-20:02");
+        c = ISO8601.parse("1969-12-31T21:58:00.000-02:02");
         assertEquals(0, c.getTimeInMillis());
         assertEquals(customMinus.getRawOffset(), c.getTimeZone().getRawOffset());
 
-        c = ISO8601.parse("1973-11-29T01:31:09.012-20:02");
+        c = ISO8601.parse("1973-11-29T19:31:09.012-02:02");
         assertEquals(123456789012L, c.getTimeInMillis());
         assertEquals(customMinus.getRawOffset(), c.getTimeZone().getRawOffset());
     }

Modified: jackrabbit/branches/2.18/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql/QueryFormat.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.18/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql/QueryFormat.java?rev=1871135&r1=1871134&r2=1871135&view=diff
==============================================================================
--- jackrabbit/branches/2.18/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql/QueryFormat.java (original)
+++ jackrabbit/branches/2.18/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/sql/QueryFormat.java Tue Dec 10 13:39:21 2019
@@ -17,10 +17,8 @@
 package org.apache.jackrabbit.spi.commons.query.sql;
 
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Iterator;
 import java.util.List;
-import java.util.TimeZone;
 
 import javax.jcr.NamespaceException;
 import javax.jcr.RepositoryException;
@@ -553,9 +551,7 @@ class QueryFormat implements QueryNodeVi
         } else if (node.getValueType() == TYPE_STRING) {
             b.append("'").append(node.getStringValue().replaceAll("'", "''")).append("'");
         } else if (node.getValueType() == TYPE_DATE || node.getValueType() == TYPE_TIMESTAMP) {
-            Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
-            cal.setTime(node.getDateValue());
-            b.append("TIMESTAMP '").append(ISO8601.format(cal)).append("'");
+            b.append("TIMESTAMP '").append(ISO8601.format(node.getDateValue())).append("'");
         } else {
             exceptions.add(new InvalidQueryException("Invalid type: " + node.getValueType()));
         }

Modified: jackrabbit/branches/2.18/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/xpath/QueryFormat.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.18/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/xpath/QueryFormat.java?rev=1871135&r1=1871134&r2=1871135&view=diff
==============================================================================
--- jackrabbit/branches/2.18/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/xpath/QueryFormat.java (original)
+++ jackrabbit/branches/2.18/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/xpath/QueryFormat.java Tue Dec 10 13:39:21 2019
@@ -17,9 +17,7 @@
 package org.apache.jackrabbit.spi.commons.query.xpath;
 
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.List;
-import java.util.TimeZone;
 
 import javax.jcr.NamespaceException;
 import javax.jcr.RepositoryException;
@@ -505,10 +503,8 @@ class QueryFormat implements QueryNodeVi
         } else if (node.getValueType() == TYPE_STRING) {
             b.append("'").append(node.getStringValue().replaceAll("'", "''")).append("'");
         } else if (node.getValueType() == TYPE_DATE || node.getValueType() == TYPE_TIMESTAMP) {
-            Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
-            cal.setTime(node.getDateValue());
             b.append(resolver.getJCRName(XPathQueryBuilder.XS_DATETIME));
-            b.append("('").append(ISO8601.format(cal)).append("')");
+            b.append("('").append(ISO8601.format(node.getDateValue())).append("')");
         } else if (node.getValueType() == TYPE_POSITION) {
             if (node.getPositionValue() == LocationStepQueryNode.LAST) {
                 b.append("last()");