From 1ea97795be8f9b8d63c5266ac7ea4889c3224a4d Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Mon, 23 Feb 2015 10:43:54 +0100 Subject: Add support for UTC times in iCal imports According to the iCal standard (4.3.12 Time): UTC time, or absolute time, is identified by a LATIN CAPITAL LETTER Z suffix character (US-ASCII decimal 90), the UTC designator, appended to the time value. Parse such time values properly when importing iCal files. Fixes GitHub issue #3. Signed-off-by: Lukas Fleischer --- src/calcurse.h | 1 + src/ical.c | 21 +++++++++++++-------- src/utils.c | 25 +++++++++++++++++++++++++ test/Makefile.am | 2 ++ test/data/ical-007.ical | 13 +++++++++++++ test/ical-007.sh | 24 ++++++++++++++++++++++++ 6 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 test/data/ical-007.ical create mode 100755 test/ical-007.sh diff --git a/src/calcurse.h b/src/calcurse.h index 6700d5b..6e686e4 100644 --- a/src/calcurse.h +++ b/src/calcurse.h @@ -1054,6 +1054,7 @@ long get_item_time(long); int get_item_hour(long); int get_item_min(long); long date2sec(struct date, unsigned, unsigned); +long utcdate2sec(struct date, unsigned, unsigned); char *date_sec2date_str(long, const char *); void date_sec2date_fmt(long, const char *, char *); long date_sec_change(long, int, int); diff --git a/src/ical.c b/src/ical.c index 4d1edab..e3ddc07 100644 --- a/src/ical.c +++ b/src/ical.c @@ -477,7 +477,7 @@ ical_chk_header(FILE * fd, char *buf, char *lstore, unsigned *lineno, * where DATE is 'YYYYMMDD' and TIME is 'HHMMSS'. * The time and 'T' separator are optional (in the case of an day-long event). * - * Optionnaly, if the type pointer is given, specify if it is an event + * Optionally, if the type pointer is given, specify if it is an event * (no time is given, meaning it is an all-day event), or an appointment * (time is given). * @@ -485,22 +485,27 @@ ical_chk_header(FILE * fd, char *buf, char *lstore, unsigned *lineno, */ static long ical_datetime2long(char *datestr, ical_vevent_e * type) { - const int NOTFOUND = 0, FORMAT_DATE = 3, FORMAT_DATETIME = 5; + const int NOTFOUND = 0, FORMAT_DATE = 3, FORMAT_DATETIME = 6, + FORMAT_DATETIMEZ = 7; struct date date; - unsigned hour, min; - long datelong; + unsigned hour, min, sec; + char c; + long datelong ; int format; - format = sscanf(datestr, "%04u%02u%02uT%02u%02u", - &date.yyyy, &date.mm, &date.dd, &hour, &min); + format = sscanf(datestr, "%04u%02u%02uT%02u%02u%02u%c", + &date.yyyy, &date.mm, &date.dd, &hour, &min, &sec, &c); if (format == FORMAT_DATE) { if (type) *type = EVENT; datelong = date2sec(date, 0, 0); - } else if (format == FORMAT_DATETIME) { + } else if (format == FORMAT_DATETIME || format == FORMAT_DATETIMEZ) { if (type) *type = APPOINTMENT; - datelong = date2sec(date, hour, min); + if (format == FORMAT_DATETIMEZ && c == 'Z') + datelong = utcdate2sec(date, hour, min); + else + datelong = date2sec(date, hour, min); } else { datelong = NOTFOUND; } diff --git a/src/utils.c b/src/utils.c index b52de74..c7dc61c 100644 --- a/src/utils.c +++ b/src/utils.c @@ -386,6 +386,31 @@ long date2sec(struct date day, unsigned hour, unsigned min) return t; } +time_t +utcdate2sec(struct date day, unsigned hour, unsigned min) +{ + char *tz; + time_t t; + + tz = getenv("TZ"); + if (tz) + tz = mem_strdup(tz); + setenv("TZ", "", 1); + tzset(); + + t = date2sec(day, hour, min); + + if (tz) { + setenv("TZ", tz, 1); + mem_free(tz); + } else { + unsetenv("TZ"); + } + tzset(); + + return t; +} + /* Return a string containing the date, given a date in seconds. */ char *date_sec2date_str(long sec, const char *datefmt) { diff --git a/test/Makefile.am b/test/Makefile.am index fe205a2..efc3d12 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -48,6 +48,7 @@ TESTS = \ ical-004.sh \ ical-005.sh \ ical-006.sh \ + ical-007.sh \ next-001.sh \ search-001.sh \ bug-002.sh \ @@ -111,4 +112,5 @@ EXTRA_DIST = \ data/ical-004.ical \ data/ical-005.ical \ data/ical-006.ical \ + data/ical-007.ical \ data/todo diff --git a/test/data/ical-007.ical b/test/data/ical-007.ical new file mode 100644 index 0000000..e46c3fb --- /dev/null +++ b/test/data/ical-007.ical @@ -0,0 +1,13 @@ +BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +SUMMARY:Local time +DTSTART:20150223T110000 +DURATION:PT1H +END:VEVENT +BEGIN:VEVENT +SUMMARY:UTC +DTSTART:20150223T110000Z +DURATION:PT1H +END:VEVENT +END:VCALENDAR diff --git a/test/ical-007.sh b/test/ical-007.sh new file mode 100755 index 0000000..8f0f472 --- /dev/null +++ b/test/ical-007.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +. "${TEST_INIT:-./test-init.sh}" + +if [ "$1" = 'actual' ]; then + mkdir .calcurse || exit 1 + cp "$DATA_DIR/conf" .calcurse || exit 1 + TZ="America/New_York" "$CALCURSE" -D "$PWD/.calcurse" \ + -i "$DATA_DIR/ical-007.ical" + "$CALCURSE" -D "$PWD/.calcurse" -s2015-02-23 + rm -rf .calcurse || exit 1 +elif [ "$1" = 'expected' ]; then + cat < 07:00 + UTC + - 11:00 -> 12:00 + Local time +EOD +else + ./run-test "$0" +fi -- cgit v1.2.3