You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by rw...@apache.org on 2019/12/06 20:16:31 UTC

svn commit: r1870930 - in /pivot/trunk: core/src/org/apache/pivot/util/CalendarDate.java core/test/org/apache/pivot/util/test/CalendarDateTest.java wtk/src/org/apache/pivot/wtk/content/CalendarDateSpinnerData.java

Author: rwhitcomb
Date: Fri Dec  6 20:16:31 2019
New Revision: 1870930

URL: http://svn.apache.org/viewvc?rev=1870930&view=rev
Log:
Cleanup of some calendar-related classes:
1) Adjust time zone usage in CalendarDate to move to the constructor(s) and
   use constructed time zone for GregorianCalendar conversions.
2) Simplify CalendarDateSpinnerData to use CalendarDate only for its values
   instead of converting to GregorianCalendar on its own.
3) Fix a lot of "check-style" errors in both classes.
4) Add more tests in CalendarDateTest.java for the new stuff in CalendarDate.

Modified:
    pivot/trunk/core/src/org/apache/pivot/util/CalendarDate.java
    pivot/trunk/core/test/org/apache/pivot/util/test/CalendarDateTest.java
    pivot/trunk/wtk/src/org/apache/pivot/wtk/content/CalendarDateSpinnerData.java

Modified: pivot/trunk/core/src/org/apache/pivot/util/CalendarDate.java
URL: http://svn.apache.org/viewvc/pivot/trunk/core/src/org/apache/pivot/util/CalendarDate.java?rev=1870930&r1=1870929&r2=1870930&view=diff
==============================================================================
--- pivot/trunk/core/src/org/apache/pivot/util/CalendarDate.java (original)
+++ pivot/trunk/core/src/org/apache/pivot/util/CalendarDate.java Fri Dec  6 20:16:31 2019
@@ -23,6 +23,7 @@ import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.util.Calendar;
 import java.util.GregorianCalendar;
