summaryrefslogtreecommitdiff
path: root/src/test/timezones.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/timezones.c')
-rw-r--r--src/test/timezones.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/test/timezones.c b/src/test/timezones.c
new file mode 100644
index 0000000..ac8598f
--- /dev/null
+++ b/src/test/timezones.c
@@ -0,0 +1,134 @@
+/* -*- Mode: C -*-
+ ======================================================================
+
+ The contents of this file are subject to the Mozilla Public License
+ Version 1.0 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and
+ limitations under the License.
+
+ ======================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libical/ical.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+ icalarray *timezones = icaltimezone_get_builtin_timezones();
+ int i;
+ int ret = 0;
+ unsigned int total_failed = 0;
+ unsigned int total_okay = 0;
+ int verbose = 0;
+ icaltimezone *utc_zone = icaltimezone_get_utc_timezone();
+
+ /* for all known time zones... */
+ for (i = 0; i < timezones->num_elements; i++) {
+ icaltimezone *zone = icalarray_element_at(timezones, i);
+ const char *zone_location = icaltimezone_get_location(zone);
+ int day;
+ time_t start_time;
+ struct tm start_tm;
+ time_t curr_time;
+ struct tm curr_tm;
+ struct icaltimetype curr_tt;
+ int failed = 0;
+ int curr_failed;
+
+ /*
+ * select this location for glibc: needs support for TZ=<location>
+ * which is not POSIX
+ */
+ setenv("TZ", zone_location, 1);
+ tzset();
+
+ /*
+ * determine current local time and date: always use midday in
+ * the current zone
+ */
+ start_time = time(NULL);
+ localtime_r(&start_time, &start_tm);
+ start_tm.tm_hour = 12;
+ start_tm.tm_min = 0;
+ start_tm.tm_sec = 0;
+ start_time = mktime(&start_tm);
+
+ /* check time conversion for the next 365 days */
+ for (day = 0, curr_time = start_time;
+ day < 365;
+ day++, curr_time += 24 * 60 * 60) {
+ /* determine date/time with glibc */
+ localtime_r(&curr_time, &curr_tm);
+ /* determine date/time with libical */
+ curr_tt = icaltime_from_timet_with_zone(curr_time, 0, utc_zone);
+ curr_tt.zone = utc_zone; /* workaround: icaltime_from_timet_with_zone() should do this, but doesn't! */
+ curr_tt = icaltime_convert_to_zone(curr_tt, zone);
+
+ /* compare... */
+ curr_failed =
+ curr_tm.tm_year + 1900 != curr_tt.year ||
+ curr_tm.tm_mon + 1 != curr_tt.month ||
+ curr_tm.tm_mday != curr_tt.day ||
+ curr_tm.tm_hour != curr_tt.hour ||
+ curr_tm.tm_min != curr_tt.minute ||
+ curr_tm.tm_sec != curr_tt.second;
+
+ /* only print first failed day and first day which is okay again */
+ if (verbose || curr_failed != failed) {
+ printf("%s: day %03d: %s: libc %04d-%02d-%02d %02d:%02d:%02d dst %d",
+ zone_location,
+ day,
+ verbose ?
+ (curr_failed ? "failed" : "okay") :
+ (curr_failed ? "first failed" : "okay again"),
+
+ curr_tm.tm_year + 1900,
+ curr_tm.tm_mon + 1,
+ curr_tm.tm_mday,
+ curr_tm.tm_hour,
+ curr_tm.tm_min,
+ curr_tm.tm_sec,
+ curr_tm.tm_isdst);
+ if (curr_failed) {
+ printf(" != libical %04d-%02d-%02d %02d:%02d:%02d dst %d",
+ curr_tt.year,
+ curr_tt.month,
+ curr_tt.day,
+ curr_tt.hour,
+ curr_tt.minute,
+ curr_tt.second,
+ curr_tt.is_daylight);
+ ret = 1;
+ }
+ printf("\n");
+ failed = curr_failed;
+ }
+
+ if (curr_failed) {
+ total_failed++;
+ } else {
+ total_okay++;
+ }
+ }
+ }
+
+ if (total_failed || total_okay) {
+ printf(" *** Summary: %d zones tested, %u days failed, %u okay => %u%% failed ***\n",
+ timezones->num_elements,
+ total_failed,
+ total_okay,
+ total_failed * 100 / (total_failed + total_okay));
+ }
+
+ return ret;
+}