aboutsummaryrefslogtreecommitdiffstats
path: root/libical/src
diff options
context:
space:
mode:
Diffstat (limited to 'libical/src')
-rw-r--r--libical/src/libical/icalrecur.c32
-rw-r--r--libical/src/libical/icaltime.c55
-rw-r--r--libical/src/libical/icaltimezone.c62
-rw-r--r--libical/src/libical/icaltimezone.h3
4 files changed, 103 insertions, 49 deletions
diff --git a/libical/src/libical/icalrecur.c b/libical/src/libical/icalrecur.c
index d998cd0e39..9af9abd8f5 100644
--- a/libical/src/libical/icalrecur.c
+++ b/libical/src/libical/icalrecur.c
@@ -148,6 +148,10 @@
#include "pvl.h"
+/* This is the last year we will go up to, since 32-bit time_t values only
+ go up to the start of 2038. */
+#define MAX_TIME_T_YEAR 2037
+
#define TEMP_MAX 1024
@@ -727,6 +731,11 @@ int has_by_data(struct icalrecur_iterator_impl* impl, enum byrule byrule){
}
+void increment_year(struct icalrecur_iterator_impl* impl, int inc)
+{
+ impl->last.year+=inc;
+}
+
int expand_year_days(struct icalrecur_iterator_impl* impl,short year);
@@ -999,11 +1008,6 @@ void icalrecur_iterator_free(icalrecur_iterator* i)
}
-void increment_year(struct icalrecur_iterator_impl* impl, int inc)
-{
- impl->last.year+=inc;
-}
-
/* Increment month is different that the other incement_* routines --
it figures out the interval for itself, and uses BYMONTH data if
available. */
@@ -1732,6 +1736,16 @@ int expand_year_days(struct icalrecur_iterator_impl* impl,short year)
case 0: {
/* FREQ=YEARLY; */
+
+ short doy;
+
+ t = impl->dtstart;
+ t.year = year;
+ t.is_date = 1;
+
+ doy = icaltime_day_of_year(t);
+
+ impl->days[days_index++] = doy;
break;
}
@@ -2031,6 +2045,12 @@ int next_year(struct icalrecur_iterator_impl* impl)
for (;;) {
increment_year(impl,impl->rule.interval);
+
+ /* Make sure we don't go past the max time_t year, or any calls to
+ mktime() etc. will fail. */
+ if (impl->last.year > MAX_TIME_T_YEAR)
+ return 1;
+
expand_year_days(impl,impl->last.year);
if (impl->days[0] != ICAL_RECURRENCE_ARRAY_MAX)
break;
@@ -2167,7 +2187,7 @@ struct icaltimetype icalrecur_iterator_next(icalrecur_iterator *itr)
}
}
- if(impl->last.year >= 2038 ){
+ if(impl->last.year > MAX_TIME_T_YEAR ){
/* HACK */
return icaltime_null_time();
}
diff --git a/libical/src/libical/icaltime.c b/libical/src/libical/icaltime.c
index 698035537b..3c99dfacf7 100644
--- a/libical/src/libical/icaltime.c
+++ b/libical/src/libical/icaltime.c
@@ -73,6 +73,10 @@ icaltime_from_timet(time_t tm, int is_date)
return tt;
}
+/* Note that DATE values and floating values do not have their own timezones,
+ so you should use the default or current timezone in that case.
+ This assumes that if is_date is set, the time_t points to the start of the
+ day in the given zone, so be very careful about using it. */
struct icaltimetype
icaltime_from_timet_with_zone(time_t tm, int is_date, icaltimezone *zone)
{
@@ -89,24 +93,24 @@ icaltime_from_timet_with_zone(time_t tm, int is_date, icaltimezone *zone)
tt.year = t.tm_year + 1900;
tt.month = t.tm_mon + 1;
tt.day = t.tm_mday;
-
+ tt.hour = t.tm_hour;
+ tt.minute = t.tm_min;
+ tt.second = t.tm_sec;
+ tt.is_date = 0;
tt.is_utc = (zone == utc_zone) ? 1 : 0;
- tt.is_date = is_date;
tt.is_daylight = 0;
tt.zone = NULL;
+ /* Use our timezone functions to convert to the required timezone. */
+ icaltimezone_convert_time (&tt, utc_zone, zone);
+
+ tt.is_date = is_date;
+
+ /* If it is a DATE value, make sure hour, minute & second are 0. */
if (is_date) {
- /* We don't convert DATE values between timezones. */
tt.hour = 0;
tt.minute = 0;
tt.second = 0;
- } else {
- tt.hour = t.tm_hour;
- tt.minute = t.tm_min;
- tt.second = t.tm_sec;
-
- /* Use our timezone functions to convert to the required timezone. */
- icaltimezone_convert_time (&tt, utc_zone, zone);
}
return tt;
@@ -229,7 +233,12 @@ time_t icaltime_as_timet(struct icaltimetype tt)
}
-time_t icaltime_as_timet_with_zone(struct icaltimetype tt, icaltimezone *zone)
+/* Note that DATE values and floating values do not have their own timezones,
+ so you should use the default or current timezone in that case.
+ If is_date is set, the time_t returned points to the start of the day in
+ the given zone. */
+time_t
+icaltime_as_timet_with_zone(struct icaltimetype tt, icaltimezone *zone)
{
icaltimezone *utc_zone;
struct tm stm;
@@ -243,9 +252,11 @@ time_t icaltime_as_timet_with_zone(struct icaltimetype tt, icaltimezone *zone)
return 0;
}
+ /* Clear the is_date flag, so we can convert the time. */
+ tt.is_date = 0;
+
/* Use our timezone functions to convert to UTC. */
- if (!tt.is_date)
- icaltimezone_convert_time (&tt, zone, utc_zone);
+ icaltimezone_convert_time (&tt, zone, utc_zone);
/* Copy the icaltimetype to a struct tm. */
memset (&stm, 0, sizeof (struct tm));
@@ -405,13 +416,25 @@ short icaltime_day_of_week(struct icaltimetype t){
stm.tm_year = t.year - 1900;
stm.tm_mon = t.month - 1;
stm.tm_mday = t.day;
- stm.tm_hour = 0;
+ stm.tm_hour = 12;
stm.tm_min = 0;
stm.tm_sec = 0;
stm.tm_isdst = -1;
mktime (&stm);
+ if (stm.tm_year != t.year - 1900
+ || stm.tm_mon != t.month - 1
+ || stm.tm_mday != t.day)
+ printf ("WARNING: icaltime_day_of_week: mktime() changed our date!!\n");
+
+#if 0
+ printf ("Day of week %i/%i/%i (%i/%i/%i) -> %i (0=Sun 6=Sat)\n",
+ t.day, t.month, t.year,
+ stm.tm_mday, stm.tm_mon + 1, stm.tm_year + 1900,
+ stm.tm_wday);
+#endif
+
return stm.tm_wday + 1;
}
@@ -423,7 +446,7 @@ short icaltime_start_doy_of_week(struct icaltimetype t){
stm.tm_year = t.year - 1900;
stm.tm_mon = t.month - 1;
stm.tm_mday = t.day;
- stm.tm_hour = 0;
+ stm.tm_hour = 12;
stm.tm_min = 0;
stm.tm_sec = 0;
stm.tm_isdst = -1;
@@ -466,7 +489,7 @@ short icaltime_week_number(struct icaltimetype ictt)
stm.tm_year = ictt.year - 1900;
stm.tm_mon = ictt.month - 1;
stm.tm_mday = ictt.day;
- stm.tm_hour = 0;
+ stm.tm_hour = 12;
stm.tm_min = 0;
stm.tm_sec = 0;
stm.tm_isdst = -1;
diff --git a/libical/src/libical/icaltimezone.c b/libical/src/libical/icaltimezone.c
index 17a3b437d7..b36e34eb74 100644
--- a/libical/src/libical/icaltimezone.c
+++ b/libical/src/libical/icaltimezone.c
@@ -53,7 +53,7 @@
/* This is the maximum year we will expand to. time_t values only go up to
somewhere around 2037. */
-#define ICALTIMEZONE_MAX_YEAR 2035
+#define ICALTIMEZONE_MAX_YEAR 2037
struct _icaltimezone {
@@ -833,15 +833,17 @@ icaltimezone_get_utc_offset (icaltimezone *zone,
/* If we are stepping backwards through the changes and we have found
a change that applies, then we know this is the change to use so
we exit the loop. */
- if (step == -1 && change_num_to_use != -1)
- break;
+ if (step == -1) {
+ if (change_num_to_use != -1)
+ break;
- change_num += step;
+ /* If we go past the start of the changes array, then return the
+ TZOFFSETFROM of the first change.. */
+ if (change_num == 0)
+ return zone_change->prev_utc_offset;
+ }
- /* If we go past the start of the changes array, then we have no data
- for this time so we return a UTC offset of 0. */
- if (change_num < 0)
- return 0;
+ change_num += step;
if (change_num >= zone->changes->num_elements)
break;
@@ -867,24 +869,28 @@ icaltimezone_get_utc_offset (icaltimezone *zone,
/* The time is in the overlapped region, so we may need to use
either the current zone_change or the previous one. If the
time has the is_daylight field set we use the matching change,
- else we use the change with standard time. */
+ else we use the change with standard time. Note that iCalendar
+ doesn't let us distinguish between the different possible
+ choices here, so it isn't very reliable. Currently the main
+ use of the is_daylight flag is for testing. */
prev_zone_change = icalarray_element_at (zone->changes,
change_num_to_use - 1);
- /* I was going to add an is_daylight flag to struct icaltimetype,
- but iCalendar doesn't let us distinguish between standard and
- daylight time anyway, so there's no point. So we just use the
- standard time instead. */
- want_daylight = (tt->is_daylight == 1) ? 1 : 0;
-
+ /* If both possible changes have the same is_daylight setting,
+ then we choose the last one for now. It looks like the standard
+ Unix functions choose the each one half the time, so we may
+ want to try to figure out the rule for doing that. */
+ if (zone_change->is_daylight == prev_zone_change->is_daylight) {
#if 0
- if (zone_change->is_daylight == prev_zone_change->is_daylight)
- printf (" **** Same is_daylight setting\n");
+ printf (" **** Same is_daylight setting (%i). Choosing last change.\n", zone_change->is_daylight);
#endif
+ } else {
+ want_daylight = (tt->is_daylight == 1) ? 1 : 0;
- if (zone_change->is_daylight != want_daylight
- && prev_zone_change->is_daylight == want_daylight)
- zone_change = prev_zone_change;
+ if (zone_change->is_daylight != want_daylight
+ && prev_zone_change->is_daylight == want_daylight)
+ zone_change = prev_zone_change;
+ }
}
}
@@ -965,15 +971,17 @@ icaltimezone_get_utc_offset_of_utc_time (icaltimezone *zone,
/* If we are stepping backwards through the changes and we have found
a change that applies, then we know this is the change to use so
we exit the loop. */
- if (step == -1 && change_num_to_use != -1)
- break;
+ if (step == -1) {
+ if (change_num_to_use != -1)
+ break;
- change_num += step;
+ /* If we go past the start of the changes array, then return the
+ TZOFFSETFROM of the first change.. */
+ if (change_num == 0)
+ return zone_change->prev_utc_offset;
+ }
- /* If we go past the start of the changes array, then we have no data
- for this time so we return a UTC offset of 0. */
- if (change_num < 0)
- return 0;
+ change_num += step;
if (change_num >= zone->changes->num_elements)
break;
diff --git a/libical/src/libical/icaltimezone.h b/libical/src/libical/icaltimezone.h
index 1e8ec70048..b072f0dd9a 100644
--- a/libical/src/libical/icaltimezone.h
+++ b/libical/src/libical/icaltimezone.h
@@ -93,6 +93,9 @@ int icaltimezone_set_component (icaltimezone *zone,
* Converting times between timezones.
*/
+/* This converts the icaltimetype from one timezone to another. Note that it
+ does not convert DATE values. If you need to do that, you should clear the
+ is_date field first. */
void icaltimezone_convert_time (struct icaltimetype *tt,
icaltimezone *from_zone,
icaltimezone *to_zone);