bump to 1.0.0 and clean up spec file
[platform/upstream/libical.git] / src / libical / icaltime.c
1 /* -*- Mode: C -*-
2   ======================================================================
3   FILE: icaltime.c
4   CREATOR: eric 02 June 2000
5   
6   $Id: icaltime.c,v 1.71 2008-01-29 18:31:48 dothebart Exp $
7   $Locker:  $
8     
9  (C) COPYRIGHT 2000, Eric Busboom <eric@softwarestudio.org>
10      http://www.softwarestudio.org
11
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of either: 
14
15     The LGPL as published by the Free Software Foundation, version
16     2.1, available at: http://www.fsf.org/copyleft/lesser.html
17
18   Or:
19
20     The Mozilla Public License Version 1.0. You may obtain a copy of
21     the License at http://www.mozilla.org/MPL/
22
23  The Original Code is eric. The Initial Developer of the Original
24  Code is Eric Busboom
25
26
27  ======================================================================*/
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include "icaltime.h"
34 #include <assert.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <time.h>
39
40 #include "astime.h"             /* Julian data handling routines */
41
42 #include "icalerror.h"
43 #include "icalmemory.h"
44
45 #include "icaltimezone.h"
46 #include "icalvalue.h"
47
48 #ifdef WIN32
49 #include <windows.h>
50 #endif
51
52 #if defined(_MSC_VER)
53 #define snprintf   _snprintf
54 #define strcasecmp stricmp
55 #endif
56
57 #ifdef WIN32
58 /* Undef the similar macro from pthread.h, it doesn't check if
59  * gmtime() returns NULL.
60  */
61 #undef gmtime_r
62
63 /* The gmtime() in Microsoft's C library is MT-safe */
64 #define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
65 #endif
66
67 #ifdef HAVE_PTHREAD
68  #include <pthread.h>    
69     static pthread_mutex_t tzid_mutex = PTHREAD_MUTEX_INITIALIZER;
70 #endif
71
72 /*
73  *  Function to convert a struct tm time specification
74  *  to an ANSI time_t using the specified time zone.
75  *  This is different from the standard mktime() function
76  *  in that we don't want the automatic adjustments for
77  *  local daylight savings time applied to the result.
78  *  This function expects well-formed input.
79  */
80 static time_t make_time(struct tm *tm, int tzm)
81 {
82   time_t tim;
83
84   static int days[] = { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 };
85
86   /* check that year specification within range */
87
88   if (tm->tm_year < 70 || tm->tm_year > 138)
89     return((time_t) -1);
90
91   /* check that month specification within range */
92
93   if (tm->tm_mon < 0 || tm->tm_mon > 11)
94     return((time_t) -1);
95
96   /* check for upper bound of Jan 17, 2038 (to avoid possibility of
97      32-bit arithmetic overflow) */
98   
99   if (tm->tm_year == 138) {
100     if (tm->tm_mon > 0)
101       return((time_t) -1);
102     else if (tm->tm_mday > 17)
103       return((time_t) -1);
104   }
105
106   /*
107    *  calculate elapsed days since start of the epoch (midnight Jan
108    *  1st, 1970 UTC) 17 = number of leap years between 1900 and 1970
109    *  (number of leap days to subtract)
110    */
111
112   tim = (tm->tm_year - 70) * 365 + ((tm->tm_year - 1) / 4) - 17;
113
114   /* add number of days elapsed in the current year */
115
116   tim += days[tm->tm_mon];
117
118   /* check and adjust for leap years (the leap year check only valid
119      during the 32-bit era */
120
121   if ((tm->tm_year & 3) == 0 && tm->tm_mon > 1)
122     tim += 1;
123
124   /* elapsed days to current date */
125
126   tim += tm->tm_mday;
127
128
129   /* calculate elapsed hours since start of the epoch */
130
131   tim = tim * 24 + tm->tm_hour;
132
133   /* calculate elapsed minutes since start of the epoch */
134
135   tim = tim * 60 + tm->tm_min;
136   
137   /* adjust per time zone specification */
138   
139   tim -= tzm;
140   
141   /* calculate elapsed seconds since start of the epoch */
142   
143   tim = tim * 60 + tm->tm_sec;
144   
145   /* return number of seconds since start of the epoch */
146   
147   return(tim);
148 }
149
150 /**     @brief Constructor (deprecated).
151  *
152  * Convert seconds past UNIX epoch to a timetype.
153  *
154  * @deprecated This constructor is deprecated and shouldn't be used in
155  *   new software.  Use icaltime_from_timet_with_zone(time_t, int,
156  *   icaltimezone *) instead.  In the meantime, calls to this method
157  *   return a floating time, which can always be converted to a local
158  *   time with an appropriate call to icaltime_convert_to_zone().
159  */
160
161 struct icaltimetype 
162 icaltime_from_timet(const time_t tm, const int is_date)
163 {
164 #ifndef NO_WARN_DEPRECATED
165         icalerror_warn("icaltime_from_timet() is DEPRECATED, use icaltime_from_timet_with_zone() instead");
166 #endif
167
168         return icaltime_from_timet_with_zone(tm, is_date, 0);
169 }
170
171
172 /**     @brief Constructor.
173  *
174  *      @param tm The time
175  *      @param is_date Boolean: 1 means we should treat tm as a DATE
176  *      @param zone The timezone tm is in, NULL means to treat tm as a
177  *              floating time
178  *
179  *      Return a new icaltime instance, initialized to the given time
180  *      expressed as seconds past UNIX epoch, optionally using the given
181  *      timezone.
182  *
183  *      If the caller specifies the is_date param as TRUE, the returned
184  *      object is of DATE type, otherwise the input is meant to be of
185  *      DATE-TIME type.
186  *      If the zone is not specified (NULL zone param) the time is taken
187  *      to be floating, that is, valid in any timezone. Note that, in
188  *      addition to the uses specified in [RFC2445], this can be used
189  *      when doing simple math on couples of times.
190  *      If the zone is specified (UTC or otherwise), it's stored in the
191  *      object and it's used as the native timezone for this object.
192  *      This means that the caller can convert this time to a different
193  *      target timezone with no need to store the source timezone.
194  *
195  */
196 struct icaltimetype 
197 icaltime_from_timet_with_zone(const time_t tm, const int is_date,
198         const icaltimezone *zone)
199 {
200     struct icaltimetype tt;
201     struct tm t;
202     icaltimezone *utc_zone;
203
204     utc_zone = icaltimezone_get_utc_timezone ();
205
206     /* Convert the time_t to a struct tm in UTC time. We can trust gmtime
207        for this. */
208 #ifdef HAVE_PTHREAD
209     gmtime_r (&tm, &t);
210 #else
211     t = *(gmtime (&tm));
212 #endif
213      
214     tt.year   = t.tm_year + 1900;
215     tt.month  = t.tm_mon + 1;
216     tt.day    = t.tm_mday;
217     tt.hour   = t.tm_hour;
218     tt.minute = t.tm_min;
219     tt.second = t.tm_sec;
220     tt.is_date = 0; 
221     tt.is_utc = (zone == utc_zone) ? 1 : 0;
222     tt.is_daylight = 0;
223     tt.zone = NULL;
224
225     /* Use our timezone functions to convert to the required timezone. */
226     icaltimezone_convert_time (&tt, utc_zone, (icaltimezone *)zone);
227
228     tt.is_date = is_date; 
229
230     /* If it is a DATE value, make sure hour, minute & second are 0. */
231     if (is_date) { 
232         tt.hour   = 0;
233         tt.minute = 0;
234         tt.second = 0;
235     }
236
237     return tt;
238 }
239
240 /**     @brief Convenience constructor.
241  * 
242  * Returns the current time in the given timezone, as an icaltimetype.
243  */
244 struct icaltimetype icaltime_current_time_with_zone(const icaltimezone *zone)
245 {
246     return icaltime_from_timet_with_zone (time (NULL), 0, zone);
247 }
248
249 /**     @brief Convenience constructor.
250  * 
251  * Returns the current day as an icaltimetype, with is_date set.
252  */
253 struct icaltimetype icaltime_today(void)
254 {
255     return icaltime_from_timet_with_zone (time (NULL), 1, NULL);
256 }
257
258 /**     @brief  Return the time as seconds past the UNIX epoch
259  *
260  *      While this function is not currently deprecated, it probably won't do
261  *      what you expect, unless you know what you're doing. In particular, you
262  *      should only pass an icaltime in UTC, since no conversion is done. Even
263  *      in that case, it's probably better to just use
264  *      icaltime_as_timet_with_zone().
265  */
266 time_t icaltime_as_timet(const struct icaltimetype tt)
267 {
268     struct tm stm;
269     time_t t;
270
271     /* If the time is the special null time, return 0. */
272     if (icaltime_is_null_time(tt)) {
273         return 0;
274     }
275
276     /* Copy the icaltimetype to a struct tm. */
277     memset (&stm, 0, sizeof (struct tm));
278
279     if (icaltime_is_date(tt)) {
280         stm.tm_sec = stm.tm_min = stm.tm_hour = 0;
281     } else {
282         stm.tm_sec = tt.second;
283         stm.tm_min = tt.minute;
284         stm.tm_hour = tt.hour;
285     }
286
287     stm.tm_mday = tt.day;
288     stm.tm_mon = tt.month-1;
289     stm.tm_year = tt.year-1900;
290     stm.tm_isdst = -1;
291
292     t = make_time(&stm, 0);
293
294     return t;
295
296 }
297
298
299 /* Structure used by set_tz to hold an old value of TZ, and the new
300    value, which is in memory we will have to free in unset_tz */
301 /* This will hold the last "TZ=XXX" string we used with putenv(). After we
302    call putenv() again to set a new TZ string, we can free the previous one.
303    As far as I know, no libc implementations actually free the memory used in
304    the environment variables (how could they know if it is a static string or
305    a malloc'ed string?), so we have to free it ourselves. */
306 static char* saved_tz = NULL;
307
308 /* If you use set_tz(), you must call unset_tz() some time later to restore the
309    original TZ. Pass unset_tz() the string that set_tz() returns. Call both the functions
310    locking the tzid mutex as in icaltime_as_timet_with_zone */
311 char* set_tz(const char* tzid)
312 {
313     char *old_tz, *old_tz_copy = NULL, *new_tz;
314
315     /* Get the old TZ setting and save a copy of it to return. */
316     old_tz = getenv("TZ");
317     if(old_tz){
318         old_tz_copy = (char*)malloc(strlen (old_tz) + 4);
319
320         if(old_tz_copy == 0){
321             icalerror_set_errno(ICAL_NEWFAILED_ERROR);
322             return 0;
323         }
324
325         strcpy (old_tz_copy, "TZ=");
326         strcpy (old_tz_copy + 3, old_tz);
327     }
328
329     /* Create the new TZ string. */
330     new_tz = (char*)malloc(strlen (tzid) + 4);
331
332     if(new_tz == 0){
333         icalerror_set_errno(ICAL_NEWFAILED_ERROR);
334         free(old_tz_copy);
335         return 0;
336     }
337
338     strcpy (new_tz, "TZ=");
339     strcpy (new_tz + 3, tzid);
340
341     /* Add the new TZ to the environment. */
342     putenv(new_tz); 
343
344     /* Free any previous TZ environment string we have used in a synchronized manner. */
345
346     free (saved_tz);
347
348     /* Save a pointer to the TZ string we just set, so we can free it later. */
349     saved_tz = new_tz;
350
351     return old_tz_copy; /* This will be zero if the TZ env var was not set */
352 }
353
354 void unset_tz(char *tzstr)
355 {
356     /* restore the original environment */
357
358     if(tzstr!=0){
359         putenv(tzstr);
360     } else {
361         /* Delete from environment.  We prefer unsetenv(3) over putenv(3)
362            because the former is POSIX and behaves consistently.  The later
363            does not unset the variable in some systems (like NetBSD), leaving
364            it with an empty value.  This causes problems later because further
365            calls to time related functions in libc will treat times in UTC. */
366 #ifdef HAVE_UNSETENV
367         unsetenv("TZ");
368 #else
369 #ifdef _MSC_VER 
370         putenv("TZ="); // The equals is required to remove with MS Visual C++
371 #else
372         putenv("TZ");
373 #endif
374 #endif
375     } 
376
377     /* Free any previous TZ environment string we have used in a synchronized manner */
378     free (saved_tz);
379
380     /* Save a pointer to the TZ string we just set, so we can free it later.
381        (This can possibly be NULL if there was no TZ to restore.) */
382     saved_tz = tzstr;
383 }
384
385 /**     Return the time as seconds past the UNIX epoch, using the
386  *      given timezone.
387  *
388  *      This convenience method combines a call to icaltime_convert_to_zone()
389  *      with a call to icaltime_as_timet().
390  *      If the input timezone is null, no conversion is done; that is, the
391  *      time is simply returned as time_t in its native timezone.
392  */
393 time_t icaltime_as_timet_with_zone(const struct icaltimetype tt,
394         const icaltimezone *zone)
395 {
396     icaltimezone *utc_zone;
397     struct tm stm;
398     time_t t;
399     char *old_tz;
400     struct icaltimetype local_tt;
401     
402     utc_zone = icaltimezone_get_utc_timezone ();
403
404     /* If the time is the special null time, return 0. */
405     if (icaltime_is_null_time(tt)) {
406         return 0;
407     }
408
409     local_tt = tt;
410     
411     /* Clear the is_date flag, so we can convert the time. */
412     local_tt.is_date = 0;
413
414     /* Use our timezone functions to convert to UTC. */
415     icaltimezone_convert_time (&local_tt, (icaltimezone *)zone, utc_zone);
416
417     /* Copy the icaltimetype to a struct tm. */
418     memset (&stm, 0, sizeof (struct tm));
419
420     stm.tm_sec = local_tt.second;
421     stm.tm_min = local_tt.minute;
422     stm.tm_hour = local_tt.hour;
423     stm.tm_mday = local_tt.day;
424     stm.tm_mon = local_tt.month-1;
425     stm.tm_year = local_tt.year-1900;
426     stm.tm_isdst = -1;
427 /* The functions putenv and mktime are not thread safe, inserting a lock
428 to prevent any crashes */
429
430 #ifdef HAVE_PTHREAD
431     pthread_mutex_lock (&tzid_mutex);
432 #endif
433     
434     /* Set TZ to UTC and use mktime to convert to a time_t. */
435     old_tz = set_tz ("UTC");
436     tzset ();
437
438     t = mktime (&stm);
439     unset_tz (old_tz);
440     tzset ();
441
442 #ifdef HAVE_PTHREAD
443     pthread_mutex_unlock (&tzid_mutex);
444 #endif
445     return t;
446 }
447
448 const char* icaltime_as_ical_string(const struct icaltimetype tt)
449 {
450         char *buf;
451         buf = icaltime_as_ical_string_r(tt);
452         icalmemory_add_tmp_buffer(buf);
453         return buf;
454 }
455
456
457 /**
458  * Return a string represention of the time, in RFC2445 format. The
459  * string is owned by libical
460  */
461 char* icaltime_as_ical_string_r(const struct icaltimetype tt)
462 {
463     size_t size = 17;
464     char* buf = icalmemory_new_buffer(size);
465
466     if(tt.is_date){
467         snprintf(buf, size,"%04d%02d%02d",tt.year,tt.month,tt.day);
468     } else {
469         const char* fmt;
470         if(tt.is_utc){
471             fmt = "%04d%02d%02dT%02d%02d%02dZ";
472         } else {
473             fmt = "%04d%02d%02dT%02d%02d%02d";
474         }
475         snprintf(buf, size,fmt,tt.year,tt.month,tt.day,
476                  tt.hour,tt.minute,tt.second);
477     }
478     
479     return buf;
480 }
481
482
483 /**
484  *      Reset all of the time components to be in their normal ranges. For
485  *      instance, given a time with minutes=70, the minutes will be reduces
486  *      to 10, and the hour incremented. This allows the caller to do
487  *      arithmetic on times without worrying about overflow or
488  *      underflow.
489  *
490  *      Implementation note: we call icaltime_adjust() with no adjustment.
491  */
492 struct icaltimetype icaltime_normalize(const struct icaltimetype tt)
493 {
494         struct icaltimetype ret = tt;
495         icaltime_adjust(&ret, 0, 0, 0, 0);
496         return ret;
497 }
498
499
500
501 /**     @brief Contructor.
502  * 
503  * Create a time from an ISO format string.
504  *
505  * @todo If the given string specifies a DATE-TIME not in UTC, there
506  *       is no way to know if this is a floating time or really refers to a
507  *       timezone. We should probably add a new constructor:
508  *       icaltime_from_string_with_zone()
509  */
510 struct icaltimetype icaltime_from_string(const char* str)
511 {
512     struct icaltimetype tt = icaltime_null_time();
513     size_t size;
514
515     icalerror_check_arg_re(str!=0,"str",icaltime_null_time());
516
517     size = strlen(str);
518     
519     if ((size == 15) || (size == 19)) { /* floating time with/without separators*/
520         tt.is_utc = 0;
521         tt.is_date = 0;
522     } else if ((size == 16) || (size == 20)) { /* UTC time, ends in 'Z'*/
523         if ((str[15] != 'Z') && (str[19] != 'Z'))
524             goto FAIL;
525
526         tt.is_utc = 1;
527         tt.zone = icaltimezone_get_utc_timezone();
528         tt.is_date = 0;
529     } else if ((size == 8) || (size == 10)) { /* A DATE */
530         tt.is_utc = 0;
531         tt.is_date = 1;
532     } else { /* error */
533         goto FAIL;
534     }
535
536     if (tt.is_date == 1){
537         if (size == 10) {
538             char dsep1, dsep2;    
539             if (sscanf(str,"%04d%c%02d%c%02d",&tt.year,&dsep1,&tt.month,&dsep2,&tt.day) < 5)
540                 goto FAIL;
541             if ((dsep1 != '-') || (dsep2 != '-'))
542                 goto FAIL;
543         } else if (sscanf(str,"%04d%02d%02d",&tt.year,&tt.month,&tt.day) < 3) {
544             goto FAIL;
545         }    
546     } else {
547        if (size > 16 ) {
548          char dsep1, dsep2, tsep, tsep1, tsep2;      
549          if (sscanf(str,"%04d%c%02d%c%02d%c%02d%c%02d%c%02d",&tt.year,&dsep1,&tt.month,&dsep2,
550                 &tt.day,&tsep,&tt.hour,&tsep1,&tt.minute,&tsep2,&tt.second) < 11)
551             goto FAIL;
552
553         if((tsep != 'T') || (dsep1 != '-') || (dsep2 != '-') || (tsep1 != ':') || (tsep2 != ':'))
554             goto FAIL;
555
556        } else {        
557         char tsep;
558         if (sscanf(str,"%04d%02d%02d%c%02d%02d%02d",&tt.year,&tt.month,&tt.day,
559                &tsep,&tt.hour,&tt.minute,&tt.second) < 7)
560             goto FAIL;
561
562         if(tsep != 'T')
563             goto FAIL;
564        }
565     }
566
567     return tt;    
568
569 FAIL:
570     icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
571     return icaltime_null_time();
572 }
573
574
575 /* Returns whether the specified year is a leap year. Year is the normal year,
576    e.g. 2001. */
577 int
578 icaltime_is_leap_year (const int year)
579 {
580
581     if (year <= 1752)
582         return (year % 4 == 0);
583     else
584         return ( (year % 4==0) && (year % 100 !=0 )) || (year % 400 == 0);
585 }
586
587
588 int
589 ycaltime_days_in_year (const int year)
590 {
591         if (icaltime_is_leap_year (year))
592                 return 366;
593         else return 365;
594 }
595
596 static int _days_in_month[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
597
598 int icaltime_days_in_month(const int month, const int year)
599 {
600
601     int days = _days_in_month[month];
602
603 /* The old code aborting if it was passed a parameter like BYMONTH=0
604  * Unfortunately it's not practical right now to pass an error all
605  * the way up the stack, so instead of aborting we're going to apply
606  * the GIGO principle and simply return '30 days' if we get an
607  * invalid month.  Modern applications cannot tolerate crashing.
608  *  assert(month > 0);
609  *  assert(month <= 12);
610  */
611     if ((month < 1) || (month > 12)) {
612         return 30;
613     }
614
615     if( month == 2){
616         days += icaltime_is_leap_year(year);
617     }
618
619     return days;
620 }
621
622 /* 1-> Sunday, 7->Saturday */
623 int icaltime_day_of_week(const struct icaltimetype t){
624         UTinstant jt;
625
626         memset(&jt,0,sizeof(UTinstant));
627
628         jt.year = t.year;
629     jt.month = t.month;
630     jt.day = t.day;
631     jt.i_hour = 0;
632     jt.i_minute = 0;
633     jt.i_second = 0;
634
635         juldat(&jt);
636
637         return jt.weekday + 1;
638 }
639
640 /** Day of the year that the first day of the week (Sunday) is on.
641  */
642 int icaltime_start_doy_week(const struct icaltimetype t, int fdow){
643         UTinstant jt;
644         int delta;
645
646         memset(&jt,0,sizeof(UTinstant));
647
648         jt.year = t.year;
649     jt.month = t.month;
650     jt.day = t.day;
651     jt.i_hour = 0;
652     jt.i_minute = 0;
653     jt.i_second = 0;
654
655         juldat(&jt);
656         caldat(&jt);
657
658         delta = jt.weekday - (fdow - 1);
659         if (delta < 0) delta += 7;
660         return jt.day_of_year - delta;
661 }
662
663 /** Day of the year that the first day of the week (Sunday) is on.
664  * 
665  *  @deprecated Doesn't take into account different week start days. 
666  */
667 int icaltime_start_doy_of_week(const struct icaltimetype t){
668
669 #ifndef NO_WARN_DEPRECATED
670     icalerror_warn("icaltime_start_doy_of_week() is DEPRECATED, use\
671         icaltime_start_doy_week() instead");
672 #endif
673
674     return icaltime_start_doy_week(t, 1);
675 }
676
677 /** 
678  * @todo Doesn't take into account the start day of the
679  * week. strftime assumes that weeks start on Monday. 
680  */
681 int icaltime_week_number(const struct icaltimetype ictt)
682 {
683         UTinstant jt;
684
685         memset(&jt,0,sizeof(UTinstant));
686
687         jt.year = ictt.year;
688     jt.month = ictt.month;
689     jt.day = ictt.day;
690     jt.i_hour = 0;
691     jt.i_minute = 0;
692     jt.i_second = 0;
693
694         juldat(&jt);
695         caldat(&jt);
696
697         return (jt.day_of_year - jt.weekday) / 7;
698 }
699
700 /* The first array is for non-leap years, the second for leap years*/
701 static const int days_in_year_passed_month[2][13] = 
702 { /* jan feb mar apr may  jun  jul  aug  sep  oct  nov  dec */
703   {  0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, 
704   {  0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
705 };
706
707 /**
708  *      Returns the day of the year, counting from 1 (Jan 1st).
709  */
710 int icaltime_day_of_year(const struct icaltimetype t){
711   int is_leap = icaltime_is_leap_year (t.year);
712
713   return days_in_year_passed_month[is_leap][t.month - 1] + t.day;
714 }
715
716 /**     @brief Contructor.
717  *
718  *      Create a new time, given a day of year and a year.
719  */
720 /* Jan 1 is day #1, not 0 */
721 struct icaltimetype icaltime_from_day_of_year(const int _doy, const int _year)
722 {
723     struct icaltimetype tt = icaltime_null_date();
724     int is_leap;
725     int month;
726     int doy = _doy;
727     int year = _year;
728
729     is_leap = icaltime_is_leap_year(year);
730
731     /* Zero and neg numbers represent days  of the previous year */
732     if(doy <1){
733         year--;
734         is_leap = icaltime_is_leap_year(year);
735         doy +=  days_in_year_passed_month[is_leap][12];
736     } else if(doy > days_in_year_passed_month[is_leap][12]){
737         /* Move on to the next year*/
738         is_leap = icaltime_is_leap_year(year);
739         doy -=  days_in_year_passed_month[is_leap][12];
740         year++;
741     }
742
743     tt.year = year;
744
745     for (month = 11; month >= 0; month--) {
746       if (doy > days_in_year_passed_month[is_leap][month]) {
747         tt.month = month + 1;
748         tt.day = doy - days_in_year_passed_month[is_leap][month];
749         break;
750       }
751     }
752
753     return tt;
754 }
755
756 /**     @brief Constructor.
757  *
758  *      Return a null time, which indicates no time has been set.
759  *      This time represents the beginning of the epoch.
760  */
761 struct icaltimetype icaltime_null_time(void)
762 {
763     struct icaltimetype t;
764     memset(&t,0,sizeof(struct icaltimetype));
765
766     return t;
767 }
768
769 /**     @brief Constructor.
770  *
771  *      Return a null date, which indicates no time has been set.
772  */
773 struct icaltimetype icaltime_null_date(void)
774 {
775     struct icaltimetype t;
776     memset(&t,0,sizeof(struct icaltimetype));
777
778     t.is_date = 1;
779
780     /*
781      * Init to -1 to match what icalyacc.y used to do.
782      * Does anything depend on this?
783      */
784     t.hour = -1;
785     t.minute = -1;
786     t.second = -1;
787
788     return t;
789 }
790
791
792 /**
793  *      Returns false if the time is clearly invalid, but is not null. This
794  *      is usually the result of creating a new time type buy not clearing
795  *      it, or setting one of the flags to an illegal value.
796  */
797 int icaltime_is_valid_time(const struct icaltimetype t){
798     if(t.is_utc > 1 || t.is_utc < 0 ||
799        t.year < 0 || t.year > 3000 ||
800        t.is_date > 1 || t.is_date < 0){
801         return 0;
802     } else {
803         return 1;
804     }
805
806 }
807
808 /**     @brief Returns true if time is a DATE
809  */
810 int icaltime_is_date(const struct icaltimetype t) {
811
812         return t.is_date;
813 }
814
815 /**     @brief Returns true if time is relative to UTC zone
816  *
817  *      @todo  We should only check the zone
818  */
819 int icaltime_is_utc(const struct icaltimetype t) {
820
821         return t.is_utc;
822 }
823
824 /**
825  *      Return true if the time is null.
826  */
827 int icaltime_is_null_time(const struct icaltimetype t)
828 {
829     if (t.second +t.minute+t.hour+t.day+t.month+t.year == 0){
830         return 1;
831     }
832
833     return 0;
834
835 }
836
837 /**
838  *      Return -1, 0, or 1 to indicate that a<b, a==b, or a>b.
839  *      This calls icaltime_compare function after converting them to the utc
840  *      timezone.
841  */
842
843 int icaltime_compare(const struct icaltimetype a_in, const struct icaltimetype b_in) 
844 {
845     struct icaltimetype a, b;
846
847     a = icaltime_convert_to_zone(a_in, icaltimezone_get_utc_timezone());
848     b = icaltime_convert_to_zone(b_in, icaltimezone_get_utc_timezone());
849
850     if (a.year > b.year)
851         return 1;
852     else if (a.year < b.year)
853         return -1;
854
855     else if (a.month > b.month)
856         return 1;
857     else if (a.month < b.month)
858         return -1;
859
860     else if (a.day > b.day)
861         return 1;
862     else if (a.day < b.day)
863         return -1;
864
865     /* if both are dates, we are done */
866     if (a.is_date && b.is_date)
867         return 0;
868
869     /* else, if only one is a date (and we already know the date part is equal),
870        then the other is greater */
871     else if (b.is_date)
872         return 1;
873     else if (a.is_date)
874         return -1;
875
876     else if (a.hour > b.hour)
877         return 1;
878     else if (a.hour < b.hour)
879         return -1;
880
881     else if (a.minute > b.minute)
882         return 1;
883     else if (a.minute < b.minute)
884         return -1;
885
886     else if (a.second > b.second)
887         return 1;
888     else if (a.second < b.second)
889         return -1;
890
891     return 0;
892 }
893
894 /**
895  *      like icaltime_compare, but only use the date parts.
896  */
897
898 int
899 icaltime_compare_date_only(const struct icaltimetype a_in, const struct icaltimetype b_in)
900 {
901     struct icaltimetype a, b;
902     icaltimezone *tz = icaltimezone_get_utc_timezone();
903
904     a = icaltime_convert_to_zone(a_in, tz);
905     b = icaltime_convert_to_zone(b_in, tz);
906
907     if (a.year > b.year)
908         return 1;
909     else if (a.year < b.year)
910         return -1;
911
912     if (a.month > b.month)
913         return 1;
914     else if (a.month < b.month)
915         return -1;
916
917     if (a.day > b.day)
918         return 1;
919     else if (a.day < b.day)
920         return -1;
921
922     return 0;
923 }
924
925 /**
926  *      like icaltime_compare, but only use the date parts; accepts timezone.
927  */
928
929 int
930 icaltime_compare_date_only_tz(const struct icaltimetype a_in, const struct icaltimetype b_in, icaltimezone *tz)
931 {
932     struct icaltimetype a, b;
933
934     a = icaltime_convert_to_zone(a_in, tz);
935     b = icaltime_convert_to_zone(b_in, tz);
936
937     if (a.year > b.year)
938         return 1;
939     else if (a.year < b.year)
940         return -1;
941
942     if (a.month > b.month)
943         return 1;
944     else if (a.month < b.month)
945         return -1;
946
947     if (a.day > b.day)
948         return 1;
949     else if (a.day < b.day)
950         return -1;
951
952     return 0;
953 }
954
955 /* These are defined in icalduration.c:
956 struct icaltimetype  icaltime_add(struct icaltimetype t,
957                                   struct icaldurationtype  d)
958 struct icaldurationtype  icaltime_subtract(struct icaltimetype t1,
959                                            struct icaltimetype t2)
960 */
961
962
963
964 /**     @brief Internal, shouldn't be part of the public API
965  *
966  *      Adds (or subtracts) a time from a icaltimetype.
967  *      NOTE: This function is exactly the same as icaltimezone_adjust_change()
968  *      except for the type of the first parameter.
969  */
970 void
971 icaltime_adjust(struct icaltimetype *tt, const int days, const int hours,
972         const int minutes, const int seconds) {
973
974     int second, minute, hour, day;
975     int minutes_overflow, hours_overflow, days_overflow = 0, years_overflow;
976     int days_in_month;
977
978     /* If we are passed a date make sure to ignore hour minute and second */
979     if (tt->is_date)
980         goto IS_DATE;
981
982     /* Add on the seconds. */
983     second = tt->second + seconds;
984     tt->second = second % 60;
985     minutes_overflow = second / 60;
986     if (tt->second < 0) {
987         tt->second += 60;
988         minutes_overflow--;
989     }
990
991     /* Add on the minutes. */
992     minute = tt->minute + minutes + minutes_overflow;
993     tt->minute = minute % 60;
994     hours_overflow = minute / 60;
995     if (tt->minute < 0) {
996         tt->minute += 60;
997         hours_overflow--;
998     }
999
1000     /* Add on the hours. */
1001     hour = tt->hour + hours + hours_overflow;
1002     tt->hour = hour % 24;
1003     days_overflow = hour / 24;
1004     if (tt->hour < 0) {
1005         tt->hour += 24;
1006         days_overflow--;
1007     }
1008
1009 IS_DATE:
1010     /* Normalize the month. We do this before handling the day since we may
1011        need to know what month it is to get the number of days in it.
1012        Note that months are 1 to 12, so we have to be a bit careful. */
1013     if (tt->month >= 13) {
1014         years_overflow = (tt->month - 1) / 12;
1015         tt->year += years_overflow;
1016         tt->month -= years_overflow * 12;
1017     } else if (tt->month <= 0) {
1018         /* 0 to -11 is -1 year out, -12 to -23 is -2 years. */
1019         years_overflow = (tt->month / 12) - 1;
1020         tt->year += years_overflow;
1021         tt->month -= years_overflow * 12;
1022     }
1023
1024     /* Add on the days. */
1025     day = tt->day + days + days_overflow;
1026     if (day > 0) {
1027         for (;;) {
1028             days_in_month = icaltime_days_in_month (tt->month, tt->year);
1029             if (day <= days_in_month)
1030                 break;
1031
1032             tt->month++;
1033             if (tt->month >= 13) {
1034                 tt->year++;
1035                 tt->month = 1;
1036             }
1037
1038             day -= days_in_month;
1039         }
1040     } else {
1041         while (day <= 0) {
1042             if (tt->month == 1) {
1043                 tt->year--;
1044                 tt->month = 12;
1045             } else {
1046                 tt->month--;
1047             }
1048
1049             day += icaltime_days_in_month (tt->month, tt->year);
1050         }
1051     }
1052     tt->day = day;
1053 }
1054
1055 /**     @brief Convert time to a given timezone
1056  *
1057  *      Convert a time from its native timezone to a given timezone.
1058  *
1059  *      If tt is a date, the returned time is an exact
1060  *      copy of the input. If it's a floating time, the returned object
1061  *      represents the same time translated to the given timezone.
1062  *      Otherwise the time will be converted to the new
1063  *      time zone, and its native timezone set to the right timezone.
1064  */
1065 struct icaltimetype icaltime_convert_to_zone(const struct icaltimetype tt,
1066         icaltimezone *zone) {
1067
1068         struct icaltimetype ret = tt;
1069
1070         /* If it's a date do nothing */
1071         if (tt.is_date) {
1072                 return ret;
1073         }
1074
1075         if (tt.zone == zone) {
1076                 return ret;
1077         }
1078
1079         /* If it's a floating time we don't want to adjust the time */
1080         if (tt.zone != NULL) {
1081                 icaltimezone_convert_time(&ret, (icaltimezone *)tt.zone, zone);
1082         }
1083
1084         ret.zone = zone;
1085         if (zone == icaltimezone_get_utc_timezone()) {
1086                 ret.is_utc = 1;
1087         } else {
1088                 ret.is_utc = 0;
1089         }
1090
1091         return ret;
1092 }
1093
1094 const icaltimezone *
1095 icaltime_get_timezone(const struct icaltimetype t) {
1096
1097         return t.zone;
1098 }
1099
1100 const char *
1101 icaltime_get_tzid(const struct icaltimetype t) {
1102
1103         if (t.zone != NULL) {
1104                 return icaltimezone_get_tzid((icaltimezone *)t.zone);
1105         } else {
1106                 return NULL;
1107         }
1108 }
1109
1110 /**     @brief Set the timezone
1111  *
1112  *      Force the icaltime to be interpreted relative to another timezone.
1113  *      If you need to do timezone conversion, applying offset adjustments,
1114  *      then you should use icaltime_convert_to_timezone instead.
1115  */
1116 struct icaltimetype
1117 icaltime_set_timezone(struct icaltimetype *t, const icaltimezone *zone) {
1118
1119         /* If it's a date do nothing */
1120         if (t->is_date) {
1121                 return *t;
1122         }
1123
1124         if (t->zone == zone) {
1125                 return *t;
1126         }
1127
1128         t->zone = zone;
1129         if (zone == icaltimezone_get_utc_timezone()) {
1130                 t->is_utc = 1;
1131         } else {
1132                 t->is_utc = 0;
1133         }
1134
1135         return *t;
1136 }
1137
1138
1139 /**
1140  *  @brief builds an icaltimespan given a start time, end time and busy value.
1141  *
1142  *  @param dtstart   The beginning time of the span, can be a date-time
1143  *                   or just a date.
1144  *  @param dtend     The end time of the span.
1145  *  @param is_busy   A boolean value, 0/1.
1146  *  @return          A span using the supplied values.
1147  *
1148  *  returned span contains times specified in UTC.
1149  */
1150
1151 icaltime_span icaltime_span_new(struct icaltimetype dtstart,
1152                                        struct icaltimetype dtend,
1153                                        int    is_busy)
1154 {
1155   icaltime_span span;
1156
1157   span.is_busy = is_busy;
1158
1159   span.start   = icaltime_as_timet_with_zone(dtstart,
1160                 dtstart.zone ? dtstart.zone : icaltimezone_get_utc_timezone());
1161
1162   if (icaltime_is_null_time(dtend)) {
1163     if (!icaltime_is_date(dtstart)) {
1164       /* If dtstart is a DATE-TIME and there is no DTEND nor DURATION
1165          it takes no time */
1166       span.end = span.start;
1167       return span;
1168     } else {
1169       dtend = dtstart;
1170     }
1171   }
1172
1173   span.end = icaltime_as_timet_with_zone(dtend, 
1174                 dtend.zone ? dtend.zone : icaltimezone_get_utc_timezone());
1175   
1176   if (icaltime_is_date(dtstart)) {
1177     /* no time specified, go until the end of the day..*/
1178     span.end += 60*60*24 - 1;
1179   }
1180   return span;
1181 }
1182
1183
1184 /** @brief Returns true if the two spans overlap
1185  *
1186  *  @param s1         1st span to test
1187  *  @param s2         2nd span to test
1188  *  @return           boolean value
1189  *
1190  *  The result is calculated by testing if the start time of s1 is contained
1191  *  by the s2 span, or if the end time of s1 is contained by the s2 span.
1192  *
1193  *  Also returns true if the spans are equal.
1194  *
1195  *  Note, this will return false if the spans are adjacent.
1196  */
1197
1198 int icaltime_span_overlaps(icaltime_span *s1, 
1199                            icaltime_span *s2)
1200 {
1201   /* s1->start in s2 */
1202   if (s1->start > s2->start && s1->start < s2->end)
1203     return 1;
1204
1205   /* s1->end in s2 */
1206   if (s1->end > s2->start && s1->end < s2->end)
1207     return 1;
1208
1209   /* s2->start in s1 */
1210   if (s2->start > s1->start && s2->start < s1->end)
1211     return 1;
1212
1213   /* s2->end in s1 */
1214   if (s2->end > s1->start && s2->end < s1->end)
1215     return 1;
1216
1217   if (s1->start == s2->start && s1->end == s2->end)
1218     return 1;
1219   
1220   return 0;
1221 }
1222
1223 /** @brief Returns true if the span is totally within the containing
1224  *  span
1225  *
1226  *  @param s          The span to test for.
1227  *  @param container  The span to test against.
1228  *  @return           boolean value.
1229  *
1230  */
1231
1232 int icaltime_span_contains(icaltime_span *s,
1233                            icaltime_span *container)
1234 {
1235
1236   if ((s->start >= container->start && s->start < container->end) &&
1237       (s->end   <= container->end   && s->end   > container->start))
1238     return 1;
1239   
1240   return 0;
1241 }