summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllen Winter <allen.winter@kdab.com>2015-06-15 17:20:58 -0400
committerAllen Winter <allen.winter@kdab.com>2015-06-15 17:20:58 -0400
commit6e11823ec46ddff04c318034325da9631cd8e654 (patch)
treeca481c963edd3839f6fd9675fc43a5d7e307ed35
parent10ff2a787d4fc17c033424cda21cbb0b4be561dc (diff)
downloadlibical-git-6e11823ec46ddff04c318034325da9631cd8e654.tar.gz
BuildTime+RunTime preference for exact vs. inter-operable timezones
ISSUE: #95
-rw-r--r--CMakeLists.txt14
-rw-r--r--Install.txt29
-rwxr-xr-xconfig.h.cmake3
-rw-r--r--src/libical/ical_file.cmake1
-rw-r--r--src/libical/icaltime.c2
-rw-r--r--src/libical/icaltimezone.h1
-rw-r--r--src/libical/icaltz-util.c298
-rw-r--r--src/libical/icaltz-util.h6
-rw-r--r--src/test/CMakeLists.txt1
-rw-r--r--src/test/timezones.c7
10 files changed, 310 insertions, 52 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cecbe631..df9c4dd0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -47,6 +47,13 @@
# Set to build using a 32bit time_t (ignored unless building with MSVC on Windows)
# Default=false (use the default size of time_t)
#
+# -DUSE_INTEROPERABLE_VTIMEZONES=[true|false]
+# Set to use inter-operable rather than exact vtimezones.
+# Default=false (build exact vtimezones)
+# Notes:
+# Change the behavior at runtime using the icaltzutil_set_exact_vtimezones_support() function.
+# Query the behavior at runtime using the icaltzutil_get_exact_vtimezones_support() function.
+#
cmake_minimum_required(VERSION 2.8.9) #first line, to shutup a cygwin warning
project(libical C CXX)
@@ -196,6 +203,13 @@ if(WIN32 OR WINCE)
endif()
endif()
+option(USE_INTEROPERABLE_VTIMEZONES "use interoperable rather than exact vtimezones." False)
+if(USE_INTEROPERABLE_VTIMEZONES)
+ set(USE_INTEROPERABLE_VTIMEZONES 1)
+else()
+ set(USE_INTEROPERABLE_VTIMEZONES 0)
+endif()
+
include(ConfigureChecks.cmake)
add_definitions(-DHAVE_CONFIG_H)
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
diff --git a/Install.txt b/Install.txt
index 90ba2eb2..c6df8d93 100644
--- a/Install.txt
+++ b/Install.txt
@@ -99,3 +99,32 @@ Then you can set the C and C++ compilers at CMake time, like so:
This C library can be built with bindings for these other languages:
* C++. By default the buildsystem will create and install the C++ bindings API.
Turn this off by passing -DWITH_CXX_BINDINGS=False option to CMake.
+
+* There are Java, Perl, PHP and Python bindings but they are old and haven't
+ been tested in a very long time. Volunteers wanted.
+
+== Tweaking the Library Behavior ==
+Use these CMake options to adjust the library behavior as follows:
+ * ICAL_ERRORS_ARE_FATALL=[true|false]
+ Set to make icalerror_* calls abort instead of internally signaling an error.
+ Default=false
+
+ * NO_WARN_DEPRECATED=[true|false]
+ Set if you DO NOT WANT to see deprecated messages.
+ Default=true
+
+ * ICAL_ALLOW_EMPTY_PROPERTIES=[true|false]
+ Set to prevent empty properties from being replaced with X-LIC-ERROR properties.
+ Default=false
+
+ * USE_BUILTIN_TZDATA=[true|false]
+ Set to build using our own (instead of the system's) timezone data.
+ Default=false (use the system timezone data on non-Windows systems)
+ ALWAYS true on Windows systems
+
+ * USE_INTEROPERABLE_VTIMEZONES=[true|false]
+ Set to use inter-operable rather than exact VTIMEZONEs.
+ Default=false (build exact VTIMEZONEs)
+ Notes:
+ Change the behavior at runtime using the icaltzutil_set_exact_vtimezones_support() function.
+ Query the behavior at runtime using the icaltzutil_get_exact_vtimezones_support() function.
diff --git a/config.h.cmake b/config.h.cmake
index 80d32455..80fd57b9 100755
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -187,6 +187,9 @@
/* whether we should bring our own TZ-Data */
#cmakedefine USE_BUILTIN_TZDATA
+/* whether we should use operable vtimezones */
+#cmakedefine USE_INTEROPERABLE_VTIMEZONES
+
/* Define to empty if `const' does not conform to ANSI C. */
#cmakedefine const
diff --git a/src/libical/ical_file.cmake b/src/libical/ical_file.cmake
index e055645f..380bac49 100644
--- a/src/libical/ical_file.cmake
+++ b/src/libical/ical_file.cmake
@@ -19,6 +19,7 @@ set(COMBINEDHEADERSICAL
${TOPS}/src/libical/pvl.h
${TOPS}/src/libical/icalcomponent.h
${TOPS}/src/libical/icaltimezone.h
+ ${TOPS}/src/libical/icaltz-util.h
${TOPS}/src/libical/icalparser.h
${TOPS}/src/libical/icalmemory.h
${TOPS}/src/libical/icalerror.h
diff --git a/src/libical/icaltime.c b/src/libical/icaltime.c
index a1e9d4fa..1be155c8 100644
--- a/src/libical/icaltime.c
+++ b/src/libical/icaltime.c
@@ -72,7 +72,7 @@ static int icaltime_leap_days(int y1, int y2)
{
--y1;
--y2;
- return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400);
+ return (y2 / 4 - y1 / 4) - (y2 / 100 - y1 / 100) + (y2 / 400 - y1 / 400);
}
/*
diff --git a/src/libical/icaltimezone.h b/src/libical/icaltimezone.h
index 1574f0c2..58c2dd42 100644
--- a/src/libical/icaltimezone.h
+++ b/src/libical/icaltimezone.h
@@ -154,7 +154,6 @@ LIBICAL_ICAL_EXPORT char *icaltimezone_get_location_from_vtimezone(icalcomponent
LIBICAL_ICAL_EXPORT char *icaltimezone_get_tznames_from_vtimezone(icalcomponent *component);
-
/*
* @par Handling the default location the timezone files
*/
diff --git a/src/libical/icaltz-util.c b/src/libical/icaltz-util.c
index e9df4cf3..39996b26 100644
--- a/src/libical/icaltz-util.c
+++ b/src/libical/icaltz-util.c
@@ -52,7 +52,7 @@
#if defined(_MSC_VER)
#if !defined(HAVE_BYTESWAP_H) && !defined(HAVE_SYS_ENDIAN_H) && !defined(HAVE_ENDIAN_H)
-#define bswap_16(x) (((x) << 8) & 0xff00) | (((x) >> 8 ) & 0xff)
+#define bswap_16(x) (((x) << 8) & 0xff00) | (((x) >> 8) & 0xff)
#define bswap_32(x) \
(((x) << 24) & 0xff000000) | \
@@ -74,7 +74,7 @@
#endif
#if defined(__APPLE__) || defined(__MINGW32__)
-#define bswap_16(x) (((x) << 8) & 0xff00) | (((x) >> 8 ) & 0xff)
+#define bswap_16(x) (((x) << 8) & 0xff00) | (((x) >> 8) & 0xff)
#define bswap_32 __builtin_bswap32
#define bswap_64 __builtin_bswap64
#endif
@@ -99,7 +99,7 @@ static char *search_paths[] = {
};
#define EFREAD(buf,size,num,fs) \
-if (fread(buf, size, num, fs) < num && ferror (fs)) { \
+if (fread(buf, size, num, fs) < num && ferror(fs)) { \
icalerror_set_errno(ICAL_FILE_ERROR); \
goto error; \
}
@@ -160,7 +160,7 @@ static char *zname_from_stridx(char *str, long idx)
i++;
}
- size = (size_t) (i - idx);
+ size = (size_t)(i - idx);
str += idx;
ret = (char *)malloc(size + 1);
ret = strncpy(ret, str, size);
@@ -193,12 +193,110 @@ const char *icaltzutil_get_zone_directory(void)
return zdir;
}
+static void find_transidx(time_t *transitions, ttinfo *types,
+ int *trans_idx, long int num_trans,
+ int *stdidx, int *dstidx)
+{
+ time_t now, year_start;
+ int i, found = 0;
+ struct icaltimetype itime;
+
+ now = time(NULL);
+ itime = icaltime_from_timet(now, 0);
+ itime.month = itime.day = 1;
+ itime.hour = itime.minute = itime.second = 0;
+ year_start = icaltime_as_timet(itime);
+
+ /* Set this by default */
+ *stdidx = (num_trans - 1);
+
+ for (i = (num_trans - 1); i >= 0; --i) {
+ if (year_start < transitions[i]) {
+ int idx;
+ found = 1;
+ idx = trans_idx[i];
+ (types[idx].isdst) ? (*dstidx = i) : (*stdidx = i);
+ }
+ }
+
+ /* If the transition found is the last among the list, prepare to use the last two transtions.
+ * Using this will most likely throw the DTSTART of the resulting component off by 1 or 2 days
+ * but it would set right by the adjustment made.
+ * NOTE: We need to use the last two transitions only because there is no data for the future
+ * transitions.
+ */
+ if (found && (*dstidx == -1)) {
+ *dstidx = ((*stdidx) - 1);
+ }
+
+ return;
+}
+
+static int calculate_pos(icaltimetype icaltime)
+{
+ static int r_pos[] = {1, 2, 3, -2, -1};
+ int pos;
+
+ pos = (icaltime.day - 1) / 7;
+
+ /* Check if pos 3 is the last occurrence of the week day in the month */
+ if (pos == 3 && ((icaltime.day + 7) > icaltime_days_in_month(icaltime.month, icaltime.year))) {
+ pos = 4;
+ }
+
+ return r_pos[pos];
+}
+
+#if defined(USE_INTEROPERABLE_VTIMEZONES)
+static int _s_use_exact_timezones = 0;
+#else
+static int _s_use_exact_timezones = 1;
+#endif
+
+void icaltzutil_set_exact_vtimezones_support(int on)
+{
+ _s_use_exact_timezones = (on != 0);
+}
+
+int icaltzutil_get_exact_vtimezones_support(void)
+{
+ return _s_use_exact_timezones;
+}
+
+static void adjust_dtstart_day_to_rrule(icalcomponent *comp, struct icalrecurrencetype rule)
+{
+ time_t now, year_start;
+ struct icaltimetype start, comp_start, iter_start, itime;
+ icalrecur_iterator *iter;
+
+ now = time(NULL);
+ itime = icaltime_from_timet(now, 0);
+ itime.month = itime.day = 1;
+ itime.hour = itime.minute = itime.second = 0;
+ year_start = icaltime_as_timet(itime);
+
+ comp_start = icalcomponent_get_dtstart(comp);
+ start = icaltime_from_timet(year_start, 0);
+
+ iter = icalrecur_iterator_new(rule, start);
+ iter_start = icalrecur_iterator_next(iter);
+ icalrecur_iterator_free(iter);
+
+ if (iter_start.day != comp_start.day) {
+ comp_start.day = iter_start.day;
+ icalcomponent_set_dtstart(comp, comp_start);
+ }
+}
+
icalcomponent *icaltzutil_fetch_timezone(const char *location)
{
tzinfo type_cnts;
size_t i, num_trans, num_chars, num_leaps, num_isstd, num_isgmt;
size_t num_types = 0;
size_t size;
+ time_t trans;
+ int dstidx = -1, stdidx = -1, pos, sign, zidx, zp_idx;
+ icalcomponent *std_comp = NULL;
const char *zonedir;
FILE *f = NULL;
@@ -213,9 +311,10 @@ icalcomponent *icaltzutil_fetch_timezone(const char *location)
time_t start, end;
int idx, prev_idx;
- icalcomponent *tz_comp = NULL, *comp = NULL;
+ icalcomponent *tz_comp = NULL, *comp = NULL, *dst_comp;
icalproperty *icalprop;
- icaltimetype dtstart;
+ icaltimetype dtstart, icaltime;
+ struct icalrecurrencetype ical_recur;
if (icaltimezone_get_builtin_tzdata()) {
goto error;
@@ -246,12 +345,12 @@ icalcomponent *icaltzutil_fetch_timezone(const char *location)
EFREAD(&type_cnts, 24, 1, f);
- num_isgmt = (size_t) decode(type_cnts.ttisgmtcnt);
- num_leaps = (size_t) decode(type_cnts.leapcnt);
- num_chars = (size_t) decode(type_cnts.charcnt);
- num_trans = (size_t) decode(type_cnts.timecnt);
- num_isstd = (size_t) decode(type_cnts.ttisstdcnt);
- num_types = (size_t) decode(type_cnts.typecnt);
+ num_isgmt = (size_t)decode(type_cnts.ttisgmtcnt);
+ num_leaps = (size_t)decode(type_cnts.leapcnt);
+ num_chars = (size_t)decode(type_cnts.charcnt);
+ num_trans = (size_t)decode(type_cnts.timecnt);
+ num_isstd = (size_t)decode(type_cnts.ttisstdcnt);
+ num_types = (size_t)decode(type_cnts.typecnt);
transitions = calloc(num_trans, sizeof(time_t));
if (transitions == NULL) {
@@ -317,7 +416,7 @@ icalcomponent *icaltzutil_fetch_timezone(const char *location)
char c[4];
EFREAD(c, 4, 1, f);
- leaps[i].transition = (time_t) decode(c);
+ leaps[i].transition = (time_t)decode(c);
EFREAD(c, 4, 1, f);
leaps[i].change = decode(c);
@@ -325,7 +424,6 @@ icalcomponent *icaltzutil_fetch_timezone(const char *location)
for (i = 0; i < num_isstd; ++i) {
int c = getc(f);
-
types[i].isstd = c != 0;
}
@@ -349,6 +447,14 @@ icalcomponent *icaltzutil_fetch_timezone(const char *location)
types[i].zname = zname_from_stridx(znames, (long)types[i].abbr);
}
+ if (!_s_use_exact_timezones) {
+ if (num_trans != 0) {
+ find_transidx(transitions, types, trans_idx, (long int)num_trans, &stdidx, &dstidx);
+ } else {
+ stdidx = 0;
+ }
+ }
+
tz_comp = icalcomponent_new(ICAL_VTIMEZONE_COMPONENT);
/* Add tzid property */
@@ -366,53 +472,147 @@ icalcomponent *icaltzutil_fetch_timezone(const char *location)
icalproperty_set_x_name(icalprop, "X-LIC-LOCATION");
icalcomponent_add_property(tz_comp, icalprop);
- prev_idx = 0;
- if (num_trans == 0) {
- prev_idx = idx = 0;
- } else {
- idx = trans_idx[0];
- }
- start = 0;
- for (i = 1; i < num_trans; i++, start = end) {
- prev_idx = idx;
- idx = trans_idx[i];
- end = transitions[i] + types[prev_idx].gmtoff;
- /* don't bother starting until the epoch */
- if (0 > end)
- continue;
-
- if (types[prev_idx].isdst) {
+ if (!_s_use_exact_timezones) {
+ if (stdidx != -1) {
+ if (num_trans != 0) {
+ zidx = trans_idx[stdidx];
+ } else {
+ zidx = 0;
+ }
+
+ std_comp = icalcomponent_new(ICAL_XSTANDARD_COMPONENT);
+ icalprop = icalproperty_new_tzname(types[zidx].zname);
+ icalcomponent_add_property(std_comp, icalprop);
+
+ if (dstidx != -1) {
+ zp_idx = trans_idx[stdidx-1];
+ } else {
+ zp_idx = zidx;
+ }
+ /* DTSTART localtime uses TZOFFSETFROM UTC offset */
+ if (num_trans != 0) {
+ trans = transitions[stdidx] + types[zp_idx].gmtoff;
+ } else {
+ trans = (time_t)types[zp_idx].gmtoff;
+ }
+ icaltime = icaltime_from_timet(trans, 0);
+ dtstart = icaltime;
+ dtstart.year = 1970;
+ dtstart.minute = dtstart.second = 0;
+ icalprop = icalproperty_new_dtstart(dtstart);
+ icalcomponent_add_property(std_comp, icalprop);
+
+ /* If DST changes are present use RRULE */
+ if (dstidx != -1) {
+ icalrecurrencetype_clear(&ical_recur);
+ ical_recur.freq = ICAL_YEARLY_RECURRENCE;
+ ical_recur.by_month[0] = icaltime.month;
+ pos = calculate_pos(icaltime);
+ pos < 0 ? (sign = -1): (sign = 1);
+ ical_recur.by_day[0] = sign * ((abs(pos) * 8) + icaltime_day_of_week(icaltime));
+ icalprop = icalproperty_new_rrule(ical_recur);
+ icalcomponent_add_property(std_comp, icalprop);
+
+ adjust_dtstart_day_to_rrule(std_comp, ical_recur);
+ }
+ icalprop = icalproperty_new_tzoffsetfrom(types[zp_idx].gmtoff);
+ icalcomponent_add_property(std_comp, icalprop);
+ icalprop = icalproperty_new_tzoffsetto(types[zidx].gmtoff);
+ icalcomponent_add_property(std_comp, icalprop);
+ icalcomponent_add_component(tz_comp, std_comp);
+ } else {
+ icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
+ }
+
+ if (dstidx != -1) {
+ zidx = trans_idx[dstidx];
+ zp_idx = trans_idx[dstidx-1];
+ dst_comp = icalcomponent_new(ICAL_XDAYLIGHT_COMPONENT);
+ icalprop = icalproperty_new_tzname(types[zidx].zname);
+ icalcomponent_add_property(dst_comp, icalprop);
+
+ /* DTSTART localtime uses TZOFFSETFROM UTC offset */
+ if (num_trans != 0) {
+ trans = transitions[dstidx] + types[zp_idx].gmtoff;
+ } else {
+ trans = (time_t)types[zp_idx].gmtoff;
+ }
+
+ icaltime = icaltime_from_timet(trans, 0);
+ dtstart = icaltime;
+ dtstart.year = 1970;
+ dtstart.minute = dtstart.second = 0;
+ icalprop = icalproperty_new_dtstart(dtstart);
+ icalcomponent_add_property(dst_comp, icalprop);
+
+ icalrecurrencetype_clear(&ical_recur);
+ ical_recur.freq = ICAL_YEARLY_RECURRENCE;
+ ical_recur.by_month[0] = icaltime.month;
+ pos = calculate_pos(icaltime);
+ pos < 0 ? (sign = -1): (sign = 1);
+ ical_recur.by_day[0] = sign * ((abs(pos) * 8) + icaltime_day_of_week(icaltime));
+ icalprop = icalproperty_new_rrule(ical_recur);
+ icalcomponent_add_property(dst_comp, icalprop);
+
+ adjust_dtstart_day_to_rrule(dst_comp, ical_recur);
+
+ icalprop = icalproperty_new_tzoffsetfrom(types[zp_idx].gmtoff);
+ icalcomponent_add_property(dst_comp, icalprop);
+
+ icalprop = icalproperty_new_tzoffsetto(types[zidx].gmtoff);
+ icalcomponent_add_property(dst_comp, icalprop);
+
+ icalcomponent_add_component(tz_comp, dst_comp);
+ }
+ } else { /*exact vtimezones*/
+ prev_idx = 0;
+ if (num_trans == 0) {
+ prev_idx = idx = 0;
+ } else {
+ idx = trans_idx[0];
+ }
+ start = 0;
+ for (i = 1; i < num_trans; i++, start = end) {
+ prev_idx = idx;
+ idx = trans_idx[i];
+ end = transitions[i] + types[prev_idx].gmtoff;
+ /* don't bother starting until the epoch */
+ if (0 > end)
+ continue;
+
+ if (types[prev_idx].isdst) {
+ comp = icalcomponent_new(ICAL_XDAYLIGHT_COMPONENT);
+ } else {
+ comp = icalcomponent_new(ICAL_XSTANDARD_COMPONENT);
+ }
+ icalprop = icalproperty_new_tzname(types[prev_idx].zname);
+ icalcomponent_add_property(comp, icalprop);
+ dtstart = icaltime_from_timet(start, 0);
+ icalprop = icalproperty_new_dtstart(dtstart);
+ icalcomponent_add_property(comp, icalprop);
+ icalprop = icalproperty_new_tzoffsetfrom(types[idx].gmtoff);
+ icalcomponent_add_property(comp, icalprop);
+ icalprop = icalproperty_new_tzoffsetto(types[prev_idx].gmtoff);
+ icalcomponent_add_property(comp, icalprop);
+ icalcomponent_add_component(tz_comp, comp);
+ }
+ /* finally, add a last zone with no end date */
+ if (types[idx].isdst) {
comp = icalcomponent_new(ICAL_XDAYLIGHT_COMPONENT);
} else {
comp = icalcomponent_new(ICAL_XSTANDARD_COMPONENT);
}
- icalprop = icalproperty_new_tzname(types[prev_idx].zname);
+ icalprop = icalproperty_new_tzname(types[idx].zname);
icalcomponent_add_property(comp, icalprop);
dtstart = icaltime_from_timet(start, 0);
icalprop = icalproperty_new_dtstart(dtstart);
icalcomponent_add_property(comp, icalprop);
- icalprop = icalproperty_new_tzoffsetfrom(types[idx].gmtoff);
+ icalprop = icalproperty_new_tzoffsetfrom(types[prev_idx].gmtoff);
icalcomponent_add_property(comp, icalprop);
- icalprop = icalproperty_new_tzoffsetto(types[prev_idx].gmtoff);
+ icalprop = icalproperty_new_tzoffsetto(types[idx].gmtoff);
icalcomponent_add_property(comp, icalprop);
icalcomponent_add_component(tz_comp, comp);
}
- /* finally, add a last zone with no end date */
- if (types[idx].isdst) {
- comp = icalcomponent_new(ICAL_XDAYLIGHT_COMPONENT);
- } else {
- comp = icalcomponent_new(ICAL_XSTANDARD_COMPONENT);
- }
- icalprop = icalproperty_new_tzname(types[idx].zname);
- icalcomponent_add_property(comp, icalprop);
- dtstart = icaltime_from_timet(start, 0);
- icalprop = icalproperty_new_dtstart(dtstart);
- icalcomponent_add_property(comp, icalprop);
- icalprop = icalproperty_new_tzoffsetfrom(types[prev_idx].gmtoff);
- icalcomponent_add_property(comp, icalprop);
- icalprop = icalproperty_new_tzoffsetto(types[idx].gmtoff);
- icalcomponent_add_property(comp, icalprop);
- icalcomponent_add_component(tz_comp, comp);
error:
if (f)
diff --git a/src/libical/icaltz-util.h b/src/libical/icaltz-util.h
index 2a9b3d89..e3981d5e 100644
--- a/src/libical/icaltz-util.h
+++ b/src/libical/icaltz-util.h
@@ -35,4 +35,10 @@ LIBICAL_ICAL_EXPORT const char *icaltzutil_get_zone_directory(void);
LIBICAL_ICAL_EXPORT icalcomponent *icaltzutil_fetch_timezone(const char *location);
+/* set @p on to 0 if inter-operable vtimezones are desired; else exact timezones are in-effect */
+LIBICAL_ICAL_EXPORT void icaltzutil_set_exact_vtimezones_support(int on);
+
+/* return 1 if exact vtimezones are in-effect; else inter-operable vtimezones are in-effect */
+LIBICAL_ICAL_EXPORT int icaltzutil_get_exact_vtimezones_support(void);
+
#endif
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
index 352c8c06..981695f4 100644
--- a/src/test/CMakeLists.txt
+++ b/src/test/CMakeLists.txt
@@ -156,7 +156,6 @@ if(NOT USE_BUILTIN_TZDATA)
testme(timezones "${timezones_SRCS}")
endif()
-
########### next target ###############
set(builtin_timezones_SRCS builtin_timezones.c)
diff --git a/src/test/timezones.c b/src/test/timezones.c
index 37d68630..b9362420 100644
--- a/src/test/timezones.c
+++ b/src/test/timezones.c
@@ -153,6 +153,13 @@ int main()
percent_failed = total_failed * 100 / (total_failed + total_okay);
printf(" *** Summary: %lu zones tested, %u days failed, %u okay => %u%% failed ***\n",
(unsigned long)timezones->num_elements, total_failed, total_okay, percent_failed);
+
+ if (!icaltzutil_get_exact_vtimezones_support()) {
+ if (!percent_failed) {
+ ret = 0;
+ printf(" *** Expect some small error rate with inter-operable vtimezones *** \n");
+ }
+ }
}
return ret;