2 ======================================================================
4 CREATOR: eric 02 June 2000
6 $Id: icaltime.c,v 1.71 2008-01-29 18:31:48 dothebart Exp $
9 (C) COPYRIGHT 2000, Eric Busboom <eric@softwarestudio.org>
10 http://www.softwarestudio.org
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of either:
15 The LGPL as published by the Free Software Foundation, version
16 2.1, available at: http://www.fsf.org/copyleft/lesser.html
20 The Mozilla Public License Version 1.0. You may obtain a copy of
21 the License at http://www.mozilla.org/MPL/
23 The Original Code is eric. The Initial Developer of the Original
27 ======================================================================*/
40 #include "astime.h" /* Julian data handling routines */
42 #include "icalerror.h"
43 #include "icalmemory.h"
45 #include "icaltimezone.h"
46 #include "icalvalue.h"
53 #define snprintf _snprintf
54 #define strcasecmp stricmp
58 /* Undef the similar macro from pthread.h, it doesn't check if
59 * gmtime() returns NULL.
63 /* The gmtime() in Microsoft's C library is MT-safe */
64 #define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
69 static pthread_mutex_t tzid_mutex = PTHREAD_MUTEX_INITIALIZER;
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.
80 static time_t make_time(struct tm *tm, int tzm)
84 static int days[] = { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 };
86 /* check that year specification within range */
88 if (tm->tm_year < 70 || tm->tm_year > 138)
91 /* check that month specification within range */
93 if (tm->tm_mon < 0 || tm->tm_mon > 11)
96 /* check for upper bound of Jan 17, 2038 (to avoid possibility of
97 32-bit arithmetic overflow) */
99 if (tm->tm_year == 138) {
102 else if (tm->tm_mday > 17)
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)
112 tim = (tm->tm_year - 70) * 365 + ((tm->tm_year - 1) / 4) - 17;
114 /* add number of days elapsed in the current year */
116 tim += days[tm->tm_mon];
118 /* check and adjust for leap years (the leap year check only valid
119 during the 32-bit era */
121 if ((tm->tm_year & 3) == 0 && tm->tm_mon > 1)
124 /* elapsed days to current date */
129 /* calculate elapsed hours since start of the epoch */
131 tim = tim * 24 + tm->tm_hour;
133 /* calculate elapsed minutes since start of the epoch */
135 tim = tim * 60 + tm->tm_min;
137 /* adjust per time zone specification */
141 /* calculate elapsed seconds since start of the epoch */
143 tim = tim * 60 + tm->tm_sec;
145 /* return number of seconds since start of the epoch */
150 /** @brief Constructor (deprecated).
152 * Convert seconds past UNIX epoch to a timetype.
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().
162 icaltime_from_timet(const time_t tm, const int is_date)
164 #ifndef NO_WARN_DEPRECATED
165 icalerror_warn("icaltime_from_timet() is DEPRECATED, use icaltime_from_timet_with_zone() instead");
168 return icaltime_from_timet_with_zone(tm, is_date, 0);
172 /** @brief Constructor.
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
179 * Return a new icaltime instance, initialized to the given time
180 * expressed as seconds past UNIX epoch, optionally using the given
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
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.
197 icaltime_from_timet_with_zone(const time_t tm, const int is_date,
198 const icaltimezone *zone)
200 struct icaltimetype tt;
202 icaltimezone *utc_zone;
204 utc_zone = icaltimezone_get_utc_timezone ();
206 /* Convert the time_t to a struct tm in UTC time. We can trust gmtime
214 tt.year = t.tm_year + 1900;
215 tt.month = t.tm_mon + 1;
218 tt.minute = t.tm_min;
219 tt.second = t.tm_sec;
221 tt.is_utc = (zone == utc_zone) ? 1 : 0;
225 /* Use our timezone functions to convert to the required timezone. */
226 icaltimezone_convert_time (&tt, utc_zone, (icaltimezone *)zone);
228 tt.is_date = is_date;
230 /* If it is a DATE value, make sure hour, minute & second are 0. */
240 /** @brief Convenience constructor.
242 * Returns the current time in the given timezone, as an icaltimetype.
244 struct icaltimetype icaltime_current_time_with_zone(const icaltimezone *zone)
246 return icaltime_from_timet_with_zone (time (NULL), 0, zone);
249 /** @brief Convenience constructor.
251 * Returns the current day as an icaltimetype, with is_date set.
253 struct icaltimetype icaltime_today(void)
255 return icaltime_from_timet_with_zone (time (NULL), 1, NULL);
258 /** @brief Return the time as seconds past the UNIX epoch
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().
266 time_t icaltime_as_timet(const struct icaltimetype tt)
271 /* If the time is the special null time, return 0. */
272 if (icaltime_is_null_time(tt)) {
276 /* Copy the icaltimetype to a struct tm. */
277 memset (&stm, 0, sizeof (struct tm));
279 if (icaltime_is_date(tt)) {
280 stm.tm_sec = stm.tm_min = stm.tm_hour = 0;
282 stm.tm_sec = tt.second;
283 stm.tm_min = tt.minute;
284 stm.tm_hour = tt.hour;
287 stm.tm_mday = tt.day;
288 stm.tm_mon = tt.month-1;
289 stm.tm_year = tt.year-1900;
292 t = make_time(&stm, 0);
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;
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)
313 char *old_tz, *old_tz_copy = NULL, *new_tz;
315 /* Get the old TZ setting and save a copy of it to return. */
316 old_tz = getenv("TZ");
318 old_tz_copy = (char*)malloc(strlen (old_tz) + 4);
320 if(old_tz_copy == 0){
321 icalerror_set_errno(ICAL_NEWFAILED_ERROR);
325 strcpy (old_tz_copy, "TZ=");
326 strcpy (old_tz_copy + 3, old_tz);
329 /* Create the new TZ string. */
330 new_tz = (char*)malloc(strlen (tzid) + 4);
333 icalerror_set_errno(ICAL_NEWFAILED_ERROR);
338 strcpy (new_tz, "TZ=");
339 strcpy (new_tz + 3, tzid);
341 /* Add the new TZ to the environment. */
344 /* Free any previous TZ environment string we have used in a synchronized manner. */
348 /* Save a pointer to the TZ string we just set, so we can free it later. */
351 return old_tz_copy; /* This will be zero if the TZ env var was not set */
354 void unset_tz(char *tzstr)
356 /* restore the original environment */
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. */
370 putenv("TZ="); // The equals is required to remove with MS Visual C++
377 /* Free any previous TZ environment string we have used in a synchronized manner */
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.) */
385 /** Return the time as seconds past the UNIX epoch, using the
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.
393 time_t icaltime_as_timet_with_zone(const struct icaltimetype tt,
394 const icaltimezone *zone)
396 icaltimezone *utc_zone;
400 struct icaltimetype local_tt;
402 utc_zone = icaltimezone_get_utc_timezone ();
404 /* If the time is the special null time, return 0. */
405 if (icaltime_is_null_time(tt)) {
411 /* Clear the is_date flag, so we can convert the time. */
412 local_tt.is_date = 0;
414 /* Use our timezone functions to convert to UTC. */
415 icaltimezone_convert_time (&local_tt, (icaltimezone *)zone, utc_zone);
417 /* Copy the icaltimetype to a struct tm. */
418 memset (&stm, 0, sizeof (struct tm));
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;
427 /* The functions putenv and mktime are not thread safe, inserting a lock
428 to prevent any crashes */
431 pthread_mutex_lock (&tzid_mutex);
434 /* Set TZ to UTC and use mktime to convert to a time_t. */
435 old_tz = set_tz ("UTC");
443 pthread_mutex_unlock (&tzid_mutex);
448 const char* icaltime_as_ical_string(const struct icaltimetype tt)
451 buf = icaltime_as_ical_string_r(tt);
452 icalmemory_add_tmp_buffer(buf);
458 * Return a string represention of the time, in RFC2445 format. The
459 * string is owned by libical
461 char* icaltime_as_ical_string_r(const struct icaltimetype tt)
464 char* buf = icalmemory_new_buffer(size);
467 snprintf(buf, size,"%04d%02d%02d",tt.year,tt.month,tt.day);
471 fmt = "%04d%02d%02dT%02d%02d%02dZ";
473 fmt = "%04d%02d%02dT%02d%02d%02d";
475 snprintf(buf, size,fmt,tt.year,tt.month,tt.day,
476 tt.hour,tt.minute,tt.second);
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
490 * Implementation note: we call icaltime_adjust() with no adjustment.
492 struct icaltimetype icaltime_normalize(const struct icaltimetype tt)
494 struct icaltimetype ret = tt;
495 icaltime_adjust(&ret, 0, 0, 0, 0);
501 /** @brief Contructor.
503 * Create a time from an ISO format string.
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()
510 struct icaltimetype icaltime_from_string(const char* str)
512 struct icaltimetype tt = icaltime_null_time();
515 icalerror_check_arg_re(str!=0,"str",icaltime_null_time());
519 if ((size == 15) || (size == 19)) { /* floating time with/without separators*/
522 } else if ((size == 16) || (size == 20)) { /* UTC time, ends in 'Z'*/
523 if ((str[15] != 'Z') && (str[19] != 'Z'))
527 tt.zone = icaltimezone_get_utc_timezone();
529 } else if ((size == 8) || (size == 10)) { /* A DATE */
536 if (tt.is_date == 1){
539 if (sscanf(str,"%04d%c%02d%c%02d",&tt.year,&dsep1,&tt.month,&dsep2,&tt.day) < 5)
541 if ((dsep1 != '-') || (dsep2 != '-'))
543 } else if (sscanf(str,"%04d%02d%02d",&tt.year,&tt.month,&tt.day) < 3) {
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)
553 if((tsep != 'T') || (dsep1 != '-') || (dsep2 != '-') || (tsep1 != ':') || (tsep2 != ':'))
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)
570 icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
571 return icaltime_null_time();
575 /* Returns whether the specified year is a leap year. Year is the normal year,
578 icaltime_is_leap_year (const int year)
582 return (year % 4 == 0);
584 return ( (year % 4==0) && (year % 100 !=0 )) || (year % 400 == 0);
589 ycaltime_days_in_year (const int year)
591 if (icaltime_is_leap_year (year))
596 static int _days_in_month[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
598 int icaltime_days_in_month(const int month, const int year)
601 int days = _days_in_month[month];
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.
609 * assert(month <= 12);
611 if ((month < 1) || (month > 12)) {
616 days += icaltime_is_leap_year(year);
622 /* 1-> Sunday, 7->Saturday */
623 int icaltime_day_of_week(const struct icaltimetype t){
626 memset(&jt,0,sizeof(UTinstant));
637 return jt.weekday + 1;
640 /** Day of the year that the first day of the week (Sunday) is on.
642 int icaltime_start_doy_week(const struct icaltimetype t, int fdow){
646 memset(&jt,0,sizeof(UTinstant));
658 delta = jt.weekday - (fdow - 1);
659 if (delta < 0) delta += 7;
660 return jt.day_of_year - delta;
663 /** Day of the year that the first day of the week (Sunday) is on.
665 * @deprecated Doesn't take into account different week start days.
667 int icaltime_start_doy_of_week(const struct icaltimetype t){
669 #ifndef NO_WARN_DEPRECATED
670 icalerror_warn("icaltime_start_doy_of_week() is DEPRECATED, use\
671 icaltime_start_doy_week() instead");
674 return icaltime_start_doy_week(t, 1);
678 * @todo Doesn't take into account the start day of the
679 * week. strftime assumes that weeks start on Monday.
681 int icaltime_week_number(const struct icaltimetype ictt)
685 memset(&jt,0,sizeof(UTinstant));
688 jt.month = ictt.month;
697 return (jt.day_of_year - jt.weekday) / 7;
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 }
708 * Returns the day of the year, counting from 1 (Jan 1st).
710 int icaltime_day_of_year(const struct icaltimetype t){
711 int is_leap = icaltime_is_leap_year (t.year);
713 return days_in_year_passed_month[is_leap][t.month - 1] + t.day;
716 /** @brief Contructor.
718 * Create a new time, given a day of year and a year.
720 /* Jan 1 is day #1, not 0 */
721 struct icaltimetype icaltime_from_day_of_year(const int _doy, const int _year)
723 struct icaltimetype tt = icaltime_null_date();
729 is_leap = icaltime_is_leap_year(year);
731 /* Zero and neg numbers represent days of the previous 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];
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];
756 /** @brief Constructor.
758 * Return a null time, which indicates no time has been set.
759 * This time represents the beginning of the epoch.
761 struct icaltimetype icaltime_null_time(void)
763 struct icaltimetype t;
764 memset(&t,0,sizeof(struct icaltimetype));
769 /** @brief Constructor.
771 * Return a null date, which indicates no time has been set.
773 struct icaltimetype icaltime_null_date(void)
775 struct icaltimetype t;
776 memset(&t,0,sizeof(struct icaltimetype));
781 * Init to -1 to match what icalyacc.y used to do.
782 * Does anything depend on this?
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.
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){
808 /** @brief Returns true if time is a DATE
810 int icaltime_is_date(const struct icaltimetype t) {
815 /** @brief Returns true if time is relative to UTC zone
817 * @todo We should only check the zone
819 int icaltime_is_utc(const struct icaltimetype t) {
825 * Return true if the time is null.
827 int icaltime_is_null_time(const struct icaltimetype t)
829 if (t.second +t.minute+t.hour+t.day+t.month+t.year == 0){
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
843 int icaltime_compare(const struct icaltimetype a_in, const struct icaltimetype b_in)
845 struct icaltimetype a, b;
847 a = icaltime_convert_to_zone(a_in, icaltimezone_get_utc_timezone());
848 b = icaltime_convert_to_zone(b_in, icaltimezone_get_utc_timezone());
852 else if (a.year < b.year)
855 else if (a.month > b.month)
857 else if (a.month < b.month)
860 else if (a.day > b.day)
862 else if (a.day < b.day)
865 /* if both are dates, we are done */
866 if (a.is_date && b.is_date)
869 /* else, if only one is a date (and we already know the date part is equal),
870 then the other is greater */
876 else if (a.hour > b.hour)
878 else if (a.hour < b.hour)
881 else if (a.minute > b.minute)
883 else if (a.minute < b.minute)
886 else if (a.second > b.second)
888 else if (a.second < b.second)
895 * like icaltime_compare, but only use the date parts.
899 icaltime_compare_date_only(const struct icaltimetype a_in, const struct icaltimetype b_in)
901 struct icaltimetype a, b;
902 icaltimezone *tz = icaltimezone_get_utc_timezone();
904 a = icaltime_convert_to_zone(a_in, tz);
905 b = icaltime_convert_to_zone(b_in, tz);
909 else if (a.year < b.year)
912 if (a.month > b.month)
914 else if (a.month < b.month)
919 else if (a.day < b.day)
926 * like icaltime_compare, but only use the date parts; accepts timezone.
930 icaltime_compare_date_only_tz(const struct icaltimetype a_in, const struct icaltimetype b_in, icaltimezone *tz)
932 struct icaltimetype a, b;
934 a = icaltime_convert_to_zone(a_in, tz);
935 b = icaltime_convert_to_zone(b_in, tz);
939 else if (a.year < b.year)
942 if (a.month > b.month)
944 else if (a.month < b.month)
949 else if (a.day < b.day)
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)
964 /** @brief Internal, shouldn't be part of the public API
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.
971 icaltime_adjust(struct icaltimetype *tt, const int days, const int hours,
972 const int minutes, const int seconds) {
974 int second, minute, hour, day;
975 int minutes_overflow, hours_overflow, days_overflow = 0, years_overflow;
978 /* If we are passed a date make sure to ignore hour minute and second */
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) {
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) {
1000 /* Add on the hours. */
1001 hour = tt->hour + hours + hours_overflow;
1002 tt->hour = hour % 24;
1003 days_overflow = hour / 24;
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;
1024 /* Add on the days. */
1025 day = tt->day + days + days_overflow;
1028 days_in_month = icaltime_days_in_month (tt->month, tt->year);
1029 if (day <= days_in_month)
1033 if (tt->month >= 13) {
1038 day -= days_in_month;
1042 if (tt->month == 1) {
1049 day += icaltime_days_in_month (tt->month, tt->year);
1055 /** @brief Convert time to a given timezone
1057 * Convert a time from its native timezone to a given timezone.
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.
1065 struct icaltimetype icaltime_convert_to_zone(const struct icaltimetype tt,
1066 icaltimezone *zone) {
1068 struct icaltimetype ret = tt;
1070 /* If it's a date do nothing */
1075 if (tt.zone == zone) {
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);
1085 if (zone == icaltimezone_get_utc_timezone()) {
1094 const icaltimezone *
1095 icaltime_get_timezone(const struct icaltimetype t) {
1101 icaltime_get_tzid(const struct icaltimetype t) {
1103 if (t.zone != NULL) {
1104 return icaltimezone_get_tzid((icaltimezone *)t.zone);
1110 /** @brief Set the timezone
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.
1117 icaltime_set_timezone(struct icaltimetype *t, const icaltimezone *zone) {
1119 /* If it's a date do nothing */
1124 if (t->zone == zone) {
1129 if (zone == icaltimezone_get_utc_timezone()) {
1140 * @brief builds an icaltimespan given a start time, end time and busy value.
1142 * @param dtstart The beginning time of the span, can be a date-time
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.
1148 * returned span contains times specified in UTC.
1151 icaltime_span icaltime_span_new(struct icaltimetype dtstart,
1152 struct icaltimetype dtend,
1157 span.is_busy = is_busy;
1159 span.start = icaltime_as_timet_with_zone(dtstart,
1160 dtstart.zone ? dtstart.zone : icaltimezone_get_utc_timezone());
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
1166 span.end = span.start;
1173 span.end = icaltime_as_timet_with_zone(dtend,
1174 dtend.zone ? dtend.zone : icaltimezone_get_utc_timezone());
1176 if (icaltime_is_date(dtstart)) {
1177 /* no time specified, go until the end of the day..*/
1178 span.end += 60*60*24 - 1;
1184 /** @brief Returns true if the two spans overlap
1186 * @param s1 1st span to test
1187 * @param s2 2nd span to test
1188 * @return boolean value
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.
1193 * Also returns true if the spans are equal.
1195 * Note, this will return false if the spans are adjacent.
1198 int icaltime_span_overlaps(icaltime_span *s1,
1201 /* s1->start in s2 */
1202 if (s1->start > s2->start && s1->start < s2->end)
1206 if (s1->end > s2->start && s1->end < s2->end)
1209 /* s2->start in s1 */
1210 if (s2->start > s1->start && s2->start < s1->end)
1214 if (s2->end > s1->start && s2->end < s1->end)
1217 if (s1->start == s2->start && s1->end == s2->end)
1223 /** @brief Returns true if the span is totally within the containing
1226 * @param s The span to test for.
1227 * @param container The span to test against.
1228 * @return boolean value.
1232 int icaltime_span_contains(icaltime_span *s,
1233 icaltime_span *container)
1236 if ((s->start >= container->start && s->start < container->end) &&
1237 (s->end <= container->end && s->end > container->start))