Diffstat (limited to 'libical/src/libical/icaltime.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | libical/src/libical/icaltime.c | 577 |
1 files changed, 577 insertions, 0 deletions
diff --git a/libical/src/libical/icaltime.c b/libical/src/libical/icaltime.c new file mode 100644 index 0000000..a04ca04 --- a/dev/null +++ b/libical/src/libical/icaltime.c | |||
@@ -0,0 +1,577 @@ | |||
1 | /* -*- Mode: C -*- | ||
2 | ====================================================================== | ||
3 | FILE: icaltime.c | ||
4 | CREATOR: eric 02 June 2000 | ||
5 | |||
6 | $Id$ | ||
7 | $Locker$ | ||
8 | |||
9 | (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org | ||
10 | |||
11 | This program is free software; you can redistribute it and/or modify | ||
12 | it under the terms of either: | ||
13 | |||
14 | The LGPL as published by the Free Software Foundation, version | ||
15 | 2.1, available at: http://www.fsf.org/copyleft/lesser.html | ||
16 | |||
17 | Or: | ||
18 | |||
19 | The Mozilla Public License Version 1.0. You may obtain a copy of | ||
20 | the License at http://www.mozilla.org/MPL/ | ||
21 | |||
22 | The Original Code is eric. The Initial Developer of the Original | ||
23 | Code is Eric Busboom | ||
24 | |||
25 | |||
26 | ======================================================================*/ | ||
27 | |||
28 | #ifdef HAVE_CONFIG_H | ||
29 | #include <config.h> | ||
30 | #endif | ||
31 | |||
32 | #include "icaltime.h" | ||
33 | #include <assert.h> | ||
34 | #include <string.h> | ||
35 | #include <stdlib.h> | ||
36 | #include <stdio.h> | ||
37 | |||
38 | int snprintf(char *str, size_t n, char const *fmt, ...); | ||
39 | |||
40 | #ifdef ICAL_NO_LIBICAL | ||
41 | #define icalerror_set_errno(x) | ||
42 | #define icalerror_check_arg_rv(x,y) | ||
43 | #define icalerror_check_arg_re(x,y,z) | ||
44 | #else | ||
45 | #include "icalerror.h" | ||
46 | #include "icalmemory.h" | ||
47 | #endif | ||
48 | |||
49 | |||
50 | |||
51 | |||
52 | struct icaltimetype | ||
53 | icaltime_from_timet(time_t tm, int is_date) | ||
54 | { | ||
55 | struct icaltimetype tt = icaltime_null_time(); | ||
56 | struct tm t; | ||
57 | |||
58 | t = *(gmtime(&tm)); | ||
59 | |||
60 | if(is_date == 0){ | ||
61 | tt.second = t.tm_sec; | ||
62 | tt.minute = t.tm_min; | ||
63 | tt.hour = t.tm_hour; | ||
64 | } else { | ||
65 | tt.second = tt.minute =tt.hour = 0 ; | ||
66 | } | ||
67 | |||
68 | tt.day = t.tm_mday; | ||
69 | tt.month = t.tm_mon + 1; | ||
70 | tt.year = t.tm_year+ 1900; | ||
71 | |||
72 | tt.is_utc = 1; | ||
73 | tt.is_date = is_date; | ||
74 | |||
75 | return tt; | ||
76 | } | ||
77 | |||
78 | /* Structure used by set_tz to hold an old value of TZ, and the new | ||
79 | value, which is in memory we will have to free in unset_tz */ | ||
80 | struct set_tz_save {char* orig_tzid; char* new_env_str;}; | ||
81 | |||
82 | /* Temporarily change the TZ environmental variable. */ | ||
83 | struct set_tz_save set_tz(const char* tzid) | ||
84 | { | ||
85 | |||
86 | char *orig_tzid = 0; | ||
87 | char *new_env_str; | ||
88 | struct set_tz_save savetz; | ||
89 | size_t tmp_sz; | ||
90 | |||
91 | savetz.orig_tzid = 0; | ||
92 | savetz.new_env_str = 0; | ||
93 | |||
94 | if(getenv("TZ") != 0){ | ||
95 | orig_tzid = (char*)icalmemory_strdup(getenv("TZ")); | ||
96 | |||
97 | if(orig_tzid == 0){ | ||
98 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | ||
99 | return savetz; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | tmp_sz =strlen(tzid)+4; | ||
104 | new_env_str = (char*)malloc(tmp_sz); | ||
105 | |||
106 | if(new_env_str == 0){ | ||
107 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | ||
108 | return savetz; | ||
109 | } | ||
110 | |||
111 | /* Copy the TZid into a string with the form that putenv expects. */ | ||
112 | strcpy(new_env_str,"TZ="); | ||
113 | strcpy(new_env_str+3,tzid); | ||
114 | |||
115 | putenv(new_env_str); | ||
116 | |||
117 | /* Old value of TZ and the string we will have to free later */ | ||
118 | savetz.orig_tzid = orig_tzid; | ||
119 | savetz.new_env_str = new_env_str; | ||
120 | return savetz; | ||
121 | } | ||
122 | |||
123 | void unset_tz(struct set_tz_save savetz) | ||
124 | { | ||
125 | /* restore the original TZ environment */ | ||
126 | |||
127 | char* orig_tzid = savetz.orig_tzid; | ||
128 | |||
129 | if(orig_tzid!=0){ | ||
130 | size_t tmp_sz =strlen(orig_tzid)+4; | ||
131 | char* orig_env_str = (char*)icalmemory_tmp_buffer(tmp_sz); | ||
132 | |||
133 | if(orig_env_str == 0){ | ||
134 | icalerror_set_errno(ICAL_NEWFAILED_ERROR); | ||
135 | return; | ||
136 | } | ||
137 | |||
138 | strcpy(orig_env_str,"TZ="); | ||
139 | strcpy(orig_env_str+3,orig_tzid); | ||
140 | #ifndef _WIN32 | ||
141 | setenv("TZ", savetz.orig_tzid,1 ); | ||
142 | #else | ||
143 | putenv("TZ=MEZ");//, savetz.orig_tzid ); | ||
144 | #endif | ||
145 | free(orig_tzid); | ||
146 | } else { | ||
147 | #ifdef __FreeBSD__ | ||
148 | unsetenv("TZ"); | ||
149 | #else | ||
150 | putenv("TZ"); /* Delete from environment */ | ||
151 | #endif | ||
152 | } | ||
153 | |||
154 | if(savetz.new_env_str != 0){ | ||
155 | free(savetz.new_env_str); | ||
156 | } | ||
157 | } | ||
158 | |||
159 | |||
160 | time_t icaltime_as_timet(struct icaltimetype tt) | ||
161 | { | ||
162 | struct tm stm; | ||
163 | time_t t; | ||
164 | |||
165 | memset(&stm,0,sizeof( struct tm)); | ||
166 | |||
167 | if(icaltime_is_null_time(tt)) { | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | stm.tm_sec = tt.second; | ||
172 | stm.tm_min = tt.minute; | ||
173 | stm.tm_hour = tt.hour; | ||
174 | stm.tm_mday = tt.day; | ||
175 | stm.tm_mon = tt.month-1; | ||
176 | stm.tm_year = tt.year-1900; | ||
177 | stm.tm_isdst = -1; | ||
178 | |||
179 | if(tt.is_utc == 1 || tt.is_date == 1){ | ||
180 | struct set_tz_save old_tz = set_tz("UTC"); | ||
181 | t = mktime(&stm); | ||
182 | unset_tz(old_tz); | ||
183 | } else { | ||
184 | t = mktime(&stm); | ||
185 | } | ||
186 | |||
187 | return t; | ||
188 | |||
189 | } | ||
190 | |||
191 | char* icaltime_as_ical_string(struct icaltimetype tt) | ||
192 | { | ||
193 | size_t size = 17; | ||
194 | char* buf = icalmemory_new_buffer(size); | ||
195 | |||
196 | if(tt.is_date){ | ||
197 | snprintf(buf, size,"%04d%02d%02d",tt.year,tt.month,tt.day); | ||
198 | } else { | ||
199 | char* fmt; | ||
200 | if(tt.is_utc){ | ||
201 | fmt = "%04d%02d%02dT%02d%02d%02dZ"; | ||
202 | } else { | ||
203 | fmt = "%04d%02d%02dT%02d%02d%02d"; | ||
204 | } | ||
205 | snprintf(buf, size,fmt,tt.year,tt.month,tt.day, | ||
206 | tt.hour,tt.minute,tt.second); | ||
207 | } | ||
208 | |||
209 | icalmemory_add_tmp_buffer(buf); | ||
210 | |||
211 | return buf; | ||
212 | |||
213 | } | ||
214 | |||
215 | |||
216 | /* convert tt, of timezone tzid, into a utc time */ | ||
217 | struct icaltimetype icaltime_as_utc(struct icaltimetype tt,const char* tzid) | ||
218 | { | ||
219 | int tzid_offset; | ||
220 | |||
221 | if(tt.is_utc == 1 || tt.is_date == 1){ | ||
222 | return tt; | ||
223 | } | ||
224 | |||
225 | tzid_offset = icaltime_utc_offset(tt,tzid); | ||
226 | |||
227 | tt.second -= tzid_offset; | ||
228 | |||
229 | tt.is_utc = 1; | ||
230 | |||
231 | return icaltime_normalize(tt); | ||
232 | } | ||
233 | |||
234 | /* convert tt, a time in UTC, into a time in timezone tzid */ | ||
235 | struct icaltimetype icaltime_as_zone(struct icaltimetype tt,const char* tzid) | ||
236 | { | ||
237 | int tzid_offset; | ||
238 | |||
239 | tzid_offset = icaltime_utc_offset(tt,tzid); | ||
240 | |||
241 | tt.second += tzid_offset; | ||
242 | |||
243 | tt.is_utc = 0; | ||
244 | |||
245 | return icaltime_normalize(tt); | ||
246 | |||
247 | } | ||
248 | |||
249 | |||
250 | /* Return the offset of the named zone as seconds. tt is a time | ||
251 | indicating the date for which you want the offset */ | ||
252 | int icaltime_utc_offset(struct icaltimetype ictt, const char* tzid) | ||
253 | { | ||
254 | |||
255 | time_t tt = icaltime_as_timet(ictt); | ||
256 | time_t offset_tt; | ||
257 | struct tm gtm; | ||
258 | struct set_tz_save old_tz; | ||
259 | |||
260 | if(tzid != 0){ | ||
261 | old_tz = set_tz(tzid); | ||
262 | } | ||
263 | |||
264 | /* Mis-interpret a UTC broken out time as local time */ | ||
265 | gtm = *(gmtime(&tt)); | ||
266 | gtm.tm_isdst = localtime(&tt)->tm_isdst; | ||
267 | offset_tt = mktime(>m); | ||
268 | |||
269 | if(tzid != 0){ | ||
270 | unset_tz(old_tz); | ||
271 | } | ||
272 | |||
273 | return tt-offset_tt; | ||
274 | } | ||
275 | |||
276 | |||
277 | |||
278 | /* Normalize by converting from localtime to utc and back to local | ||
279 | time. This uses localtime because localtime and mktime are inverses | ||
280 | of each other */ | ||
281 | |||
282 | struct icaltimetype icaltime_normalize(struct icaltimetype tt) | ||
283 | { | ||
284 | struct tm stm; | ||
285 | time_t tut; | ||
286 | |||
287 | memset(&stm,0,sizeof( struct tm)); | ||
288 | |||
289 | stm.tm_sec = tt.second; | ||
290 | stm.tm_min = tt.minute; | ||
291 | stm.tm_hour = tt.hour; | ||
292 | stm.tm_mday = tt.day; | ||
293 | stm.tm_mon = tt.month-1; | ||
294 | stm.tm_year = tt.year-1900; | ||
295 | stm.tm_isdst = -1; /* prevents mktime from changing hour based on | ||
296 | daylight savings */ | ||
297 | |||
298 | tut = mktime(&stm); | ||
299 | |||
300 | stm = *(localtime(&tut)); | ||
301 | |||
302 | tt.second = stm.tm_sec; | ||
303 | tt.minute = stm.tm_min; | ||
304 | tt.hour = stm.tm_hour; | ||
305 | tt.day = stm.tm_mday; | ||
306 | tt.month = stm.tm_mon +1; | ||
307 | tt.year = stm.tm_year+1900; | ||
308 | |||
309 | return tt; | ||
310 | } | ||
311 | |||
312 | |||
313 | #ifndef ICAL_NO_LIBICAL | ||
314 | #include "icalvalue.h" | ||
315 | |||
316 | struct icaltimetype icaltime_from_string(const char* str) | ||
317 | { | ||
318 | struct icaltimetype tt = icaltime_null_time(); | ||
319 | int size; | ||
320 | |||
321 | icalerror_check_arg_re(str!=0,"str",icaltime_null_time()); | ||
322 | |||
323 | size = strlen(str); | ||
324 | |||
325 | if(size == 15) { /* floating time */ | ||
326 | tt.is_utc = 0; | ||
327 | tt.is_date = 0; | ||
328 | } else if (size == 16) { /* UTC time, ends in 'Z'*/ | ||
329 | tt.is_utc = 1; | ||
330 | tt.is_date = 0; | ||
331 | |||
332 | if(str[15] != 'Z'){ | ||
333 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
334 | return icaltime_null_time(); | ||
335 | } | ||
336 | |||
337 | } else if (size == 8) { /* A DATE */ | ||
338 | tt.is_utc = 1; | ||
339 | tt.is_date = 1; | ||
340 | } else { /* error */ | ||
341 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
342 | return icaltime_null_time(); | ||
343 | } | ||
344 | |||
345 | if(tt.is_date == 1){ | ||
346 | sscanf(str,"%04d%02d%02d",&tt.year,&tt.month,&tt.day); | ||
347 | } else { | ||
348 | char tsep; | ||
349 | sscanf(str,"%04d%02d%02d%c%02d%02d%02d",&tt.year,&tt.month,&tt.day, | ||
350 | &tsep,&tt.hour,&tt.minute,&tt.second); | ||
351 | |||
352 | if(tsep != 'T'){ | ||
353 | icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR); | ||
354 | return icaltime_null_time(); | ||
355 | } | ||
356 | |||
357 | } | ||
358 | |||
359 | return tt; | ||
360 | } | ||
361 | #endif | ||
362 | |||
363 | char ctime_str[20]; | ||
364 | char* icaltime_as_ctime(struct icaltimetype t) | ||
365 | { | ||
366 | time_t tt; | ||
367 | |||
368 | tt = icaltime_as_timet(t); | ||
369 | sprintf(ctime_str,"%s",ctime(&tt)); | ||
370 | |||
371 | ctime_str[strlen(ctime_str)-1] = 0; | ||
372 | |||
373 | return ctime_str; | ||
374 | } | ||
375 | |||
376 | |||
377 | short days_in_month[] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; | ||
378 | |||
379 | short icaltime_days_in_month(short month,short year) | ||
380 | { | ||
381 | |||
382 | int is_leap =0; | ||
383 | int days = days_in_month[month]; | ||
384 | |||
385 | assert(month > 0); | ||
386 | assert(month <= 12); | ||
387 | |||
388 | if( (year % 4 == 0 && year % 100 != 0) || | ||
389 | year % 400 == 0){ | ||
390 | is_leap =1; | ||
391 | } | ||
392 | |||
393 | if( month == 2){ | ||
394 | days += is_leap; | ||
395 | } | ||
396 | |||
397 | return days; | ||
398 | } | ||
399 | |||
400 | /* 1-> Sunday, 7->Saturday */ | ||
401 | short icaltime_day_of_week(struct icaltimetype t){ | ||
402 | |||
403 | time_t tt = icaltime_as_timet(t); | ||
404 | struct tm *tm; | ||
405 | |||
406 | if(t.is_utc == 1 || t.is_date == 1){ | ||
407 | tm = gmtime(&tt); | ||
408 | } else { | ||
409 | tm = localtime(&tt); | ||
410 | } | ||
411 | |||
412 | return tm->tm_wday+1; | ||
413 | } | ||
414 | |||
415 | /* Day of the year that the first day of the week (Sunday) is on */ | ||
416 | short icaltime_start_doy_of_week(struct icaltimetype t){ | ||
417 | time_t tt = icaltime_as_timet(t); | ||
418 | time_t start_tt; | ||
419 | struct tm *stm; | ||
420 | int syear; | ||
421 | |||
422 | stm = gmtime(&tt); | ||
423 | syear = stm->tm_year; | ||
424 | |||
425 | start_tt = tt - stm->tm_wday*(60*60*24); | ||
426 | |||
427 | stm = gmtime(&start_tt); | ||
428 | |||
429 | if(syear == stm->tm_year){ | ||
430 | return stm->tm_yday+1; | ||
431 | } else { | ||
432 | /* return negative to indicate that start of week is in | ||
433 | previous year. */ | ||
434 | int is_leap = 0; | ||
435 | int year = stm->tm_year; | ||
436 | |||
437 | if( (year % 4 == 0 && year % 100 != 0) || | ||
438 | year % 400 == 0){ | ||
439 | is_leap =1; | ||
440 | } | ||
441 | |||
442 | return (stm->tm_yday+1)-(365+is_leap); | ||
443 | } | ||
444 | |||
445 | } | ||
446 | |||
447 | short icaltime_week_number(struct icaltimetype ictt) | ||
448 | { | ||
449 | char str[5]; | ||
450 | time_t t = icaltime_as_timet(ictt); | ||
451 | int week_no; | ||
452 | |||
453 | strftime(str,5,"%V", gmtime(&t)); | ||
454 | |||
455 | week_no = atoi(str); | ||
456 | |||
457 | return week_no; | ||
458 | |||
459 | } | ||
460 | |||
461 | |||
462 | short icaltime_day_of_year(struct icaltimetype t){ | ||
463 | time_t tt; | ||
464 | struct tm *stm; | ||
465 | struct set_tz_save old_tz; | ||
466 | |||
467 | tt = icaltime_as_timet(t); | ||
468 | |||
469 | old_tz = set_tz("UTC"); | ||
470 | stm = localtime(&tt); | ||
471 | unset_tz(old_tz); | ||
472 | |||
473 | return stm->tm_yday+1; | ||
474 | |||
475 | } | ||
476 | |||
477 | /* Jan 1 is day #1, not 0 */ | ||
478 | struct icaltimetype icaltime_from_day_of_year(short doy, short year) | ||
479 | { | ||
480 | struct tm stm; | ||
481 | time_t tt; | ||
482 | struct set_tz_save old_tz; | ||
483 | |||
484 | /* Get the time of january 1 of this year*/ | ||
485 | memset(&stm,0,sizeof(struct tm)); | ||
486 | stm.tm_year = year-1900; | ||
487 | stm.tm_mday = 1; | ||
488 | |||
489 | old_tz = set_tz("UTC"); | ||
490 | tt = mktime(&stm); | ||
491 | unset_tz(old_tz); | ||
492 | |||
493 | |||
494 | /* Now add in the days */ | ||
495 | |||
496 | doy--; | ||
497 | tt += doy *60*60*24; | ||
498 | |||
499 | return icaltime_from_timet(tt, 1); | ||
500 | } | ||
501 | |||
502 | struct icaltimetype icaltime_null_time() | ||
503 | { | ||
504 | struct icaltimetype t; | ||
505 | memset(&t,0,sizeof(struct icaltimetype)); | ||
506 | |||
507 | return t; | ||
508 | } | ||
509 | |||
510 | |||
511 | int icaltime_is_valid_time(struct icaltimetype t){ | ||
512 | if(t.is_utc > 1 || t.is_utc < 0 || | ||
513 | t.year < 0 || t.year > 3000 || | ||
514 | t.is_date > 1 || t.is_date < 0){ | ||
515 | return 0; | ||
516 | } else { | ||
517 | return 1; | ||
518 | } | ||
519 | |||
520 | } | ||
521 | |||
522 | int icaltime_is_null_time(struct icaltimetype t) | ||
523 | { | ||
524 | if (t.second +t.minute+t.hour+t.day+t.month+t.year == 0){ | ||
525 | return 1; | ||
526 | } | ||
527 | |||
528 | return 0; | ||
529 | |||
530 | } | ||
531 | |||
532 | int icaltime_compare(struct icaltimetype a,struct icaltimetype b) | ||
533 | { | ||
534 | time_t t1 = icaltime_as_timet(a); | ||
535 | time_t t2 = icaltime_as_timet(b); | ||
536 | |||
537 | if (t1 > t2) { | ||
538 | return 1; | ||
539 | } else if (t1 < t2) { | ||
540 | return -1; | ||
541 | } else { | ||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | } | ||
546 | |||
547 | int | ||
548 | icaltime_compare_date_only (struct icaltimetype a, struct icaltimetype b) | ||
549 | { | ||
550 | time_t t1; | ||
551 | time_t t2; | ||
552 | |||
553 | if (a.year == b.year && a.month == b.month && a.day == b.day) | ||
554 | return 0; | ||
555 | |||
556 | t1 = icaltime_as_timet (a); | ||
557 | t2 = icaltime_as_timet (b); | ||
558 | |||
559 | if (t1 > t2) | ||
560 | return 1; | ||
561 | else if (t1 < t2) | ||
562 | return -1; | ||
563 | else { | ||
564 | /* not reached */ | ||
565 | assert (0); | ||
566 | return 0; | ||
567 | } | ||
568 | } | ||
569 | |||
570 | |||
571 | /* These are defined in icalduration.c: | ||
572 | struct icaltimetype icaltime_add(struct icaltimetype t, | ||
573 | struct icaldurationtype d) | ||
574 | struct icaldurationtype icaltime_subtract(struct icaltimetype t1, | ||
575 | struct icaltimetype t2) | ||
576 | */ | ||
577 | |||