diff options
author | Damon Chaplin <damon@ximian.com> | 2001-07-11 11:56:03 +0800 |
---|---|---|
committer | Damon Chaplin <damon@src.gnome.org> | 2001-07-11 11:56:03 +0800 |
commit | 0e6d346872289d1ee71cb7b1092b5229b11dab3e (patch) | |
tree | 588b9cbac780c577af5c56d020c98f2f3822b38f | |
parent | 552d3501e9bf05d42ce6f342e85a526a1cea702c (diff) | |
download | gsoc2013-evolution-0e6d346872289d1ee71cb7b1092b5229b11dab3e.tar gsoc2013-evolution-0e6d346872289d1ee71cb7b1092b5229b11dab3e.tar.gz gsoc2013-evolution-0e6d346872289d1ee71cb7b1092b5229b11dab3e.tar.bz2 gsoc2013-evolution-0e6d346872289d1ee71cb7b1092b5229b11dab3e.tar.lz gsoc2013-evolution-0e6d346872289d1ee71cb7b1092b5229b11dab3e.tar.xz gsoc2013-evolution-0e6d346872289d1ee71cb7b1092b5229b11dab3e.tar.zst gsoc2013-evolution-0e6d346872289d1ee71cb7b1092b5229b11dab3e.zip |
more timezone updates. I'm pretty much done with the calendar code now,
2001-07-10 Damon Chaplin <damon@ximian.com>
* gui/calendar-model.c:
* gui/e-calendar-table.c:
* gui/e-day-view-main-item.c:
* gui/e-day-view-top-item.c:
* gui/e-day-view.[hc]:
* gui/e-week-view.c:
* gui/gnome-cal.c:
* gui/print.c:
* gui/dialogs/cal-prefs-dialog.c:
* gui/dialogs/comp-editor-util.c:
* gui/dialogs/event-page.c:
* pcs/cal-backend-file.c:
* pcs/query.c:
* cal-util/cal-component.[hc]:
* cal-util/cal-recur.c:
* cal-util/timeutil.[hc]:
* cal-client/cal-client.[hc]: more timezone updates. I'm pretty much
done with the calendar code now, except for alarms and conduits,
which Federico and JP know more about. And there are a couple of
other minor things to fix. But it is still pretty buggy.
svn path=/trunk/; revision=10984
-rw-r--r-- | calendar/ChangeLog | 23 | ||||
-rw-r--r-- | calendar/cal-client/cal-client.c | 10 | ||||
-rw-r--r-- | calendar/cal-client/cal-client.h | 5 | ||||
-rw-r--r-- | calendar/cal-util/cal-component.c | 39 | ||||
-rw-r--r-- | calendar/cal-util/cal-component.h | 4 | ||||
-rw-r--r-- | calendar/cal-util/cal-recur.c | 267 | ||||
-rw-r--r-- | calendar/cal-util/timeutil.c | 606 | ||||
-rw-r--r-- | calendar/cal-util/timeutil.h | 123 | ||||
-rw-r--r-- | calendar/gui/calendar-model.c | 100 | ||||
-rw-r--r-- | calendar/gui/dialogs/cal-prefs-dialog.c | 2 | ||||
-rw-r--r-- | calendar/gui/dialogs/comp-editor-util.c | 5 | ||||
-rw-r--r-- | calendar/gui/dialogs/event-page.c | 7 | ||||
-rw-r--r-- | calendar/gui/e-calendar-table.c | 1 | ||||
-rw-r--r-- | calendar/gui/e-day-view-main-item.c | 30 | ||||
-rw-r--r-- | calendar/gui/e-day-view-top-item.c | 8 | ||||
-rw-r--r-- | calendar/gui/e-day-view.c | 25 | ||||
-rw-r--r-- | calendar/gui/e-day-view.h | 2 | ||||
-rw-r--r-- | calendar/gui/e-week-view.c | 12 | ||||
-rw-r--r-- | calendar/gui/gnome-cal.c | 48 | ||||
-rw-r--r-- | calendar/gui/print.c | 354 | ||||
-rw-r--r-- | calendar/pcs/cal-backend-file.c | 5 | ||||
-rw-r--r-- | calendar/pcs/query.c | 7 |
22 files changed, 1030 insertions, 653 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index b12f8a8d90..2b6bf179e0 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,26 @@ +2001-07-10 Damon Chaplin <damon@ximian.com> + + * gui/calendar-model.c: + * gui/e-calendar-table.c: + * gui/e-day-view-main-item.c: + * gui/e-day-view-top-item.c: + * gui/e-day-view.[hc]: + * gui/e-week-view.c: + * gui/gnome-cal.c: + * gui/print.c: + * gui/dialogs/cal-prefs-dialog.c: + * gui/dialogs/comp-editor-util.c: + * gui/dialogs/event-page.c: + * pcs/cal-backend-file.c: + * pcs/query.c: + * cal-util/cal-component.[hc]: + * cal-util/cal-recur.c: + * cal-util/timeutil.[hc]: + * cal-client/cal-client.[hc]: more timezone updates. I'm pretty much + done with the calendar code now, except for alarms and conduits, + which Federico and JP know more about. And there are a couple of + other minor things to fix. But it is still pretty buggy. + 2001-07-10 JP Rosevear <jpr@ximian.com> * gui/dialogs/meeting-page.c: Add popup support so you can delete diff --git a/calendar/cal-client/cal-client.c b/calendar/cal-client/cal-client.c index 8acbbc376a..dc81ec044a 100644 --- a/calendar/cal-client/cal-client.c +++ b/calendar/cal-client/cal-client.c @@ -833,6 +833,8 @@ cal_client_get_timezone (CalClient *client, icalcomponent *icalcomp; icaltimezone *tmp_zone; + g_print ("In cal_client_get_timezone: %s\n", tzid); + g_return_val_if_fail (client != NULL, CAL_CLIENT_GET_NOT_FOUND); g_return_val_if_fail (IS_CAL_CLIENT (client), CAL_CLIENT_GET_NOT_FOUND); @@ -845,12 +847,14 @@ cal_client_get_timezone (CalClient *client, /* If tzid is NULL or "" we return NULL, since it is a 'local time'. */ if (!tzid || !tzid[0]) { *zone = NULL; + g_print (" zone is local time (NULL)\n"); return CAL_CLIENT_GET_SUCCESS; } /* If it is UTC, we return the special UTC timezone. */ if (!strcmp (tzid, "UTC")) { *zone = icaltimezone_get_utc_timezone (); + g_print (" zone is UTC\n"); return CAL_CLIENT_GET_SUCCESS; } @@ -858,12 +862,15 @@ cal_client_get_timezone (CalClient *client, tmp_zone = g_hash_table_lookup (priv->timezones, tzid); if (tmp_zone) { *zone = tmp_zone; + g_print (" zone is in cache\n"); return CAL_CLIENT_GET_SUCCESS; } retval = CAL_CLIENT_GET_NOT_FOUND; *zone = NULL; + g_print (" getting zone from server\n"); + /* We don't already have it, so we try to get it from the server. */ CORBA_exception_init (&ev); comp_str = GNOME_Evolution_Calendar_Cal_getTimezoneObject (priv->cal, (char *) tzid, &ev); @@ -876,6 +883,7 @@ cal_client_get_timezone (CalClient *client, goto out; } + g_print (" parsing zone:\n%s\n", comp_str); icalcomp = icalparser_parse_string (comp_str); CORBA_free (comp_str); @@ -884,6 +892,7 @@ cal_client_get_timezone (CalClient *client, goto out; } + g_print (" creating icaltimezone\n"); tmp_zone = icaltimezone_new (); if (!tmp_zone) { /* FIXME: Needs better error code - out of memory. Or just @@ -901,6 +910,7 @@ cal_client_get_timezone (CalClient *client, g_hash_table_insert (priv->timezones, icaltimezone_get_tzid (tmp_zone), tmp_zone); + g_print (" returning icaltimezone\n"); *zone = tmp_zone; retval = CAL_CLIENT_GET_SUCCESS; diff --git a/calendar/cal-client/cal-client.h b/calendar/cal-client/cal-client.h index 12d04b70d4..4681574289 100644 --- a/calendar/cal-client/cal-client.h +++ b/calendar/cal-client/cal-client.h @@ -135,8 +135,13 @@ gboolean cal_client_get_alarms_for_object (CalClient *client, const char *uid, time_t start, time_t end, CalComponentAlarms **alarms); +/* Add or update a single object. When adding an object only builtin timezones + are allowed. To use external VTIMEZONE data call update_objects() instead.*/ gboolean cal_client_update_object (CalClient *client, CalComponent *comp); +/* Add or update multiple objects, possibly including VTIMEZONE data. */ +gboolean cal_client_update_objects (CalClient *client, icalcomponent *icalcomp); + gboolean cal_client_remove_object (CalClient *client, const char *uid); CalQuery *cal_client_get_query (CalClient *client, const char *sexp); diff --git a/calendar/cal-util/cal-component.c b/calendar/cal-util/cal-component.c index 1ebc398e63..d340cea60f 100644 --- a/calendar/cal-util/cal-component.c +++ b/calendar/cal-util/cal-component.c @@ -4933,5 +4933,44 @@ cal_component_event_dates_match (CalComponent *comp1, return TRUE; } +/* Returns TRUE if the TZIDs are equivalent, i.e. both NULL or the same. */ +static gboolean +cal_component_compare_tzid (const char *tzid1, const char *tzid2) +{ + gboolean retval = TRUE; + + if (tzid1) { + if (!tzid2 || strcmp (tzid1, tzid2)) + retval = FALSE; + } else { + if (tzid2) + retval = FALSE; + } + + return retval; +} +/* Returns TRUE if the component uses the given timezones for both DTSTART + and DTEND. */ +gboolean +cal_component_compare_event_timezone (CalComponent *comp, icaltimezone *zone) +{ + CalComponentDateTime datetime; + const char *tzid; + gboolean match; + tzid = icaltimezone_get_tzid (zone); + + cal_component_get_dtstart (comp, &datetime); + match = cal_component_compare_tzid (tzid, datetime.tzid); + cal_component_free_datetime (&datetime); + if (!match) + return FALSE; + + /* FIXME: DURATION may be used instead. */ + cal_component_get_dtend (comp, &datetime); + match = cal_component_compare_tzid (tzid, datetime.tzid); + cal_component_free_datetime (&datetime); + + return match; +} diff --git a/calendar/cal-util/cal-component.h b/calendar/cal-util/cal-component.h index 2dcc06ce61..f0628cb967 100644 --- a/calendar/cal-util/cal-component.h +++ b/calendar/cal-util/cal-component.h @@ -335,6 +335,10 @@ void cal_component_set_attendee_list (CalComponent *comp, GSList *attendee_list) gboolean cal_component_event_dates_match (CalComponent *comp1, CalComponent *comp2); +/* Returns TRUE if the component uses the given timezones for both DTSTART + and DTEND. */ +gboolean cal_component_compare_event_timezone (CalComponent *comp, icaltimezone *zone); + /* Functions to free returned values */ void cal_component_free_categories_list (GSList *categ_list); diff --git a/calendar/cal-util/cal-recur.c b/calendar/cal-util/cal-recur.c index 1e21f3109c..8df567fa5c 100644 --- a/calendar/cal-util/cal-recur.c +++ b/calendar/cal-util/cal-recur.c @@ -115,8 +115,8 @@ typedef struct { int interval; - /* Specifies the end of the recurrence. No occurrences are generated - after this date. If it is 0, the event recurs forever. */ + /* Specifies the end of the recurrence, inclusive. No occurrences are + generated after this date. If it is 0, the event recurs forever. */ time_t enddate; /* WKST property - the week start day: 0 = Monday to 6 = Sunday. */ @@ -197,8 +197,13 @@ struct _CalObjTime { guint8 hour; /* 0 - 23 */ guint8 minute; /* 0 - 59 */ guint8 second; /* 0 - 59 (maybe up to 61 for leap seconds) */ - guint8 is_rdate; /* TRUE if this is an RDATE, which may have an - end or duration set. */ + guint8 flags; /* The meaning of this depends on where the + CalObjTime is used. In most cases this is + set to TRUE to indicate that this is an + RDATE with an end or a duration set. + In the exceptions code, this is set to TRUE + to indicate that this is an EXDATE with a + DATE value. */ }; /* This is what we use to represent specific recurrence dates. @@ -262,7 +267,8 @@ static void cal_recur_generate_instances_of_rule (CalComponent *comp, gpointer tz_cb_data); static CalRecurrence * cal_recur_from_icalproperty (icalproperty *prop, - gboolean exception); + gboolean exception, + icaltimezone *zone); static gint cal_recur_ical_weekday_to_weekday (enum icalrecurrencetype_weekday day); static void cal_recur_free (CalRecurrence *r); @@ -276,6 +282,7 @@ static void cal_object_compute_duration (CalObjTime *start, static gboolean generate_instances_for_chunk (CalComponent *comp, time_t comp_dtstart, + icaltimezone *zone, GSList *rrules, GSList *rdates, GSList *exrules, @@ -291,6 +298,7 @@ static gboolean generate_instances_for_chunk (CalComponent *comp, gpointer cb_data); static GArray* cal_obj_expand_recurrence (CalObjTime *event_start, + icaltimezone *zone, CalRecurrence *recur, CalObjTime *interval_start, CalObjTime *interval_end, @@ -458,11 +466,10 @@ static gint cal_obj_time_day_of_year (CalObjTime *cotime); static void cal_obj_time_find_first_week (CalObjTime *cotime, RecurData *recur_data); static void cal_object_time_from_time (CalObjTime *cotime, - time_t t); -#if 0 -static gint cal_obj_date_only_compare_func (const void *arg1, - const void *arg2); -#endif + time_t t, + icaltimezone *zone); +static gint cal_obj_date_only_compare_func (const void *arg1, + const void *arg2); @@ -722,13 +729,14 @@ cal_recur_generate_instances_of_rule (CalComponent *comp, /* Convert the interval start & end to CalObjTime. Note that if end is -1 interval_end won't be set, so don't use it! Also note that we use end - 1 since we want the interval to be - inclusive as it makes the code simpler. */ - cal_object_time_from_time (&interval_start, start); + inclusive as it makes the code simpler. We do all calculation + in the timezone of the DTSTART. */ + cal_object_time_from_time (&interval_start, start, start_zone); if (end != -1) - cal_object_time_from_time (&interval_end, end - 1); + cal_object_time_from_time (&interval_end, end - 1, start_zone); - cal_object_time_from_time (&event_start, dtstart_time); - cal_object_time_from_time (&event_end, dtend_time); + cal_object_time_from_time (&event_start, dtstart_time, start_zone); + cal_object_time_from_time (&event_end, dtend_time, start_zone); /* Calculate the duration of the event, which we use for all occurrences. We can't just subtract start from end since that may @@ -776,10 +784,11 @@ cal_recur_generate_instances_of_rule (CalComponent *comp, chunk_end.hour = 23; chunk_end.minute = 59; chunk_end.second = 61; - chunk_end.is_rdate = FALSE; + chunk_end.flags = FALSE; } if (!generate_instances_for_chunk (comp, dtstart_time, + start_zone, rrules, rdates, exrules, exdates, single_rule, @@ -820,6 +829,8 @@ array_to_list (short *array, int max_elements) /** * cal_recur_from_icalproperty: * @ir: An RRULE or EXRULE #icalproperty. + * @zone: The DTSTART timezone, used for converting the UNTIL property if it + * is given as a DATE value. * * Converts an #icalproperty to a #CalRecurrence. This should be * freed using the cal_recur_free() function. @@ -827,7 +838,8 @@ array_to_list (short *array, int max_elements) * Return value: #CalRecurrence structure. **/ static CalRecurrence * -cal_recur_from_icalproperty (icalproperty *prop, gboolean exception) +cal_recur_from_icalproperty (icalproperty *prop, gboolean exception, + icaltimezone *zone) { struct icalrecurrencetype ir; CalRecurrence *r; @@ -846,16 +858,31 @@ cal_recur_from_icalproperty (icalproperty *prop, gboolean exception) r->interval = ir.interval; if (ir.count != 0) { + /* If COUNT is set, we use the pre-calculated enddate. */ r->enddate = cal_recur_get_rule_end_date (prop); } else { - /* FIXME: icaltime_as_timet() seems to return -1 if UNTIL isn't - set, but a simpler test would be better. */ - r->enddate = icaltime_as_timet (ir.until); - if (r->enddate == -1) + if (icaltime_is_null_time (ir.until)) { + /* If neither COUNT or UNTIL is set, the event + recurs forever. */ r->enddate = 0; - else if (ir.until.is_date) - /* FIXME: Decide what to do here. */ - r->enddate = time_add_day (r->enddate, 1) - 1; + } else if (ir.until.is_date) { + /* If UNTIL is a DATE, we stop at the end of + the day, in local time (with the DTSTART timezone). + Note that UNTIL is inclusive so we stop before + midnight. */ + ir.until.hour = 23; + ir.until.minute = 59; + ir.until.second = 59; + + r->enddate = icaltime_as_timet_with_zone (ir.until, + zone); + } else { + /* If UNTIL is a DATE-TIME, it must be in UTC. */ + icaltimezone *utc_zone; + utc_zone = icaltimezone_get_utc_timezone (); + r->enddate = icaltime_as_timet_with_zone (ir.until, + utc_zone); + } } r->week_start_day = cal_recur_ical_weekday_to_weekday (ir.week_start); @@ -984,6 +1011,7 @@ cal_recur_free (CalRecurrence *r) static gboolean generate_instances_for_chunk (CalComponent *comp, time_t comp_dtstart, + icaltimezone *zone, GSList *rrules, GSList *rdates, GSList *exrules, @@ -1003,7 +1031,7 @@ generate_instances_for_chunk (CalComponent *comp, GSList *elem; gint i; time_t start_time, end_time; - struct tm start_tm, end_tm; + struct icaltimetype start_tt, end_tt; gboolean cb_status = TRUE, rule_finished, finished = TRUE; #if 0 @@ -1041,9 +1069,9 @@ generate_instances_for_chunk (CalComponent *comp, CalRecurrence *r; prop = elem->data; - r = cal_recur_from_icalproperty (prop, FALSE); + r = cal_recur_from_icalproperty (prop, FALSE, zone); - tmp_occs = cal_obj_expand_recurrence (event_start, r, + tmp_occs = cal_obj_expand_recurrence (event_start, zone, r, chunk_start, chunk_end, &rule_finished); @@ -1058,16 +1086,26 @@ generate_instances_for_chunk (CalComponent *comp, g_array_free (tmp_occs, TRUE); } - /* Add on specific occurrence dates, flag them as RDATEs, and store - a pointer to the period in the rdate_periods array. */ + /* Add on specific RDATE occurrence dates. If they have an end time + or duration set, flag them as RDATEs, and store a pointer to the + period in the rdate_periods array. Otherwise we can just treat them + as normal occurrences. */ for (elem = rdates; elem; elem = elem->next) { CalComponentPeriod *p; CalObjRecurrenceDate rdate; - time_t t; p = elem->data; - t = icaltime_as_timet (p->start); - cal_object_time_from_time (&cotime, t); + + /* FIXME: We currently assume RDATEs are in the same timezone + as DTSTART. We should get the RDATE timezone and convert + to the DTSTART timezone first. */ + cotime.year = p->start.year; + cotime.month = p->start.month - 1; + cotime.day = p->start.day; + cotime.hour = p->start.hour; + cotime.minute = p->start.minute; + cotime.second = p->start.second; + cotime.flags = FALSE; /* If the rdate is after the current chunk we set finished to FALSE, and we skip it. */ @@ -1078,10 +1116,11 @@ generate_instances_for_chunk (CalComponent *comp, /* Check if the end date or duration is set. If it is we need to store it so we can get it later. (libical seems to set - second to -1 to denote an unset time. See icalvalue.c) */ + second to -1 to denote an unset time. See icalvalue.c) + FIXME. */ if (p->type != CAL_COMPONENT_PERIOD_DATETIME || p->u.end.second != -1) { - cotime.is_rdate = TRUE; + cotime.flags = TRUE; rdate.start = cotime; rdate.period = p; @@ -1097,9 +1136,9 @@ generate_instances_for_chunk (CalComponent *comp, CalRecurrence *r; prop = elem->data; - r = cal_recur_from_icalproperty (prop, FALSE); + r = cal_recur_from_icalproperty (prop, FALSE, zone); - tmp_occs = cal_obj_expand_recurrence (event_start, r, + tmp_occs = cal_obj_expand_recurrence (event_start, zone, r, chunk_start, chunk_end, &rule_finished); @@ -1112,16 +1151,30 @@ generate_instances_for_chunk (CalComponent *comp, /* Add on specific exception dates. */ for (elem = exdates; elem; elem = elem->next) { CalComponentDateTime *cdt; - time_t t; - - /* FIXME we should only be dealing with dates, not times too. - No, I think it is supposed to be dates & times - Damon. - I'm not sure what the semantics of just a date would be, - since the event could recur several times each day. */ cdt = elem->data; - t = icaltime_as_timet (*cdt->value); - cal_object_time_from_time (&cotime, t); + + /* FIXME: We currently assume EXDATEs are in the same timezone + as DTSTART. We should get the EXDATE timezone and convert + to the DTSTART timezone first. */ + cotime.year = cdt->value->year; + cotime.month = cdt->value->month - 1; + cotime.day = cdt->value->day; + + /* If the EXDATE has a DATE value, set the time to the start + of the day and set flags to TRUE so we know to skip all + occurrences on that date. */ + if (cdt->value->is_date) { + cotime.hour = 0; + cotime.minute = 0; + cotime.second = 0; + cotime.flags = TRUE; + } else { + cotime.hour = cdt->value->hour; + cotime.minute = cdt->value->minute; + cotime.second = cdt->value->second; + cotime.flags = FALSE; + } g_array_append_val (ex_occs, cotime); } @@ -1148,17 +1201,17 @@ generate_instances_for_chunk (CalComponent *comp, g_print ("Checking occurrence: %s\n", cal_obj_time_to_string (occ)); #endif - start_tm.tm_year = occ->year - 1900; - start_tm.tm_mon = occ->month; - start_tm.tm_mday = occ->day; - start_tm.tm_hour = occ->hour; - start_tm.tm_min = occ->minute; - start_tm.tm_sec = occ->second; - start_tm.tm_isdst = -1; - start_time = mktime (&start_tm); + start_tt.year = occ->year; + start_tt.month = occ->month + 1; + start_tt.day = occ->day; + start_tt.hour = occ->hour; + start_tt.minute = occ->minute; + start_tt.second = occ->second; + start_tt.is_daylight = -1; + start_time = icaltime_as_timet_with_zone (start_tt, zone); if (start_time == -1) { - g_warning ("mktime failed - time_t out of range?"); + g_warning ("time_t out of range"); finished = TRUE; break; } @@ -1177,7 +1230,10 @@ generate_instances_for_chunk (CalComponent *comp, continue; } - if (occ->is_rdate) { + if (occ->flags) { + /* If it is an RDATE, we see if the end date or + duration was set. If not, we use the same duration + as the original occurrence. */ if (!cal_object_get_rdate_end (occ, rdate_periods)) { cal_obj_time_add_days (occ, duration_days); cal_obj_time_add_seconds (occ, @@ -1188,17 +1244,17 @@ generate_instances_for_chunk (CalComponent *comp, cal_obj_time_add_seconds (occ, duration_seconds); } - end_tm.tm_year = occ->year - 1900; - end_tm.tm_mon = occ->month; - end_tm.tm_mday = occ->day; - end_tm.tm_hour = occ->hour; - end_tm.tm_min = occ->minute; - end_tm.tm_sec = occ->second; - end_tm.tm_isdst = -1; - end_time = mktime (&end_tm); + end_tt.year = occ->year; + end_tt.month = occ->month + 1; + end_tt.day = occ->day; + end_tt.hour = occ->hour; + end_tt.minute = occ->minute; + end_tt.second = occ->second; + end_tt.is_daylight = -1; + end_time = icaltime_as_timet_with_zone (end_tt, zone); if (end_time == -1) { - g_warning ("mktime failed - time_t out of range?"); + g_warning ("time_t out of range"); finished = TRUE; break; } @@ -1238,7 +1294,6 @@ cal_object_get_rdate_end (CalObjTime *occ, CalObjRecurrenceDate *rdate = NULL; CalComponentPeriod *p; gint lower, upper, middle, cmp = 0; - time_t t; lower = 0; upper = rdate_periods->len; @@ -1267,8 +1322,16 @@ cal_object_get_rdate_end (CalObjTime *occ, p = rdate->period; if (p->type == CAL_COMPONENT_PERIOD_DATETIME) { - t = icaltime_as_timet (p->u.end); - cal_object_time_from_time (occ, t); + /* FIXME: We currently assume RDATEs are in the same timezone + as DTSTART. We should get the RDATE timezone and convert + to the DTSTART timezone first. */ + occ->year = p->u.end.year; + occ->month = p->u.end.month - 1; + occ->day = p->u.end.day; + occ->hour = p->u.end.hour; + occ->minute = p->u.end.minute; + occ->second = p->u.end.second; + occ->flags = FALSE; } else { cal_obj_time_add_days (occ, p->u.duration.weeks * 7 + p->u.duration.days); @@ -1319,6 +1382,7 @@ cal_object_compute_duration (CalObjTime *start, after the given interval.*/ static GArray* cal_obj_expand_recurrence (CalObjTime *event_start, + icaltimezone *zone, CalRecurrence *recur, CalObjTime *interval_start, CalObjTime *interval_end, @@ -1346,7 +1410,7 @@ cal_obj_expand_recurrence (CalObjTime *event_start, /* Compute the event_end, if the recur's enddate is set. */ if (recur->enddate > 0) { cal_object_time_from_time (&event_end_cotime, - recur->enddate); + recur->enddate, zone); event_end = &event_end_cotime; /* If the enddate is before the requested interval return. */ @@ -1653,7 +1717,7 @@ static CalRecurVTable* cal_obj_get_vtable (icalrecurrencetype_frequency recur_ty vtable = &cal_obj_secondly_vtable; break; default: - g_warning ("Unknown recurrence frequenct"); + g_warning ("Unknown recurrence frequency"); vtable = NULL; } @@ -1836,15 +1900,15 @@ cal_obj_remove_exceptions (GArray *occs, && cal_obj_time_compare_func (occ, prev_occ) == 0) { keep_occ = FALSE; - /* If this occurrence is an RDATE, and the previous - occurrence in the array was kept, set the RDATE flag - of the last one, so we still use the end date - or duration. */ - if (occ->is_rdate && !current_time_is_exception) { + /* If this occurrence is an RDATE with an end or + duration set, and the previous occurrence in the + array was kept, set the RDATE flag of the last one, + so we still use the end date or duration. */ + if (occ->flags && !current_time_is_exception) { last_occ_kept = &g_array_index (occs, CalObjTime, j - 1); - last_occ_kept->is_rdate = TRUE; + last_occ_kept->flags = TRUE; } } else { /* We've found a new occurrence time. Reset the flag @@ -1857,9 +1921,14 @@ cal_obj_remove_exceptions (GArray *occs, to one that matches or follows this occurrence. */ while (ex_occ) { - cmp = cal_obj_time_compare_func (ex_occ, occ); - /* I'm pretty sure this is wrong. */ - /*cmp = cal_obj_date_only_compare_func (ex_occ, occ);*/ + /* If the exception is an EXDATE with + a DATE value, we only have to + compare the date. */ + if (ex_occ->flags) + cmp = cal_obj_date_only_compare_func (ex_occ, occ); + else + cmp = cal_obj_time_compare_func (ex_occ, occ); + if (cmp > 0) break; @@ -1886,6 +1955,10 @@ cal_obj_remove_exceptions (GArray *occs, } if (keep_occ) { + /* We are keeping this occurrence, so we move it to + the next free space, unless its position hasn't + changed (i.e. all previous occurrences were also + kept). */ if (i != j) g_array_index (occs, CalObjTime, j) = g_array_index (occs, CalObjTime, i); @@ -3465,7 +3538,7 @@ cal_obj_time_compare_func (const void *arg1, return retval; } -#if 0 + static gint cal_obj_date_only_compare_func (const void *arg1, const void *arg2) @@ -3492,7 +3565,7 @@ cal_obj_date_only_compare_func (const void *arg1, return 0; } -#endif + /* Returns the weekday of the given CalObjTime, from 0 (Mon) - 6 (Sun). */ static gint @@ -3590,23 +3663,21 @@ cal_obj_time_find_first_week (CalObjTime *cotime, static void -cal_object_time_from_time (CalObjTime *cotime, - time_t t) +cal_object_time_from_time (CalObjTime *cotime, + time_t t, + icaltimezone *zone) { - struct tm *tmp_tm; - time_t tmp_time_t; + struct icaltimetype tt; - tmp_time_t = t; - /* FIXME */ - tmp_tm = localtime (&tmp_time_t); + tt = icaltime_from_timet_with_zone (t, FALSE, zone); - cotime->year = tmp_tm->tm_year + 1900; - cotime->month = tmp_tm->tm_mon; - cotime->day = tmp_tm->tm_mday; - cotime->hour = tmp_tm->tm_hour; - cotime->minute = tmp_tm->tm_min; - cotime->second = tmp_tm->tm_sec; - cotime->is_rdate = FALSE; + cotime->year = tt.year; + cotime->month = tt.month - 1; + cotime->day = tt.day; + cotime->hour = tt.hour; + cotime->minute = tt.minute; + cotime->second = tt.second; + cotime->flags = FALSE; } @@ -3746,6 +3817,7 @@ cal_recur_get_rule_end_date (icalproperty *prop) const char *xname, *xvalue; icalvalue *value; struct icaltimetype icaltime; + icaltimezone *utc_zone; param = icalproperty_get_first_parameter (prop, ICAL_X_PARAMETER); while (param) { @@ -3758,7 +3830,9 @@ cal_recur_get_rule_end_date (icalproperty *prop) icaltime = icalvalue_get_datetime (value); icalvalue_free (value); - return icaltime_as_timet (icaltime); + utc_zone = icaltimezone_get_utc_timezone (); + return icaltime_as_timet_with_zone (icaltime, + utc_zone); } } @@ -3776,10 +3850,13 @@ cal_recur_set_rule_end_date (icalproperty *prop, { icalparameter *param; icalvalue *value; + icaltimezone *utc_zone; struct icaltimetype icaltime; const char *end_date_string, *xname; - icaltime = icaltime_from_timet (end_date, FALSE); + /* We save the value as a UTC DATE-TIME. */ + utc_zone = icaltimezone_get_utc_timezone (); + icaltime = icaltime_from_timet_with_zone (end_date, FALSE, utc_zone); value = icalvalue_new_datetime (icaltime); end_date_string = icalvalue_as_ical_string (value); icalvalue_free (value); diff --git a/calendar/cal-util/timeutil.c b/calendar/cal-util/timeutil.c index 3bb254dbf7..eb68376449 100644 --- a/calendar/cal-util/timeutil.c +++ b/calendar/cal-util/timeutil.c @@ -2,10 +2,10 @@ * * Copyright (C) 1998 The Free Software Foundation * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 2000 Ximian, Inc. * * Authors: Federico Mena <federico@ximian.com> * Miguel de Icaza <miguel@ximian.com> + * Damon Chaplin <damon@ximian.com> */ #include <string.h> @@ -16,108 +16,36 @@ -void -print_time_t (time_t t) -{ - struct tm *tm = localtime (&t); - - printf ("%d/%02d/%02d %02d:%02d:%02d", - 1900 + tm->tm_year, tm->tm_mon+1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); -} - -/** - * isodate_from_time_t: - * @t: A time value. - * - * Creates an ISO 8601 local time representation from a time value. - * - * Return value: String with the ISO 8601 representation of the local time. - **/ -char * -isodate_from_time_t (time_t t) -{ - struct tm *tm; - char isotime[40]; - - tm = gmtime (&t); - strftime (isotime, sizeof (isotime)-1, "%Y%m%dT%H%M%SZ", tm); - return g_strdup (isotime); -} - -/** - * time_from_isodate: - * @str: Date/time value in ISO 8601 format. - * - * Converts an ISO 8601 time string into a time_t value. - * - * Return value: Time_t corresponding to the specified ISO string. - * Note that we only allow UTC times at present. - **/ -time_t -time_from_isodate (const char *str) -{ - int len; - struct tm my_tm; - time_t t; - int i; - char *old_tz; - - g_return_val_if_fail (str != NULL, -1); - - /* yyyymmdd[Thhmmss[Z]] */ - - len = strlen (str); +#define REFORMATION_DAY 639787 /* First day of the reformation, counted from 1 Jan 1 */ +#define MISSING_DAYS 11 /* They corrected out 11 days */ +#define THURSDAY 4 /* First day of reformation */ +#define SATURDAY 6 /* Offset value; 1 Jan 1 was a Saturday */ - if (!(len == 8 || len == 15 || len == 16)) - return -1; - for (i = 0; i < len; i++) - if (!((i != 8 && i != 15 && isdigit (str[i])) - || (i == 8 && str[i] == 'T') - || (i == 15 && str[i] == 'Z'))) - return -1; - - memset (&my_tm, 0, sizeof (my_tm)); - -#define digit_at(x,y) (x[y] - '0') - - my_tm.tm_year = (digit_at (str, 0) * 1000 + digit_at (str, 1) * 100 + - digit_at (str, 2) * 10 + digit_at (str, 3)) - 1900; - - my_tm.tm_mon = digit_at (str, 4) * 10 + digit_at (str, 5) - 1; - my_tm.tm_mday = digit_at (str, 6) * 10 + digit_at (str, 7); - - if (len > 8) { - my_tm.tm_hour = digit_at (str, 9) * 10 + digit_at (str, 10); - my_tm.tm_min = digit_at (str, 11) * 10 + digit_at (str, 12); - my_tm.tm_sec = digit_at (str, 13) * 10 + digit_at (str, 14); - } +/* Number of days in a month, using 0 (Jan) to 11 (Dec). For leap years, + add 1 to February (month 1). */ +static const int days_in_month[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; - my_tm.tm_isdst = -1; - old_tz = set_tz ("UTC"); - t = mktime (&my_tm); - unset_tz (old_tz); - return t; -} +/************************************************************************** + * time_t manipulation functions. + * + * NOTE: these use the Unix timezone functions like mktime() and localtime() + * and so should not be used in Evolution. New Evolution code should use + * icaltimetype values rather than time_t values wherever possible. + **************************************************************************/ -time_t -time_add_minutes (time_t time, int minutes) +static void +print_time_t (time_t t) { - struct tm *tm = localtime (&time); - time_t new_time; - - tm->tm_min += minutes; - if ((new_time = mktime (tm)) == -1) { - g_message ("time_add_minutes(): mktime() could not handle " - "adding %d minutes with\n", minutes); - print_time_t (time); - printf ("\n"); - return time; - } - return new_time; + struct tm *tm = localtime (&t); + + printf ("%d/%02d/%02d %02d:%02d:%02d", + 1900 + tm->tm_year, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); } /* Adds a day onto the time, using local time. @@ -132,9 +60,6 @@ time_add_day (time_t time, int days) { struct tm *tm = localtime (&time); time_t new_time; -#if 0 - int dst_flag = tm->tm_isdst; -#endif tm->tm_mday += days; tm->tm_isdst = -1; @@ -147,18 +72,6 @@ time_add_day (time_t time, int days) return time; } -#if 0 - /* I don't know what this is for. See also time_day_begin() and - time_day_end(). - Damon. */ - if (dst_flag > tm->tm_isdst) { - tm->tm_hour++; - new_time += 3600; - } else if (dst_flag < tm->tm_isdst) { - tm->tm_hour--; - new_time -= 3600; - } -#endif - return new_time; } @@ -197,63 +110,23 @@ time_add_month (time_t time, int months) } time_t -time_add_year (time_t time, int years) -{ - struct tm *tm = localtime (&time); - time_t new_time; - - tm->tm_year += years; - if ((new_time = mktime (tm)) == -1) { - g_message ("time_add_year(): mktime() could not handling adding %d years with\n", - years); - print_time_t (time); - printf ("\n"); - return time; - } - return new_time; -} - -/* Number of days in a month, for normal and leap years */ -static const int days_in_month[2][12] = { - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } -}; - -/* Returns whether the specified year is a leap year */ -static int -is_leap_year (int year) -{ - if (year <= 1752) - return !(year % 4); - else - return (!(year % 4) && (year % 100)) || !(year % 400); -} - -int -time_days_in_month (int year, int month) -{ - g_return_val_if_fail (year >= 1900, 0); - g_return_val_if_fail ((month >= 0) && (month < 12), 0); - - return days_in_month [is_leap_year (year)][month]; -} - -time_t -time_from_day (int year, int month, int day) +time_year_begin (time_t t) { struct tm tm; - memset (&tm, 0, sizeof (tm)); - tm.tm_year = year - 1900; - tm.tm_mon = month; - tm.tm_mday = day; + tm = *localtime (&t); + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + tm.tm_mon = 0; + tm.tm_mday = 1; tm.tm_isdst = -1; return mktime (&tm); } time_t -time_year_begin (time_t t) +time_month_begin (time_t t) { struct tm tm; @@ -261,32 +134,37 @@ time_year_begin (time_t t) tm.tm_hour = 0; tm.tm_min = 0; tm.tm_sec = 0; - tm.tm_mon = 0; tm.tm_mday = 1; tm.tm_isdst = -1; return mktime (&tm); } +/* Returns the start of the week. week_start_day should use the same values + as mktime(), i.e. 0 (Sun) to 6 (Sat). */ time_t -time_year_end (time_t t) +time_week_begin (time_t t, int week_start_day) { struct tm tm; + int offset; tm = *localtime (&t); + + /* Calculate the current offset from the week start day. */ + offset = (tm.tm_wday + 7 - week_start_day) % 7; + tm.tm_hour = 0; tm.tm_min = 0; tm.tm_sec = 0; - tm.tm_mon = 0; - tm.tm_mday = 1; - tm.tm_year++; + tm.tm_mday -= offset; tm.tm_isdst = -1; return mktime (&tm); } +/* Returns the start of the day, according to the local time. */ time_t -time_month_begin (time_t t) +time_day_begin (time_t t) { struct tm tm; @@ -294,99 +172,397 @@ time_month_begin (time_t t) tm.tm_hour = 0; tm.tm_min = 0; tm.tm_sec = 0; - tm.tm_mday = 1; tm.tm_isdst = -1; return mktime (&tm); } +/* Returns the end of the day, according to the local time. */ time_t -time_month_end (time_t t) +time_day_end (time_t t) { struct tm tm; tm = *localtime (&t); + tm.tm_mday++; tm.tm_hour = 0; tm.tm_min = 0; tm.tm_sec = 0; - tm.tm_mday = 1; - tm.tm_mon++; tm.tm_isdst = -1; return mktime (&tm); } -/* Returns the start of the week. week_start_day should use the same values - as mktime(), i.e. 0 (Sun) to 6 (Sat). */ + +/************************************************************************** + * time_t manipulation functions, using timezones in libical. + * + * NOTE: these are only here to make the transition to the timezone + * functions easier. New code should use icaltimetype values rather than + * time_t values wherever possible. + **************************************************************************/ + + +/* Adds or subtracts a number of days to/from the given time_t value, using + the given timezone. + NOTE: this function is only here to make the transition to the timezone + functions easier. New code should use icaltimetype values and + icaltime_adjust() to add or subtract days, hours, minutes & seconds. */ time_t -time_week_begin (time_t t, int week_start_day) +time_add_day_with_zone (time_t time, int days, icaltimezone *zone) { - struct tm tm; - int offset; + struct icaltimetype tt; - tm = *localtime (&t); + /* Convert to an icaltimetype. */ + tt = icaltime_from_timet_with_zone (time, FALSE, zone); - /* Calculate the current offset from the week start day. */ - offset = (tm.tm_wday + 7 - week_start_day) % 7; + /* Add/subtract the number of days. */ + icaltime_adjust (&tt, days, 0, 0, 0); - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_mday -= offset; - tm.tm_isdst = -1; + /* Convert back to a time_t. */ + return icaltime_as_timet_with_zone (tt, zone); +} - return mktime (&tm); + +/* Adds or subtracts a number of weeks to/from the given time_t value, using + the given timezone. + NOTE: this function is only here to make the transition to the timezone + functions easier. New code should use icaltimetype values and + icaltime_adjust() to add or subtract days, hours, minutes & seconds. */ +time_t +time_add_week_with_zone (time_t time, int weeks, icaltimezone *zone) +{ + return time_add_day_with_zone (time, weeks * 7, zone); } -/* Returns the end of the week. week_start_day should use the same values - as mktime(), i.e. 0 (Sun) to 6 (Sat). */ + +/* Adds or subtracts a number of months to/from the given time_t value, using + the given timezone. + NOTE: this function is only here to make the transition to the timezone + functions easier. New code should use icaltimetype values and + icaltime_adjust() to add or subtract days, hours, minutes & seconds. */ time_t -time_week_end (time_t t, int week_start_day) +time_add_month_with_zone (time_t time, int months, icaltimezone *zone) { - struct tm tm; - int offset; + struct icaltimetype tt; - tm = *localtime (&t); + /* Convert to an icaltimetype. */ + tt = icaltime_from_timet_with_zone (time, FALSE, zone); + + /* Add on the number of months. */ + tt.month += months; + + /* Normalize it, fixing any overflow. */ + tt = icaltime_normalize (tt); + + /* Convert back to a time_t. */ + return icaltime_as_timet_with_zone (tt, zone); +} + + +/* Returns the start of the year containing the given time_t, using the given + timezone. + NOTE: this function is only here to make the transition to the timezone + functions easier. New code should use icaltimetype values and + icaltime_adjust() to add or subtract days, hours, minutes & seconds. */ +time_t +time_year_begin_with_zone (time_t time, icaltimezone *zone) +{ + struct icaltimetype tt; + + /* Convert to an icaltimetype. */ + tt = icaltime_from_timet_with_zone (time, FALSE, zone); + + /* Set it to the start of the year. */ + tt.month = 1; + tt.day = 1; + tt.hour = 0; + tt.minute = 0; + tt.second = 0; + tt.is_daylight = -1; + + /* Convert back to a time_t. */ + return icaltime_as_timet_with_zone (tt, zone); +} + + +/* Returns the start of the month containing the given time_t, using the given + timezone. + NOTE: this function is only here to make the transition to the timezone + functions easier. New code should use icaltimetype values and + icaltime_adjust() to add or subtract days, hours, minutes & seconds. */ +time_t +time_month_begin_with_zone (time_t time, icaltimezone *zone) +{ + struct icaltimetype tt; + + /* Convert to an icaltimetype. */ + tt = icaltime_from_timet_with_zone (time, FALSE, zone); + + /* Set it to the start of the month. */ + tt.day = 1; + tt.hour = 0; + tt.minute = 0; + tt.second = 0; + tt.is_daylight = -1; + + /* Convert back to a time_t. */ + return icaltime_as_timet_with_zone (tt, zone); +} + + +/* Returns the start of the week containing the given time_t, using the given + timezone. week_start_day should use the same values as mktime(), + i.e. 0 (Sun) to 6 (Sat). + NOTE: this function is only here to make the transition to the timezone + functions easier. New code should use icaltimetype values and + icaltime_adjust() to add or subtract days, hours, minutes & seconds. */ +time_t +time_week_begin_with_zone (time_t time, int week_start_day, icaltimezone *zone) +{ + struct icaltimetype tt; + int weekday, offset; + + /* Convert to an icaltimetype. */ + tt = icaltime_from_timet_with_zone (time, FALSE, zone); + + /* Get the weekday. */ + weekday = time_day_of_week (tt.day, tt.month - 1, tt.year); /* Calculate the current offset from the week start day. */ - offset = (tm.tm_wday + 7 - week_start_day) % 7; + offset = (weekday + 7 - week_start_day) % 7; - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_mday += 7 - offset; - tm.tm_isdst = -1; + /* Set it to the start of the month. */ + tt.day -= offset; + tt.hour = 0; + tt.minute = 0; + tt.second = 0; + tt.is_daylight = -1; - return mktime (&tm); + /* Normalize it, to fix any overflow. */ + tt = icaltime_normalize (tt); + + /* Convert back to a time_t. */ + return icaltime_as_timet_with_zone (tt, zone); } -/* Returns the start of the day, according to the local time. */ + +/* Returns the start of the day containing the given time_t, using the given + timezone. + NOTE: this function is only here to make the transition to the timezone + functions easier. New code should use icaltimetype values and + icaltime_adjust() to add or subtract days, hours, minutes & seconds. */ time_t -time_day_begin (time_t t) +time_day_begin_with_zone (time_t time, icaltimezone *zone) { - struct tm tm; + struct icaltimetype tt; - tm = *localtime (&t); - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_isdst = -1; + /* Convert to an icaltimetype. */ + tt = icaltime_from_timet_with_zone (time, FALSE, zone); - return mktime (&tm); + /* Set it to the start of the day. */ + tt.hour = 0; + tt.minute = 0; + tt.second = 0; + tt.is_daylight = -1; + + /* Convert back to a time_t. */ + return icaltime_as_timet_with_zone (tt, zone); } -/* Returns the end of the day, according to the local time. */ + +/* Returns the end of the day containing the given time_t, using the given + timezone. (The end of the day is the start of the next day.) + NOTE: this function is only here to make the transition to the timezone + functions easier. New code should use icaltimetype values and + icaltime_adjust() to add or subtract days, hours, minutes & seconds. */ time_t -time_day_end (time_t t) +time_day_end_with_zone (time_t time, icaltimezone *zone) { - struct tm tm; + struct icaltimetype tt; - tm = *localtime (&t); - tm.tm_mday++; - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_isdst = -1; + /* Convert to an icaltimetype. */ + tt = icaltime_from_timet_with_zone (time, FALSE, zone); - return mktime (&tm); + /* Set it to the start of the next day. */ + tt.day++; + tt.hour = 0; + tt.minute = 0; + tt.second = 0; + tt.is_daylight = -1; + + /* Normalize it, to fix any overflow. */ + tt = icaltime_normalize (tt); + + /* Convert back to a time_t. */ + return icaltime_as_timet_with_zone (tt, zone); } + + +/************************************************************************** + * General time functions. + **************************************************************************/ + + +/* Returns the number of days in the month. Year is the normal year, e.g. 2001. + Month is 0 (Jan) to 11 (Dec). */ +int +time_days_in_month (int year, int month) +{ + int days; + + g_return_val_if_fail (year >= 1900, 0); + g_return_val_if_fail ((month >= 0) && (month < 12), 0); + + days = days_in_month[month]; + if (month == 1 && time_is_leap_year (year)) + days++; + + return days; +} + + +/* Returns the 1-based day number within the year of the specified date. + Year is the normal year, e.g. 2001. Month is 0 to 11. */ +int +time_day_of_year (int day, int month, int year) +{ + int i; + + for (i = 0; i < month; i++) { + day += days_in_month[i]; + + if (month == 1 && time_is_leap_year (year)) + day++; + } + + return day; +} + + +/* Returns the day of the week for the specified date, 0 (Sun) to 6 (Sat). + For the days that were removed on the Gregorian reformation, it returns + Thursday. Year is the normal year, e.g. 2001. Month is 0 to 11. */ +int +time_day_of_week (int day, int month, int year) +{ + int n; + + n = (year - 1) * 365 + time_leap_years_up_to (year - 1) + + time_day_of_year (day, month, year); + + if (n < REFORMATION_DAY) + return (n - 1 + SATURDAY) % 7; + + if (n >= (REFORMATION_DAY + MISSING_DAYS)) + return (n - 1 + SATURDAY - MISSING_DAYS) % 7; + + return THURSDAY; +} + + +/* Returns whether the specified year is a leap year. Year is the normal year, + e.g. 2001. */ +gboolean +time_is_leap_year (int year) +{ + if (year <= 1752) + return !(year % 4); + else + return (!(year % 4) && (year % 100)) || !(year % 400); +} + + +/* Returns the number of leap years since year 1 up to (but not including) the + specified year. Year is the normal year, e.g. 2001. */ +int +time_leap_years_up_to (int year) +{ + /* There is normally a leap year every 4 years, except at the turn of + centuries since 1700. But there is a leap year on centuries since 1700 + which are divisible by 400. */ + return (year / 4 + - ((year > 1700) ? (year / 100 - 17) : 0) + + ((year > 1600) ? ((year - 1600) / 400) : 0)); +} + + +/** + * isodate_from_time_t: + * @t: A time value. + * + * Creates an ISO 8601 UTC representation from a time value. + * + * Return value: String with the ISO 8601 representation of the UTC time. + **/ +char * +isodate_from_time_t (time_t t) +{ + struct tm *tm; + char isotime[40]; + + tm = gmtime (&t); + strftime (isotime, sizeof (isotime)-1, "%Y%m%dT%H%M%SZ", tm); + return g_strdup (isotime); +} + +/** + * time_from_isodate: + * @str: Date/time value in ISO 8601 format. + * + * Converts an ISO 8601 UTC time string into a time_t value. + * + * Return value: Time_t corresponding to the specified ISO string. + * Note that we only allow UTC times at present. + **/ +time_t +time_from_isodate (const char *str) +{ + struct icaltimetype tt = icaltime_null_time (); + icaltimezone *utc_zone; + int len, i; + + g_return_val_if_fail (str != NULL, -1); + + /* yyyymmdd[Thhmmss[Z]] */ + + len = strlen (str); + + if (!(len == 8 || len == 15 || len == 16)) + return -1; + + for (i = 0; i < len; i++) + if (!((i != 8 && i != 15 && isdigit (str[i])) + || (i == 8 && str[i] == 'T') + || (i == 15 && str[i] == 'Z'))) + return -1; + +#define digit_at(x,y) (x[y] - '0') + + tt.year = digit_at (str, 0) * 1000 + + digit_at (str, 1) * 100 + + digit_at (str, 2) * 10 + + digit_at (str, 3); + + tt.month = digit_at (str, 4) * 10 + + digit_at (str, 5); + + tt.day = digit_at (str, 6) * 10 + + digit_at (str, 7); + + if (len > 8) { + tt.hour = digit_at (str, 9) * 10 + + digit_at (str, 10); + tt.minute = digit_at (str, 11) * 10 + + digit_at (str, 12); + tt.second = digit_at (str, 13) * 10 + + digit_at (str, 14); + } + + tt.is_daylight = -1; + + utc_zone = icaltimezone_get_utc_timezone (); + + return icaltime_as_timet_with_zone (tt, utc_zone); +} + diff --git a/calendar/cal-util/timeutil.h b/calendar/cal-util/timeutil.h index b01747ecfc..3679173572 100644 --- a/calendar/cal-util/timeutil.h +++ b/calendar/cal-util/timeutil.h @@ -2,10 +2,10 @@ * * Copyright (C) 1998 The Free Software Foundation * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 2000 Ximian, Inc. * * Authors: Federico Mena <federico@ximian.com> * Miguel de Icaza <miguel@ximian.com> + * Damon Chaplin <damon@ximian.com> */ #ifndef TIMEUTIL_H @@ -14,52 +14,107 @@ #include <time.h> #include <ical.h> +#include <glib.h> -char *isodate_from_time_t (time_t t); -time_t time_from_isodate (const char *str); +/************************************************************************** + * General time functions. + **************************************************************************/ -time_t time_add_minutes (time_t time, int minutes); -time_t time_add_day (time_t time, int days); -time_t time_add_week (time_t time, int weeks); -time_t time_add_month (time_t time, int months); -time_t time_add_year (time_t time, int years); +/* Returns the number of days in the month. Year is the normal year, e.g. 2001. + Month is 0 (Jan) to 11 (Dec). */ +int time_days_in_month (int year, int month); +/* Returns the 1-based day number within the year of the specified date. + Year is the normal year, e.g. 2001. Month is 0 to 11. */ +int time_day_of_year (int day, int month, int year); -/* Returns the number of days in the specified month. Years are full years - (starting from year 1). Months are in [0, 11]. */ -int time_days_in_month (int year, int month); +/* Returns the day of the week for the specified date, 0 (Sun) to 6 (Sat). + For the days that were removed on the Gregorian reformation, it returns + Thursday. Year is the normal year, e.g. 2001. Month is 0 to 11. */ +int time_day_of_week (int day, int month, int year); -/* Converts the specified date to a time_t at the start of the specified day. - Years are full years (starting from year 1). Months are in [0, 11]. - Days are 1-based. */ -time_t time_from_day (int year, int month, int day); +/* Returns whether the specified year is a leap year. Year is the normal year, + e.g. 2001. */ +gboolean time_is_leap_year (int year); -/* For the functions below, time ranges are considered to contain the start - time, but not the end time. */ +/* Returns the number of leap years since year 1 up to (but not including) the + specified year. Year is the normal year, e.g. 2001. */ +int time_leap_years_up_to (int year); -/* These two functions take a time value and return the beginning or end of - the corresponding year, respectively. */ -time_t time_year_begin (time_t t); -time_t time_year_end (time_t t); +/* Convert to or from an ISO 8601 representation of a time, in UTC, + e.g. "20010708T183000Z". */ +char *isodate_from_time_t (time_t t); +time_t time_from_isodate (const char *str); -/* These two functions take a time value and return the beginning or end of - the corresponding month, respectively. */ -time_t time_month_begin (time_t t); -time_t time_month_end (time_t t); -/* These functions take a time value and return the beginning or end of the - corresponding week, respectively. week_start_day should use the same values +/************************************************************************** + * time_t manipulation functions. + * + * NOTE: these use the Unix timezone functions like mktime() and localtime() + * and so should not be used in Evolution. New Evolution code should use + * icaltimetype values rather than time_t values wherever possible. + **************************************************************************/ + +/* Add or subtract a number of days, weeks or months. */ +time_t time_add_day (time_t time, int days); +time_t time_add_week (time_t time, int weeks); +time_t time_add_month (time_t time, int months); + +/* Returns the beginning of the year or month. */ +time_t time_year_begin (time_t t); +time_t time_month_begin (time_t t); + +/* Returns the beginning of the week. week_start_day should use the same values as mktime(), i.e. 0 (Sun) to 6 (Sat). */ -time_t time_week_begin (time_t t, int week_start_day); -time_t time_week_end (time_t t, int week_start_day); +time_t time_week_begin (time_t t, int week_start_day); -/* These two functions take a time value and return the beginning or end of - the corresponding day, respectively. */ -time_t time_day_begin (time_t t); -time_t time_day_end (time_t t); +/* Returns the beginning or end of the day. */ +time_t time_day_begin (time_t t); +time_t time_day_end (time_t t); -void print_time_t (time_t t); + +/************************************************************************** + * time_t manipulation functions, using timezones in libical. + * + * NOTE: these are only here to make the transition to the timezone + * functions easier. New code should use icaltimetype values rather than + * time_t values wherever possible. + **************************************************************************/ + +/* Adds or subtracts a number of days to/from the given time_t value, using + the given timezone. */ +time_t time_add_day_with_zone (time_t time, int days, icaltimezone *zone); + +/* Adds or subtracts a number of weeks to/from the given time_t value, using + the given timezone. */ +time_t time_add_week_with_zone (time_t time, int weeks, icaltimezone *zone); + +/* Adds or subtracts a number of months to/from the given time_t value, using + the given timezone. */ +time_t time_add_month_with_zone (time_t time, int months, icaltimezone *zone); + +/* Returns the start of the year containing the given time_t, using the given + timezone. */ +time_t time_year_begin_with_zone (time_t time, icaltimezone *zone); + +/* Returns the start of the month containing the given time_t, using the given + timezone. */ +time_t time_month_begin_with_zone (time_t time, icaltimezone *zone); + +/* Returns the start of the week containing the given time_t, using the given + timezone. week_start_day should use the same values as mktime(), + i.e. 0 (Sun) to 6 (Sat). */ +time_t time_week_begin_with_zone (time_t time, int week_start_day, + icaltimezone *zone); + +/* Returns the start of the day containing the given time_t, using the given + timezone. */ +time_t time_day_begin_with_zone (time_t time, icaltimezone *zone); + +/* Returns the end of the day containing the given time_t, using the given + timezone. (The end of the day is the start of the next day.) */ +time_t time_day_end_with_zone (time_t time, icaltimezone *zone); #endif diff --git a/calendar/gui/calendar-model.c b/calendar/gui/calendar-model.c index 6d1625238d..10e18b106d 100644 --- a/calendar/gui/calendar-model.c +++ b/calendar/gui/calendar-model.c @@ -328,6 +328,10 @@ get_time_t (CalendarModel *model, time_t *t, gboolean show_midnight) if (*t <= 0) { buffer[0] = '\0'; } else { + /* Note that although the property may be in a different + timezone, we convert it to the current timezone to display + it in the table. If the user actually edits the value, + it will be set to the current timezone. See set_datetime. */ tt = icaltime_from_timet_with_zone (*t, FALSE, model->priv->zone); tmp_tm.tm_year = tt.year - 1900; @@ -338,8 +342,8 @@ get_time_t (CalendarModel *model, time_t *t, gboolean show_midnight) tmp_tm.tm_sec = tt.second; tmp_tm.tm_isdst = -1; - /* Call mktime() to set the weekday. */ - mktime (&tmp_tm); + tmp_tm.tm_wday = time_day_of_week (tt.day, tt.month - 1, + tt.year); e_time_format_date_and_time (&tmp_tm, model->priv->use_24_hour_format, @@ -401,14 +405,13 @@ get_completed (CalendarModel *model, struct icaltimetype *completed; time_t t; - /* FIXME: COMPLETED is in UTC, but we probably want to show it in - the current timezone. */ - cal_component_get_completed (comp, &completed); if (!completed) t = 0; else { + /* Note that COMPLETED is stored in UTC, though we show it in + the current timezone. */ t = icaltime_as_timet_with_zone (*completed, icaltimezone_get_utc_timezone ()); cal_component_free_icaltimetype (completed); } @@ -424,8 +427,15 @@ get_and_free_datetime (CalendarModel *model, CalComponentDateTime dt) if (!dt.value) t = 0; - else - t = icaltime_as_timet (*dt.value); + else { + CalClientGetStatus status; + icaltimezone *zone; + + /* FIXME: TIMEZONES: Handle error. */ + status = cal_client_get_timezone (model->priv->client, dt.tzid, + &zone); + t = icaltime_as_timet_with_zone (*dt.value, zone); + } cal_component_free_datetime (&dt); @@ -601,7 +611,7 @@ is_complete (CalComponent *comp) * get_color() below. */ static gboolean -is_overdue (CalComponent *comp) +is_overdue (CalendarModel *model, CalComponent *comp) { CalComponentDateTime dt; gboolean retval; @@ -613,7 +623,9 @@ is_overdue (CalComponent *comp) if (!dt.value) retval = FALSE; else { - time_t t; + struct icaltimetype now_tt; + CalClientGetStatus status; + icaltimezone *zone; /* Second, is it already completed? */ @@ -624,9 +636,13 @@ is_overdue (CalComponent *comp) /* Third, are we overdue as of right now? */ - t = icaltime_as_timet (*dt.value); + /* Get the current time in the same timezone as the DUE date.*/ + /* FIXME: TIMEZONES: Handle error. */ + status = cal_client_get_timezone (model->priv->client, dt.tzid, + &zone); + now_tt = icaltime_current_time_with_zone (zone); - if (t <= time (NULL)) + if (icaltime_compare (*dt.value, now_tt) <= 0) retval = TRUE; else retval = FALSE; @@ -641,7 +657,7 @@ is_overdue (CalComponent *comp) /* Computes the color to be used to display a component */ static const char * -get_color (CalComponent *comp) +get_color (CalendarModel *model, CalComponent *comp) { CalComponentDateTime dt; const char *retval; @@ -653,8 +669,9 @@ get_color (CalComponent *comp) if (!dt.value) retval = NULL; else { - time_t t, t_now; - struct tm tm, tm_now; + struct icaltimetype now_tt; + CalClientGetStatus status; + icaltimezone *zone; /* Second, is it already completed? */ @@ -665,15 +682,13 @@ get_color (CalComponent *comp) /* Third, is it due today? */ - t = icaltime_as_timet (*dt.value); - tm = *localtime (&t); - - t_now = time (NULL); - tm_now = *localtime (&t_now); + /* Get the current time in the same timezone as the DUE date.*/ + /* FIXME: TIMEZONES: Handle error. */ + status = cal_client_get_timezone (model->priv->client, dt.tzid, + &zone); + now_tt = icaltime_current_time_with_zone (zone); - if (tm.tm_year == tm_now.tm_year - && tm.tm_mon == tm_now.tm_mon - && tm.tm_mday == tm_now.tm_mday) { + if (icaltime_compare_date_only (*dt.value, now_tt) == 0) { retval = calendar_config_get_tasks_due_today_color (); goto out; } @@ -683,7 +698,7 @@ get_color (CalComponent *comp) * immediately. */ - if (t <= t_now) + if (icaltime_compare (*dt.value, now_tt) <= 0) retval = calendar_config_get_tasks_overdue_color (); else retval = NULL; @@ -811,10 +826,10 @@ calendar_model_value_at (ETableModel *etm, int col, int row) return GINT_TO_POINTER (cal_component_has_recurrences (comp)); case CAL_COMPONENT_FIELD_OVERDUE: - return GINT_TO_POINTER (is_overdue (comp)); + return GINT_TO_POINTER (is_overdue (model, comp)); case CAL_COMPONENT_FIELD_COLOR: - return (void *) get_color (comp); + return (void *) get_color (model, comp); case CAL_COMPONENT_FIELD_STATUS: return get_status (comp); @@ -995,9 +1010,6 @@ set_completed (CalendarModel *model, CalComponent *comp, const char *value) struct tm tmp_tm; time_t t; - /* FIXME: COMPLETED is in UTC, but we probably want to show it in - the current timezone. */ - status = e_time_parse_date_and_time (value, &tmp_tm); if (status == E_TIME_PARSE_INVALID) { @@ -1005,7 +1017,20 @@ set_completed (CalendarModel *model, CalComponent *comp, const char *value) } else if (status == E_TIME_PARSE_NONE) { ensure_task_not_complete (comp); } else { - t = mktime (&tmp_tm); + struct icaltimetype itt = icaltime_null_time (); + + itt.year = tmp_tm.tm_year + 1900; + itt.month = tmp_tm.tm_mon + 1; + itt.day = tmp_tm.tm_mday; + itt.hour = tmp_tm.tm_hour; + itt.minute = tmp_tm.tm_min; + itt.second = tmp_tm.tm_sec; + itt.is_daylight = -1; + + /* We assume that COMPLETED is entered in the current timezone, + even though it gets stored in UTC. */ + t = icaltime_as_timet_with_zone (itt, model->priv->zone); + ensure_task_complete (comp, t); } } @@ -2171,7 +2196,6 @@ ensure_task_complete (CalComponent *comp, time_t completed_date) { struct icaltimetype *old_completed = NULL; - struct icaltimetype new_completed; int *old_percent, new_percent; icalproperty_status status; gboolean set_completed = TRUE; @@ -2189,7 +2213,14 @@ ensure_task_complete (CalComponent *comp, } if (set_completed) { - new_completed = icaltime_from_timet (completed_date, FALSE); + icaltimezone *utc_zone; + struct icaltimetype new_completed; + + /* COMPLETED is stored in UTC. */ + utc_zone = icaltimezone_get_utc_timezone (); + new_completed = icaltime_from_timet_with_zone (completed_date, + FALSE, + utc_zone); cal_component_set_completed (comp, &new_completed); } @@ -2354,6 +2385,11 @@ calendar_model_set_timezone (CalendarModel *model, { g_return_if_fail (IS_CALENDAR_MODEL (model)); - if (model->priv->zone != zone) + if (model->priv->zone != zone) { model->priv->zone = zone; + + /* The timezone affects the times shown for COMPLETED and + maybe other fields, so we need to redisplay everything. */ + e_table_model_changed (E_TABLE_MODEL (model)); + } } diff --git a/calendar/gui/dialogs/cal-prefs-dialog.c b/calendar/gui/dialogs/cal-prefs-dialog.c index 59acefc263..7176354a73 100644 --- a/calendar/gui/dialogs/cal-prefs-dialog.c +++ b/calendar/gui/dialogs/cal-prefs-dialog.c @@ -194,7 +194,7 @@ get_widgets (CalPrefsDialog *prefs) priv->dialog = GW ("cal-prefs-dialog"); - /* The indices must match the mktime() values. */ + /* The indices must be 0 (Sun) to 6 (Sat). */ priv->working_days[0] = GW ("sun_button"); priv->working_days[1] = GW ("mon_button"); priv->working_days[2] = GW ("tue_button"); diff --git a/calendar/gui/dialogs/comp-editor-util.c b/calendar/gui/dialogs/comp-editor-util.c index dcad6a44cf..63dd407677 100644 --- a/calendar/gui/dialogs/comp-editor-util.c +++ b/calendar/gui/dialogs/comp-editor-util.c @@ -29,6 +29,7 @@ #include <libgnome/gnome-defs.h> #include <libgnome/gnome-i18n.h> #include <e-util/e-time-utils.h> +#include <cal-util/timeutil.h> #include "../calendar-config.h" #include "comp-editor-util.h" @@ -109,9 +110,7 @@ write_label_piece (struct icaltimetype *tt, char *buffer, int size, tmp_tm.tm_sec = tt->second; tmp_tm.tm_isdst = -1; - /* Call mktime() to set the weekday. FIXME: Don't do this. mktime() - could in theory adjust the time if it thought it was invalid. */ - mktime (&tmp_tm); + tmp_tm.tm_wday = time_day_of_week (tt->day, tt->month - 1, tt->year); len = strlen (buffer); e_time_format_date_and_time (&tmp_tm, diff --git a/calendar/gui/dialogs/event-page.c b/calendar/gui/dialogs/event-page.c index 6b6736f041..5d0249bbd0 100644 --- a/calendar/gui/dialogs/event-page.c +++ b/calendar/gui/dialogs/event-page.c @@ -698,6 +698,7 @@ date_changed_cb (EDateEdit *dedit, gpointer data) &end_tt.minute); g_assert (date_set); + /* FIXME: TIMEZONES. */ cmp = icaltime_compare (start_tt, end_tt); if (cmp >= 0) { if (cmp == 0 && start_tt.hour == 0 @@ -711,6 +712,9 @@ date_changed_cb (EDateEdit *dedit, gpointer data) } else if (GTK_WIDGET (dedit) == priv->start_time) { /* Modify the end time, to be the start + 1 hour. */ + /* FIXME: TIMEZONES - Probably want to leave the + timezone as it is, so we need to convert the time.*/ + end_tt = start_tt; icaltime_adjust (&end_tt, 0, 1, 0, 0); @@ -728,6 +732,9 @@ date_changed_cb (EDateEdit *dedit, gpointer data) } else if (GTK_WIDGET (dedit) == priv->end_time) { /* Modify the start time, to be the end - 1 hour. */ + /* FIXME: TIMEZONES - Probably want to leave the + timezone as it is, so we need to convert the time.*/ + start_tt = end_tt; icaltime_adjust (&start_tt, 0, -1, 0, 0); diff --git a/calendar/gui/e-calendar-table.c b/calendar/gui/e-calendar-table.c index 9f5726b01e..c5a66fccde 100644 --- a/calendar/gui/e-calendar-table.c +++ b/calendar/gui/e-calendar-table.c @@ -217,6 +217,7 @@ task_compare_cb (gconstpointer a, gconstpointer b) if (due_a.value && due_b.value) { int v; + /* FIXME: TIMEZONES. */ v = icaltime_compare (*due_a.value, *due_b.value); if (v == 0) diff --git a/calendar/gui/e-day-view-main-item.c b/calendar/gui/e-day-view-main-item.c index cc6224987a..d65193b08b 100644 --- a/calendar/gui/e-day-view-main-item.c +++ b/calendar/gui/e-day-view-main-item.c @@ -467,7 +467,7 @@ e_day_view_main_item_draw_day_event (EDayViewMainItem *dvmitem, CalComponent *comp; gint num_icons, icon_x, icon_y, icon_x_inc, icon_y_inc; gint max_icon_w, max_icon_h; - gboolean draw_reminder_icon, draw_recurrence_icon; + gboolean draw_reminder_icon, draw_recurrence_icon, draw_timezone_icon; GSList *categories_list, *elem; day_view = dvmitem->day_view; @@ -563,6 +563,7 @@ e_day_view_main_item_draw_day_event (EDayViewMainItem *dvmitem, num_icons = 0; draw_reminder_icon = FALSE; draw_recurrence_icon = FALSE; + draw_timezone_icon = FALSE; icon_x = item_x + E_DAY_VIEW_BAR_WIDTH + E_DAY_VIEW_ICON_X_PAD; icon_y = item_y + E_DAY_VIEW_EVENT_BORDER_HEIGHT + E_DAY_VIEW_ICON_Y_PAD; @@ -578,6 +579,14 @@ e_day_view_main_item_draw_day_event (EDayViewMainItem *dvmitem, num_icons++; } + /* If the DTSTART or DTEND are in a different timezone to our current + timezone, we display the timezone icon. */ + if (!cal_component_compare_event_timezone (comp, day_view->zone)) { + draw_timezone_icon = TRUE; + num_icons++; + } + + cal_component_get_categories_list (comp, &categories_list); num_icons += g_slist_length (categories_list); @@ -632,6 +641,25 @@ e_day_view_main_item_draw_day_event (EDayViewMainItem *dvmitem, icon_y += icon_y_inc; } + if (draw_timezone_icon) { + max_icon_w = item_x + item_w - icon_x + - E_DAY_VIEW_EVENT_BORDER_WIDTH; + max_icon_h = item_y + item_h - icon_y + - E_DAY_VIEW_EVENT_BORDER_HEIGHT; + + gdk_gc_set_clip_origin (gc, icon_x, icon_y); + gdk_gc_set_clip_mask (gc, day_view->timezone_mask); + gdk_draw_pixmap (drawable, gc, + day_view->timezone_icon, + 0, 0, icon_x, icon_y, + MIN (E_DAY_VIEW_ICON_WIDTH, + max_icon_w), + MIN (E_DAY_VIEW_ICON_HEIGHT, + max_icon_h)); + icon_x += icon_x_inc; + icon_y += icon_y_inc; + } + /* draw categories icons */ for (elem = categories_list; elem; elem = elem->next) { char *category; diff --git a/calendar/gui/e-day-view-top-item.c b/calendar/gui/e-day-view-top-item.c index 1417dfee1e..237e7589ba 100644 --- a/calendar/gui/e-day-view-top-item.c +++ b/calendar/gui/e-day-view-top-item.c @@ -31,6 +31,7 @@ #include <libgnome/gnome-defs.h> #include <libgnome/gnome-i18n.h> #include "e-util/e-categories-config.h" +#include "cal-util/timeutil.h" #include "e-day-view-top-item.h" static void e_day_view_top_item_class_init (EDayViewTopItemClass *class); @@ -274,10 +275,9 @@ e_day_view_top_item_draw (GnomeCanvasItem *canvas_item, day_start.tm_mday = day_start_tt.day; day_start.tm_isdst = -1; - /* Call mktime() to set the weekday. FIXME: Don't do this. - mktime() could in theory adjust the time if it thought it - was invalid. */ - mktime (&day_start); + day_start.tm_wday = time_day_of_week (day_start_tt.day, + day_start_tt.month - 1, + day_start_tt.year); if (day_view->date_format == E_DAY_VIEW_DATE_FULL) /* strftime format %A = full weekday name, %d = day of month, diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c index d8e9736449..9e38224bb0 100644 --- a/calendar/gui/e-day-view.c +++ b/calendar/gui/e-day-view.c @@ -61,6 +61,7 @@ /* Images */ #include "art/bell.xpm" #include "art/recur.xpm" +#include "art/timezone-16.xpm" /* The minimum amount of space wanted on each side of the date string. */ #define E_DAY_VIEW_DATE_X_PAD 4 @@ -992,6 +993,7 @@ e_day_view_realize (GtkWidget *widget) /* Create the pixmaps. */ day_view->reminder_icon = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &day_view->reminder_mask, NULL, bell_xpm); day_view->recurrence_icon = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &day_view->recurrence_mask, NULL, recur_xpm); + day_view->timezone_icon = gdk_pixmap_colormap_create_from_xpm_d (NULL, colormap, &day_view->timezone_mask, NULL, timezone_16_xpm); @@ -2087,7 +2089,7 @@ e_day_view_set_selected_time_range (EDayView *day_view, start of the day given by start_time, otherwise it is the previous work-week start day. */ if (!day_view->work_week_view) { - lower = time_day_begin (start_time); + lower = time_day_begin_with_zone (start_time, day_view->zone); } else { lower = e_day_view_find_work_week_start (day_view, start_time); } @@ -2150,6 +2152,7 @@ e_day_view_find_work_week_start (EDayView *day_view, { GDate date; gint weekday, day, i, offset; + struct icaltimetype tt = icaltime_null_time (); g_date_clear (&date, 1); g_date_set_time (&date, start_time); @@ -2175,9 +2178,11 @@ e_day_view_find_work_week_start (EDayView *day_view, g_date_subtract_days (&date, offset); - return time_from_day (g_date_year (&date), - g_date_month (&date) - 1, - g_date_day (&date)); + tt.year = g_date_year (&date); + tt.month = g_date_month (&date); + tt.day = g_date_day (&date); + + return icaltime_as_timet_with_zone (tt, day_view->zone); } @@ -2229,11 +2234,13 @@ e_day_view_recalc_day_starts (EDayView *day_view, day_view->day_starts[0] = start_time; for (day = 1; day <= day_view->days_shown; day++) { - day_view->day_starts[day] = time_add_day (day_view->day_starts[day - 1], 1); + day_view->day_starts[day] = time_add_day_with_zone (day_view->day_starts[day - 1], 1, day_view->zone); } +#if 0 for (day = 0; day <= day_view->days_shown; day++) g_print ("Day Starts %i: %s", day, ctime (&day_view->day_starts[day])); +#endif day_view->lower = start_time; day_view->upper = day_view->day_starts[day_view->days_shown]; @@ -4508,6 +4515,10 @@ e_day_view_reshape_long_event (EDayView *day_view, if (cal_component_has_recurrences (comp)) num_icons++; + if (!cal_component_compare_event_timezone (comp, + day_view->zone)) + num_icons++; + cal_component_get_categories_list (comp, &categories_list); num_icons += g_slist_length (categories_list); cal_component_free_categories_list (categories_list); @@ -4645,6 +4656,10 @@ e_day_view_reshape_day_event (EDayView *day_view, if (cal_component_has_recurrences (comp)) num_icons++; + if (!cal_component_compare_event_timezone (comp, + day_view->zone)) + num_icons++; + cal_component_get_categories_list (comp, &categories_list); num_icons += g_slist_length (categories_list); cal_component_free_categories_list (categories_list); diff --git a/calendar/gui/e-day-view.h b/calendar/gui/e-day-view.h index 94354244ba..bddc36b708 100644 --- a/calendar/gui/e-day-view.h +++ b/calendar/gui/e-day-view.h @@ -360,6 +360,8 @@ struct _EDayView GdkBitmap *reminder_mask; GdkPixmap *recurrence_icon; GdkBitmap *recurrence_mask; + GdkPixmap *timezone_icon; + GdkBitmap *timezone_mask; /* Colors for drawing. */ GdkColor colors[E_DAY_VIEW_COLOR_LAST]; diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c index a31961dd98..264827e590 100644 --- a/calendar/gui/e-week-view.c +++ b/calendar/gui/e-week-view.c @@ -1253,8 +1253,10 @@ e_week_view_set_selected_time_range (EWeekView *week_view, if (!g_date_valid (&week_view->first_day_shown) || g_date_compare (&week_view->first_day_shown, &base_date)) { week_view->first_day_shown = base_date; - start_time = time_add_day (start_time, -day_offset); - start_time = time_day_begin (start_time); + start_time = time_add_day_with_zone (start_time, -day_offset, + week_view->zone); + start_time = time_day_begin_with_zone (start_time, + week_view->zone); e_week_view_recalc_day_starts (week_view, start_time); update_query (week_view); } @@ -1263,7 +1265,8 @@ e_week_view_set_selected_time_range (EWeekView *week_view, week_view->selection_start_day = g_date_julian (&date) - g_date_julian (&base_date); if (end_time == start_time - || end_time <= time_add_day (start_time, 1)) + || end_time <= time_add_day_with_zone (start_time, 1, + week_view->zone)) week_view->selection_end_day = week_view->selection_start_day; else { g_date_clear (&end_date, 1); @@ -1426,7 +1429,8 @@ e_week_view_recalc_day_starts (EWeekView *week_view, tmp_time = lower; week_view->day_starts[0] = tmp_time; for (day = 1; day <= num_days; day++) { - tmp_time = time_add_day (tmp_time, 1); + tmp_time = time_add_day_with_zone (tmp_time, 1, + week_view->zone); week_view->day_starts[day] = tmp_time; } } diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c index 5ea48a4d6e..166f715fa4 100644 --- a/calendar/gui/gnome-cal.c +++ b/calendar/gui/gnome-cal.c @@ -351,19 +351,14 @@ static struct tm get_current_time (ECalendarItem *calitem, gpointer data) { GnomeCalendar *cal = data; - char *location; - icaltimezone *zone; struct tm tmp_tm = { 0 }; struct icaltimetype tt; g_return_val_if_fail (cal != NULL, tmp_tm); g_return_val_if_fail (GNOME_IS_CALENDAR (cal), tmp_tm); - /* Get the current timezone. */ - location = calendar_config_get_timezone (); - zone = icaltimezone_get_builtin_timezone (location); - - tt = icaltime_from_timet_with_zone (time (NULL), FALSE, zone); + tt = icaltime_from_timet_with_zone (time (NULL), FALSE, + cal->priv->zone); /* Now copy it to the struct tm and return it. */ tmp_tm.tm_year = tt.year - 1900; @@ -505,8 +500,9 @@ gnome_calendar_init (GnomeCalendar *gcal) setup_widgets (gcal); - priv->selection_start_time = time_day_begin (time (NULL)); - priv->selection_end_time = time_add_day (priv->selection_start_time, 1); + priv->selection_start_time = time_day_begin_with_zone (time (NULL), + priv->zone); + priv->selection_end_time = time_add_day_with_zone (priv->selection_start_time, 1, priv->zone); priv->view_collection = NULL; priv->view_menus = NULL; @@ -585,8 +581,9 @@ gnome_calendar_goto (GnomeCalendar *gcal, time_t new_time) priv = gcal->priv; - priv->selection_start_time = time_day_begin (new_time); - priv->selection_end_time = time_add_day (priv->selection_start_time, 1); + priv->selection_start_time = time_day_begin_with_zone (new_time, + priv->zone); + priv->selection_end_time = time_add_day_with_zone (priv->selection_start_time, 1, priv->zone); gnome_calendar_update_view_times (gcal); gnome_calendar_update_date_navigator (gcal); @@ -644,23 +641,31 @@ gnome_calendar_direction (GnomeCalendar *gcal, int direction) switch (priv->current_view_type) { case GNOME_CAL_DAY_VIEW: - start_time = time_add_day (start_time, direction); - end_time = time_add_day (end_time, direction); + start_time = time_add_day_with_zone (start_time, direction, + priv->zone); + end_time = time_add_day_with_zone (end_time, direction, + priv->zone); break; case GNOME_CAL_WORK_WEEK_VIEW: - start_time = time_add_week (start_time, direction); - end_time = time_add_week (end_time, direction); + start_time = time_add_week_with_zone (start_time, direction, + priv->zone); + end_time = time_add_week_with_zone (end_time, direction, + priv->zone); break; case GNOME_CAL_WEEK_VIEW: - start_time = time_add_week (start_time, direction); - end_time = time_add_week (end_time, direction); + start_time = time_add_week_with_zone (start_time, direction, + priv->zone); + end_time = time_add_week_with_zone (end_time, direction, + priv->zone); break; case GNOME_CAL_MONTH_VIEW: - start_time = time_add_month (start_time, direction); - end_time = time_add_month (end_time, direction); + start_time = time_add_month_with_zone (start_time, direction, + priv->zone); + end_time = time_add_month_with_zone (end_time, direction, + priv->zone); break; default: @@ -704,8 +709,9 @@ gnome_calendar_dayjump (GnomeCalendar *gcal, time_t time) priv = gcal->priv; - priv->selection_start_time = time_day_begin (time); - priv->selection_end_time = time_add_day (priv->selection_start_time, 1); + priv->selection_start_time = time_day_begin_with_zone (time, + priv->zone); + priv->selection_end_time = time_add_day_with_zone (priv->selection_start_time, 1, priv->zone); if (priv->day_button) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->day_button), TRUE); diff --git a/calendar/gui/print.c b/calendar/gui/print.c index c4feb28575..5fda525e71 100644 --- a/calendar/gui/print.c +++ b/calendar/gui/print.c @@ -95,17 +95,8 @@ #define DAY_VIEW_EVENT_X_PAD 8 -/* copied from gnome-month-item.c this should be shared?? */ - -/* Number of days in a month, for normal and leap years */ -static const int days_in_month[2][12] = { - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } -}; - -/* The weird month of September 1752, where 3 Sep through 13 Sep were eliminated due to the - * Gregorian reformation. - */ +/* The weird month of September 1752, where 3 Sep through 13 Sep were + eliminated due to the Gregorian reformation. */ static const int sept_1752[42] = { 0, 0, 1, 2, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, @@ -114,11 +105,6 @@ static const int sept_1752[42] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - -#define REFORMATION_DAY 639787 /* First day of the reformation, counted from 1 Jan 1 */ -#define MISSING_DAYS 11 /* They corrected out 11 days */ -#define THURSDAY 4 /* First day of reformation */ -#define SATURDAY 6 /* Offset value; 1 Jan 1 was a Saturday */ #define SEPT_1752_START 2 /* Start day within month */ #define SEPT_1752_END 20 /* End day within month */ @@ -175,58 +161,43 @@ struct einfo static const GnomePaper *paper_info = NULL; -/* Returns the number of leap years since year 1 up to (but not including) the specified year */ -static int -leap_years_up_to (int year) -{ - return (year / 4 /* trivial leapness */ - - ((year > 1700) ? (year / 100 - 17) : 0) /* minus centuries since 1700 */ - + ((year > 1600) ? ((year - 1600) / 400) : 0)); /* plus centuries since 1700 divisible by 400 */ -} -/* Returns whether the specified year is a leap year */ -static int -is_leap_year (int year) +/* Convenience function to help the transition to timezone functions. + It returns the current timezone. */ +static icaltimezone* +get_timezone (void) { - if (year <= 1752) - return !(year % 4); - else - return (!(year % 4) && (year % 100)) || !(year % 400); + char *location = calendar_config_get_timezone (); + return icaltimezone_get_builtin_timezone (location); } -/* Returns the 1-based day number within the year of the specified date */ -static int -day_in_year (int day, int month, int year) -{ - int is_leap, i; - - is_leap = is_leap_year (year); - for (i = 0; i < month; i++) - day += days_in_month [is_leap][i]; - - return day; -} - -/* Returns the day of the week (zero-based, zero is Sunday) for the specified date. For the days - * that were removed on the Gregorian reformation, it returns Thursday. - */ -static int -day_in_week (int day, int month, int year) +/* Convenience function to help the transition to timezone functions. + It converts a time_t to a struct tm. */ +static struct tm* +convert_timet_to_struct_tm (time_t time, icaltimezone *zone) { - int n; + static struct tm my_tm; + struct icaltimetype tt; - n = (year - 1) * 365 + leap_years_up_to (year - 1) + day_in_year (day, month, year); + /* Convert it to an icaltimetype. */ + tt = icaltime_from_timet_with_zone (time, FALSE, zone); - if (n < REFORMATION_DAY) - return (n - 1 + SATURDAY) % 7; + /* Fill in the struct tm. */ + my_tm.tm_year = tt.year - 1900; + my_tm.tm_mon = tt.month - 1; + my_tm.tm_mday = tt.day; + my_tm.tm_hour = tt.hour; + my_tm.tm_min = tt.minute; + my_tm.tm_sec = tt.second; + my_tm.tm_isdst = tt.is_daylight; - if (n >= (REFORMATION_DAY + MISSING_DAYS)) - return (n - 1 + SATURDAY - MISSING_DAYS) % 7; + my_tm.tm_wday = time_day_of_week (tt.day, tt.month - 1, tt.year); - return THURSDAY; + return &my_tm; } + /* Fills the 42-element days array with the day numbers for the specified month. Slots outside the * bounds of the month are filled with zeros. The starting and ending indexes of the days are * returned in the start and end arguments. @@ -254,9 +225,9 @@ build_month (int month, int year, int *days, int *start, int *end) for (i = 0; i < 42; i++) days[i] = 0; - d_month = days_in_month[is_leap_year (year)][month]; + d_month = time_days_in_month (year, month); /* Get the start weekday in the month, 0=Sun to 6=Sat. */ - d_week = day_in_week (1, month, year); + d_week = time_day_of_week (1, month, year); /* Get the configuration setting specifying which weekday we put on the left column, 0=Sun to 6=Sat. */ @@ -463,10 +434,12 @@ static char *days[] = { static char * format_date(time_t time, int flags, char *buffer, int bufflen) { + icaltimezone *zone = get_timezone (); char fmt[64]; struct tm tm; - tm = *localtime(&time); + tm = *convert_timet_to_struct_tm (time, zone); + fmt[0] = 0; if (flags & DATE_DAYNAME) { strcat(fmt, "%A"); @@ -502,6 +475,7 @@ print_month_small (GnomePrintContext *pc, GnomeCalendar *gcal, time_t month, int titleflags, time_t greystart, time_t greyend, int bordertitle) { + icaltimezone *zone = get_timezone (); CalClient *client; GnomeFont *font, *font_bold, *font_normal; time_t now, next; @@ -552,7 +526,7 @@ print_month_small (GnomePrintContext *pc, GnomeCalendar *gcal, time_t month, /* get month days */ - tm = *localtime (&month); + tm = *convert_timet_to_struct_tm (month, zone); build_month (tm.tm_mon, tm.tm_year + 1900, days, 0, 0); font_normal = gnome_font_new_closest ("Times", GNOME_FONT_BOOK, 0, @@ -580,7 +554,7 @@ print_month_small (GnomePrintContext *pc, GnomeCalendar *gcal, time_t month, top -= row_height * 1.4; - now = time_month_begin (month); + now = time_month_begin_with_zone (month, zone); for (y = 0; y < 6; y++) { cell_top = top - y * row_height; @@ -605,11 +579,11 @@ print_month_small (GnomePrintContext *pc, GnomeCalendar *gcal, time_t month, /* this is a slow messy way to do this ... but easy ... */ uids = cal_client_get_objects_in_range (client, CALOBJ_TYPE_EVENT, - now, time_day_end (now)); + now, time_day_end_with_zone (now, zone)); font = uids ? font_bold : font_normal; cal_obj_uid_list_free (uids); - next = time_add_day (now, 1); + next = time_add_day_with_zone (now, 1, zone); if ((now >= greystart && now < greyend) || (greystart >= now && greystart < next)) { print_border (pc, @@ -831,9 +805,10 @@ print_day_add_event (CalComponent *comp, GArray **events) { + icaltimezone *zone = get_timezone (); EDayViewEvent event; gint day, offset; - struct tm start_tm, end_tm; + struct icaltimetype start_tt, end_tt; #if 0 g_print ("Day view lower: %s", ctime (&day_starts[0])); @@ -847,8 +822,8 @@ print_day_add_event (CalComponent *comp, g_return_val_if_fail (start < day_starts[days_shown], -1); g_return_val_if_fail (end > day_starts[0], -1); - start_tm = *(localtime (&start)); - end_tm = *(localtime (&end)); + start_tt = icaltime_from_timet_with_zone (start, FALSE, zone); + end_tt = icaltime_from_timet_with_zone (end, FALSE, zone); event.comp = comp; gtk_object_ref (GTK_OBJECT (comp)); @@ -861,8 +836,8 @@ print_day_add_event (CalComponent *comp, /*offset = day_view->first_hour_shown * 60 + day_view->first_minute_shown;*/ offset = 0; - event.start_minute = start_tm.tm_hour * 60 + start_tm.tm_min - offset; - event.end_minute = end_tm.tm_hour * 60 + end_tm.tm_min - offset; + event.start_minute = start_tt.hour * 60 + start_tt.minute - offset; + event.end_minute = end_tt.hour * 60 + end_tt.minute - offset; event.start_row_or_col = -1; event.num_columns = -1; @@ -1089,6 +1064,7 @@ static void print_day_details (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, double left, double right, double top, double bottom) { + icaltimezone *zone = get_timezone (); CalClient *client; EDayViewEvent *event; GnomeFont *font; @@ -1097,8 +1073,8 @@ print_day_details (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, gint rows_in_top_display, i; double font_size, max_font_size; - start = time_day_begin (whence); - end = time_day_end (start); + start = time_day_begin_with_zone (whence, zone); + end = time_day_end_with_zone (start, zone); pdi.days_shown = 1; pdi.day_starts[0] = start; @@ -1182,134 +1158,6 @@ print_day_details (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, } -/* - * Print Day Summary - */ -#if 0 -#define TIME_FMT "%X" -#else -#define TIME_FMT "%l:%M%p" -#endif - -#if 0 -static gboolean -print_day_summary_cb (CalComponent *comp, time_t istart, time_t iend, gpointer data) -{ - CalComponentText text; - struct psinfo *psi = (struct psinfo *)data; - struct einfo *ei; - - ei = g_new (struct einfo, 1); - - cal_component_get_summary (comp, &text); - ei->text = g_strdup (text.value); - - ei->start = istart; - ei->end = iend; - ei->count = 0; - - psi->events = g_list_append (psi->events, ei); - - return TRUE; -} - -static void -print_day_summary (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, - double left, double right, double top, double bottom, - double size, int totime, int titleformat) -{ - CalClient *client; - struct psinfo psi; - time_t start, end; - GList *l; - GnomeFont *font_summary; - double y, yend, x, xend, inc, incsmall; - char buf[100]; - double margin; - struct tm tm; - - client = gnome_calendar_get_cal_client (gcal); - - /* fill static detail */ - font_summary = gnome_font_new_closest ("Times", GNOME_FONT_BOOK, 0, size); - - gnome_print_setfont (pc, font_summary); - - start = time_day_begin(whence); - end = time_day_end(start); - - tm = *localtime(&start); - - format_date(start, titleformat, buf, 100); - titled_box (pc, buf, font_summary, ALIGN_RIGHT | ALIGN_BORDER, - &left, &right, &top, &bottom, 0.0); - - psi.events = NULL; - - cal_client_generate_instances (client, CALOBJ_TYPE_EVENT, start, end, - print_day_summary_cb, &psi); - inc = size*0.3; - incsmall = size*0.2; - - y = top-inc; - yend = bottom-incsmall; - - /* do a good rough approximation of the 'widest' time */ - tm.tm_year = 2000; - tm.tm_mon = 12; - tm.tm_mday = 22; - tm.tm_sec = 22; - tm.tm_min = 22; - tm.tm_hour = 23; - strftime(buf, 100, TIME_FMT, &tm); - margin = gnome_font_get_width_string(font_summary, buf); - - for (l = psi.events; l; l = l->next) { - struct einfo *ei = (struct einfo *)l->data; - - x = left + incsmall; - xend = right - inc; - - if (y - gnome_font_get_size (font_summary) < bottom) - break; - - tm = *localtime (&ei->start); - strftime (buf, 100, TIME_FMT, &tm); - gnome_print_moveto (pc, x + (margin - - gnome_font_get_width_string (font_summary, buf)), - y - gnome_font_get_size (font_summary)); - gnome_print_show (pc, buf); - - if (totime) { - tm = *localtime (&ei->end); - strftime (buf, 100, TIME_FMT, &tm); - gnome_print_moveto (pc, - (x + margin + inc - + (margin - - gnome_font_get_width_string (font_summary, buf))), - y - gnome_font_get_size (font_summary)); - gnome_print_show (pc, buf); - - y = bound_text (pc, font_summary, ei->text, - x + margin * 2 + inc * 2, xend, - y, yend, 0); - } else { - /* we also indent back after each time is printed */ - y = bound_text (pc, font_summary, ei->text, - x + margin + inc, xend, - y, yend, -margin + inc); - } - - y += gnome_font_get_size (font_summary) - inc; - - g_free (ei); - } - g_list_free (psi.events); - - gtk_object_unref (GTK_OBJECT (font_summary)); -} -#endif - /* This adds one event to the view, adding it to the appropriate array. */ static gboolean print_week_summary_cb (CalComponent *comp, @@ -1318,8 +1166,9 @@ print_week_summary_cb (CalComponent *comp, gpointer data) { + icaltimezone *zone = get_timezone (); EWeekViewEvent event; - struct tm start_tm, end_tm; + struct icaltimetype start_tt, end_tt; struct psinfo *psi = (struct psinfo *)data; @@ -1335,8 +1184,8 @@ print_week_summary_cb (CalComponent *comp, g_return_val_if_fail (start < psi->day_starts[psi->days_shown], TRUE); g_return_val_if_fail (end > psi->day_starts[0], TRUE); - start_tm = *(localtime (&start)); - end_tm = *(localtime (&end)); + start_tt = icaltime_from_timet_with_zone (start, FALSE, zone); + end_tt = icaltime_from_timet_with_zone (end, FALSE, zone); event.comp = comp; gtk_object_ref (GTK_OBJECT (event.comp)); @@ -1345,8 +1194,8 @@ print_week_summary_cb (CalComponent *comp, event.spans_index = 0; event.num_spans = 0; - event.start_minute = start_tm.tm_hour * 60 + start_tm.tm_min; - event.end_minute = end_tm.tm_hour * 60 + end_tm.tm_min; + event.start_minute = start_tt.hour * 60 + start_tt.minute; + event.end_minute = end_tt.hour * 60 + end_tt.minute; if (event.end_minute == 0 && start != end) event.end_minute = 24 * 60; @@ -1553,6 +1402,7 @@ print_week_view_background (GnomePrintContext *pc, GnomeFont *font, double left, double top, double cell_width, double cell_height) { + icaltimezone *zone = get_timezone (); int day, day_x, day_y, day_h; double x1, x2, y1, y2, font_size, fillcolor; struct tm tm; @@ -1571,7 +1421,7 @@ print_week_view_background (GnomePrintContext *pc, GnomeFont *font, y1 = top - day_y * cell_height; y2 = y1 - day_h * cell_height; - tm = *localtime (&psi->day_starts[day]); + tm = *convert_timet_to_struct_tm (psi->day_starts[day], zone); /* In the month view we draw a grey background for the end of the previous month and the start of the following. */ @@ -1617,6 +1467,7 @@ print_week_summary (GnomePrintContext *pc, GnomeCalendar *gcal, int month, double font_size, double left, double right, double top, double bottom) { + icaltimezone *zone = get_timezone (); CalClient *client; EWeekViewEvent *event; struct psinfo psi; @@ -1644,10 +1495,10 @@ print_week_summary (GnomePrintContext *pc, GnomeCalendar *gcal, if (psi.compress_weekend && psi.display_start_weekday == 6) psi.display_start_weekday = 5; - day_start = time_day_begin (whence); + day_start = time_day_begin_with_zone (whence, zone); for (day = 0; day <= psi.days_shown; day++) { psi.day_starts[day] = day_start; - day_start = time_add_day (day_start, 1); + day_start = time_add_day_with_zone (day_start, 1, zone); } /* Get the events from the server. */ @@ -1717,6 +1568,7 @@ print_year_summary (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, double left, double right, double top, double bottom, int morerows) { + icaltimezone *zone = get_timezone (); double row_height, col_width, l, r, t, b; time_t now; int col, row, rows, cols; @@ -1738,7 +1590,7 @@ print_year_summary (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, col_width = (right - left) / cols; r = l + col_width; b = top - row_height; - now = time_year_begin (whence); + now = time_year_begin_with_zone (whence, zone); for (row = 0; row < rows; row++) { t = top - row_height * row; @@ -1749,7 +1601,7 @@ print_year_summary (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, print_month_small (pc, gcal, now, l + 8, r - 8, t - 8, b + 8, DATE_MONTH, 0, 0, TRUE); - now = time_add_month (now, 1); + now = time_add_month_with_zone (now, 1, zone); } } } @@ -1758,8 +1610,10 @@ static void print_month_summary (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, double left, double right, double top, double bottom) { + icaltimezone *zone = get_timezone (); time_t date; struct tm tm; + struct icaltimetype tt; char buffer[100]; GnomeFont *font; gboolean compress_weekend; @@ -1770,21 +1624,27 @@ print_month_summary (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, compress_weekend = calendar_config_get_compress_weekend (); /* Remember which month we want. */ - tm = *localtime (&whence); - month = tm.tm_mon; + tt = icaltime_from_timet_with_zone (whence, FALSE, zone); + month = tt.month - 1; /* Find the start of the month, and then the start of the week on or before that day. */ - date = time_month_begin (whence); - date = time_week_begin (date, weekday); + date = time_month_begin_with_zone (whence, zone); + date = time_week_begin_with_zone (date, weekday, zone); /* If weekends are compressed then we can't start on a Sunday. */ if (compress_weekend && weekday == 0) - date = time_add_day (date, -1); - - tm = *localtime (&date); + date = time_add_day_with_zone (date, -1, zone); /* do day names ... */ + + /* We are only interested in outputting the weekday here, but we want + to be able to step through the week without worrying about + overflows making strftime choke, so we move near to the start of + the month. */ + tm = *convert_timet_to_struct_tm (date, zone); + tm.tm_mday = (tm.tm_mday % 7) + 7; + font = gnome_font_new_closest ("Times", GNOME_FONT_BOLD, 0, MONTH_NORMAL_FONT_SIZE); font_size = gnome_font_get_size (font); @@ -1800,7 +1660,7 @@ print_month_summary (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, strftime (buffer, sizeof (buffer), "%a/", &tm); len = strlen (buffer); tm.tm_mday++; - mktime (&tm); + tm.tm_wday = (tm.tm_wday + 1) % 7; strftime (buffer + len, sizeof (buffer) - len, "%a", &tm); } else { @@ -1814,7 +1674,7 @@ print_month_summary (GnomePrintContext *pc, GnomeCalendar *gcal, time_t whence, print_text (pc, font, buffer, ALIGN_CENTER, x1, x2, y1, y2); tm.tm_mday++; - mktime (&tm); + tm.tm_wday = (tm.tm_wday + 1) % 7; } gtk_object_unref (GTK_OBJECT (font)); @@ -1934,6 +1794,7 @@ static const int print_view_map[] = { static GtkWidget * range_selector_new (GtkWidget *dialog, time_t at, int *view) { + icaltimezone *zone = get_timezone (); GtkWidget *box; GtkWidget *radio; GSList *group; @@ -1947,7 +1808,7 @@ range_selector_new (GtkWidget *dialog, time_t at, int *view) box = gtk_vbox_new (FALSE, GNOME_PAD_SMALL); - tm = *localtime (&at); + tm = *convert_timet_to_struct_tm (at, zone); /* Day */ @@ -1959,15 +1820,15 @@ range_selector_new (GtkWidget *dialog, time_t at, int *view) /* Week */ week_start_day = calendar_config_get_week_start_day (); - week_begin = time_week_begin (at, week_start_day); + week_begin = time_week_begin_with_zone (at, week_start_day, zone); /* If the week starts on a Sunday, we have to show the Saturday first, since the weekend is compressed. */ if (week_start_day == 0) - week_begin = time_add_day (week_begin, -1); - week_end = time_add_day (week_end, 6); + week_begin = time_add_day_with_zone (week_begin, -1, zone); + week_end = time_add_day_with_zone (week_begin, 6, zone); - week_begin_tm = *localtime (&week_begin); - week_end_tm = *localtime (&week_end); + week_begin_tm = *convert_timet_to_struct_tm (week_begin, zone); + week_end_tm = *convert_timet_to_struct_tm (week_end, zone); if (week_begin_tm.tm_mon == week_end_tm.tm_mon) { strftime (str1, sizeof (str1), _("%a %b %d"), &week_begin_tm); @@ -2015,6 +1876,7 @@ static void print_day_view (GnomePrintContext *pc, GnomeCalendar *gcal, time_t date, double left, double right, double top, double bottom) { + icaltimezone *zone = get_timezone (); int i, days = 1; double todo, header, l; char buf[100]; @@ -2046,7 +1908,8 @@ print_day_view (GnomePrintContext *pc, GnomeCalendar *gcal, time_t date, DATE_MONTH | DATE_YEAR, date, date, FALSE); l += SMALL_MONTH_SPACING + SMALL_MONTH_WIDTH; - print_month_small (pc, gcal, time_add_month (date, 1), + print_month_small (pc, gcal, + time_add_month_with_zone (date, 1, zone), l, l + SMALL_MONTH_WIDTH, top - 4, header + 4, DATE_MONTH | DATE_YEAR, 0, 0, FALSE); @@ -2063,7 +1926,7 @@ print_day_view (GnomePrintContext *pc, GnomeCalendar *gcal, time_t date, left + 4, todo, top - 32, top - 32 - 18); gnome_print_showpage (pc); - date = time_add_day (date, 1); + date = time_add_day_with_zone (date, 1, zone); } } @@ -2072,6 +1935,7 @@ static void print_week_view (GnomePrintContext *pc, GnomeCalendar *gcal, time_t date, double left, double right, double top, double bottom) { + icaltimezone *zone = get_timezone (); double header, l; char buf[100]; time_t when; @@ -2083,11 +1947,11 @@ print_week_view (GnomePrintContext *pc, GnomeCalendar *gcal, time_t date, gnome_print_beginpage (pc, "Calendar Week View"); week_start_day = calendar_config_get_week_start_day (); - when = time_week_begin (date, week_start_day); + when = time_week_begin_with_zone (date, week_start_day, zone); /* If the week starts on a Sunday, we have to show the Saturday first, since the weekend is compressed. */ if (week_start_day == 0) - when = time_add_day (when, -1); + when = time_add_day_with_zone (when, -1, zone); /* Print the main week view. */ print_week_summary (pc, gcal, when, FALSE, 1, 0, @@ -2107,14 +1971,15 @@ print_week_view (GnomePrintContext *pc, GnomeCalendar *gcal, time_t date, l, l + SMALL_MONTH_WIDTH, top - 4, header + 4, DATE_MONTH | DATE_YEAR, when, - time_add_week (when, 1), FALSE); + time_add_week_with_zone (when, 1, zone), FALSE); l += SMALL_MONTH_SPACING + SMALL_MONTH_WIDTH; - print_month_small (pc, gcal, time_add_month (when, 1), + print_month_small (pc, gcal, + time_add_month_with_zone (when, 1, zone), l, l + SMALL_MONTH_WIDTH, top - 4, header + 4, DATE_MONTH | DATE_YEAR, when, - time_add_week (when, 1), FALSE); + time_add_week_with_zone (when, 1, zone), FALSE); /* Print the start day of the week, e.g. '7th May 2001'. */ format_date (when, DATE_DAY | DATE_MONTH | DATE_YEAR, buf, 100); @@ -2122,7 +1987,7 @@ print_week_view (GnomePrintContext *pc, GnomeCalendar *gcal, time_t date, left + 3, right, top - 4, top - 4 - 24); /* Print the end day of the week, e.g. '13th May 2001'. */ - when = time_add_day (when, 6); + when = time_add_day_with_zone (when, 6, zone); format_date (when, DATE_DAY | DATE_MONTH | DATE_YEAR, buf, 100); print_text_size (pc, 24, buf, ALIGN_LEFT, left + 3, right, top - 24 - 3, top - 24 - 3 - 24); @@ -2135,6 +2000,7 @@ static void print_month_view (GnomePrintContext *pc, GnomeCalendar *gcal, time_t date, double left, double right, double top, double bottom) { + icaltimezone *zone = get_timezone (); double header; char buf[100]; @@ -2150,11 +2016,13 @@ print_month_view (GnomePrintContext *pc, GnomeCalendar *gcal, time_t date, print_border (pc, left, right, top, header, 1.0, 0.9); /* Print the 2 mini calendar-months. */ - print_month_small (pc, gcal, time_add_month (date, 1), + print_month_small (pc, gcal, + time_add_month_with_zone (date, 1, zone), right - (right - left) / 7 + 2, right - 8, top - 4, header, DATE_MONTH | DATE_YEAR, 0, 0, FALSE); - print_month_small (pc, gcal, time_add_month (date, -1), + print_month_small (pc, gcal, + time_add_month_with_zone (date, -1, zone), left + 8, left + (right - left) / 7 - 2, top - 4, header, DATE_MONTH | DATE_YEAR, 0, 0, FALSE); @@ -2191,10 +2059,12 @@ print_year_view (GnomePrintContext *pc, GnomeCalendar *gcal, time_t date, static void write_label_piece (time_t t, char *buffer, int size, char *stext, char *etext) { + icaltimezone *zone = get_timezone (); struct tm *tmp_tm; int len; - tmp_tm = localtime (&t); + tmp_tm = convert_timet_to_struct_tm (t, zone); + if (stext != NULL) strcat (buffer, stext); @@ -2211,22 +2081,30 @@ static void print_date_label (GnomePrintContext *pc, CalComponent *comp, double left, double right, double top, double bottom) { + icaltimezone *zone = get_timezone (); CalComponentDateTime datetime; time_t start = 0, end = 0, complete = 0, due = 0; static char buffer[1024]; cal_component_get_dtstart (comp, &datetime); if (datetime.value) - start = icaltime_as_timet (*datetime.value); + start = icaltime_as_timet_with_zone (*datetime.value, zone); + cal_component_free_datetime (&datetime); + cal_component_get_dtend (comp, &datetime); if (datetime.value) - end = icaltime_as_timet (*datetime.value); + end = icaltime_as_timet_with_zone (*datetime.value, zone); + cal_component_free_datetime (&datetime); + cal_component_get_due (comp, &datetime); if (datetime.value) - due = icaltime_as_timet (*datetime.value); + due = icaltime_as_timet_with_zone (*datetime.value, zone); + cal_component_free_datetime (&datetime); + cal_component_get_completed (comp, &datetime.value); if (datetime.value) - complete = icaltime_as_timet (*datetime.value); + complete = icaltime_as_timet_with_zone (*datetime.value, zone); + cal_component_free_icaltimetype (&datetime.value); buffer[0] = '\0'; diff --git a/calendar/pcs/cal-backend-file.c b/calendar/pcs/cal-backend-file.c index 11dc82e7a2..967b2d4520 100644 --- a/calendar/pcs/cal-backend-file.c +++ b/calendar/pcs/cal-backend-file.c @@ -831,19 +831,24 @@ cal_backend_file_get_timezone_object (CalBackend *backend, const char *tzid) cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; + g_print ("In cal_backend_file_get_timezone_object: %s\n", tzid); + g_return_val_if_fail (tzid != NULL, NULL); g_return_val_if_fail (priv->icalcomp != NULL, NULL); g_assert (priv->comp_uid_hash != NULL); + g_print (" getting icaltz\n"); icaltz = icalcomponent_get_timezone (priv->icalcomp, tzid); if (!icaltz) return NULL; + g_print (" getting icalcomp\n"); icalcomp = icaltimezone_get_component (icaltz); if (!icalcomp) return NULL; + g_print (" getting ical_string\n"); ical_string = icalcomponent_as_ical_string (icalcomp); /* We dup the string; libical owns that memory. */ if (ical_string) diff --git a/calendar/pcs/query.c b/calendar/pcs/query.c index 6f3e276ae0..f96b74b88e 100644 --- a/calendar/pcs/query.c +++ b/calendar/pcs/query.c @@ -269,6 +269,9 @@ func_make_time (ESExp *esexp, int argc, ESExpResult **argv, void *data) * N - int, number of days to add * * Adds the specified number of days to a time value. + * + * FIXME: TIMEZONES - need to use a timezone or daylight saving changes will + * make the result incorrect. */ static ESExpResult * func_time_add_day (ESExp *esexp, int argc, ESExpResult **argv, void *data) @@ -307,6 +310,8 @@ func_time_add_day (ESExp *esexp, int argc, ESExpResult **argv, void *data) * TIME - time_t, base time * * Returns the start of the day, according to the local time. + * + * FIXME: TIMEZONES - this uses the current Unix timezone. */ static ESExpResult * func_time_day_begin (ESExp *esexp, int argc, ESExpResult **argv, void *data) @@ -337,6 +342,8 @@ func_time_day_begin (ESExp *esexp, int argc, ESExpResult **argv, void *data) * TIME - time_t, base time * * Returns the end of the day, according to the local time. + * + * FIXME: TIMEZONES - this uses the current Unix timezone. */ static ESExpResult * func_time_day_end (ESExp *esexp, int argc, ESExpResult **argv, void *data) |