25 #include "opensync_internals.h"
32 time_t timegm(
struct tm *t)
57 return (tl - (tb - tl));
72 static char *osync_time_timestamp_remove_dash(
const char *timestamp) {
74 GString *str = g_string_new(
"");
76 len = strlen(timestamp);
78 for (i=0; i < len; i++) {
79 if (timestamp[i] ==
'-')
82 if (timestamp[i] ==
':')
85 str = g_string_append_c(str, timestamp[i]);
88 return (
char*) g_string_free(str, FALSE);
96 char *osync_time_timestamp(
const char *vtime) {
101 timestamp = osync_time_timestamp_remove_dash(vtime);
112 char *osync_time_datestamp(
const char *vtime) {
117 GString *str = g_string_new (
"");
119 tmp = osync_time_timestamp_remove_dash(vtime);
121 for (p=tmp; *p && *p !=
'T'; p++)
122 str = g_string_append_c (str, *p);
127 return (
char*) g_string_free(str, FALSE);
134 osync_bool osync_time_isdate(
const char *vtime) {
136 int year, month, day;
138 if (strstr(vtime,
"T"))
142 if (sscanf(vtime,
"%04d%02d%02d", &year, &month, &day) != 3)
152 osync_bool osync_time_isutc(
const char *vtime) {
154 if (!strstr(vtime,
"Z"))
194 struct tm *osync_time_vtime2tm(
const char *vtime) {
198 struct tm *utime = g_malloc0(
sizeof(
struct tm));
207 sscanf(vtime,
"%04d%02d%02dT%02d%02d%02d%*01c",
208 &(utime->tm_year), &(utime->tm_mon), &(utime->tm_mday),
209 &(utime->tm_hour), &(utime->tm_min), &(utime->tm_sec));
211 utime->tm_year -= 1900;
215 utime->tm_isdst = -1;
230 char *osync_time_tm2vtime(
const struct tm *time, osync_bool is_utc) {
233 GString *vtime = g_string_new(
"");
235 g_string_printf(vtime,
"%04d%02d%02dT%02d%02d%02d",
236 time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
237 time->tm_hour, time->tm_min, time->tm_sec);
240 vtime = g_string_append(vtime,
"Z");
243 return g_string_free(vtime, FALSE);
252 time_t osync_time_vtime2unix(
const char *vtime,
int offset) {
255 struct tm *utime = NULL;
259 utc = osync_time_vtime2utc(vtime, offset);
260 utime = osync_time_vtime2tm(utc);
262 timestamp = osync_time_tm2unix(utime);
276 char *osync_time_unix2vtime(
const time_t *timestamp) {
282 gmtime_r(timestamp, &utc);
283 vtime = osync_time_tm2vtime(&utc, TRUE);
294 time_t osync_time_tm2unix(
const struct tm *tmtime) {
297 struct tm *tmp = g_malloc0(
sizeof(
struct tm));
299 memcpy(tmp, tmtime,
sizeof(
struct tm));
301 timestamp = timegm(tmp);
313 struct tm *osync_time_unix2tm(
const time_t *timestamp) {
318 gmtime_r(timestamp, &tmtime);
334 int osync_time_timezone_diff(
const struct tm *time) {
337 struct tm ltime, utime;
338 unsigned int lsecs, usecs;
342 timestamp = osync_time_tm2unix(time);
346 localtime_r(×tamp, <ime);
347 gmtime_r(×tamp, &utime);
349 lsecs = 3600 * ltime.tm_hour + 60 * ltime.tm_min + ltime.tm_sec;
350 usecs = 3600 * utime.tm_hour + 60 * utime.tm_min + utime.tm_sec;
352 zonediff = lsecs - usecs;
355 if (utime.tm_mday != ltime.tm_mday) {
356 if (utime.tm_mday < ltime.tm_mday)
357 zonediff += 24 * 3600;
359 zonediff -= 24 * 3600;
373 struct tm *osync_time_tm2utc(
const struct tm *ltime,
int offset) {
376 struct tm *tmtime = g_malloc0(
sizeof(
struct tm));
378 tmtime->tm_year = ltime->tm_year;
379 tmtime->tm_mon = ltime->tm_mon;
380 tmtime->tm_mday = ltime->tm_mday;
381 tmtime->tm_hour = ltime->tm_hour;
382 tmtime->tm_min = ltime->tm_min;
383 tmtime->tm_sec = ltime->tm_sec;
386 tmtime->tm_hour -= offset / 3600;
387 tmtime->tm_min -= (offset % 3600) / 60;
389 if (tmtime->tm_hour > 23 || tmtime->tm_hour < 0) {
391 if (tmtime->tm_hour < 0) {
392 tmtime->tm_hour += 24;
393 tmtime->tm_mday -= 1;
395 tmtime->tm_hour -= 24;
396 tmtime->tm_mday += 1;
411 struct tm *osync_time_tm2localtime(
const struct tm *utime,
int offset) {
413 struct tm *tmtime = g_malloc0(
sizeof(
struct tm));
415 tmtime->tm_year = utime->tm_year;
416 tmtime->tm_mon = utime->tm_mon;
417 tmtime->tm_mday = utime->tm_mday;
418 tmtime->tm_hour = utime->tm_hour;
419 tmtime->tm_min = utime->tm_min;
420 tmtime->tm_sec = utime->tm_sec;
422 tmtime->tm_hour += offset / 3600;
423 tmtime->tm_min += (offset % 3600) / 60;
425 if (tmtime->tm_hour > 23 || tmtime->tm_hour < 0) {
427 if (tmtime->tm_hour < 0) {
428 tmtime->tm_mday -= 1;
429 tmtime->tm_hour += 24;
431 tmtime->tm_mday += 1;
432 tmtime->tm_hour -= 24;
445 char *osync_time_vtime2utc(
const char* localtime,
int offset) {
449 struct tm *tm_local = NULL, *tm_utc = NULL;
451 if (strstr(localtime,
"Z")) {
452 utc = strdup(localtime);
456 tm_local = osync_time_vtime2tm(localtime);
457 tm_utc = osync_time_tm2utc(tm_local, offset);
458 utc = osync_time_tm2vtime(tm_utc, TRUE);
474 char *osync_time_vtime2localtime(
const char* utc,
int offset) {
476 char *localtime = NULL;
477 struct tm *tm_local = NULL, *tm_utc = NULL;
479 if (!strstr(utc,
"Z")) {
480 localtime = strdup(utc);
484 tm_utc = osync_time_vtime2tm(utc);
485 tm_local = osync_time_tm2localtime(tm_utc, offset);
486 localtime = osync_time_tm2vtime(tm_local, FALSE);
502 const char *_time_attr[] = {
518 static void _convert_time_field(GString *entry,
const char *field, osync_bool toUTC) {
522 char *new_stamp = NULL;
524 GString *stamp = g_string_new(
"");
526 if ((res = strstr(entry->str, field))) {
527 res += strlen(field);
529 for (i=0; res[i] !=
'\n' && res[i] !=
'\r'; i++)
530 stamp = g_string_append_c(stamp, res[i]);
532 gssize pos = res - entry->str;
533 entry = g_string_erase(entry, pos, i);
536 struct tm *tm_stamp = osync_time_vtime2tm(stamp->str);
537 tzdiff = osync_time_timezone_diff(tm_stamp);
541 new_stamp = osync_time_vtime2utc(stamp->str, tzdiff);
543 new_stamp = osync_time_vtime2localtime(stamp->str, tzdiff);
545 entry = g_string_insert(entry, pos, new_stamp);
556 char *_convert_entry(
const char *vcal, osync_bool toUTC) {
559 GString *new_entry = g_string_new(vcal);
561 for (i=0; _time_attr[i] != NULL; i++)
562 _convert_time_field(new_entry, _time_attr[i], toUTC);
564 return g_string_free(new_entry, FALSE);
572 char *osync_time_vcal2localtime(
const char *vcal) {
574 return _convert_entry(vcal, FALSE);
582 char *osync_time_vcal2utc(
const char *vcal) {
584 return _convert_entry(vcal, TRUE);
593 char *osync_time_sec2alarmdu(
int seconds) {
601 tmp = g_strdup(
"PT0S");
606 prefix = g_strdup(
"P");
608 prefix = g_strdup(
"-P");
613 if (!(seconds % (3600 * 24))) {
614 tmp = g_strdup_printf(
"%s%iD", prefix, seconds / (3600 * 24));
619 if (!(seconds % 3600)) {
620 tmp = g_strdup_printf(
"%sT%iH", prefix, seconds / 3600);
625 if (!(seconds % 60) && seconds < 3600) {
626 tmp = g_strdup_printf(
"%sT%iM", prefix, seconds / 60);
632 tmp = g_strdup_printf(
"%sT%iS", prefix, seconds);
637 tmp = g_strdup_printf(
"%sT%iM", prefix, seconds / 60);
640 tmp = g_strdup_printf(
"%sT%iH%iM", prefix, seconds / 3600,
641 (seconds % 3600) / 60);
643 if (seconds > (3600 * 24))
644 tmp = g_strdup_printf(
"%s%iDT%iH%iM", prefix, seconds / (3600 * 24),
645 seconds % (3600 * 24) / 3600,
646 ((seconds % (3600 * 24) % 3600)) / 60);
663 int osync_time_alarmdu2sec(
const char *alarm) {
670 int days = 0, weeks = 0, hours = 0, minutes = 0, seconds = 0;
672 for (i=0; i < (int) strlen(alarm); i++) {
714 sscanf((
char*)(alarm+i),
"%d",&digits);
720 secs = (weeks * 7 * 24 * 3600) + (days * 24 * 3600) + (hours * 3600) + (minutes * 60) + seconds;
737 int osync_time_str2wday(
const char *swday) {
741 if (!strcmp(swday,
"SU"))
743 else if (!strcmp(swday,
"MO"))
745 else if (!strcmp(swday,
"TU"))
747 else if (!strcmp(swday,
"WE"))
749 else if (!strcmp(swday,
"TH"))
751 else if (!strcmp(swday,
"FR"))
753 else if (!strcmp(swday,
"SA"))
769 struct tm *osync_time_relative2tm(
const char *byday,
const int bymonth,
const int year) {
771 struct tm *datestamp = g_malloc0(
sizeof(
struct tm));
773 int first_wday = 0, last_wday = 0;
774 int daymod, mday, searched_wday;
776 sscanf(byday,
"%d%s", &daymod, weekday);
779 searched_wday = osync_time_str2wday(weekday);
781 datestamp->tm_year = year - 1900;
782 datestamp->tm_mon = bymonth - 1;
783 datestamp->tm_mday = 0;
784 datestamp->tm_hour = 0;
785 datestamp->tm_min = 0;
786 datestamp->tm_sec = 0;
787 datestamp->tm_isdst = -1;
789 for (mday = 0; mday <= 31; mday++) {
790 datestamp->tm_mday = mday;
793 if (datestamp->tm_wday == searched_wday) {
795 first_wday = searched_wday;
797 last_wday = searched_wday;
802 datestamp->tm_mday = first_wday + (7 * (daymod - 1));
804 datestamp->tm_mday = last_wday - (7 * (daymod - 1));
816 int osync_time_utcoffset2sec(
const char *offset) {
820 int seconds = 0, sign = 1;
821 int hours = 0, minutes = 0;
823 sscanf(offset,
"%c%2d%2d", &csign, &hours, &minutes);
828 seconds = (hours * 3600 + minutes * 60) * sign;
841 struct tm *osync_time_dstchange(xmlNode *dstNode) {
844 struct tm *dst_change = NULL, *tm_started = NULL;
845 char *started = NULL, *rule = NULL, *byday = NULL;
847 xmlNode *current = osxml_get_node(dstNode,
"DateStarted");
848 started = (
char*) xmlNodeGetContent(current);
849 tm_started = osync_time_vtime2tm(started);
853 current = osxml_get_node(dstNode,
"RecurrenceRule");
854 current = current->children;
857 rule = (
char *) xmlNodeGetContent(current);
859 if (strstr(rule,
"BYDAY="))
860 byday = g_strdup(rule + 6);
861 else if (strstr(rule,
"BYMONTH="))
862 sscanf(rule,
"BYMONTH=%d", &month);
866 current = current->next;
869 dst_change = osync_time_relative2tm(byday, month, tm_started->tm_year + 1900);
873 dst_change->tm_hour = tm_started->tm_hour;
874 dst_change->tm_min = tm_started->tm_min;
887 osync_bool osync_time_isdst(
const char *vtime, xmlNode *tzid) {
892 char *newyear = NULL;
893 time_t newyear_t, timestamp;
894 struct tm *std_changetime, *dst_changetime;
895 time_t dstStamp, stdStamp;
896 xmlNode *current = NULL;
898 sscanf(vtime,
"%4d%*2d%*2dT%*2d%*d%*2d%*c", &year);
900 newyear = g_strdup_printf(
"%4d0101T000000", year);
901 newyear_t = osync_time_vtime2unix(newyear, 0);
902 timestamp = osync_time_vtime2unix(vtime, 0);
905 current = osxml_get_node(tzid,
"Standard");
906 std_changetime = osync_time_dstchange(current);
908 current = osxml_get_node(tzid,
"DaylightSavings");
909 dst_changetime = osync_time_dstchange(current);
912 dstStamp = osync_time_tm2unix(dst_changetime);
913 stdStamp = osync_time_tm2unix(std_changetime);
915 if (timestamp > stdStamp && timestamp < dstStamp) {
931 int osync_time_tzoffset(
const char *vtime, xmlNode *tz) {
937 xmlNode *current = NULL;
939 if (osync_time_isdst(vtime, tz))
940 current = osxml_get_node(tz,
"DaylightSavings");
942 current = osxml_get_node(tz,
"Standard");
944 offset = osxml_find_node(current,
"TZOffsetFrom");
945 seconds = osync_time_utcoffset2sec(offset);
956 char *osync_time_tzid(xmlNode *tz) {
961 id = osxml_find_node(tz,
"TimezoneID");
972 char *osync_time_tzlocation(xmlNode *tz) {
975 char *location = NULL;
977 location = osxml_find_node(tz,
"TimezoneLocation");
989 xmlNode *osync_time_tzinfo(xmlNode *root,
const char *tzid) {
994 char *tzinfo_tzid = NULL;
997 xmlNodeSet *nodes = NULL;
998 xmlXPathObject *xobj = NULL;
1001 xobj = osxml_get_nodeset(root->doc,
"/vcal/Timezone");
1002 nodes = xobj->nodesetval;
1003 numnodes = (nodes) ? nodes->nodeNr : 0;
1011 for (i=0; i < numnodes; i++) {
1012 tz = nodes->nodeTab[i];
1013 tzinfo_tzid = osync_time_tzid(tz);
1016 g_free(tzinfo_tzid);
1021 if (!strcmp(tzinfo_tzid, tzid))
1025 g_free(tzinfo_tzid);
1035 osync_trace(
TRACE_EXIT,
"%s: No matching Timezone node found. Seems to be a be a floating timestamp.", __func__);
1045 char *osync_time_tzlocal2utc(xmlNode *root,
const char *field) {
1049 char *utc = NULL, *field_tzid = NULL, *vtime = NULL;
1060 field_tzid = osync_time_tzid(root);
1066 tz = osync_time_tzinfo(root, field_tzid);
1072 vtime = osxml_find_node(root,
"Content");
1075 offset = osync_time_tzoffset(vtime, tz);
1076 struct tm *ttm = osync_time_vtime2tm(vtime);
1077 ttm->tm_hour -= offset / 3600;
1078 ttm->tm_min -= (offset % 3600) / 60;
1080 utc = osync_time_tm2vtime(ttm, TRUE);