[california/wip/calendar-spans: 9/13] Cleaned up Calendar class heirarchy



commit 15aa1d21907303682a0047a81fc48a444c91d08f
Author: Jim Nelson <jim yorba org>
Date:   Thu May 8 20:25:19 2014 -0700

    Cleaned up Calendar class heirarchy
    
    A cleaner inheritance tree: Span at the bottom for all date-
    oriented classes, DiscreteUnit for well-recognized units,
    UnitSpan for groupings of those units, both Spans.  Less reliance
    on interfaces.

 src/Makefile.am                          |    2 +
 src/calendar/calendar-date-span.vala     |  154 +++------------------------
 src/calendar/calendar-date.vala          |  126 +++++------------------
 src/calendar/calendar-discrete-unit.vala |  112 ++++++++++++++++++++
 src/calendar/calendar-month-of-year.vala |   26 +++--
 src/calendar/calendar-month-span.vala    |   78 ++++----------
 src/calendar/calendar-span.vala          |  167 ++++++++++++++++++++++++------
 src/calendar/calendar-unit-span.vala     |   57 ++++++++++
 src/calendar/calendar-unit.vala          |   98 +-----------------
 src/calendar/calendar-week-span.vala     |   85 ++++++----------
 src/calendar/calendar-week.vala          |   26 +++--
 src/calendar/calendar-year.vala          |   30 +++++-
 src/tests/tests-calendar-date.vala       |    8 +-
 src/tests/tests-calendar-month-span.vala |   16 ++--
 src/view/month/month-cell.vala           |    2 +-
 src/view/month/month-controller.vala     |    4 +-
 src/view/month/month-grid.vala           |    2 +-
 17 files changed, 483 insertions(+), 510 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 62dcd01..1cc3f22 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -52,6 +52,7 @@ california_VALASOURCES = \
        calendar/calendar-day-of-week.vala \
        calendar/calendar-date.vala \
        calendar/calendar-dbus.vala \
+       calendar/calendar-discrete-unit.vala \
        calendar/calendar-duration.vala \
        calendar/calendar-error.vala \
        calendar/calendar-exact-time.vala \
@@ -65,6 +66,7 @@ california_VALASOURCES = \
        calendar/calendar-system.vala \
        calendar/calendar-timezone.vala \
        calendar/calendar-unit.vala \
+       calendar/calendar-unit-span.vala \
        calendar/calendar-wall-time.vala \
        calendar/calendar-week.vala \
        calendar/calendar-week-span.vala \
