event: fix timezone handling
Using libical with libecal means that the dates are always stored as UTF dates, and we receive the timezone as the ECalComponentDateTime::tzid value. This fact was net being considered when adding date support on GcalEvent, and was causing various issues when displaying dates. Fix that by properly handling timezones in GcalEvent.
This commit is contained in:
+73
-59
@@ -63,25 +63,69 @@ enum {
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GTimeZone*
|
||||
get_timezone_from_ical (ECalComponentDateTime *comp)
|
||||
{
|
||||
GTimeZone *tz;
|
||||
|
||||
if (comp->value->is_date)
|
||||
{
|
||||
/*
|
||||
* When loading an all day event, the timezone must not be taken into account
|
||||
* when loading the date. Since all events in ical are UTC, we match it by
|
||||
* setting the timezone as UTC as well.
|
||||
*/
|
||||
tz = g_time_zone_new_utc ();
|
||||
}
|
||||
else if (icaltime_get_timezone (*comp->value))
|
||||
{
|
||||
gchar *tzid;
|
||||
gint offset;
|
||||
|
||||
offset = icaltimezone_get_utc_offset ((icaltimezone*) icaltime_get_timezone (*comp->value),
|
||||
comp->value, NULL);
|
||||
tzid = format_utc_offset (offset);
|
||||
tz = g_time_zone_new (tzid);
|
||||
|
||||
g_free (tzid);
|
||||
}
|
||||
else if (comp->tzid)
|
||||
{
|
||||
tz = g_time_zone_new (comp->tzid);
|
||||
}
|
||||
else
|
||||
{
|
||||
tz = g_time_zone_new_utc ();
|
||||
}
|
||||
|
||||
return tz;
|
||||
}
|
||||
|
||||
static ECalComponentDateTime*
|
||||
build_component_from_datetime (GcalEvent *self,
|
||||
GDateTime *dt)
|
||||
{
|
||||
ECalComponentDateTime *comp_dt;
|
||||
const gchar *tzid;
|
||||
GDateTime *utf_dt;
|
||||
|
||||
if (!dt)
|
||||
return NULL;
|
||||
|
||||
utf_dt = g_date_time_to_utc (dt);
|
||||
|
||||
comp_dt = g_new0 (ECalComponentDateTime, 1);
|
||||
comp_dt->value = NULL;
|
||||
comp_dt->tzid = NULL;
|
||||
|
||||
tzid = g_date_time_get_timezone_abbreviation (dt);
|
||||
|
||||
comp_dt->value = datetime_to_icaltime (dt);
|
||||
comp_dt->value = datetime_to_icaltime (utf_dt);
|
||||
comp_dt->value->zone = NULL;
|
||||
comp_dt->value->is_date = self->all_day;
|
||||
comp_dt->tzid = g_strdup (tzid ? tzid : "UTC");
|
||||
|
||||
/* All day events have no timezone */
|
||||
if (!self->all_day)
|
||||
comp_dt->tzid = format_utc_offset (g_date_time_get_utc_offset (dt));
|
||||
|
||||
g_clear_pointer (&utf_dt, g_date_time_unref);
|
||||
|
||||
return comp_dt;
|
||||
}
|
||||
@@ -138,31 +182,40 @@ gcal_event_set_component_internal (GcalEvent *self,
|
||||
ECalComponentDateTime start;
|
||||
ECalComponentDateTime end;
|
||||
GDateTime *date_start;
|
||||
GTimeZone *zone_start;
|
||||
GDateTime *date_end;
|
||||
GTimeZone *tz;
|
||||
GTimeZone *zone_end;
|
||||
GDateTime *aux;
|
||||
gboolean start_is_all_day, end_is_all_day;
|
||||
gchar *description;
|
||||
|
||||
/* Setup start date */
|
||||
e_cal_component_get_dtstart (component, &start);
|
||||
date_start = icaltime_to_datetime (start.value, &tz);
|
||||
zone_start = get_timezone_from_ical (&start);
|
||||
aux = icaltime_to_datetime (start.value);
|
||||
date_start = g_date_time_to_timezone (aux, zone_start);
|
||||
start_is_all_day = datetime_is_date (aux);
|
||||
|
||||
gcal_event_set_date_start (self, date_start);
|
||||
self->dt_start = g_date_time_ref (date_start);
|
||||
|
||||
g_clear_pointer (&aux, g_date_time_unref);
|
||||
|
||||
/* The timezone of the event is the timezone of the start date */
|
||||
self->timezone = g_time_zone_ref (zone_start);
|
||||
|
||||
/* Setup end date */
|
||||
e_cal_component_get_dtend (component, &end);
|
||||
date_end = icaltime_to_datetime (end.value, NULL);
|
||||
zone_end = get_timezone_from_ical (&end);
|
||||
aux = icaltime_to_datetime (end.value);
|
||||
date_end = g_date_time_to_timezone (aux, zone_end);
|
||||
end_is_all_day = datetime_is_date (aux);
|
||||
|
||||
gcal_event_set_date_end (self, date_end);
|
||||
self->dt_end = g_date_time_ref (date_end);
|
||||
|
||||
/*
|
||||
* Setup timezone. We use the timezone from the start
|
||||
* date as the timezone of the event, and the end date
|
||||
* is adjusted if necessary.
|
||||
*/
|
||||
gcal_event_set_timezone (self, tz);
|
||||
g_clear_pointer (&aux, g_date_time_unref);
|
||||
|
||||
/* Setup all day */
|
||||
gcal_event_set_all_day (self, datetime_is_date (date_start) && datetime_is_date (date_end));
|
||||
self->all_day = start_is_all_day && end_is_all_day;
|
||||
|
||||
/* Setup description */
|
||||
description = get_desc_from_component (component, "\n\n");
|
||||
@@ -176,7 +229,9 @@ gcal_event_set_component_internal (GcalEvent *self,
|
||||
g_object_notify (G_OBJECT (self), "summary");
|
||||
|
||||
g_clear_pointer (&date_start, g_date_time_unref);
|
||||
g_clear_pointer (&zone_start, g_time_zone_unref);
|
||||
g_clear_pointer (&date_end, g_date_time_unref);
|
||||
g_clear_pointer (&zone_end, g_time_zone_unref);
|
||||
g_clear_pointer (&description, g_free);
|
||||
}
|
||||
}
|
||||
@@ -583,48 +638,7 @@ gcal_event_set_all_day (GcalEvent *self,
|
||||
self->all_day = all_day;
|
||||
|
||||
g_object_notify (G_OBJECT (self), "all-day");
|
||||
|
||||
/*
|
||||
* If we just set an all day event, the hour & minute fields
|
||||
* from the start & end date should be set to 0.
|
||||
*/
|
||||
if (self->all_day)
|
||||
{
|
||||
GDateTime *dt;
|
||||
|
||||
/* Update start date */
|
||||
if (self->dt_start)
|
||||
{
|
||||
dt = g_date_time_new (self->timezone,
|
||||
g_date_time_get_year (self->dt_start),
|
||||
g_date_time_get_month (self->dt_start),
|
||||
g_date_time_get_day_of_month (self->dt_start),
|
||||
self->all_day ? 0 : g_date_time_get_hour (self->dt_start),
|
||||
self->all_day ? 0 : g_date_time_get_minute (self->dt_start),
|
||||
0);
|
||||
|
||||
gcal_event_set_date_start (self, dt);
|
||||
|
||||
g_clear_pointer (&dt, g_date_time_unref);
|
||||
}
|
||||
|
||||
/* Update end date */
|
||||
if (self->dt_end)
|
||||
{
|
||||
dt = g_date_time_new (self->timezone,
|
||||
g_date_time_get_year (self->dt_end),
|
||||
g_date_time_get_month (self->dt_end),
|
||||
g_date_time_get_day_of_month (self->dt_end),
|
||||
self->all_day ? 0 : g_date_time_get_hour (self->dt_end),
|
||||
self->all_day ? 0 : g_date_time_get_minute (self->dt_end),
|
||||
0);
|
||||
|
||||
gcal_event_set_date_end (self, dt);
|
||||
|
||||
g_clear_pointer (&dt, g_date_time_unref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -488,6 +488,8 @@ rebuild_popover_for_day (GcalMonthView *view,
|
||||
PangoFontDescription *ofont_desc;
|
||||
gint font_height, padding_bottom;
|
||||
|
||||
GTimeZone *tz;
|
||||
|
||||
priv = gcal_month_view_get_instance_private (view);
|
||||
ppriv = GCAL_SUBSCRIBER_VIEW (view)->priv;
|
||||
|
||||
@@ -499,6 +501,7 @@ rebuild_popover_for_day (GcalMonthView *view,
|
||||
gtk_container_foreach (GTK_CONTAINER (priv->events_list_box), (GtkCallback) gtk_widget_destroy, NULL);
|
||||
|
||||
l = g_hash_table_lookup (ppriv->overflow_cells, GINT_TO_POINTER (priv->pressed_overflow_indicator));
|
||||
tz = g_time_zone_new_local ();
|
||||
|
||||
/* Setup the start & end dates of the events as the begin & end of day */
|
||||
if (l != NULL)
|
||||
@@ -506,9 +509,7 @@ rebuild_popover_for_day (GcalMonthView *view,
|
||||
GDateTime *current_date;
|
||||
GDateTime *dt_start;
|
||||
GDateTime *dt_end;
|
||||
GTimeZone *tz;
|
||||
|
||||
current_date = icaltime_to_datetime (priv->date, &tz);
|
||||
current_date = icaltime_to_datetime (priv->date);
|
||||
dt_start = g_date_time_new (tz,
|
||||
g_date_time_get_year (current_date),
|
||||
g_date_time_get_month (current_date),
|
||||
@@ -536,9 +537,10 @@ rebuild_popover_for_day (GcalMonthView *view,
|
||||
g_clear_pointer (¤t_date, g_date_time_unref);
|
||||
g_clear_pointer (&dt_start, g_date_time_unref);
|
||||
g_clear_pointer (&dt_end, g_date_time_unref);
|
||||
g_clear_pointer (&tz, g_time_zone_unref);
|
||||
}
|
||||
|
||||
g_clear_pointer (&tz, g_time_zone_unref);
|
||||
|
||||
/* placement calculation */
|
||||
start_grid_y = get_start_grid_y (GTK_WIDGET (view));
|
||||
shown_rows = ceil ((priv->days_delay + icaltime_days_in_month (priv->date->month, priv->date->year)) / 7.0);
|
||||
|
||||
+23
-12
@@ -110,8 +110,7 @@ datetime_to_icaltime (GDateTime *dt)
|
||||
}
|
||||
|
||||
GDateTime*
|
||||
icaltime_to_datetime (const icaltimetype *date,
|
||||
GTimeZone **timezone)
|
||||
icaltime_to_datetime (const icaltimetype *date)
|
||||
{
|
||||
GDateTime *dt;
|
||||
GTimeZone *tz;
|
||||
@@ -125,10 +124,7 @@ icaltime_to_datetime (const icaltimetype *date,
|
||||
date->is_date ? 0 : date->minute,
|
||||
date->is_date ? 0 : date->second);
|
||||
|
||||
if (timezone)
|
||||
*timezone = tz;
|
||||
else
|
||||
g_clear_pointer (&tz, g_time_zone_unref);
|
||||
g_clear_pointer (&tz, g_time_zone_unref);
|
||||
|
||||
return dt;
|
||||
}
|
||||
@@ -427,15 +423,11 @@ build_component_from_details (const gchar *summary,
|
||||
ECalComponent *event;
|
||||
ECalComponentDateTime dt;
|
||||
ECalComponentText summ;
|
||||
GTimeZone *tz;
|
||||
|
||||
tz = g_time_zone_new_local ();
|
||||
|
||||
event = e_cal_component_new ();
|
||||
e_cal_component_set_new_vtype (event, E_CAL_COMPONENT_EVENT);
|
||||
|
||||
dt.value = (icaltimetype*) initial_date;
|
||||
dt.tzid = g_time_zone_get_abbreviation (tz, 0);
|
||||
e_cal_component_set_dtstart (event, &dt);
|
||||
|
||||
if (final_date != NULL)
|
||||
@@ -458,8 +450,6 @@ build_component_from_details (const gchar *summary,
|
||||
|
||||
e_cal_component_commit_sequence (event);
|
||||
|
||||
g_clear_pointer (&tz, g_time_zone_unref);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
@@ -785,3 +775,24 @@ get_source_parent_name_color (GcalManager *manager,
|
||||
*color = gdk_rgba_to_string (&c);
|
||||
}
|
||||
}
|
||||
|
||||
gchar*
|
||||
format_utc_offset (gint offset)
|
||||
{
|
||||
const char *sign = "+";
|
||||
gint hours, minutes, seconds;
|
||||
|
||||
if (offset < 0) {
|
||||
offset = -offset;
|
||||
sign = "-";
|
||||
}
|
||||
|
||||
hours = offset / 3600;
|
||||
minutes = (offset % 3600) / 60;
|
||||
seconds = offset % 60;
|
||||
|
||||
if (seconds > 0)
|
||||
return g_strdup_printf ("%s%02i%02i%02i", sign, hours, minutes, seconds);
|
||||
else
|
||||
return g_strdup_printf ("%s%02i%02i", sign, hours, minutes);
|
||||
}
|
||||
|
||||
+3
-2
@@ -59,8 +59,7 @@ icaltimetype* datetime_to_icaltime (GDateTime
|
||||
|
||||
gboolean datetime_is_date (GDateTime *dt);
|
||||
|
||||
GDateTime* icaltime_to_datetime (const icaltimetype *date,
|
||||
GTimeZone **timezone);
|
||||
GDateTime* icaltime_to_datetime (const icaltimetype *date);
|
||||
|
||||
icaltimetype* gcal_dup_icaltime (const icaltimetype *date);
|
||||
|
||||
@@ -122,4 +121,6 @@ void get_source_parent_name_color (GcalManager
|
||||
gchar **name,
|
||||
gchar **color);
|
||||
|
||||
gchar* format_utc_offset (gint offset);
|
||||
|
||||
#endif // __GCAL_UTILS_H__
|
||||
|
||||
@@ -272,7 +272,6 @@ add_event_to_day_array (GcalYearView *year_view,
|
||||
|
||||
GDateTime *dt_start, *dt_end;
|
||||
GDateTime *date, *second_date;
|
||||
GTimeZone *tz;
|
||||
|
||||
gint i;
|
||||
|
||||
@@ -284,8 +283,8 @@ add_event_to_day_array (GcalYearView *year_view,
|
||||
dt_end = gcal_event_get_date_end (event);
|
||||
|
||||
/* normalize date on each new event */
|
||||
date = icaltime_to_datetime (year_view->start_selected_date, &tz);
|
||||
second_date = g_date_time_new (tz,
|
||||
date = icaltime_to_datetime (year_view->start_selected_date);
|
||||
second_date = g_date_time_new (gcal_event_get_timezone (event),
|
||||
g_date_time_get_year (date),
|
||||
g_date_time_get_month (date),
|
||||
g_date_time_get_day_of_month (date) + 1,
|
||||
|
||||
Reference in New Issue
Block a user