[california] Set iCal component to proper Olson zoneinfo: Closes bgo#725777



commit d06760303e87ee5b29a4e1b1659354482fb396be
Author: Jim Nelson <jim yorba org>
Date:   Thu Mar 6 18:37:40 2014 -0800

    Set iCal component to proper Olson zoneinfo: Closes bgo#725777
    
    libical could parse PST into an Olson code but choked on PDT,
    bringing this problem to light.  Time zone objects now always carry
    their Olson zoneinfo with them.  Also some work here to clean up
    how system information is maintained (Calendar.System) and the local
    time zone is now being fetched from timedated rather than relying on
    GLib.TimeZone.local, which did not offer the Olson code.

 src/Makefile.am                            |    4 +
 src/calendar/calendar-date.vala            |   13 ++--
 src/calendar/calendar-dbus.vala            |   58 +++++++++++++
 src/calendar/calendar-exact-time-span.vala |    8 +-
 src/calendar/calendar-exact-time.vala      |   29 ++++---
 src/calendar/calendar-olson-zone.vala      |   66 +++++++++++++++
 src/calendar/calendar-span.vala            |    4 +-
 src/calendar/calendar-system.vala          |  124 ++++++++++++++++++++++++++++
 src/calendar/calendar-timezone.vala        |   74 +++++++++++++++++
 src/calendar/calendar.vala                 |   29 ++-----
 src/component/component-date-time.vala     |   20 ++--
 src/component/component-instance.vala      |    9 +-
 src/component/component-uid.vala           |    2 +-
 src/host/host-create-update-event.vala     |   13 ++--
 src/host/host-main-window.vala             |    2 +-
 src/host/host-show-event.vala              |    6 +-
 src/view/month/month-cell.vala             |   10 +--
 src/view/month/month-controllable.vala     |   20 ++--
 vapi/libical.vapi                          |    2 +-
 19 files changed, 405 insertions(+), 88 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index a74ca36..e8942d2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -32,13 +32,17 @@ california_VALASOURCES = \
        calendar/calendar-day-of-month.vala \
        calendar/calendar-day-of-week.vala \
        calendar/calendar-date.vala \
+       calendar/calendar-dbus.vala \
        calendar/calendar-error.vala \
        calendar/calendar-exact-time.vala \
        calendar/calendar-exact-time-span.vala \
        calendar/calendar-first-of-week.vala \
        calendar/calendar-month.vala \
        calendar/calendar-month-of-year.vala \
+       calendar/calendar-olson-zone.vala \
        calendar/calendar-span.vala \
+       calendar/calendar-system.vala \
+       calendar/calendar-timezone.vala \
        calendar/calendar-unit.vala \
        calendar/calendar-wall-time.vala \
        calendar/calendar-week.vala \
diff --git a/src/calendar/calendar-date.vala b/src/calendar/calendar-date.vala
index c04d27e..a401342 100644
--- a/src/calendar/calendar-date.vala
+++ b/src/calendar/calendar-date.vala
@@ -78,9 +78,9 @@ public class Date : BaseObject, Gee.Comparable<Date>, Gee.Hashable<Date> {
     }
     
     /**
-     * Creates a { link Date} that corresponds to the current time in the specified timezone.
+     * Creates a { link Date} that corresponds to the current time in the specified { link Timezone}.
      */