diff --git a/src/calendar/calendar-date-span.vala b/src/calendar/calendar-date-span.vala
index 3725fa6..df1d8b0 100644
--- a/src/calendar/calendar-date-span.vala
+++ b/src/calendar/calendar-date-span.vala
@@ -7,152 +7,47 @@
 namespace California.Calendar {
 
 /**
- * Represents an immutable span of consecutive { link Date}s.
+ * Represents an immutable arbitrary span of consecutive { link Date}s.
  *
- * A DateSpan may be naturally iterated over its { link Date}s.  It also provides iterators for
- * { link Week}s.
+ * Although DateSpan is technically a { link UnitSpan} of Dates, it's such a fundamental way of
+ * representing any unit of dates that { link Span} offers a conversion method.  Thus, a
+ * { link Week} is a { link DiscreteUnit} but it can easily be converted into a { link DateSpan}.
+ * The only reason Week does not inherit from DateSpan -- indeed, all units of calendar time don't
+ * inherit from DateSpan -- is to avoid inheritance problems and circularities.  (Another way to
+ * look at things is that Span is a lightweight DateSpan.)
  */
 
-public class DateSpan : BaseObject, Collection.SimpleIterable<Date>, Span<Date>, Gee.Comparable<DateSpan>,
+public class DateSpan : UnitSpan<Date>, Collection.SimpleIterable<Date>, Gee.Comparable<DateSpan>,
     Gee.Hashable<DateSpan> {
-    private class DateSpanIterator : BaseObject, Collection.SimpleIterator<Date> {
-        public Date first;
-        public Date last;
-        public Date? current = null;
-        
-        public DateSpanIterator(DateSpan owner) {
-            first = owner.start_date;
-            last = owner.end_date;
-        }
-        
-        public new Date get() {
-            return current;
-        }
-        
-        public bool next() {
-            if (current == null)
-                current = first;
-            else if (current.compare_to(last) < 0)
-                current = current.next();
-            else
-                return false;
-            
-            return true;
-        }
-        
-        public override string to_string() {
-            return "DateSpanIterator %s::%s".printf(first.to_string(), last.to_string());
-        }
-    }
-    
-    /**
-     * @inheritDoc
-     */
-    private Date _start_date;
-    public Date start_date { owned get { return _start_date; } }
-    
-    /**
-     * @inheritDoc
-     */
-    private Date _end_date;
-    public Date end_date { owned get { return _end_date; } }
-    
-    /**
-     * Convenience property indicating if the { link DateSpan} spans only one day.
-     */
-    public bool is_same_day { get { return start_date.equal_to(end_date); } }
-    
-    /**
-     * Returns the { link Duration} this { link DateSpan} represents.
-     */
-    public Duration duration { owned get { return new Duration(end_date.difference(start_date)); } }
-    
     /**
      * Create a { link DateSpan} with the specified start and end dates.
-     *
-     * DateSpan will arrange the two dates so start_date is chronologically earlier (or the same
-     * as) the end_date.
      */
     public DateSpan(Date start_date, Date end_date) {
-        init_span(start_date, end_date);
+        base (start_date, end_date, start_date, end_date);
     }
     
     /**
      * Create a { link DateSpan} from the { link ExactTimeSpan}.
      */
     public DateSpan.from_exact_time_span(ExactTimeSpan exact_time_span) {
-        init_span(new Date.from_exact_time(exact_time_span.start_exact_time),
-            new Date.from_exact_time(exact_time_span.end_exact_time));
-    }
-    
-    /**
-     * Create an unintialized { link DateSpan).
-     *
-     * Because it's sometimes inconvenient to generate the necessary { link Date}s until the
-     * subclass's constructor completes, DateSpan allows for itself to be created empty assuming
-     * that the subclass will call { link init_span} as soon as it's finished initializing.
-     *
-     * init_span() must be called.  DateSpan will not function properly when uninitialized.
-     */
-    protected DateSpan.uninitialized() {
-    }
-    
-    /**
-     * Initialize the { link DateSpan} with s start and end date.
-     *
-     * DateSpan will sort the start and end to ensure that start is chronologically prior
-     * to end.
-     */
-    protected void init_span(Date start_date, Date end_date) {
-        if (start_date.compare_to(end_date) <= 0) {
-            _start_date = start_date;
-            _end_date = end_date;
-        } else {
-            _start_date = end_date;
-            _end_date = start_date;
-        }
-    }
-    
-    /**
-     * @inheritDoc
-     */
-    public Date start() {
-        return _start_date;
-    }
-    
-    /**
-     * @inheritDoc
-     */
-    public Date end() {
-        return _end_date;
-    }
-    
-    /**
-     * @inheritDoc
-     */
-    public bool contains(Date date) {
-        return (start_date.compare_to(date) <= 0) && (end_date.compare_to(date) >= 0);
+        Date start_date = new Date.from_exact_time(exact_time_span.start_exact_time);
+        Date end_date = new Date.from_exact_time(exact_time_span.end_exact_time);
+        
+        base(start_date, end_date, start_date, end_date);
     }
     
     /**
      * @inheritDoc
      */
-    public bool has(Date date) {
-        return contains(date);
+    public override bool contains(Date date) {
+        return has_date(date);
     }
     
     /**
      * Returns an Iterator for all { link Date}s in the { link DateSpan}.
      */
-    public Collection.SimpleIterator<Date> iterator() {
-        return new DateSpanIterator(this);
-    }
-    
-    /**
-     * Returns a { link WeekSpan} for each { link Week} (full and partial) in the { link DateSpan}.
-     */
-    public WeekSpan weeks(FirstOfWeek first_of_week) {
-        return new WeekSpan(this, first_of_week);
+    public override Collection.SimpleIterator<Date> iterator() {
+        return date_iterator();
     }
     
     /**
@@ -186,21 +81,6 @@ public class DateSpan : BaseObject, Collection.SimpleIterable<Date>, Span<Date>,
     }
     
     /**
-     * Returns a { link DateSpan} with starting and ending points within the boundary specified
-     * (inclusive).
-     *
-     * If this DateSpan is within the clamped dates, this object may be returned.
-     *
-     * This method will not expand a DateSpan to meet the clamp range.
-     */
-    public DateSpan clamp(DateSpan span) {
-        Date new_start = (start_date.compare_to(span.start_date) < 0) ? span.start_date : start_date;
-        Date new_end = (end_date.compare_to(span.end_date) > 0) ? span.end_date : end_date;
-        
-        return new DateSpan(new_start, new_end);
-    }
-    
-    /**
      * Compares two { link DateSpan}s by their { link start_date}.
      */
     public int compare_to(DateSpan other) {
diff --git a/src/calendar/calendar-date.vala b/src/calendar/calendar-date.vala
index 96e8219..4291b99 100644
--- a/src/calendar/calendar-date.vala
+++ b/src/calendar/calendar-date.vala
@@ -13,15 +13,19 @@ namespace California.Calendar {
  * this class is immutable.  This means this object is incapable of representing a DMY prior to
  * Year 1 (BCE).
  *
- * GLib.Date has many powerful features for representing a calenday day, but it's interface is
+ * GLib.Date has many powerful features for representing a calendar day, but it's interface is
  * inconvenient when working in Vala.  It can also exist in an uninitialized and an invalid
  * state.  It's desired to avoid both of those.  It is also not an Object, has no signals or
  * properties, doesn't work well with Gee, and is mutable.  This class attempts to solve these
  * issues.
  */
 
-public class Date : BaseObject, Collection.SimpleIterable<Date>, Span<Date>, DiscreteUnit<Date>,
-    Gee.Comparable<Date>, Gee.Hashable<Date> {
+public class Date : DiscreteUnit<Date>, Gee.Comparable<Date>, Gee.Hashable<Date> {
+    public const string PROP_DAY_OF_WEEK = "day-of-week";
+    public const string PROP_DAY_OF_MONTH = "day-of-month";
+    public const string PROP_MONTH = "month";
+    public const string PROP_YEAR = "year";
+    
     /**
      * Options for { link to_pretty_string}.
      */
@@ -43,51 +47,25 @@ public class Date : BaseObject, Collection.SimpleIterable<Date>, Span<Date>, Dis
         NO_TODAY
     }
     
-    private class DateIterator : BaseObject, Collection.SimpleIterator<Date> {
-        private Date date;
-        
-        public DateIterator(Date date) {
-            this.date = date;
-        }
-        
-        /**
-         * @inheritDoc
-         */
-        public bool next() {
-            return false;
-        }
-        
-        /**
-         * @inheritDoc
-         */
-        public new Date get() {
-            return date;
-        }
-        
-        public override string to_string() {
-            return "DateIterator:%s".printf(date.to_string());
-        }
-    }
-    
-    public DayOfWeek day_of_week { get; private set; }
-    public DayOfMonth day_of_month { get; private set; }
-    public Month month { get; private set; }
-    public Year year { get; private set; }
     
     /**
      * @inheritDoc
+     *
+     * Overridden to prevent a reference cycle in { link Span.start_date}.
      */
-    public DateUnit date_unit { get { return DateUnit.DAY; } }
+    public override Date start_date { get { return this; } }
     
     /**
      * @inheritDoc
+     *
+     * Overridden to prevent a reference cycle in { link Span.end_date}.
      */
-    public Date start_date { owned get { return this; } }
+    public override Date end_date { get { return this; } }
     
-    /**
-     * @inheritDoc
-     */
-    public Date end_date { owned get { return this; } }
+    public DayOfWeek day_of_week { get; private set; }
+    public DayOfMonth day_of_month { get; private set; }
+    public Month month { get; private set; }
+    public Year year { get; private set; }
     
     private GLib.Date gdate;
     
@@ -97,6 +75,8 @@ public class Date : BaseObject, Collection.SimpleIterable<Date>, Span<Date>, Dis
      * @throws CalendarError if an invalid calendar day
      */
     public Date(DayOfMonth day_of_month, Month month, Year year) throws CalendarError {
+        base.uninitialized(DateUnit.DAY);
+        
         gdate.set_dmy(day_of_month.to_date_day(), month.to_date_month(), year.to_date_year());
         if (!gdate.valid()) {
             throw new CalendarError.INVALID("Invalid day/month/year %s/%s/%s", day_of_month.to_string(),
@@ -113,6 +93,8 @@ public class Date : BaseObject, Collection.SimpleIterable<Date>, Span<Date>, Dis
      * Creates a { link Date} for the { link ExactTime}.
      */
     public Date.from_exact_time(ExactTime exact_time) {
+        base.uninitialized(DateUnit.DAY);
+        
         // Can use for_checked() methods because ExactTime can only be created with proper values
         day_of_month = exact_time.day_of_month;
         month = exact_time.month;
@@ -132,6 +114,8 @@ public class Date : BaseObject, Collection.SimpleIterable<Date>, Span<Date>, Dis
     }
     
     internal Date.from_gdate(GLib.Date gdate) {
+        base.uninitialized(DateUnit.DAY);
+        
         assert(gdate.valid());
         
         this.gdate = gdate;
@@ -143,34 +127,6 @@ public class Date : BaseObject, Collection.SimpleIterable<Date>, Span<Date>, Dis
     }
     
     /**
-     * @inheritDoc
-     */
-    public Date start() {
-        return this;
-    }
-    
-    /**
-     * @inheritDoc
-     */
-    public Date end() {
-        return this;
-    }
-    
-    /**
-     * @inheritDoc
-     */
-    public bool contains(Date date) {
-        return equal_to(date);
-    }
-    
-    /**
-     * @inheritDoc
-     */
-    public bool has(Date date) {
-        return equal_to(date);
-    }
-    
-    /**
      * Returns the { link Week} the { link Date} falls in.
      */
     public Week week_of(FirstOfWeek first) {
@@ -235,30 +191,9 @@ public class Date : BaseObject, Collection.SimpleIterable<Date>, Span<Date>, Dis
     }
     
     /**
-     * Returns the { link Date} as the earliest ExactTime possible for the specified { link Timezone}.
-     *
-     * @see latest_exact_time
-     */
-    public ExactTime earliest_exact_time(Timezone tz) {
-        return new ExactTime(tz, this, WallTime.earliest);
-    }
-    
-    /**
-     * Returns the { link Date} as the latest { link ExactTime} possible for the specified
-     * { link Timezone}.
-     *
-     * By latest, the precision of ExactTime.seconds will be 59.0.
-     *
-     * @see earliest_exact_time
-     */
-    public ExactTime latest_exact_time(Timezone tz) {
-        return new ExactTime(tz, this, WallTime.latest);
-    }
-    
-    /**
      * @inheritDoc
      */
-    public Date adjust(int quantity) {
+    public override Date adjust(int quantity) {
         return adjust_by(quantity, DateUnit.DAY);
     }
     
@@ -309,19 +244,10 @@ public class Date : BaseObject, Collection.SimpleIterable<Date>, Span<Date>, Dis
     }
     
     /**
-     * Returns the difference (in days) between this { link Date} and another Date.
-     *
-     * If the supplied Date is earlier than this one, a negative value will be returned.
-     */
-    public int difference(Date other) {
-        return (this != other) ? gdate.days_between(other.gdate) : 0;
-    }
-    
-    /**
      * @inheritDoc
      */
-    public Collection.SimpleIterator<Date> iterator() {
-        return new DateIterator(this);
+    public override int difference(Date other) {
+        return (this != other) ? gdate.days_between(other.gdate) : 0;
     }
     
     /**
diff --git a/src/calendar/calendar-discrete-unit.vala b/src/calendar/calendar-discrete-unit.vala
new file mode 100644
index 0000000..3bbac26
--- /dev/null
+++ b/src/calendar/calendar-discrete-unit.vala
@@ -0,0 +1,112 @@
+/* Copyright 2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later).  See the COPYING file in this distribution.
+ */
+
+namespace California.Calendar {
+
+/**
+ * An immutable, discrete, well-recognized unit of calendar dates.
+ *
+ * This interface indicates the { link Calendar.Span} represents a discrete unit of time (each of
+ * which may not contain the same number of days, such as { link Year}s, while some might, such as
+ * { link Week}s), in contrast to a { link DateSpan}, which represents an ''arbitrary''
+ * span of dates that may or may not correspond to a well-recognized unit of dates.
+ *
+ * Note that this different than a { link UnitSpan} such as { link MonthSpan} which is designed to
+ * hold an arbitrary consecutive number of their date units (i.e. a span of months).  DiscreteUnit
+ * represents a single unit of time (a week or a month).
+ *
+ * If Vala supported constrained generics, a UnitSpan would be defined as requiring a generic type
+ * of DiscreteUnit.
+ *
+ * DiscreteUnit is not designed to work with discrete { link ExactTime} or { link WallTime} units.
+ *
+ * @see Date
+ * @see Week
+ * @see MonthOfYear
+ * @see Year
+ */
+
+public abstract class DiscreteUnit<G> : Span, Collection.SimpleIterable<Date> {
+    public const string PROP_DATE_UNIT = "date-unit";
+    
+    /**
+     * Returns the { link DateUnit} this { link DiscreteUnit} represents.
+     */
+    public DateUnit date_unit { get; private set; }
+    
+    protected DiscreteUnit(DateUnit date_unit, Date start_date, Date end_date) {
+        base (start_date, end_date);
+        
+        this.date_unit = date_unit;
+    }
+    
+    /**
+     * This is specifically for { link Date}, which can't pass itself down to { link Span} as that
+     * will create a reference cycle, or for child classes which need to do more work before
+     * providing a date span.
+     *
+     * If the latter, the child class should call { link init_span} to complete initialization.
+     */
+    protected DiscreteUnit.uninitialized(DateUnit date_unit) {
+        base.uninitialized();
+        
+        this.date_unit = date_unit;
+    }
+    
+    /**
+     * The next chronological discrete unit of time.
+     */
+    public G next() {
+        return adjust(1);
+    }
+    
+    /**
+     * The previous chronological discrete unit of time.
+     */
+    public G previous() {
+        return adjust(-1);
+    }
+    
+    /**
+     * Returns the same type of { link DiscreteUnit} adjusted a quantity of units from this one.
+     *
+     * Subtraction (adjusting to a past date) is acheived by using a negative quantity.
+     */
+    public abstract G adjust(int quantity);
+    
+    /**
+     * Returns the number of { link DiscreteUnit}s between the two.
+     *
+     * If the supplied DiscreteUnit is earlier than this one, a negative value is returned.
+     */
+    public abstract int difference(G other);
+    
+    /**
+     * True if the { link DiscreteUnit} contains the specified { link Date}.
+     *
+     * This is named to conform to Vala's rule for automatic syntax support.  This allows for the
+     * ''in'' operator to function on DiscreteUnits, but only for Dates (which is a common
+     * operation).
+     */
+    public bool contains(Date date) {
+        return has_date(date);
+    }
+    
+    /**
+     * Returns a { link Collection.SimpleIterator} of all the { link Date}s in the
+     * { link DiscreteUnit}'s span of time.
+     *
+     * This is named to conform to Vala's rule for automatic iterator support.  This allows for
+     * the ''foreach'' operator to function on DiscreteUnits, but only for Dates (which is a
+     * common operation).
+     */
+    public Collection.SimpleIterator<Date> iterator() {
+        return date_iterator();
+    }
+}
+
+}
+
diff --git a/src/calendar/calendar-month-of-year.vala b/src/calendar/calendar-month-of-year.vala
index 5d429fd..5110928 100644
--- a/src/calendar/calendar-month-of-year.vala
+++ b/src/calendar/calendar-month-of-year.vala
@@ -10,12 +10,7 @@ namespace California.Calendar {
  * An immutable representation of a { link Month} of a { link Year}.
  */
 
-public class MonthOfYear : DiscreteUnit<MonthOfYear>, DateSpan {
-    /**
-     * @inheritDoc
-     */
-    public DateUnit date_unit { get { return DateUnit.MONTH; } }
-    
+public class MonthOfYear : DiscreteUnit<MonthOfYear>, Gee.Comparable<MonthOfYear>, Gee.Hashable<MonthOfYear> 
{
     /**
      * The { link Month} of the associated { link Year}.
      */
@@ -42,7 +37,7 @@ public class MonthOfYear : DiscreteUnit<MonthOfYear>, DateSpan {
     public string abbrev_name { get; private set; }
     
     public MonthOfYear(Month month, Year year) {
-        base.uninitialized();
+        base.uninitialized(DateUnit.MONTH);
         
         this.month = month;
         this.year = year;
@@ -83,14 +78,14 @@ public class MonthOfYear : DiscreteUnit<MonthOfYear>, DateSpan {
     /**
      * @inheritDoc
      */
-    public MonthOfYear adjust(int quantity) {
+    public override MonthOfYear adjust(int quantity) {
         return start_date.adjust_by(quantity, DateUnit.MONTH).month_of_year();
     }
     
     /**
      * @inheritDoc
      */
-    public int difference(MonthOfYear other) {
+    public override int difference(MonthOfYear other) {
         int compare = compare_to(other);
         if (compare == 0)
             return 0;
@@ -107,6 +102,19 @@ public class MonthOfYear : DiscreteUnit<MonthOfYear>, DateSpan {
         }
     }
     
+    public int compare_to(MonthOfYear other) {
+        return (this != other) ? start_date.compare_to(other.start_date) : 0;
+    }
+    
+    public bool equal_to(MonthOfYear other) {
+        return compare_to(other) == 0;
+    }
+    
+    public uint hash() {
+        // 4 bits for month (1 - 12)
+        return (year.value << 4) | month.value;
+    }
+    
     public override string to_string() {
         return "%s %s".printf(month.to_string(), year.to_string());
     }
diff --git a/src/calendar/calendar-month-span.vala b/src/calendar/calendar-month-span.vala
index 506dbc8..2961878 100644
--- a/src/calendar/calendar-month-span.vala
+++ b/src/calendar/calendar-month-span.vala
@@ -8,13 +8,9 @@ namespace California.Calendar {
 
 /**
  * An immutable representation of a span of { link MonthOfYear}s.
- *
- * This class provides methods that can turn a { link DateSpan} an iteration of MonthOfYear objects.
- * Partial months are included; the caller needs to do their own clamping if they want to avoid
- * days outside of the DateSpan.
  */
 
-public class MonthSpan : BaseObject, Collection.SimpleIterable<MonthOfYear>, Span<MonthOfYear>,
+public class MonthSpan : UnitSpan<MonthOfYear>, Collection.SimpleIterable<MonthOfYear>,
     Gee.Comparable<MonthSpan>, Gee.Hashable<MonthSpan> {
     private class MonthSpanIterator : BaseObject, Collection.SimpleIterator<MonthOfYear> {
         public MonthOfYear first;
@@ -22,8 +18,8 @@ public class MonthSpan : BaseObject, Collection.SimpleIterable<MonthOfYear>, Spa
         public MonthOfYear? current = null;
         
         public MonthSpanIterator(MonthSpan owner) {
-            first = owner.start();
-            last = owner.end();
+            first = owner.first;
+            last = owner.last;
         }
         
         public new MonthOfYear get() {
@@ -47,73 +43,45 @@ public class MonthSpan : BaseObject, Collection.SimpleIterable<MonthOfYear>, Spa
     }
     
     /**
-     * The { link DateSpan} of the { link MonthOfYear}s.
-     */
-    public DateSpan dates { get; private set; }
-    
-    /**
-     * inheritDoc
-     */
-    public Date start_date { owned get { return dates.start_date; } }
-    
-    /**
-     * inheritDoc
-     */
-    public Date end_date { owned get { return dates.end_date; } }
-    
-    /**
-     * Create a span of { link MonthOfYear}s corresponding to the { link DateSpan}.
-     */
-    public MonthSpan(DateSpan dates) {
-        this.dates = dates;
-    }
-    
-    /**
      * Create a span of { link MonthOfYear}s corresponding to the start and end months.
      */
-    public MonthSpan.from_months(MonthOfYear start, MonthOfYear end) {
-        dates = new DateSpan(start.start_date, end.end_date);
-    }
-    
-    /**
-     * Create an arbitrary span of { link MonthOfYear}s starting from the specified starting month.
-     */
-    public MonthSpan.count(MonthOfYear start, int count) {
-        dates = new DateSpan(start.start_date, start.adjust(count).end_date);
-    }
-    
-    /**
-     * inheritDoc
-     */
-    public MonthOfYear start() {
-        return dates.start_date.month_of_year();
+    public MonthSpan(MonthOfYear first, MonthOfYear last) {
+        base (first, last, first.start_date, last.end_date);
     }
     
     /**
-     * inheritDoc
+     * Create a span of { link MonthOfYear}s starting from the specified starting month.
      */
-    public MonthOfYear end() {
-        return dates.end_date.month_of_year();
+    public MonthSpan.count(MonthOfYear first, int count) {
+        MonthOfYear last = first.adjust(count);
+        
+        base (first, last, first.start_date, last.end_date);
     }
     
     /**
-     * @inheritDoc
+     * Create a span of { link MonthOfYear}s from the start and end of a { link Span}.
+     *
+     * The month of the Span's start_date and the month of Span's end_date are used to determine
+     * the MonthSpan.
      */
-    public bool contains(Date date) {
-        return dates.contains(date);
+    public MonthSpan.from_date_span(DateSpan date_span) {
+        MonthOfYear first = date_span.start_date.month_of_year();
+        MonthOfYear last = date_span.end_date.month_of_year();
+        
+        base (first, last, first.start_date, last.end_date);
     }
     
     /**
      * @inheritDoc
      */
-    public bool has(MonthOfYear month) {
-        return (start().compare_to(month) <= 0) && (end().compare_to(month) >= 0);
+    public override bool contains(MonthOfYear month) {
+        return (first.compare_to(month) <= 0) && (last.compare_to(month) >= 0);
     }
     
     /**
      * Returns an Iterator for each { link MonthOfYear} (full and partial) in the { link MonthSpan}.
      */
-    public Collection.SimpleIterator<MonthOfYear> iterator() {
+    public override Collection.SimpleIterator<MonthOfYear> iterator() {
         return new MonthSpanIterator(this);
     }
     
@@ -136,7 +104,7 @@ public class MonthSpan : BaseObject, Collection.SimpleIterable<MonthOfYear>, Spa
     }
     
     public override string to_string() {
-        return "months of %s".printf(dates.to_string());
+        return "months of %s".printf(to_date_span().to_string());
     }
 }
 
diff --git a/src/calendar/calendar-span.vala b/src/calendar/calendar-span.vala
index 2f8b0d3..373ff4f 100644
--- a/src/calendar/calendar-span.vala
+++ b/src/calendar/calendar-span.vala
@@ -7,45 +7,103 @@
 namespace California.Calendar {
 
 /**
- * An immutable generic span or range of consecutive calendar dates.
+ * An immutable span or range of consecutive calendar { link Date}s.
  *
- * The Span is delineated by specific lengths of time (such as { link Date}, { link Week}, or
- * { link Month} and is required to be a { link SimpleIterable}.
+ * Span is not currently designed for { link ExactTime} resolution or to be used as the base
+ * class of { link ExactTimeSpan}.  It's possible this will change in the future.
  *
- * Since the start and end Date of a Span may fall within the larger delineated unit of time,
- * the contract is that partial units will always be returned.  If the caller wants to only deal
- * with full units within this Span, they must check all returned values.
- *
- * Although not specified, it's expected that all Spans will also implement Gee.Comparable and
- * Gee.Hashable.
- *
- * Span is not designed for { link ExactTime} resolution.
- *
- * @see DateSpan
- * @see WeekSpan
- * @see MonthSpan
+ * @see DiscreteUnit
+ * @see UnitSpan
  */
 
-public interface Span<G> : BaseObject, Collection.SimpleIterable<G> {
+public abstract class Span : BaseObject {
+    public const string PROP_START_DATE = "start-date";
+    public const string PROP_END_DATE = "end-date";
+    public const string PROP_IS_SAME_DAY = "is-same-day";
+    public const string PROP_DURATION = "duration";
+    
+    private class SpanIterator : BaseObject, Collection.SimpleIterator<Date> {
+        private Date first;
+        private Date last;
+        private Date? current = null;
+        
+        public SpanIterator(Span span) {
+            first = span.start_date;
+            last = span.end_date;
+        }
+        
+        public new Date get() {
+            return current;
+        }
+        
+        public bool next() {
+            if (current == null)
+                current = first;
+            else if (current.compare_to(last) < 0)
+                current = current.next();
+            else
+                return false;
+            
+            return true;
+        }
+        
+        public override string to_string() {
+            return "SpanIterator %s::%s".printf(first.to_string(), last.to_string());
+        }
+    }
+    
     /**
      * Returns the earliest { link Date} within the { link Span}.
      */
-    public abstract Date start_date { owned get; }
+    private Date? _start_date = null;
+    public virtual Date start_date { get { return _start_date; } }
     
     /**
      * Returns the latest { link Date} within the { link Span}.
      */
-    public abstract Date end_date { owned get; }
+    private Date? _end_date = null;
+    public virtual Date end_date { get { return _end_date; } }
     
     /**
-     * The earliest delinated unit of time within the { link Span}.
+     * Convenience property indicating if the { link Span} spans only one day.
      */
-    public abstract G start();
+    public bool is_same_day { get { return start_date.equal_to(end_date); } }
     
     /**
-     * The latest delineated unit of time within the { link Span}.
+     * Returns the { link Duration} this { link Span} represents.
      */
-    public abstract G end();
+    public Duration duration { owned get { return new Duration(end_date.difference(start_date).abs()); } }
+    
+    protected Span(Date start_date, Date end_date) {
+        init_span(start_date, end_date);
+    }
+    
+    /**
+     * Create an unintialized { link Span) on the presumption that { link start_date} and
+     * { link end_date} are overridden or that the child class needs to do more work before
+     * providing a date span.
+     *
+     * Because it's sometimes inconvenient to generate the necessary { link Date}s until the
+     * subclass's constructor completes, Span allows for itself to be created empty assuming
+     * that the subclass will call { link init_span} as soon as it's finished initializing.
+     *
+     * init_span() must be called.  Span will not function properly when uninitialized.
+     */
+    protected Span.uninitialized() {
+    }
+    
+    /**
+     * @see Span.uninitialized
+     */
+    protected void init_span(Date start_date, Date end_date) {
+        if (start_date.compare_to(end_date) <= 0) {
+            _start_date = start_date;
+            _end_date = end_date;
+        } else {
+            _start_date = end_date;
+            _end_date = start_date;
+        }
+    }
     
     /**
      * Returns the earliest { link ExactTime} for this { link Span}.
@@ -53,7 +111,7 @@ public interface Span<G> : BaseObject, Collection.SimpleIterable<G> {
      * @see Date.earliest_exact_time
      */
     public ExactTime earliest_exact_time(Timezone tz) {
-        return start_date.earliest_exact_time(tz);
+        return new ExactTime(tz, start_date, WallTime.earliest);
     }
     
     /**
@@ -62,7 +120,7 @@ public interface Span<G> : BaseObject, Collection.SimpleIterable<G> {
      * @see Date.latest_exact_time
      */
     public ExactTime latest_exact_time(Timezone tz) {
-        return end_date.latest_exact_time(tz);
+        return new ExactTime(tz, end_date, WallTime.latest);
     }
     
     /**
@@ -73,22 +131,65 @@ public interface Span<G> : BaseObject, Collection.SimpleIterable<G> {
     }
     
     /**
-     * true if the { link Span} contains the specified { link Date}.
+     * Converts the { link Span} into a { link WeekSpan} using the supplied { link FirstOfWeek}.
      *
-     * This is named to conform to Vala's rule for automatic syntax support.  This allows for the
-     * ''in'' operator to function on Spans, but only for Dates (which is perceived as a common
-     * operation).
+     * Dates covering a partial week are included.
+     */
+    public WeekSpan to_week_span(FirstOfWeek first_of_week) {
+        return new WeekSpan.from_date_span(to_date_span(), first_of_week);
+    }
+    
+    /**
+     * Converts the { link Span} into a { link MonthSpan}.
      *
-     * @see has
+     * Dates covering a partial month are included.
      */
-    public abstract bool contains(Date date);
+    public MonthSpan to_month_span() {
+        return new MonthSpan.from_date_span(to_date_span());
+    }
     
     /**
-     * true if the { link Span} contains the specified unit of time.
+     * Returns an { link ExactTimeSpan} for this { link Span}.
+     */
+    public ExactTimeSpan to_exact_time_span(Timezone tz) {
+        return new ExactTimeSpan(earliest_exact_time(tz), latest_exact_time(tz));
+    }
+    
+    /**
+     * Returns a { link DateSpan} with starting and ending points within the boundary specified
+     * (inclusive).
+     *
+     * If this { link Span} is within the clamped dates, this object may be returned.
      *
-     * @see contains
+     * This method will not expand a DateSpan to meet the clamp range.
      */
-    public abstract bool has(G unit);
+    public DateSpan clamp_between(Span span) {
+        Date new_start = (start_date.compare_to(span.start_date) < 0) ? span.start_date : start_date;
+        Date new_end = (end_date.compare_to(span.end_date) > 0) ? span.end_date : end_date;
+        
+        return new DateSpan(new_start, new_end);
+    }
+    
+    /**
+     * True if the { link Span} contains the specified { link Date}.
+     */
+    public bool has_date(Date date) {
+        int compare = start_date.compare_to(date);
+        if (compare == 0)
+            return true;
+        else if (compare > 0)
+            return false;
+        
+        return end_date.compare_to(date) >= 0;
+    }
+    
+    /**
+     * Returns a { link Collection.SimpleIterator} of all the { link Date}s in the
+     * { link Span}'s range of time.
+     */
+    public Collection.SimpleIterator<Date> date_iterator() {
+        return new SpanIterator(this);
+    }
 }
 
 }
diff --git a/src/calendar/calendar-unit-span.vala b/src/calendar/calendar-unit-span.vala
new file mode 100644
index 0000000..293dd4a
--- /dev/null
+++ b/src/calendar/calendar-unit-span.vala
@@ -0,0 +1,57 @@
+/* Copyright 2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later).  See the COPYING file in this distribution.
+ */
+
+namespace California.Calendar {
+
+/**
+ * An arbitrary, immutable span of { link DiscreteUnit}s.
+ *
+ * @see DateSpan
+ * @see MonthSpan
+ * @see WeekSpan
+ * @see YearSpan
+ */
+
+public abstract class UnitSpan<G> : Span, Collection.SimpleIterable<G> {
+    public const string PROP_FIRST = "first";
+    public const string PROP_LAST = "last";
+    
+    /**
+     * The earliest delinated unit of time within the { link UnitSpan}.
+     */
+    public G first { get; private set; }
+    
+    /**
+     * The latest delineated unit of time within the { link UnitSpan}.
+     */
+    public G last { get; private set; }
+    
+    protected UnitSpan(G first, G last, Date start_date, Date end_date) {
+        base (start_date, end_date);
+        
+        this.first = first;
+        this.last = last;
+    }
+    
+    /**
+     * True if the { link UnitSpan} contains the specified unit of time.
+     *
+     * This is named to conform to Vala's rule for automatic syntax support.  This allows for the
+     * ''in'' operator to function on UnitSpans.
+     *
+     * To determine if the UnitSpan contains a { link Date}, convert it to a { link DateSpan} with
+     * { link Span.to_date_span} and call its contains() method.
+     */
+    public abstract bool contains(G unit);
+    
+    /**
+     * Returns a { link Collection.SimpleIterator} of the { link UnitSpan}'s unit of time.
+     */
+    public abstract Collection.SimpleIterator<G> iterator();
+}
+
+}
+
diff --git a/src/calendar/calendar-unit.vala b/src/calendar/calendar-unit.vala
index 30c2424..dd145fe 100644
--- a/src/calendar/calendar-unit.vala
+++ b/src/calendar/calendar-unit.vala
@@ -8,6 +8,8 @@ namespace California.Calendar {
 
 /**
  * An enumeration of various calendar units.
+ *
+ * @see DiscreteUnit
  */
 
 public enum DateUnit {
@@ -29,100 +31,4 @@ public enum TimeUnit {
     HOUR
 }
 
-/**
- * An immutable, discrete, well-recognized unit of calendar dates.
- *
- * This interface indicates the { link Calendar.Span} represents a discrete unit of time (each of
- * which may not contain the same number of days, such as { link Year}s, while some might, such as
- * { link Week}s.
- *
- * Note that this different than a { link WeekSpan} or { link MonthSpan} which are designed to hold
- * an arbitrary consecutive number of their date units.  DiscreteUnits represent a single unit of
- * time.
- *
- * DiscreteUnit is not designed to work with discrete { link ExactTime} or { link WallTime} units.
- *
- * @see Date
- * @see Week
- * @see MonthOfYear
- * @see Year
- */
-
-public interface DiscreteUnit<G> : Span<G> {
-    private class DiscreteUnitIterator<G> : BaseObject, Collection.SimpleIterator<G> {
-        private G unit;
-        private DateUnit date_unit;
-        private bool finished = false;
-        
-        public DiscreteUnitIterator(G unit, DateUnit date_unit) {
-            this.unit = unit;
-            this.date_unit = date_unit;
-        }
-        
-        /**
-         * @inheritDoc
-         */
-        public bool next() {
-            if (!finished) {
-                finished = true;
-                
-                return true;
-            }
-            
-            return false;
-        }
-        
-        /**
-         * @inheritDoc
-         */
-        public new G get() {
-            return unit;
-        }
-        
-        public override string to_string() {
-            return "DiscreteUnitIterator:%s".printf(date_unit.to_string());
-        }
-    }
-    
-    /**
-     * Returns the { link DateUnit} this { link DiscreteUnit} represents.
-     */
-    public abstract DateUnit date_unit { get; }
-    
-    /**
-     * The next chronological discrete unit of time.
-     */
-    public G next() {
-        return adjust(1);
-    }
-    
-    /**
-     * The previous chronological discrete unit of time.
-     */
-    public G previous() {
-        return adjust(-1);
-    }
-    
-    /**
-     * @inheritDoc
-     */
-    public Collection.SimpleIterator<G> iterator() {
-        return new DiscreteUnitIterator<G>(this, date_unit);
-    }
-    
-    /**
-     * Returns the { link DiscreteUnit} adjusted a quantity of months from this one.
-     *
-     * Subtraction (adjusting to a past date) is acheived by using a negative quantity.
-     */
-    public abstract G adjust(int quantity);
-    
-    /**
-     * Returns the number of { link DiscreteUnit}s between the two.
-     *
-     * If the supplied DiscreteUnit is earlier than this one, a negative value is returned.
-     */
-    public abstract int difference(G other);
-}
-
 }
diff --git a/src/calendar/calendar-week-span.vala b/src/calendar/calendar-week-span.vala
index 16a54b8..dc77e94 100644
--- a/src/calendar/calendar-week-span.vala
+++ b/src/calendar/calendar-week-span.vala
@@ -8,13 +8,9 @@ namespace California.Calendar {
 
 /**
  * An immutable representation of a span of { link Week}s.
- *
- * This class provides methods that can turn a { link DateSpan} an iteration of Week objects.
- * Partial weeks are included; the caller needs to do their own clamping if they want to avoid
- * days outside of the DateSpan.
  */
 
-public class WeekSpan : BaseObject, Collection.SimpleIterable<Week>, Span<Week>, Gee.Comparable<WeekSpan>,
+public class WeekSpan : UnitSpan<Week>, Collection.SimpleIterable<Week>, Gee.Comparable<WeekSpan>,
     Gee.Hashable<WeekSpan> {
     private class WeekSpanIterator : BaseObject, Collection.SimpleIterator<Week> {
         public Week first;
@@ -22,8 +18,8 @@ public class WeekSpan : BaseObject, Collection.SimpleIterable<Week>, Span<Week>,
         public Week? current = null;
         
         public WeekSpanIterator(WeekSpan owner) {
-            first = owner.start();
-            last = owner.end();
+            first = owner.first;
+            last = owner.last;
         }
         
         public new Week get() {
@@ -47,76 +43,59 @@ public class WeekSpan : BaseObject, Collection.SimpleIterable<Week>, Span<Week>,
     }
     
     /**
-     * The { link DateSpan} of the { link Week}s.
-     */
-    public DateSpan dates { get; private set; }
-    
-    /**
-     * The defined first day of the week.
+     * The defined first day of the week for the weeks in the span.
      */
     public FirstOfWeek first_of_week { get; private set; }
     
     /**
-     * inheritDoc
-     */
-    public Date start_date { owned get { return dates.start_date; } }
-    
-    /**
-     * inheritDoc
-     */
-    public Date end_date { owned get { return dates.end_date; } }
-    
-    /**
-     * Create a span of { link Week}s corresponding to the { link DateSpan} according to
-     * { link FirstOfWeek}'s definition of a week's starting day.
+     * Create a span of { link Week}s from the start and end week.
+     *
+     * The start week's { link FirstOfWeek} is used.  The end week is converted if it uses a
+     * different first of week value.
      */
-    public WeekSpan(DateSpan dates, FirstOfWeek first_of_week) {
-        this.dates = dates;
-        this.first_of_week = first_of_week;
+    public WeekSpan(Week first, Week last) {
+        base (first, last, first.start_date, last.end_date.week_of(first.first_of_week).end_date);
+        
+        first_of_week = first.first_of_week;
     }
     
     /**
      * Create an arbitrary span of { link Week}s starting from the specified { link Week}.
      *
-     * Week's first-of-week is preserved.
+     * start's first-of-week is preserved.
      */
-    public WeekSpan.count(Week start, int count) {
-        dates = new DateSpan(start.start_date, start.adjust(count).end_date);
-        first_of_week = start.first_of_week;
-    }
-    
-    /**
-     * inheritDoc
-     */
-    public Week start() {
-        return dates.start_date.week_of(first_of_week);
-    }
-    
-    /**
-     * inheritDoc
-     */
-    public Week end() {
-        return dates.end_date.week_of(first_of_week);
+    public WeekSpan.count(Week first, int count) {
+        Week last = first.adjust(count);
+        
+        base (first, last, first.start_date, last.end_date);
+        
+        first_of_week = first.first_of_week;
     }
     
     /**
-     * @inheritDoc
+     * Create a span of { link Week}s corresponding to the { link DateSpan} according to
+     * { link FirstOfWeek}'s definition of a week's starting day.
      */
-    public bool contains(Date date) {
-        return dates.contains(date);
+    public WeekSpan.from_date_span(DateSpan date_span, FirstOfWeek first_of_week) {
+        Week first = date_span.start_date.week_of(first_of_week);
+        Week last = date_span.end_date.week_of(first_of_week);
+        
+        base (first, last, first.start_date, last.end_date);
+        
+        this.first_of_week = first_of_week;
     }
     
     /**
      * @inheritDoc
      */
-    public bool has(Week week) {
-        return (start().compare_to(week) <= 0) && (end().compare_to(week) >= 0);
+    public override bool contains(Week week) {
+        return (first.compare_to(week) <= 0) && (last.compare_to(week) >= 0);
     }
     
     /**
      * Returns an Iterator for each { link Week} (full and partial) in the { link WeekSpan}.
      */
-    public Collection.SimpleIterator<Week> iterator() {
+    public override Collection.SimpleIterator<Week> iterator() {
         return new WeekSpanIterator(this);
     }
     
@@ -139,7 +118,7 @@ public class WeekSpan : BaseObject, Collection.SimpleIterable<Week>, Span<Week>,
     }
     
     public override string to_string() {
-        return "weeks of %s".printf(dates.to_string());
+        return "weeks of %s".printf(to_date_span().to_string());
     }
 }
 
diff --git a/src/calendar/calendar-week.vala b/src/calendar/calendar-week.vala
index b80ebe4..64349e7 100644
--- a/src/calendar/calendar-week.vala
+++ b/src/calendar/calendar-week.vala
@@ -18,12 +18,7 @@ namespace California.Calendar {
  * { link Date.week_of} to obtain a Week for a particular calendar day.
  */
 
-public class Week : DateSpan, DiscreteUnit<Week> {
-    /**
-     * @inheritDoc
-     */
-    public DateUnit date_unit { get { return DateUnit.MONTH; } }
-    
+public class Week : DiscreteUnit<Week>, Gee.Comparable<Week>, Gee.Hashable<Week> {
     /**
      * The one-based week of the month (1 to 6).
      */
@@ -57,7 +52,7 @@ public class Week : DateSpan, DiscreteUnit<Week> {
      */
     internal Week(Date start, Date end, int week_of_month, int week_of_year, MonthOfYear month_of_year,
         FirstOfWeek first_of_week) {
-        base (start, end);
+        base (DateUnit.WEEK, start, end);
         
         this.week_of_month = week_of_month;
         this.week_of_year = week_of_year;
@@ -68,14 +63,14 @@ public class Week : DateSpan, DiscreteUnit<Week> {
     /**
      * @inheritDoc
      */
-    public Week adjust(int quantity) {
+    public override Week adjust(int quantity) {
         return start_date.adjust_by(quantity, DateUnit.WEEK).week_of(first_of_week);
     }
     
     /**
      * @inheritDoc
      */
-    public int difference(Week other) {
+    public override int difference(Week other) {
         int compare = compare_to(other);
         if (compare == 0)
             return 0;
@@ -92,6 +87,19 @@ public class Week : DateSpan, DiscreteUnit<Week> {
         }
     }
     
+    public int compare_to(Week other) {
+        return (this != other) ? start_date.compare_to(other.start_date) : 0;
+    }
+    
+    public bool equal_to(Week other) {
+        return compare_to(other) == 0;
+    }
+    
+    public uint hash() {
+        // 6 bits for week of year (1 - 52)
+        return (month_of_year.hash() << 6) | week_of_year;
+    }
+    
     public override string to_string() {
         return "week %d of %s (%s)".printf(week_of_year, month_of_year.to_string(), base.to_string());
     }
diff --git a/src/calendar/calendar-year.vala b/src/calendar/calendar-year.vala
index f1ab980..a5b8eb1 100644
--- a/src/calendar/calendar-year.vala
+++ b/src/calendar/calendar-year.vala
@@ -13,7 +13,7 @@ namespace California.Calendar {
  * value is described as thousands of years from now.
  */
 
-public class Year : DateSpan {
+public class Year : DiscreteUnit<Year>, Gee.Comparable<Year>, Gee.Hashable<Year> {
     /**
      * The year as an integer.
      */
@@ -25,7 +25,7 @@ public class Year : DateSpan {
      * Negative values and zero are clamped to 1 CE.
      */
     public Year(int value) {
-        base.uninitialized();
+        base.uninitialized(DateUnit.YEAR);
         
         this.value = value.clamp(1, int.MAX);
         
@@ -47,6 +47,32 @@ public class Year : DateSpan {
         return (DateYear) value;
     }
     
+    /**
+     * @inheritDoc
+     */
+    public override Year adjust(int quantity) {
+        return new Year(value + quantity);
+    }
+    
+    /**
+     * @inheritDoc
+     */
+    public override int difference(Year other) {
+        return value - other.value;
+    }
+    
+    public int compare_to(Year other) {
+        return (this != other) ? start_date.compare_to(other.start_date) : 0;
+    }
+    
+    public bool equal_to(Year other) {
+        return compare_to(other) == 0;
+    }
+    
+    public uint hash() {
+        return value;
+    }
+    
     public override string to_string() {
         return value.to_string();
     }
diff --git a/src/tests/tests-calendar-date.vala b/src/tests/tests-calendar-date.vala
index 82d8374..fb05d3d 100644
--- a/src/tests/tests-calendar-date.vala
+++ b/src/tests/tests-calendar-date.vala
@@ -33,7 +33,7 @@ private class CalendarDate : UnitTest.Harness {
     private bool clamp_start() throws Error {
         Calendar.DateSpan span = span_from_today(0, 5);
         Calendar.DateSpan clamp = span_from_today(1, 5);
-        Calendar.DateSpan adj = span.clamp(clamp);
+        Calendar.DateSpan adj = span.clamp_between(clamp);
         
         return adj.start_date.equal_to(clamp.start_date) && adj.end_date.equal_to(span.end_date);
     }
@@ -41,7 +41,7 @@ private class CalendarDate : UnitTest.Harness {
     private bool clamp_end() throws Error {
         Calendar.DateSpan span = span_from_today(0, 5);
         Calendar.DateSpan clamp = span_from_today(0, 4);
-        Calendar.DateSpan adj = span.clamp(clamp);
+        Calendar.DateSpan adj = span.clamp_between(clamp);
         
         return adj.start_date.equal_to(span.start_date) && adj.end_date.equal_to(clamp.end_date);
     }
@@ -49,7 +49,7 @@ private class CalendarDate : UnitTest.Harness {
     private bool clamp_both() throws Error {
         Calendar.DateSpan span = span_from_today(0, 5);
         Calendar.DateSpan clamp = span_from_today(1, 4);
-        Calendar.DateSpan adj = span.clamp(clamp);
+        Calendar.DateSpan adj = span.clamp_between(clamp);
         
         return adj.start_date.equal_to(clamp.start_date) && adj.end_date.equal_to(clamp.end_date);
     }
@@ -57,7 +57,7 @@ private class CalendarDate : UnitTest.Harness {
     private bool clamp_neither() throws Error {
         Calendar.DateSpan span = span_from_today(0, 5);
         Calendar.DateSpan clamp = span_from_today(-1, 6);
-        Calendar.DateSpan adj = span.clamp(clamp);
+        Calendar.DateSpan adj = span.clamp_between(clamp);
         
         return adj.start_date.equal_to(span.start_date) && adj.end_date.equal_to(span.end_date);
     }
diff --git a/src/tests/tests-calendar-month-span.vala b/src/tests/tests-calendar-month-span.vala
index 5a9e72d..aa488ad 100644
--- a/src/tests/tests-calendar-month-span.vala
+++ b/src/tests/tests-calendar-month-span.vala
@@ -27,33 +27,33 @@ private class CalendarMonthSpan : UnitTest.Harness {
     }
     
     private bool todays_month() throws Error {
-        Calendar.MonthSpan span = new Calendar.MonthSpan(new Calendar.DateSpan(
+        Calendar.MonthSpan span = new Calendar.MonthSpan.from_date_span(new Calendar.DateSpan(
             from_today(0), from_today(0)));
         
-        return span.start().equal_to(Calendar.System.today.month_of_year())
-            && span.end().equal_to(Calendar.System.today.month_of_year());
+        return span.first.equal_to(Calendar.System.today.month_of_year())
+            && span.last.equal_to(Calendar.System.today.month_of_year());
     }
     
     private bool contains_date() throws Error {
         Calendar.Date first = new Calendar.Date(Calendar.DayOfMonth.for_checked(1), Calendar.Month.JAN, new 
Calendar.Year(2014));
         Calendar.Date last = new Calendar.Date(Calendar.DayOfMonth.for_checked(30), Calendar.Month.JAN, new 
Calendar.Year(2014));
-        Calendar.MonthSpan span = new Calendar.MonthSpan(new Calendar.DateSpan(first, last));
+        Calendar.MonthSpan span = new Calendar.MonthSpan.from_date_span(new Calendar.DateSpan(first, last));
         
-        return span.contains(first.adjust(15));
+        return span.has_date(first.adjust(15));
     }
     
     private bool has_month() throws Error {
         Calendar.Date first = new Calendar.Date(Calendar.DayOfMonth.for_checked(1), Calendar.Month.JAN, new 
Calendar.Year(2014));
         Calendar.Date last = new Calendar.Date(Calendar.DayOfMonth.for_checked(30), Calendar.Month.MAR, new 
Calendar.Year(2014));
-        Calendar.MonthSpan span = new Calendar.MonthSpan(new Calendar.DateSpan(first, last));
+        Calendar.MonthSpan span = new Calendar.MonthSpan.from_date_span(new Calendar.DateSpan(first, last));
         
-        return span.has(new Calendar.MonthOfYear(Calendar.Month.FEB, new Calendar.Year(2014)));
+        return span.contains(new Calendar.MonthOfYear(Calendar.Month.FEB, new Calendar.Year(2014)));
     }
     
     private bool iterator() throws Error {
         Calendar.Date first = new Calendar.Date(Calendar.DayOfMonth.for_checked(1), Calendar.Month.JAN, new 
Calendar.Year(2014));
         Calendar.Date last = new Calendar.Date(Calendar.DayOfMonth.for_checked(30), Calendar.Month.JUN, new 
Calendar.Year(2014));
-        Calendar.MonthSpan span = new Calendar.MonthSpan(new Calendar.DateSpan(first, last));
+        Calendar.MonthSpan span = new Calendar.MonthSpan.from_date_span(new Calendar.DateSpan(first, last));
         
         Calendar.Month[] months = {
             Calendar.Month.JAN,
diff --git a/src/view/month/month-cell.vala b/src/view/month/month-cell.vala
index 0933d02..4cdf2d2 100644
--- a/src/view/month/month-cell.vala
+++ b/src/view/month/month-cell.vala
@@ -309,7 +309,7 @@ private class Cell : Gtk.EventBox {
         if (reassigned.size > 0) {
             // only need to tell cells following this day's in the current week about the reassignment
             Calendar.Week this_week = date.week_of(owner.first_of_week);
-            Calendar.DateSpan span = new Calendar.DateSpan(date.next(), this_week.end_date).clamp(this_week);
+            Calendar.DateSpan span = new Calendar.DateSpan(date.next(), 
this_week.end_date).clamp_between(this_week);
             
             foreach (Calendar.Date span_date in span) {
                 Cell? cell = owner.get_cell_for_date(span_date);
diff --git a/src/view/month/month-controller.vala b/src/view/month/month-controller.vala
index 62d6f55..cc20779 100644
--- a/src/view/month/month-controller.vala
+++ b/src/view/month/month-controller.vala
@@ -115,7 +115,7 @@ public class Controller : BaseObject, View.Controllable {
     // previous month and that Grids outside that range are dropped.  The current chronological
     // month is never discarded.
     private void update_month_grid_cache() {
-        Calendar.MonthSpan cache_span = new Calendar.MonthSpan.from_months(
+        Calendar.MonthSpan cache_span = new Calendar.MonthSpan(
             month_of_year.adjust(0 - (CACHE_NEIGHBORS_COUNT / 2)),
             month_of_year.adjust(CACHE_NEIGHBORS_COUNT / 2));
         
@@ -129,7 +129,7 @@ public class Controller : BaseObject, View.Controllable {
                 continue;
             
             // keep if grid is in cache span
-            if (cache_span.has(grid_moy))
+            if (grid_moy in cache_span)
                 continue;
             
             // drop, remove from GtkStack and local storage
diff --git a/src/view/month/month-grid.vala b/src/view/month/month-grid.vala
index bb21d85..fd76f99 100644
--- a/src/view/month/month-grid.vala
+++ b/src/view/month/month-grid.vala
@@ -168,7 +168,7 @@ private class Grid : Gtk.Grid {
         
         // create a WeekSpan for the first week of the month to the last displayed week (not all
         // months will fill all displayed weeks, but some will)
-        Calendar.WeekSpan span = new 
Calendar.WeekSpan.count(month_of_year.weeks(owner.first_of_week).start(),
+        Calendar.WeekSpan span = new 
Calendar.WeekSpan.count(month_of_year.to_week_span(owner.first_of_week).first,
             ROWS - 1);
         
         // fill in weeks of the displayed month


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]