aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/cal-util
diff options
context:
space:
mode:
authorDamon Chaplin <damon@ximian.com>2001-07-11 11:56:03 +0800
committerDamon Chaplin <damon@src.gnome.org>2001-07-11 11:56:03 +0800
commit0e6d346872289d1ee71cb7b1092b5229b11dab3e (patch)
tree588b9cbac780c577af5c56d020c98f2f3822b38f /calendar/cal-util
parent552d3501e9bf05d42ce6f342e85a526a1cea702c (diff)
downloadgsoc2013-evolution-0e6d346872289d1ee71cb7b1092b5229b11dab3e.tar.gz
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
Diffstat (limited to 'calendar/cal-util')
-rw-r--r--calendar/cal-util/cal-component.c39
-rw-r--r--calendar/cal-util/cal-component.h4
-rw-r--r--calendar/cal-util/cal-recur.c267
-rw-r--r--calendar/cal-util/timeutil.c606
-rw-r--r--calendar/cal-util/timeutil.h123
5 files changed, 695 insertions, 344 deletions
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