Add support for timezones
authorAndy Spencer <andy753421@gmail.com>
Sun, 27 Nov 2016 07:39:37 +0000 (07:39 +0000)
committerAndy Spencer <andy753421@gmail.com>
Mon, 28 Nov 2016 09:54:02 +0000 (09:54 +0000)
date_t is always in local time so that we can work with it easier when
displaying calendars but stamp_t is always in UTC UNIX time. Calendar's
should can convert to the configured local time by first converting to
stamp_t then to date_t.

cals/ical.c
src/date.c
src/date.h
src/main.c
src/util.c

index b21cad0..57fff1e 100644 (file)
@@ -58,26 +58,14 @@ static int ical_compare(const void *_a, const void *_b)
               ecomp != 0 ? ecomp : 0 ;
 }
 
-static date_t to_date(struct icaltimetype time)
+static date_t to_date(struct icaltimetype itime)
 {
-       return (date_t){
-               .year  = time.year,
-               .month = time.month ? time.month-1 : 0,
-               .day   = time.day   ? time.day  -1 : 0,
-               .hour  = time.hour,
-               .min   = time.minute,
-       };
+       return get_date(icaltime_as_timet_with_zone(itime, itime.zone));
 }
 
-static icaltimetype to_itime(date_t time)
+static icaltimetype to_itime(date_t date)
 {
-       return (struct icaltimetype){
-               .year   = time.year,
-               .month  = time.month + 1,
-               .day    = time.day   + 1,
-               .hour   = time.hour,
-               .minute = time.min
-       };
+       return icaltime_from_timet_with_zone(get_stamp(date), 0, NULL);
 }
 
 static void add_recur(cal_t *cal,
index 8441441..4371dff 100644 (file)
 
 /* Time Keeping Bugs Abound! */
 
+#define _POSIX_C_SOURCE 200112L
+
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <time.h>
 
+#include "util.h"
+#include "conf.h"
 #include "date.h"
 
 /* Global data */
@@ -29,27 +35,24 @@ date_t  SEL;
 /* Initialize */
 void date_init(void)
 {
-       time_t     sec = time(NULL);
-       struct tm *tm  = localtime(&sec);
+       /* Sync current time */
+       NOW = get_date(0);
 
-       SEL.year  = tm->tm_year+1900;
-       SEL.month = tm->tm_mon;
-       SEL.day   = tm->tm_mday-1;
+       /* Sync selection */
+       SEL.year  = NOW.year;
+       SEL.month = NOW.month;
+       SEL.day   = NOW.day;
+}
 
-       date_sync();
+void date_config(const char *group, const char *name, const char *key, const char *value)
+{
+       if (match(group, "date") && match(key, "timezone") && value)
+               setenv("TZ", get_string(value), 1);
 }
 
 void date_sync(void)
 {
-       time_t     sec = time(NULL);
-       struct tm *tm  = localtime(&sec);
-
-       NOW.year  = tm->tm_year+1900;
-       NOW.month = tm->tm_mon;
-       NOW.day   = tm->tm_mday-1;
-       NOW.hour  = tm->tm_hour;
-       NOW.min   = tm->tm_min;
-       NOW.sec   = tm->tm_sec;
+       NOW = get_date(0);
 }
 
 /* Time functions */
@@ -101,16 +104,17 @@ wday_t start_of_month(year_t year, month_t month)
 
 void add_days(year_t *year, month_t *month, day_t *day, int days)
 {
-       time_t time = mktime(&(struct tm){
-                       .tm_year = *year-1900,
-                       .tm_mon  = *month,
-                       .tm_mday = *day+1,
-                       .tm_hour = 12});
-       time  += days*24*60*60;
-       struct tm *tm = localtime(&time);
-       *year  = tm->tm_year+1900;
-       *month = tm->tm_mon;
-       *day   = tm->tm_mday-1;
+       date_t date = {
+               .year  = *year,
+               .month = *month,
+               .day   = *day,
+               .hour  = 12
+       };
+       stamp_t stamp = get_stamp(date);
+       date_t  then  = get_date(stamp + days*24*60*60);
+       *year  = then.year;
+       *month = then.month;
+       *day   = then.day;
 }
 
 void add_months(year_t *year, month_t *month, int months)
@@ -120,19 +124,39 @@ void add_months(year_t *year, month_t *month, int months)
        *month = total % 12;
 }
 
