diff options
Diffstat (limited to 'libical/src')
-rw-r--r-- | libical/src/libical/icalrecur.c | 32 | ||||
-rw-r--r-- | libical/src/libical/icaltime.c | 55 | ||||
-rw-r--r-- | libical/src/libical/icaltimezone.c | 62 | ||||
-rw-r--r-- | libical/src/libical/icaltimezone.h | 3 |
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); |