-    public Date.now(TimeZone tz) {
+    public Date.now(Timezone tz) {
         this.from_exact_time(new ExactTime.now(tz));
     }
     
@@ -160,22 +160,23 @@ public class Date : BaseObject, Gee.Comparable<Date>, Gee.Hashable<Date> {
     }
     
     /**
-     * Returns the { link Date} as the earliest ExactTime possible for the specified TimeZone.
+     * 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) {
+    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 TimeZone.
+     * 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) {
+    public ExactTime latest_exact_time(Timezone tz) {
         return new ExactTime(tz, this, WallTime.latest);
     }
     
diff --git a/src/calendar/calendar-dbus.vala b/src/calendar/calendar-dbus.vala
new file mode 100644
index 0000000..aa1de83
--- /dev/null
+++ b/src/calendar/calendar-dbus.vala
@@ -0,0 +1,58 @@
+/* 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.
+ */
+
+/**
+ * D-Bus interfaces needed for system time/date information.
+ */
+
+namespace California.Calendar.DBus {
+
+/**
+ * D-Bus interface to systemd-timedated which holds various useful time/date-related information.
+ *
+ * See [[http://www.freedesktop.org/wiki/Software/systemd/timedated/]]
+ */
+
+[DBus (name = "org.freedesktop.timedate1")]
+public interface timedated : Object {
+    public const string NAME = "org.freedesktop.timedate1";
+    public const string OBJECT_PATH = "/org/freedesktop/timedate1";
+    
+    public const string PROP_TIMEZONE = "Timezone";
+    public const string PROP_LOCAL_RTC = "LocalRTC";
+    public const string PROP_NTP = "NTP";
+    
+    public abstract string timezone { owned get; }
+    public abstract bool local_rtc { get; }
+    public abstract bool ntp { get; }
+    
+    public abstract void set_time(int64 usec_etc, bool relative, bool user_interaction) throws IOError;
+    public abstract void set_timezone(string timezone, bool user_interaction) throws IOError;
+    public abstract void set_local_rtc(bool local_rtc, bool fix_system, bool user_interaction)
+        throws IOError;
+    public abstract void set_ntp(bool use_ntp, bool user_interaction) throws IOError;
+}
+
+/**
+ * D-Bus interface for querying and monitoring properties.
+ *
+ * See [[https://pythonhosted.org/txdbus/dbus_overview.html]], "org.freedesktop.DBus.Properties"
+ */
+
+[DBus (name = "org.freedesktop.DBus.Properties")]
+public interface Properties : Object {
+    public const string NAME = "org.freedesktop.DBus.Properties";
+    
+    public signal void properties_changed(string interf, HashTable<string, Variant> 
changed_properties_values,
+        string[] changed_properties);
+    
+    public abstract Variant get(string interf, string property) throws IOError;
+    public abstract void get_all(string interf, HashTable<string, Variant> properties) throws IOError;
+    public abstract void set(string interf, string property, Variant value) throws IOError;
+}
+
+}
+
diff --git a/src/calendar/calendar-exact-time-span.vala b/src/calendar/calendar-exact-time-span.vala
index 002addc..ec58fa7 100644
--- a/src/calendar/calendar-exact-time-span.vala
+++ b/src/calendar/calendar-exact-time-span.vala
@@ -11,7 +11,7 @@ namespace California.Calendar {
  *
  * This is conceptually similar to { link DateSpan}, but (currently) doesn't allow for iteration.
  *
- * Note that there's no checking for matching TimeZones; in the future, these times may be
+ * Note that there's no checking for matching Timezones; in the future, these times may be
  * normalized to UTC.
  */
 
@@ -62,7 +62,7 @@ public class ExactTimeSpan : BaseObject, Gee.Comparable<ExactTimeSpan>, Gee.Hash
         end_date = new Date.from_exact_time(end_exact_time);
     }
     
-    public ExactTimeSpan.from_date_span(DateSpan span, TimeZone tz) {
+    public ExactTimeSpan.from_date_span(DateSpan span, Timezone tz) {
         this (span.earliest_exact_time(tz), span.latest_exact_time(tz));
     }
     
@@ -75,9 +75,9 @@ public class ExactTimeSpan : BaseObject, Gee.Comparable<ExactTimeSpan>, Gee.Hash
     
     /**
      * Returns a new { link ExactTimeSpan} with both { link start_date_time} and
-     * { link end_date_time} converted to the supplied TimeZone.
+     * { link end_date_time} converted to the supplied { link Timezone}.
      */
-    public ExactTimeSpan to_timezone(TimeZone new_tz) {
+    public ExactTimeSpan to_timezone(Timezone new_tz) {
         return new ExactTimeSpan(start_exact_time.to_timezone(new_tz),
             end_exact_time.to_timezone(new_tz));
     }
diff --git a/src/calendar/calendar-exact-time.vala b/src/calendar/calendar-exact-time.vala
index 0f9388e..74078cd 100644
--- a/src/calendar/calendar-exact-time.vala
+++ b/src/calendar/calendar-exact-time.vala
@@ -10,7 +10,8 @@ namespace California.Calendar {
  * An immutable representation of an exact moment of time on a particular calendar day.
  *
  * This uses GLib's DateTime class but adds some extra logic useful to California, including
- * storing the TimeZone used to generate the DateTime and making this object work well with Gee.
+ * storing the { link Timezone} used to generate the DateTime and making this object work well with
+ * Gee.
  *
  * "Exact" is limited, of course, to the precision of DateTime, but it's close enough for our needs.
  */
@@ -41,16 +42,16 @@ public class ExactTime : BaseObject, Gee.Comparable<ExactTime>, Gee.Hashable<Exa
     public bool is_dst { get { return date_time.is_daylight_savings(); } }
     
     /**
-     * The timezone used to generate this moment of time.
+     * The { link Timezone} used to generate this moment of time.
      *
      * @see to_timezone
      */
-    public TimeZone tz { get; private set; }
+    public Timezone tz { get; private set; }
     
     /**
-     * The TZID for the current time's timezone.
+     * A human-oriented string representing the current time's time zone as an abbreviation.
      *
-     * TZID is (generally) three-letter acronyms, i.e. "PST" for Pacific Standard Time.
+     * This value should ''not'' be used to generate an { link OlsonZone}.
      *
      * @see tz
      */
@@ -63,7 +64,7 @@ public class ExactTime : BaseObject, Gee.Comparable<ExactTime>, Gee.Hashable<Exa
     
     private DateTime date_time;
     
-    public ExactTime(TimeZone tz, Date date, WallTime time) {
+    public ExactTime(Timezone tz, Date date, WallTime time) {
         try {
             init(tz, date.year.value, date.month.value, date.day_of_month.value,
                 time.hour, time.minute, time.second);
@@ -73,26 +74,26 @@ public class ExactTime : BaseObject, Gee.Comparable<ExactTime>, Gee.Hashable<Exa
         }
     }
     
-    public ExactTime.full(TimeZone tz, int year, int month, int day, int hour, int minute,
+    public ExactTime.full(Timezone tz, int year, int month, int day, int hour, int minute,
         double second) throws CalendarError {
         init(tz, year, month, day, hour, minute, second);
     }
     
-    public ExactTime.now(TimeZone tz) {
-        date_time = new DateTime.now(tz);
+    public ExactTime.now(Timezone tz) {
+        date_time = new DateTime.now(tz.time_zone);
         if (date_time == null)
             error("DateTime.now failed");
         this.tz = tz;
     }
     
-    public ExactTime.from_date_time(DateTime date_time, TimeZone tz) {
+    public ExactTime.from_date_time(DateTime date_time, Timezone tz) {
         this.date_time = date_time;
         this.tz = tz;
     }
     
-    private void init(TimeZone tz, int year, int month, int day, int hour, int minute, double second)
+    private void init(Timezone tz, int year, int month, int day, int hour, int minute, double second)
         throws CalendarError {
-        date_time = new DateTime(tz, year, month, day, hour, minute, second);
+        date_time = new DateTime(tz.time_zone, year, month, day, hour, minute, second);
         if (date_time == null) {
             throw new CalendarError.INVALID("Invalid specified DateTime: %02d/%02d/%d %02d:%02d:%02lf",
                 day, month, year, hour, minute, second);
@@ -161,8 +162,8 @@ public class ExactTime : BaseObject, Gee.Comparable<ExactTime>, Gee.Hashable<Exa
     /**
      * See DateTime.to_timezone.
      */
-    public ExactTime to_timezone(TimeZone new_tz) {
-        return new ExactTime.from_date_time(date_time.to_timezone(new_tz), new_tz);
+    public ExactTime to_timezone(Timezone new_tz) {
+        return new ExactTime.from_date_time(date_time.to_timezone(new_tz.time_zone), new_tz);
     }
     
     /**
diff --git a/src/calendar/calendar-olson-zone.vala b/src/calendar/calendar-olson-zone.vala
new file mode 100644
index 0000000..e97d04d
--- /dev/null
+++ b/src/calendar/calendar-olson-zone.vala
@@ -0,0 +1,66 @@
+/* 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 {
+
+/**
+ * The Olson name of a time zone in the tz (or zoneinfo) database.
+ *
+ * An Olson name is in the form of "Area/Location".  This class merely encapsulates this string
+ * and gives it some type-ness; actual time zone calculations is left to { link Timezone}.
+ * In particular, little error-checking is performed by this class.  It also does no processing
+ * or consideration for zone aliases ("links"), which is why it does not implement Gee.Hashable or
+ * Gee.Comparable.
+ *
+ * This class is immutable.
+ *
+ * Future expansion may include some processing or parsing of the name itself, but that's not
+ * planned at the moment.
+ *
+ * The IANA database of Olson zones and related information is located at
+ * [[https://www.iana.org/time-zones]]
+ */
+
+public class OlsonZone : BaseObject {
+    /**
+     * The string value this class uses if an empty string is passed to the constructor.
+     *
+     * Note that this is not the only definition of UTC in the zoneinfo database.  That is,
+     * a simple comparison of { link value} to this constant is no guarantee that an
+     * { link OlsonZone} is or is not UTC.
+     */
+    public const string UTC = "UTC";
+    
+    /**
+     * An { link OlsonZone} representation of UTC.
+     *
+     * @see UTC
+     */
+    public static OlsonZone utc { get; private set; }
+    
+    /**
+     * The raw Olson zoneinfo name.
+     */
+    public string value { get; private set; }
+    
+    public OlsonZone(string area_location) {
+        value = !String.is_empty(area_location) ? area_location : UTC;
+    }
+    
+    internal static void init() {
+        utc = new OlsonZone(UTC);
+    }
+    
+    internal static void terminate() {
+        utc = null;
+    }
+    
+    public override string to_string() {
+        return value;
+    }
+}
+
+}
diff --git a/src/calendar/calendar-span.vala b/src/calendar/calendar-span.vala
index f8cfe37..187bd88 100644
--- a/src/calendar/calendar-span.vala
+++ b/src/calendar/calendar-span.vala
@@ -52,7 +52,7 @@ public interface Span<G> : BaseObject, Collection.SimpleIterable<G> {
      *
      * @see Date.earliest_exact_time
      */
-    public ExactTime earliest_exact_time(TimeZone tz) {
+    public ExactTime earliest_exact_time(Timezone tz) {
         return start_date.earliest_exact_time(tz);
     }
     
@@ -61,7 +61,7 @@ public interface Span<G> : BaseObject, Collection.SimpleIterable<G> {
      *
      * @see Date.latest_exact_time
      */
-    public ExactTime latest_exact_time(TimeZone tz) {
+    public ExactTime latest_exact_time(Timezone tz) {
         return end_date.latest_exact_time(tz);
     }
     
diff --git a/src/calendar/calendar-system.vala b/src/calendar/calendar-system.vala
new file mode 100644
index 0000000..bcb452c
--- /dev/null
+++ b/src/calendar/calendar-system.vala
@@ -0,0 +1,124 @@
+/* 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 {
+
+/**
+ * A singleton offering system-based calendar and time information and updates of important changes.
+ *
+ * Most of System's properties are static as a convenience for callers (to avoid having to always
+ * reference { link instance}).  Since static properties have no notification mechanism, callers
+ * interested in being notified of changes must subscribe to the instance's particular signals,
+ * i.e. { link zone_changed}.
+ */
+
+public class System : BaseObject {
+    public static System instance { get; private set; }
+    
+    /**
+     * The current date according to the local timezone.
+     *
+     * TODO: This currently does not update as the program executes.
+     */
+    public static Date today { get; private set; }
+    
+    /**
+     * Returns the current { link ExactTime} of the local { link Timezone}.
+     */
+    public static ExactTime now {
+        owned get {
+            return new ExactTime.now(Timezone.local);
+        }
+    }
+    
+    /**
+     * If the current user is configured to use 12 or 24-hour time.
+     */
+    public static bool is_24hr { get; private set; }
+    
+    /**
+     * Returns the system's configured zone as an { link OlsonZone}.
+     */
+    public static OlsonZone zone { get; private set; }
+    
+    /**
+     * The current system { link Timezone}.
+     *
+     * @see timezone_changed
+     * @see Timezone.utc
+     */
+    public static Timezone timezone { get; private set; }
+    
+    private static DBus.timedated timedated_service;
+    private static DBus.Properties timedated_properties;
+    
+    /**
+     * Fired when { link zone} changes.
+     *
+     * This generally indicates that the user has changed system time zone manually or that the
+     * system detected the change through geolocation services.
+     */
+    public signal void zone_changed(OlsonZone new_zone);
+    
+    /**
+     * Fired when { link local_timezone} changes due to system configuration changes.
+     */
+    public signal void timezone_changed(Timezone new_timezone);
+    
+    private System() {
+        zone = new OlsonZone(timedated_service.timezone);
+        timezone = new Timezone(zone);
+        debug("Local zone: %s", zone.to_string());
+        
+        // to be notified of changes as they occur
+        timedated_properties.properties_changed.connect(on_timedated_properties_changed);
+        
+        // TODO: Fetch and update from GNOME settings
+        is_24hr = false;
+        
+        // TODO: Tie this into the event loop so it's properly updated
+        today = new Date.now(Timezone.local);
+    }
+    
+    internal static void preinit() throws IOError {
+        timedated_service = Bus.get_proxy_sync(BusType.SYSTEM, DBus.timedated.NAME,
+            DBus.timedated.OBJECT_PATH);
+        timedated_properties = Bus.get_proxy_sync(BusType.SYSTEM, DBus.Properties.NAME,
+            DBus.timedated.OBJECT_PATH);
+    }
+    
+    internal static void init() {
+        instance = new System();
+    }
+    
+    internal static void terminate() {
+        instance = null;
+        timedated_service = null;
+        timedated_properties = null;
+    }
+    
+    private void on_timedated_properties_changed(string interf,
+        HashTable<string, Variant> changed_properties_values, string[] changed_properties) {
+        if (changed_properties_values.contains(DBus.timedated.PROP_TIMEZONE)
+            || DBus.timedated.PROP_TIMEZONE in changed_properties) {
+            zone = new OlsonZone(timedated_service.timezone);
+            timezone = new Timezone(zone);
+            debug("New local zone: %s", zone.to_string());
+            
+            // fire signals last in case a subscriber monitoring zone thinks that local_timezone
+            // has also changed
+            zone_changed(zone);
+            timezone_changed(timezone);
+        }
+    }
+    
+    public override string to_string() {
+        return get_class().get_type().name();
+    }
+}
+
+}
+
diff --git a/src/calendar/calendar-timezone.vala b/src/calendar/calendar-timezone.vala
new file mode 100644
index 0000000..6ee5140
--- /dev/null
+++ b/src/calendar/calendar-timezone.vala
@@ -0,0 +1,74 @@
+/* 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 representation of a time zone and its associated Olson zoneinfo.
+ *
+ * Like { link ExactTime}, this class arose because GLib's TimeZone works well for many things but
+ * additional functionality needed to be added.  The most pressing need is to maintain the Olson
+ * zone information for the lifetime of the object.
+ */
+
+public class Timezone : BaseObject {
+    /**
+     * The { link Timezone} for UTC.
+     */
+    public static Timezone utc { get; private set; }
+    
+    /**
+     * The system's configured { link Timezone}.
+     *
+     * This is merely a convenience method for { link System.timezone}.
+     *
+     * @see System.timezone_changed
+     */
+    public static Timezone local { get { return System.timezone; } }
+    
+    /**
+     * The { link OlsonZone} for this { link Timezone}.
+     */
+    public OlsonZone zone { get; private set; }
+    
+    /**
+     * Returns true if this { link Timezone} represents UTC.
+     *
+     * This merely tests that this object is the same as the current { link local} object; no deep
+     * equality is tested.
+     */
+    public bool is_utc { get { return this == utc; } }
+    
+    /**
+     * Returns true if this { link Timezone} represents the system's configured time zone.
+     *
+     * This merely tests that this object is the same as the current { link local} object; no deep
+     * equality is tested.
+     */
+    public bool is_local { get { return this == local; } }
+    
+    internal TimeZone time_zone { get; private set; }
+    
+    public Timezone(OlsonZone zone) {
+        time_zone = new TimeZone(zone.value);
+        this.zone = zone;
+    }
+    
+    internal static void init() {
+        utc = new Timezone(OlsonZone.utc);
+    }
+    
+    internal static void terminate() {
+        utc = null;
+    }
+    
+    public override string to_string() {
+        return zone.to_string();
+    }
+}
+
+}
+
diff --git a/src/calendar/calendar.vala b/src/calendar/calendar.vala
index 096861a..6ab23da 100644
--- a/src/calendar/calendar.vala
+++ b/src/calendar/calendar.vala
@@ -17,13 +17,6 @@
 
 namespace California.Calendar {
 
-/**
- * The current date according to the local timezone.
- *
- * This currently does not update as the program executes.
- */
-public Date today;
-
 private int init_count = 0;
 
 private static unowned string FMT_MONTH_YEAR_FULL;
@@ -57,34 +50,30 @@ public void init() throws Error {
     FMT_PRETTY_DATE_ABBREV = _("%a, %b %e, %Y");
     FMT_PRETTY_DATE_ABBREV_NO_YEAR = _("%a, %b %e");
     
+    // This init() throws an IOError, so perform before others to prevent unnecessary unwinding
+    System.preinit();
+    
     // internal initialization
+    OlsonZone.init();
     DayOfWeek.init();
     DayOfMonth.init();
     Month.init();
     WallTime.init();
-    
-    // TODO: Tie this into the event loop so it's properly updated; also make it a property of
-    // an instance so it can be monitored
-    today = new Date.now(new TimeZone.local());
+    System.init();
+    Timezone.init();
 }
 
 public void terminate() {
     if (!California.Unit.do_terminate(ref init_count))
         return;
     
-    today = null;
-    
+    Timezone.terminate();
+    System.terminate();
     WallTime.terminate();
     Month.terminate();
     DayOfMonth.terminate();
     DayOfWeek.terminate();
-}
-
-/**
- * Returns the { link ExactTime} of the local TimeZone.
- */
-public ExactTime now() {
-    return new ExactTime.now(new TimeZone.local());
+    OlsonZone.terminate();
 }
 
 }
diff --git a/src/component/component-date-time.vala b/src/component/component-date-time.vala
index 7c5f6e2..4a23b96 100644
--- a/src/component/component-date-time.vala
+++ b/src/component/component-date-time.vala
@@ -10,12 +10,12 @@ public class DateTime : BaseObject {
     /**
      * The TZID for the iCal component and property kind.
      *
-     * TZID in libical means Olson city timezone.  A null tzid indicates floating time or a DATE.
+     * TZID in libical means Olson city timezone.  A null zone indicates floating time or a DATE.
      *
      * @see is_floating_time
      * @see is_date
      */
-    public string? tzid { get; private set; default = null; }
+    public Calendar.OlsonZone? zone { get; private set; default = null; }
     
     /**
      * Indicates if this { link DateTime} is for UTC time.
@@ -27,7 +27,7 @@ public class DateTime : BaseObject {
      *
      * See [[https://tools.ietf.org/html/rfc5545#section-3.8.3.1]]
      */
-    public bool is_floating { get { return tzid == null && !is_date; } }
+    public bool is_floating { get { return zone == null && !is_date; } }
     
     /**
      * Indicates if this is a DATE rather than a DATE-TIME.
@@ -78,7 +78,7 @@ public class DateTime : BaseObject {
         
         unowned iCal.icalparameter? param = prop.get_first_parameter(iCal.icalparameter_kind.TZID_PARAMETER);
         if (param != null)
-            tzid = param.get_tzid();
+            zone = new Calendar.OlsonZone(param.get_tzid());
     }
     
     /**
@@ -108,22 +108,22 @@ public class DateTime : BaseObject {
     }
     
     /**
-     * Returns a TimeZone for the DATE-TIME.
+     * Returns a { link Timezone} for the DATE-TIME.
      *
      * Returns null if { link is_date} is true.  Returns the local timezone if { link is_floating}
      * is true.  Returns the timezone for UTC if { link is_utc} is true.
      */
-    public TimeZone? get_timezone() {
+    public Calendar.Timezone? get_timezone() {
         if (is_date)
             return null;
         
         if (is_utc)
-            return new TimeZone.utc();
+            return Calendar.Timezone.utc;
         
-        if (is_floating || tzid == null)
-            return new TimeZone.local();
+        if (is_floating || zone == null)
+            return Calendar.Timezone.local;
         
-        return new TimeZone(tzid);
+        return new Calendar.Timezone(zone);
     }
     
     /**
diff --git a/src/component/component-instance.vala b/src/component/component-instance.vala
index 2218aa4..307af70 100644
--- a/src/component/component-instance.vala
+++ b/src/component/component-instance.vala
@@ -134,7 +134,7 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
         if (from_full_update)
             return;
         
-        dtstamp = Calendar.now();
+        dtstamp = Calendar.System.now;
         
         iCal.icaltimetype ical_dtstamp = {};
         exact_time_to_ical(dtstamp, &ical_dtstamp);
@@ -250,11 +250,12 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
         ical_dt->hour = exact_time.hour;
         ical_dt->minute = exact_time.minute;
         ical_dt->second = exact_time.second;
-        ical_dt->is_utc = 0;
+        ical_dt->is_utc = exact_time.tz.is_utc ? 1 : 0;
         ical_dt->is_date = 0;
         ical_dt->is_daylight = exact_time.is_dst ? 1 : 0;
-        ical_dt->zone = iCal.icaltimezone.get_builtin_timezone_from_offset(exact_time.utc_offset,
-            exact_time.tzid);
+        ical_dt->zone = iCal.icaltimezone.get_builtin_timezone(exact_time.tz.zone.value);
+        if (ical_dt->zone == null)
+            message("Unable to get builtin iCal timezone for %s", exact_time.tz.zone.to_string());
     }
     
     /**
diff --git a/src/component/component-uid.vala b/src/component/component-uid.vala
index 63b684d..758f961 100644
--- a/src/component/component-uid.vala
+++ b/src/component/component-uid.vala
@@ -24,7 +24,7 @@ public class UID : BaseObject, Gee.Hashable<UID>, Gee.Comparable<UID> {
     public static UID generate() {
         // Borrowed liberally from EDS' e_cal_component_gen_uid
         return new UID("%s-%d-%d-%d-%08X %s".printf(
-            Calendar.now().format("%FT%H:%M:%S%z"),
+            Calendar.System.now.format("%FT%H:%M:%S%z"),
             Posix.getpid(),
             (int) Posix.getgid(),
             (int) Posix.getppid(),
diff --git a/src/host/host-create-update-event.vala b/src/host/host-create-update-event.vala
index 32e28b3..8de92da 100644
--- a/src/host/host-create-update-event.vala
+++ b/src/host/host-create-update-event.vala
@@ -102,17 +102,17 @@ public class CreateUpdateEvent : Gtk.Grid {
             all_day_toggle.active = false;
             selected_date_span = event.exact_time_span.get_date_span();
             initial_start_time = new Calendar.WallTime.from_exact_time(
-                event.exact_time_span.start_exact_time.to_timezone(new TimeZone.local()));
+                event.exact_time_span.start_exact_time.to_timezone(Calendar.Timezone.local));
             initial_end_time = new Calendar.WallTime.from_exact_time(
-                event.exact_time_span.end_exact_time.to_timezone(new TimeZone.local()));
+                event.exact_time_span.end_exact_time.to_timezone(Calendar.Timezone.local));
         } else {
             assert(event.date_span != null);
             
             all_day_toggle.active = true;
             selected_date_span = event.date_span;
-            initial_start_time = new Calendar.WallTime.from_exact_time(Calendar.now());
+            initial_start_time = new Calendar.WallTime.from_exact_time(Calendar.System.now);
             initial_end_time = new Calendar.WallTime.from_exact_time(
-                Calendar.now().adjust_time(1, Calendar.TimeUnit.HOUR));
+                Calendar.System.now.adjust_time(1, Calendar.TimeUnit.HOUR));
         }
         
         // initialize start and end time (as in, wall clock time)
@@ -239,8 +239,9 @@ public class CreateUpdateEvent : Gtk.Grid {
             event.set_event_date_span(selected_date_span);
         } else {
             // use existing timezone unless not specified in original event
-            TimeZone tz = (event.exact_time_span != null) ? event.exact_time_span.start_exact_time.tz
-                : new TimeZone.local();
+            Calendar.Timezone tz = (event.exact_time_span != null)
+                ? event.exact_time_span.start_exact_time.tz
+                : Calendar.Timezone.local;
             event.set_event_exact_time_span(
                 new Calendar.ExactTimeSpan(
                     new Calendar.ExactTime(tz, selected_date_span.start_date,
diff --git a/src/host/host-main-window.vala b/src/host/host-main-window.vala
index 73619db..6673f70 100644
--- a/src/host/host-main-window.vala
+++ b/src/host/host-main-window.vala
@@ -98,7 +98,7 @@ public class MainWindow : Gtk.ApplicationWindow {
     
     private void on_new_event() {
         // create all-day event for today
-        Calendar.DateSpan initial = new Calendar.DateSpan(Calendar.today, Calendar.today);
+        Calendar.DateSpan initial = new Calendar.DateSpan(Calendar.System.today, Calendar.System.today);
         
         // revert to today's date and use the widget for the popover
         create_event(null, initial, null, current_view.today(), null);
diff --git a/src/host/host-show-event.vala b/src/host/host-show-event.vala
index 151f47f..afb5367 100644
--- a/src/host/host-show-event.vala
+++ b/src/host/host-show-event.vala
@@ -35,8 +35,8 @@ public class ShowEvent : Gtk.Grid {
         // if any dates are not in current year, display year in all dates
         Calendar.Date.PrettyFlag date_flags = Calendar.Date.PrettyFlag.NONE;
         Calendar.DateSpan date_span = event.get_event_date_span();
-        if (!date_span.start_date.year.equal_to(Calendar.today.year)
-            || !date_span.end_date.year.equal_to(Calendar.today.year)) {
+        if (!date_span.start_date.year.equal_to(Calendar.System.today.year)
+            || !date_span.end_date.year.equal_to(Calendar.System.today.year)) {
             date_flags |= Calendar.Date.PrettyFlag.INCLUDE_YEAR;
         }
         
@@ -56,7 +56,7 @@ public class ShowEvent : Gtk.Grid {
             }
         } else {
             Calendar.ExactTimeSpan exact_time_span = event.exact_time_span.to_timezone(
-                new TimeZone.local());
+                Calendar.Timezone.local);
             if (exact_time_span.is_same_day) {
                 // Single-day timed event, print "<full date>\n<full start time> to <full end time>",
                 // including year if not current year
diff --git a/src/view/month/month-cell.vala b/src/view/month/month-cell.vala
index 20fca89..587f42d 100644
--- a/src/view/month/month-cell.vala
+++ b/src/view/month/month-cell.vala
@@ -184,7 +184,7 @@ public class Cell : Gtk.EventBox {
         if (selected) {
             Gdk.cairo_set_source_rgba(ctx, RGBA_SELECTED);
             ctx.paint();
-        } else if (date != null && date.equal_to(Calendar.today)) {
+        } else if (date != null && date.equal_to(Calendar.System.today)) {
             Gdk.cairo_set_source_rgba(ctx, RGBA_CURRENT_DAY);
             ctx.paint();
         }
@@ -226,17 +226,15 @@ public class Cell : Gtk.EventBox {
         int line_number = 0;
         line_to_event.clear();
         
-        // convert all times to local timezone
-        TimeZone local = new TimeZone.local();
-        
         // draw all events in chronological order, all-day events first, storing lookup data
-        // as the "lines" are drawn
+        // as the "lines" are drawn ... make sure to convert them all to local timezone
         foreach (Component.Event event in days_events) {
             string text;
             if (event.is_all_day) {
                 text = event.summary;
             } else {
-                Calendar.ExactTime local_start = event.exact_time_span.start_exact_time.to_timezone(local);
+                Calendar.ExactTime local_start = event.exact_time_span.start_exact_time.to_timezone(
+                    Calendar.Timezone.local);
                 text = "%s %s".printf(local_start.to_pretty_time_string(PRETTY_TIME_FLAGS), event.summary);
             }
             
diff --git a/src/view/month/month-controllable.vala b/src/view/month/month-controllable.vala
index c6d5133..5c7ed5a 100644
--- a/src/view/month/month-controllable.vala
+++ b/src/view/month/month-controllable.vala
@@ -108,7 +108,7 @@ public class Controllable : Gtk.Grid, View.Controllable {
         notify[PROP_SHOW_OUTSIDE_MONTH].connect(update_cells);
         
         // update now that signal handlers are in place
-        month_of_year = Calendar.today.month_of_year();
+        month_of_year = Calendar.System.today.month_of_year();
         first_of_week = Calendar.FirstOfWeek.SUNDAY;
     }
     
@@ -132,13 +132,13 @@ public class Controllable : Gtk.Grid, View.Controllable {
     public Gtk.Widget today() {
         // since changing the date is expensive in terms of adding/removing subscriptions, only
         // update the property if it's actually different
-        Calendar.MonthOfYear now = Calendar.today.month_of_year();
+        Calendar.MonthOfYear now = Calendar.System.today.month_of_year();
         if (!now.equal_to(month_of_year))
             month_of_year = now;
         
-        assert(date_to_cell.has_key(Calendar.today));
+        assert(date_to_cell.has_key(Calendar.System.today));
         
-        return date_to_cell.get(Calendar.today);
+        return date_to_cell.get(Calendar.System.today);
     }
     
     /**
@@ -231,12 +231,12 @@ public class Controllable : Gtk.Grid, View.Controllable {
     
     private void on_month_of_year_changed() {
         current_label = month_of_year.full_name;
-        is_viewing_today = month_of_year.equal_to(Calendar.today.month_of_year());
+        is_viewing_today = month_of_year.equal_to(Calendar.System.today.month_of_year());
         
         // default date is first of month unless displaying current month, in which case it's
         // current date
         try {
-            default_date = is_viewing_today ? Calendar.today
+            default_date = is_viewing_today ? Calendar.System.today
                 : month_of_year.date_for(month_of_year.first_day_of_month());
         } catch (CalendarError calerr) {
             // this should always work
@@ -247,7 +247,7 @@ public class Controllable : Gtk.Grid, View.Controllable {
         
         // generate new ExactTimeSpan window for all calendar subscriptions
         Calendar.ExactTimeSpan window = new Calendar.ExactTimeSpan.from_date_span(month_of_year,
-            new TimeZone.local());
+            Calendar.Timezone.local);
         
         // clear current subscriptions and generate new subscriptions for new window
         subscriptions.clear();
@@ -405,10 +405,10 @@ public class Controllable : Gtk.Grid, View.Controllable {
         
         // TODO: Define default time better
         Calendar.ExactTime start;
-        if(release_cell.date.equal_to(Calendar.today)) {
-            start = new Calendar.ExactTime.now(new TimeZone.local());
+        if(release_cell.date.equal_to(Calendar.System.today)) {
+            start = new Calendar.ExactTime.now(Calendar.Timezone.local);
         } else {
-            start = new Calendar.ExactTime(new TimeZone.local(), release_cell.date,
+            start = new Calendar.ExactTime(Calendar.Timezone.local, release_cell.date,
                 new Calendar.WallTime(13, 0, 0));
         }
         
diff --git a/vapi/libical.vapi b/vapi/libical.vapi
index e80e748..fb5e7df 100644
--- a/vapi/libical.vapi
+++ b/vapi/libical.vapi
@@ -57,7 +57,7 @@ namespace iCal {
                [CCode (cname = "icalcomponent_add_property")]
                public void add_property (iCal.icalproperty property);
                [CCode (cname = "icalcomponent_as_ical_string")]
-               public unowned string as_ical_string ();
+               public string as_ical_string ();
                [CCode (cname = "icalcomponent_as_ical_string_r")]
                public unowned string as_ical_string_r ();
                [CCode (cname = "icalcomponent_begin_component")]



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