+import java.util.TimeZone;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -34,7 +35,10 @@ import org.apache.pivot.serialization.Se
 /**
  * <tt>CalendarDate</tt> allows a specific day to be identified within the
  * Gregorian calendar system. This identification has no association with any
- * particular time zone and no notion of the time of day.
+ * particular time zone and no notion of the time of day, except that
+ * conversions to/from Gregorian calendar may be affected by time zone, so
+ * the zone may be set during construction if desired, and the time of day
+ * can also be set for such conversions.
  */
 public final class CalendarDate implements Comparable<CalendarDate>, Serializable {
     private static final long serialVersionUID = 3974393986540543704L;
@@ -238,6 +242,19 @@ public final class CalendarDate implemen
      */
     public final int day;
 
+    /**
+     * The {@link TimeZone} associated with this calendar date (if any).
+     * <p> By default this is not set, which means using the local timezone.
+     * <p> This is only meaningful for conversions to/from Gregorian calendar
+     * (and implicitly then for difference calculations which use a calculated
+     * calendar value). Can be set in the non-default constructor
+     * (for instance to GMT for the <tt>CalendarDateSpinnerData</tt> class).
+     * <p> Note: difference calculations will only be affected by the timezone
+     * if the two dates are in different ones, otherwise the calculations
+     * will be the same no matter what zone is used.
+     */
+    public final TimeZone timeZone;
+
     private static final int[] MONTH_LENGTHS = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
     private static final Pattern PATTERN = Pattern.compile("^(\\d{4})-(\\d{2})-(\\d{2})$");
@@ -249,6 +266,14 @@ public final class CalendarDate implemen
     /** Maximum supported year (must be less or equal). */
     public static final int MAX_CALENDAR_YEAR = 9999;
 
+    /** The number of milliseconds in a day. Used by various pieces of code. */
+    public static final long MILLIS_PER_DAY = 1000L * 60 * 60 * 24;
+
+    /** The timezone of the (universal) GMT zone (at the prime meridian). */
+    public static final TimeZone TIMEZONE_GMT = TimeZone.getTimeZone("GMT");
+    /** The midnight time of day {@code Time(0,0,0)}. */
+    public static final Time MIDNIGHT_TIME = new Time(0, 0, 0);
+
     /**
      * Creates a new <tt>CalendarDate</tt> representing the current day in the
      * default timezone and the default locale.
@@ -258,6 +283,16 @@ public final class CalendarDate implemen
     }
 
     /**
+     * Creates a new <tt>CalendarDate</tt> representing the current day in the
+     * given timezone and the default locale.
+     *
+     * @param timeZone The timezone to use for this calendar date.
+     */
+    public CalendarDate(final TimeZone timeZone) {
+        this(new GregorianCalendar(timeZone));
+    }
+
+    /**
      * Creates a new <tt>CalendarDate</tt> representing the day contained in the
      * specified Gregorian calendar (assuming the default locale and the default
      * timezone).
@@ -267,7 +302,8 @@ public final class CalendarDate implemen
     public CalendarDate(final GregorianCalendar calendar) {
         this(calendar.get(Calendar.YEAR),
              calendar.get(Calendar.MONTH),
-             calendar.get(Calendar.DAY_OF_MONTH) - 1);
+             calendar.get(Calendar.DAY_OF_MONTH) - 1,
+             calendar.getTimeZone());
     }
 
     /**
@@ -280,7 +316,8 @@ public final class CalendarDate implemen
     public CalendarDate(final LocalDate localDate) {
         this(localDate.getYear(),
              localDate.getMonthValue() - 1,
-             localDate.getDayOfMonth() - 1);
+             localDate.getDayOfMonth() - 1,
+             null);
     }
 
     /**
@@ -294,6 +331,22 @@ public final class CalendarDate implemen
      * @see #MAX_CALENDAR_YEAR
      */
     public CalendarDate(final int year, final int month, final int day) {
+        this(year, month, day, null);
+    }
+
+    /**
+     * Creates a new <tt>CalendarDate</tt> representing the specified year,
+     * month, day of month, and timezone.
+     *
+     * @param year The year field. (e.g. <tt>2008</tt>)
+     * @param month The month field, 0-based. (e.g. <tt>2</tt> for March)
+     * @param day The day of the month, 0-based. (e.g. <tt>14</tt> for the 15th)
+     * @param timeZone The timezone to assume for conversions and differences (if
+     * <tt>null</tt> then the default TimeZone will be used).
+     * @see #MIN_CALENDAR_YEAR
+     * @see #MAX_CALENDAR_YEAR
+     */
+    public CalendarDate(final int year, final int month, final int day, final TimeZone timeZone) {
         if (year < MIN_CALENDAR_YEAR || year > MAX_CALENDAR_YEAR) {
             throw new IllegalArgumentException("Invalid year: " + year);
         }
@@ -315,6 +368,27 @@ public final class CalendarDate implemen
         this.year = year;
         this.month = month;
         this.day = day;
+
+        // Can be null to use the default
+        this.timeZone = timeZone;
+    }
+
+    /**
+     * This is used to get a new instance from the given calendar value
+     * EXCEPT that we use the existing time zone value instead of the
+     * calendar one so that we will remain in the same zone for future
+     * conversions.
+     *
+     * @param newCalendar A Gregorian calendar value adjusted from
+     * our current values.
+     * @return The new instance with the calendar values and our
+     * existing (probably null) time zone value.
+     */
+    private CalendarDate newDate(final GregorianCalendar newCalendar) {
+        return new CalendarDate(newCalendar.get(Calendar.YEAR),
+                                newCalendar.get(Calendar.MONTH),
+                                newCalendar.get(Calendar.DAY_OF_MONTH) - 1,
+                                this.timeZone);
     }
 
     /**
@@ -322,8 +396,8 @@ public final class CalendarDate implemen
      * resulting calendar date. The number of days may be negative, in which
      * case the result will be a date before this calendar date. <p> More
      * formally, it is defined that given calendar dates <tt>c1</tt> and
-     * <tt>c2</tt>, the following will return <tt>true</tt>: <pre>
-     * c1.add(c2.subtract(c1)).equals(c2); </pre>
+     * <tt>c2</tt>, the following will return <tt>true</tt>:
+     * <pre> c1.add(c2.subtract(c1)).equals(c2); </pre>
      *
      * @param days The number of days to add to (or subtract from if negative)
      * this calendar date.
@@ -332,7 +406,7 @@ public final class CalendarDate implemen
     public CalendarDate add(final int days) {
         GregorianCalendar calendar = toCalendar();
         calendar.add(Calendar.DAY_OF_YEAR, days);
-        return new CalendarDate(calendar);
+        return newDate(calendar);
     }
 
     /**
@@ -340,8 +414,8 @@ public final class CalendarDate implemen
      * resulting calendar date. The number of months may be negative, in which
      * case the result will be a date before this calendar date. <p> More
      * formally, it is defined that given calendar dates <tt>c1</tt> and
-     * <tt>c2</tt>, the following will return <tt>true</tt>: <pre>
-     * c1.add(c2.subtract(c1)).equals(c2); </pre>
+     * <tt>c2</tt>, the following will return <tt>true</tt>:
+     * <pre> c1.add(c2.subtract(c1)).equals(c2); </pre>
      *
      * @param months The number of months to add to (or subtract from if negative)
      * this calendar date.
@@ -350,7 +424,7 @@ public final class CalendarDate implemen
     public CalendarDate addMonths(final int months) {
         GregorianCalendar calendar = toCalendar();
         calendar.add(Calendar.MONTH, months);
-        return new CalendarDate(calendar);
+        return newDate(calendar);
     }
 
     /**
@@ -358,8 +432,8 @@ public final class CalendarDate implemen
      * resulting calendar date. The number of years may be negative, in which
      * case the result will be a date before this calendar date. <p> More
      * formally, it is defined that given calendar dates <tt>c1</tt> and
-     * <tt>c2</tt>, the following will return <tt>true</tt>: <pre>
-     * c1.add(c2.subtract(c1)).equals(c2); </pre>
+     * <tt>c2</tt>, the following will return <tt>true</tt>:
+     * <pre> c1.add(c2.subtract(c1)).equals(c2); </pre>
      *
      * @param years The number of years to add to (or subtract from if negative)
      * this calendar date.
@@ -368,7 +442,7 @@ public final class CalendarDate implemen
     public CalendarDate addYears(final int years) {
         GregorianCalendar calendar = toCalendar();
         calendar.add(Calendar.YEAR, years);
-        return new CalendarDate(calendar);
+        return newDate(calendar);
     }
 
     /**
@@ -377,12 +451,12 @@ public final class CalendarDate implemen
      * calendar date, the difference will be positive. If this calendar date
      * represents a day before the specified calendar date, the difference will
      * be negative. If the two calendar dates represent the same day, the
-     * difference will be zero. <p> More formally, it is defined that given
-     * calendar dates <tt>c1</tt> and <tt>c2</tt>, the following will return
-     * <tt>true</tt>: <pre> c1.add(c2.subtract(c1)).equals(c2); </pre>
+     * difference will be zero.
+     * <p> More formally, it is defined that given calendar dates <tt>c1</tt>
+     * and <tt>c2</tt>, the following will return <tt>true</tt>:
+     * <pre> c1.add(c2.subtract(c1)).equals(c2); </pre>
      *
-     * @param calendarDate The calendar date to subtract from this calendar
-     * date.
+     * @param calendarDate The calendar date to subtract from this calendar date.
      * @return The number of days in between this calendar date and
      * <tt>calendarDate</tt>.
      */
@@ -393,25 +467,25 @@ public final class CalendarDate implemen
         long t1 = c1.getTimeInMillis();
         long t2 = c2.getTimeInMillis();
 
-        return (int) ((t1 - t2) / (1000L * 60 * 60 * 24));
+        return (int) ((t1 - t2) / MILLIS_PER_DAY);
     }
 
     /**
      * Translates this calendar date to an instance of
      * <tt>GregorianCalendar</tt>, with the <tt>year</tt>, <tt>month</tt>, and
-     * <tt>dayOfMonth</tt> fields set in the default time zone with the default
-     * locale.
+     * <tt>dayOfMonth</tt> fields set in the time zone set at construction with
+     * the default locale.
      *
      * @return This calendar date as a <tt>GregorianCalendar</tt>.
      */
     public GregorianCalendar toCalendar() {
-        return toCalendar(new Time(0, 0, 0));
+        return toCalendar(MIDNIGHT_TIME);
     }
 
     /**
-     * Translates this calendar date to an instance of
+     * Translates this calendar date along with the given time of day to an instance of
      * <tt>GregorianCalendar</tt>, with the <tt>year</tt>, <tt>month</tt>, and
-     * <tt>dayOfMonth</tt> fields set in the default time zone with the default
+     * <tt>dayOfMonth</tt> fields set in the time zone set at construction with the default
      * locale.
      *
      * @param time The time of day.
@@ -421,6 +495,9 @@ public final class CalendarDate implemen
         GregorianCalendar calendar = new GregorianCalendar(this.year, this.month, this.day + 1,
             time.hour, time.minute, time.second);
         calendar.set(Calendar.MILLISECOND, time.millisecond);
+        if (timeZone != null) {
+            calendar.setTimeZone(timeZone);
+        }
 
         return calendar;
     }

Modified: pivot/trunk/core/test/org/apache/pivot/util/test/CalendarDateTest.java
URL: http://svn.apache.org/viewvc/pivot/trunk/core/test/org/apache/pivot/util/test/CalendarDateTest.java?rev=1870930&r1=1870929&r2=1870930&view=diff
==============================================================================
--- pivot/trunk/core/test/org/apache/pivot/util/test/CalendarDateTest.java (original)
+++ pivot/trunk/core/test/org/apache/pivot/util/test/CalendarDateTest.java Fri Dec  6 20:16:31 2019
@@ -18,6 +18,7 @@ package org.apache.pivot.util.test;
 
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.util.TimeZone;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -32,6 +33,9 @@ public class CalendarDateTest {
     private static final String D1 = "1941-12-07";
     private static final String D2 = "1929-10-29";
     private static final String D3 = "2008-09-29";
+    private static final String D4 = "1945-08-14";
+    private static final String D5 = "2019-12-06";
+    private static final int DAYS_FROM_D1_TO_D5 = 28_488;
 
     @Test
     public void test1() {
@@ -79,4 +83,46 @@ public class CalendarDateTest {
 
         assertEquals(dt1, dt1a);
     }
+
+    @Test
+    public void test3() {
+        // Testing new stuff in CalendarDate that tries to deal with time zones
+        // more effectively
+        TimeZone gmtZone = CalendarDate.TIMEZONE_GMT;
+        TimeZone pstZone = TimeZone.getTimeZone("America/Los_Angeles");
+        CalendarDate d1 = new CalendarDate(1941, 11, 6, gmtZone);
+        CalendarDate d2 = new CalendarDate(1941, 11, 6, pstZone);
+        CalendarDate d3 = new CalendarDate(1945, 7, 13, gmtZone);
+        CalendarDate d4 = d1.add(1346);
+        CalendarDate d5 = d2.add(1346);
+
+        // First we should establish that dates don't depend on timezone for equality
+        // nor do their string representations
+        assertTrue(d1.equals(d2));
+        assertEquals(d1.toString(), d2.toString());
+
+        // Now, establish whether (or not) timezones might make a difference in durations
+        assertEquals(d3.subtract(d1), 1346);
+        // Surprise! they do!
+        assertEquals(d3.subtract(d2), 1345);
+        assertEquals(d4, d5);
+    }
+
+    @Test
+    public void test4() {
+        // Now let's test some of the other duration-related methods
+        CalendarDate d1 = CalendarDate.decode(D1);
+        CalendarDate d2 = d1.addMonths(44).add(7);
+        CalendarDate d3 = d1.addYears(3).addMonths(8).add(7);
+        CalendarDate d4 = CalendarDate.decode(D4);
+        CalendarDate d5 = CalendarDate.decode(D5);
+
+        assertEquals(d2, d3);
+        assertEquals(d2, d4);
+        assertEquals(d3, d4);
+
+        assertEquals(d5.subtract(d1), DAYS_FROM_D1_TO_D5);
+        assertEquals(d1.add(DAYS_FROM_D1_TO_D5), d5);
+        assertEquals(d1.add(DAYS_FROM_D1_TO_D5).add(-DAYS_FROM_D1_TO_D5), d1);
+    }
 }

Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/content/CalendarDateSpinnerData.java
URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/content/CalendarDateSpinnerData.java?rev=1870930&r1=1870929&r2=1870930&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/content/CalendarDateSpinnerData.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/content/CalendarDateSpinnerData.java Fri Dec  6 20:16:31 2019
@@ -16,16 +16,14 @@
  */
 package org.apache.pivot.wtk.content;
 