-stamp_t get_time(date_t *date)
+/* Date functions */
+date_t get_date(stamp_t stamp)
+{
+       time_t t = stamp ? stamp : time(NULL);
+       struct tm *tm = localtime(&t);
+       date_t date = {
+               .year  = tm->tm_year+1900,
+               .month = tm->tm_mon,
+               .day   = tm->tm_mday-1,
+               .hour  = tm->tm_hour,
+               .min   = tm->tm_min,
+               .sec   = tm->tm_sec,
+       };
+       return date;
+}
+
+stamp_t get_stamp(date_t date)
 {
-       return mktime(&(struct tm){
-               .tm_year = date->year-1900,
-               .tm_mon  = date->month,
-               .tm_mday = date->day+1,
-               .tm_hour = date->hour,
-               .tm_min  = date->min});
+       struct tm tm = {
+               .tm_year = date.year-1900,
+               .tm_mon  = date.month,
+               .tm_mday = date.day+1,
+               .tm_hour = date.hour,
+               .tm_min  = date.min,
+               .tm_sec  = date.sec,
+       };
+       time_t t = mktime(&tm);
+       return (stamp_t)t;
 }
 
 int get_mins(date_t *start, date_t *end)
 {
-       return (get_time(end)-get_time(start))/60;
+       return (get_stamp(*end)-get_stamp(*start))/60;
 }
 
 int compare(date_t *a, date_t *b)
@@ -209,6 +233,19 @@ const char *day_to_string(wday_t day)
 /* Test functions */
 void date_test(void)
 {
+       setenv("TZ", "US/Central", 1);
+
+       time_t  timet = time(NULL);
+       date_t  date  = get_date(timet);
+       stamp_t stamp = get_stamp(date);
+
+       printf("Time\n");
+       printf("  time  %ld\n",  timet);
+       printf("  stamp %lld\n", stamp);
+       printf("  date  %04d-%02d-%02d %02d:%02d %02ds\n",
+                       date.year, date.month, date.day,
+                       date.hour, date.min,   date.sec);
+
        printf("Info\n");
        printf("  Year   Month       Start   Weeks   Days\n");
        for (int y = 2012; y <= 2012; y++)
index 7a0c8ac..ccd2252 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-/* Time types */
+/* UTC time stamp */
 typedef long long stamp_t;
 
+/* Local time type */
 typedef int year_t;
 typedef int day_t;
 typedef int hour_t;
@@ -65,6 +66,7 @@ extern date_t SEL; // date and time the user is looking at
 /* Initialize */
 void date_init(void);
 void date_sync(void);
+void date_config(const char *group, const char *name, const char *key, const char *value);
 
 /* Time functions */
 int is_leap_year(year_t year);
@@ -77,7 +79,9 @@ day_t start_of_week(year_t year, month_t month, day_t day);
 void add_days(year_t *year, month_t *month, day_t *day, int days);
 void add_months(year_t *year, month_t *month, int months);
 
-stamp_t get_stamp(date_t *date);
+/* Date functions */
+date_t get_date(stamp_t stamp);
+stamp_t get_stamp(date_t date);
 int get_mins(date_t *start, date_t *end);
 int compare(date_t *a, date_t *b);
 int same_day(date_t *a, date_t *b);
index 99816b1..ce35539 100644 (file)
@@ -28,8 +28,9 @@
 /* Config parser */
 static void on_config(const char *group, const char *name, const char *key, const char *value)
 {
-       view_config(group, name, key, value);
+       date_config(group, name, key, value);
        cal_config(group, name, key, value);
+       view_config(group, name, key, value);
 }
 
 /* Control-C handler, so we don't hose the therminal */
index 1ebecfc..d74a746 100644 (file)
@@ -28,6 +28,7 @@
 #include "view.h"
 #include "util.h"
 
+#pragma weak view_exit
 #pragma weak view_debug
 
 /* Static data */
@@ -155,6 +156,7 @@ void error(char *fmt, ...)
        fflush(stderr);
        message(stderr, "error", fmt, ap);
        va_end(ap);
-       view_exit();
+       if (view_exit)
+               view_exit();
        exit(-1);
 }