-import java.util.Calendar;
 import java.util.Comparator;
-import java.util.GregorianCalendar;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
-import java.util.TimeZone;
 
+import org.apache.pivot.annotations.UnsupportedOperation;
 import org.apache.pivot.collections.List;
 import org.apache.pivot.collections.ListListener;
-import org.apache.pivot.collections.Sequence;
+import org.apache.pivot.collections.ReadOnlySequence;
 import org.apache.pivot.util.CalendarDate;
 import org.apache.pivot.util.ListenerList;
 import org.apache.pivot.util.Utils;
@@ -36,7 +34,9 @@ import org.apache.pivot.util.Utils;
  * calendar instance from which <tt>CalendarDate</tt> instances are created on
  * demand.
  */
-public class CalendarDateSpinnerData implements List<CalendarDate> {
+public class CalendarDateSpinnerData extends ReadOnlySequence<CalendarDate> implements List<CalendarDate> {
+    private static final long serialVersionUID = 8422963466022375674L;
+
     /**
      * Iterator that simply wraps calls to the list. Since the internal list
      * data is spoofed, each accessor runs in constant time, so there's no
@@ -60,19 +60,22 @@ public class CalendarDateSpinnerData imp
             return get(index++);
         }
 
+        @UnsupportedOperation
         @Override
         public void remove() {
-            throw new UnsupportedOperationException();
+            throw new UnsupportedOperationException(unsupportedOperationMsg);
         }
     }
 
-    private GregorianCalendar calendar;
+    /** The current date of this set of data (offset by {@link #calendarIndex} from the base date of the range). */
+    private CalendarDate currentDate;
+    /** The current offset from the base date. */
     private int calendarIndex;
 
     // Calculated during construction
     private transient int length;
 
-    private ListListenerList<CalendarDate> listListeners = new ListListenerList<>();
+    private transient ListListenerList<CalendarDate> listListeners = new ListListenerList<>();
 
     /**
      * Creates a new <tt>CalendarDateSpinnerData</tt> bounded from
@@ -89,7 +92,7 @@ public class CalendarDateSpinnerData imp
      * @param lowerBound The earliest date to include in this spinner data.
      * @param upperBound The latest date to include in this spinner data.
      */
-    public CalendarDateSpinnerData(CalendarDate lowerBound, CalendarDate upperBound) {
+    public CalendarDateSpinnerData(final CalendarDate lowerBound, final CalendarDate upperBound) {
         Utils.checkNull(lowerBound, "lowerBound");
         Utils.checkNull(upperBound, "upperBound");
 
@@ -97,59 +100,11 @@ public class CalendarDateSpinnerData imp
             throw new IllegalArgumentException("lowerBound is after upperBound.");
         }
 
-        calendar = new GregorianCalendar(lowerBound.year, lowerBound.month, lowerBound.day + 1);
-        calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
+        currentDate = lowerBound;
         calendarIndex = 0;
 
-        // Calculate our length and cache it, since it is guaranteed to
-        // remain fixed
-        GregorianCalendar upperBoundCalendar = new GregorianCalendar(upperBound.year,
-            upperBound.month, upperBound.day + 1);
-        upperBoundCalendar.setTimeZone(TimeZone.getTimeZone("GMT"));
-        long lowerBoundMilliseconds = calendar.getTimeInMillis();
-        long upperBoundMilliseconds = upperBoundCalendar.getTimeInMillis();
-        long indexDiff = (upperBoundMilliseconds - lowerBoundMilliseconds) / (1000L * 60 * 60 * 24);
-        length = (int) indexDiff + 1;
-    }
-
-    /**
-     * Throws <tt>UnsupportedOperationException</tt>.
-     */
-    @Override
-    public int add(CalendarDate item) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Throws <tt>UnsupportedOperationException</tt>.
-     */
-    @Override
-    public void insert(CalendarDate item, int index) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Throws <tt>UnsupportedOperationException</tt>.
-     */
-    @Override
-    public CalendarDate update(int index, CalendarDate item) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Throws <tt>UnsupportedOperationException</tt>.
-     */
-    @Override
-    public int remove(CalendarDate item) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Throws <tt>UnsupportedOperationException</tt>.
-     */
-    @Override
-    public Sequence<CalendarDate> remove(int index, int count) {
-        throw new UnsupportedOperationException();
+        // Calculate our length and cache it, since it is guaranteed to remain fixed
+        length = upperBound.subtract(lowerBound) + 1;
     }
 
     /**
@@ -158,33 +113,22 @@ public class CalendarDateSpinnerData imp
      * @param index The index of the calendar date to retrieve.
      */
     @Override
-    public CalendarDate get(int index) {
+    public final CalendarDate get(final int index) {
         if (index < 0 || index >= length) {
             throw new IndexOutOfBoundsException("Index out of bounds: " + index);
         }
 
         // Move the calendar's fields to match the specified index
-        calendar.add(Calendar.DAY_OF_YEAR, index - calendarIndex);
+        currentDate = currentDate.add(index - calendarIndex);
         calendarIndex = index;
 
-        // Calculate the desired fields
-        int year = calendar.get(Calendar.YEAR);
-        int month = calendar.get(Calendar.MONTH);
-        int day = calendar.get(Calendar.DAY_OF_MONTH) - 1;
-
-        return new CalendarDate(year, month, day);
+        return currentDate;
     }
 
     @Override
-    public int indexOf(CalendarDate item) {
-        long currentMilliseconds = calendar.getTimeInMillis();
-
-        GregorianCalendar tmpCalendar = new GregorianCalendar(item.year, item.month, item.day + 1);
-        tmpCalendar.setTimeZone(TimeZone.getTimeZone("GMT"));
-        long itemMilliseconds = tmpCalendar.getTimeInMillis();
-
-        long indexDiff = (itemMilliseconds - currentMilliseconds) / (1000L * 60 * 60 * 24);
-        int index = calendarIndex + (int) indexDiff;
+    public final int indexOf(final CalendarDate item) {
+        int indexDiffDays = item.subtract(this.currentDate);
+        int index = calendarIndex + indexDiffDays;
 
         return (index < 0 || index >= length) ? -1 : index;
     }
@@ -192,13 +136,14 @@ public class CalendarDateSpinnerData imp
     /**
      * Throws <tt>UnsupportedOperationException</tt>.
      */
+    @UnsupportedOperation
     @Override
     public void clear() {
-        throw new UnsupportedOperationException();
+        throw new UnsupportedOperationException(unsupportedOperationMsg);
     }
 
     @Override
-    public boolean isEmpty() {
+    public final boolean isEmpty() {
         return (length == 0);
     }
 
@@ -214,8 +159,8 @@ public class CalendarDateSpinnerData imp
 
     /**
      * Gets the comparator for this list, which is guaranteed to always be
-     * <tt>null</tt>. This class does not support comparators since there's no
-     * real data to sort (it's all spoofed).
+     * <tt>null</tt>. The generated data is inherently in date order, thus
+     * sorting doesn't make sense.
      */
     @Override
     public Comparator<CalendarDate> getComparator() {
@@ -223,20 +168,22 @@ public class CalendarDateSpinnerData imp
     }
 
     /**
-     * Throws <tt>UnsupportedOperationException</tt>.
+     * Throws {@link UnsupportedOperationException} because the generated data
+     * is inherently in date order, thus sorting makes no sense.
      */
+    @UnsupportedOperation
     @Override
-    public void setComparator(Comparator<CalendarDate> comparator) {
-        throw new UnsupportedOperationException();
+    public final void setComparator(final Comparator<CalendarDate> comparator) {
+        throw new UnsupportedOperationException(unsupportedOperationMsg);
     }
 
     @Override
-    public Iterator<CalendarDate> iterator() {
+    public final Iterator<CalendarDate> iterator() {
         return new DataIterator();
     }
 
     @Override
-    public ListenerList<ListListener<CalendarDate>> getListListeners() {
+    public final ListenerList<ListListener<CalendarDate>> getListListeners() {
         return listListeners;
     }
 }