$darkmode
Libical API Documentation 4.0 STABLE VERSION Visit the v3.0 documentation
icaltime.c
Go to the documentation of this file.
1 /*======================================================================
2  FILE: icaltime.c
3  CREATOR: eric 02 June 2000
4 
5  SPDX-FileCopyrightText: 2000, Eric Busboom <eric@civicknowledge.com>
6  SPDX-License-Identifier: LGPL-2.1-only OR MPL-2.0
7 
8  The timegm code is Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
9 
10  The Original Code is eric. The Initial Developer of the Original
11  Code is Eric Busboom
12 
13  The timegm code in this file is copyrighted by NLNET LABS 2001-2006,
14  according to the following conditions:
15 
16  * Redistributions of source code must retain the above copyright notice,
17  this list of conditions and the following disclaimer.
18 
19  * Redistributions in binary form must reproduce the above copyright notice,
20  this list of conditions and the following disclaimer in the documentation
21  * and/or other materials provided with the distribution.
22 
23  * Neither the name of the NLNET LABS nor the names of its contributors may
24  be used to endorse or promote products derived from this software without
25  specific prior written permission.
26 
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
31  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  POSSIBILITY OF SUCH DAMAGE.
38 ======================================================================*/
39 
45 #ifdef HAVE_CONFIG_H
46 #include <config.h>
47 #endif
48 
49 #include "icaltime.h"
50 #include "icaldate_p.h"
51 #include "icalerror_p.h"
52 #include "icalerror.h"
53 #include "icalmemory.h"
54 #include "icaltimezone.h"
55 
56 #include <ctype.h>
57 #include <stdlib.h>
58 
59 /* The first array is for non-leap years, the second for leap years*/
60 static const int days_in_year_passed_month[2][13] = {
61  /* jan feb mar apr may jun jul aug sep oct nov dec */
62  {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
63  {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
64 
65 static int icaltime_leap_days(int y1, int y2)
66 {
67  --y1;
68  --y2;
69  return (y2 / 4 - y1 / 4) - (y2 / 100 - y1 / 100) + (y2 / 400 - y1 / 400);
70 }
71 
72 /*
73  * Function to convert a struct tm time specification
74  * to an ANSI-compatible icaltime_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  * The out_time_t is to store the result, it can be NULL.
81  * Returns false on failure, true on success.
82  */
83 static bool make_time(const struct tm *tm, int tzm, icaltime_t *out_time_t)
84 {
85  icaltime_t tim;
86  int febs;
87 
88  static const int days[] = {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364};
89 
90  /* check that month specification within range */
91 
92  if (tm->tm_mon < 0 || tm->tm_mon > 11) {
93  return false;
94  }
95 
96  if (tm->tm_year < 2) {
97  return false;
98  }
99 
100 #if (SIZEOF_ICALTIME_T == 4)
101  /* check that year specification within range */
102 
103  if (tm->tm_year > 138) {
104  return false;
105  }
106 
107  /* check for upper bound of Jan 17, 2038 (to avoid possibility of 32-bit arithmetic overflow) */
108  if (tm->tm_year == 138) {
109  if (tm->tm_mon > 0) {
110  return false;
111  } else if (tm->tm_mday > 17) {
112  return false;
113  }
114  }
115 #else
116  /* We don't support years >= 10000, because the function has not been tested at this range. */
117  if (tm->tm_year >= 8100) {
118  return false;
119  }
120 #endif /* SIZEOF_ICALTIME_T */
121 
122  /*
123  * calculate elapsed days since start of the epoch (midnight Jan
124  * 1st, 1970 UTC) 17 = number of leap years between 1900 and 1970
125  * (number of leap days to subtract)
126  */
127 
128  tim = (icaltime_t)((tm->tm_year - 70) * 365 + ((tm->tm_year - 1) / 4) - 17);
129 
130  /* adjust: no leap days every 100 years, except every 400 years. */
131 
132  febs = (tm->tm_year - 100) - ((tm->tm_mon <= 1) ? 1 : 0);
133  tim -= febs / 100;
134  tim += febs / 400;
135 
136  /* add number of days elapsed in the current year */
137 
138  tim += days[tm->tm_mon];
139 
140  /* check and adjust for leap years */
141 
142  if ((tm->tm_year & 3) == 0 && tm->tm_mon > 1) {
143  tim += 1;
144  }
145 
146  /* elapsed days to current date */
147 
148  tim += tm->tm_mday;
149 
150  /* calculate elapsed hours since start of the epoch */
151 
152  tim = tim * 24 + tm->tm_hour;
153 
154  /* calculate elapsed minutes since start of the epoch */
155 
156  tim = tim * 60 + tm->tm_min;
157 
158  /* adjust per time zone specification */
159 
160  tim -= tzm;
161 
162  /* calculate elapsed seconds since start of the epoch */
163 
164  tim = tim * 60 + tm->tm_sec;
165 
166  /* return number of seconds since start of the epoch */
167 
168  if (out_time_t) {
169  *out_time_t = tim;
170  }
171 
172  return true;
173 }
174 
175 /*
176  * Code adapted from Python 2.4.1 sources (Lib/calendar.py).
177  */
178 static icaltime_t icaltime_timegm(const struct tm *tm)
179 {
180  int year;
181  icaltime_t days;
182  icaltime_t hours;
183  icaltime_t minutes;
184  icaltime_t seconds;
185 
186  /* Validate the tm structure by passing it through make_time() */
187  if (!make_time(tm, 0, NULL)) {
188  /* we have some invalid data in the tm struct */
189  return 0;
190  }
191 
192  year = 1900 + tm->tm_year;
193  int idays = (365 * (year - 1970) + icaltime_leap_days(1970, year));
194  days = (icaltime_t)idays;
195  days += days_in_year_passed_month[0][tm->tm_mon];
196 
197  if (tm->tm_mon > 1 && icaltime_is_leap_year(year)) {
198  ++days;
199  }
200 
201  days += tm->tm_mday - 1;
202  hours = days * 24 + tm->tm_hour;
203  minutes = hours * 60 + tm->tm_min;
204  seconds = minutes * 60 + tm->tm_sec;
205 
206  return seconds;
207 }
208 
209 struct icaltimetype icaltime_from_timet_with_zone(const icaltime_t tm, const bool is_date,
210  const icaltimezone *zone)
211 {
212  struct icaltimetype tt;
213  struct tm t;
214  icaltimezone *utc_zone;
215 
216  utc_zone = icaltimezone_get_utc_timezone();
217 
218  /* Convert the icaltime_t to a struct tm in UTC time. We can trust gmtime for this. */
219  memset(&t, 0, sizeof(struct tm));
220  if (!icalgmtime_r(&tm, &t)) {
221  return is_date ? icaltime_null_date() : icaltime_null_time();
222  }
223 
224  tt.year = t.tm_year + 1900;
225  tt.month = t.tm_mon + 1;
226  tt.day = t.tm_mday;
227  tt.hour = t.tm_hour;
228  tt.minute = t.tm_min;
229  tt.second = t.tm_sec;
230  tt.is_date = 0;
231  tt.is_daylight = 0;
232  tt.zone = (zone == NULL) ? NULL : utc_zone;
233 
234  /* Use our timezone functions to convert to the required timezone. */
235  icaltimezone_convert_time(&tt, utc_zone, (icaltimezone *)zone);
236 
237  tt.is_date = is_date;
238 
239  /* If it is a DATE value, make sure hour, minute & second are 0. */
240  if (is_date) {
241  tt.hour = 0;
242  tt.minute = 0;
243  tt.second = 0;
244  }
245 
246  return tt;
247 }
248 
250 {
251  return icaltime_from_timet_with_zone(icaltime(NULL), 0, zone);
252 }
253 
255 {
256  return icaltime_from_timet_with_zone(icaltime(NULL), 1, NULL);
257 }
258 
259 icaltime_t icaltime_as_timet(const struct icaltimetype tt)
260 {
261  struct tm stm;
262  icaltime_t t = (icaltime_t)-1;
263 
264  /* If the time is the special null time, return 0. */
265  if (icaltime_is_null_time(tt)) {
266  return 0;
267  }
268 
269  /* Copy the icaltimetype to a struct tm. */
270  memset(&stm, 0, sizeof(struct tm));
271 
272  if (icaltime_is_date(tt)) {
273  stm.tm_sec = stm.tm_min = stm.tm_hour = 0;
274  } else {
275  stm.tm_sec = tt.second;
276  stm.tm_min = tt.minute;
277  stm.tm_hour = tt.hour;
278  }
279 
280  stm.tm_mday = tt.day;
281  stm.tm_mon = tt.month - 1;
282  stm.tm_year = tt.year - 1900;
283  stm.tm_isdst = -1;
284 
285  if (!make_time(&stm, 0, &t)) {
286  t = ((icaltime_t)-1);
287  }
288 
289  return t;
290 }
291 
292 icaltime_t icaltime_as_timet_with_zone(const struct icaltimetype tt, const icaltimezone *zone)
293 {
294  icaltimezone *utc_zone;
295  struct tm stm;
296  icaltime_t t;
297  struct icaltimetype local_tt;
298 
299  utc_zone = icaltimezone_get_utc_timezone();
300 
301  /* Return 0 if the time is the special null time or a bad time */
303  return 0;
304  }
305 
306  local_tt = tt;
307 
308  /* Clear the is_date flag, so we can convert the time. */
309  local_tt.is_date = 0;
310 
311  /* Use our timezone functions to convert to UTC. */
312  if (tt.zone != utc_zone) {
313  icaltimezone_convert_time(&local_tt, (icaltimezone *)zone, utc_zone);
314  }
315 
316  /* Copy the icaltimetype to a struct tm. */
317  memset(&stm, 0, sizeof(struct tm));
318 
319  stm.tm_sec = local_tt.second;
320  stm.tm_min = local_tt.minute;
321  stm.tm_hour = local_tt.hour;
322  stm.tm_mday = local_tt.day;
323  stm.tm_mon = local_tt.month - 1;
324  stm.tm_year = local_tt.year - 1900;
325  stm.tm_isdst = -1;
326 
327  t = icaltime_timegm(&stm);
328 
329  return t;
330 }
331 
332 const char *icaltime_as_ical_string(const struct icaltimetype tt)
333 {
334  char *buf;
335 
336  buf = icaltime_as_ical_string_r(tt);
338  return buf;
339 }
340 
342 {
343  size_t size = 17;
344  char *buf = icalmemory_new_buffer(size);
345 
346  if (tt.is_date) {
347  snprintf(buf, size, "%04d%02d%02d", tt.year, tt.month, tt.day);
348  } else {
349 #pragma GCC diagnostic push
350 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
351  const char *fmt;
352 
353  if (icaltime_is_utc(tt)) {
354  fmt = "%04d%02d%02dT%02d%02d%02dZ";
355  } else {
356  fmt = "%04d%02d%02dT%02d%02d%02d";
357  }
358  snprintf(buf, size, fmt, tt.year, tt.month, tt.day, tt.hour, tt.minute, tt.second);
359 #pragma GCC diagnostic pop
360  }
361 
362  return buf;
363 }
364 
365 /* Implementation note: we call icaltime_adjust() with no adjustment. */
367 {
368  struct icaltimetype ret = tt;
369 
370  icaltime_adjust(&ret, 0, 0, 0, 0);
371  return ret;
372 }
373 
374 struct icaltimetype icaltime_from_string(const char *str)
375 {
376  struct icaltimetype tt = icaltime_null_time();
377  size_t size;
378 
379  icalerror_check_arg_re(str != 0, "str", icaltime_null_time());
380 
381  size = strlen(str);
382 
383  if ((size == 15) || (size == 19)) { /* floating time with/without separators */
384  tt.is_date = 0;
385  } else if ((size == 16) || (size == 20)) { /* UTC time, ends in 'Z' */
386  if ((str[size - 1] != 'Z')) {
387  goto FAIL;
388  }
389 
391  tt.is_date = 0;
392  } else if ((size == 8) || (size == 10)) { /* A DATE */
393  tt.is_date = 1;
394  } else { /* error */
395  goto FAIL;
396  }
397 
398  if (tt.is_date == 1) {
399  if (size == 10) {
400  char dsep1, dsep2;
401 
402  if (sscanf(str, "%04d%c%02d%c%02d",
403  &tt.year, &dsep1, &tt.month, &dsep2, &tt.day) < 5) {
404  goto FAIL;
405  }
406 
407  if ((dsep1 != '-') || (dsep2 != '-')) {
408  goto FAIL;
409  }
410  } else if (sscanf(str, "%04d%02d%02d", &tt.year, &tt.month, &tt.day) < 3) {
411  goto FAIL;
412  }
413  } else {
414  if (size > 16) {
415  char dsep1, dsep2, tsep, tsep1, tsep2;
416 
417  if (sscanf(str, "%04d%c%02d%c%02d%c%02d%c%02d%c%02d",
418  &tt.year, &dsep1, &tt.month, &dsep2, &tt.day, &tsep,
419  &tt.hour, &tsep1, &tt.minute, &tsep2, &tt.second) < 11) {
420  goto FAIL;
421  }
422 
423  if ((tsep != 'T') ||
424  (dsep1 != '-') || (dsep2 != '-') ||
425  (tsep1 != ':') || (tsep2 != ':')) {
426  goto FAIL;
427  }
428 
429  } else {
430  char tsep;
431 
432  if (sscanf(str, "%04d%02d%02d%c%02d%02d%02d",
433  &tt.year, &tt.month, &tt.day, &tsep,
434  &tt.hour, &tt.minute, &tt.second) < 7) {
435  goto FAIL;
436  }
437 
438  if (tsep != 'T') {
439  goto FAIL;
440  }
441  }
442  }
443 
444  return tt;
445 
446 FAIL:
448  return icaltime_null_time();
449 }
450 
451 bool icaltime_is_leap_year(const int year)
452 {
453  if (year <= 1752) {
454  return (year % 4 == 0);
455  } else {
456  return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
457  }
458 }
459 
460 int icaltime_days_in_year(const int year)
461 {
462  if (icaltime_is_leap_year(year)) {
463  return 366;
464  } else {
465  return 365;
466  }
467 }
468 
469 static const int _days_in_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
470 
471 int icaltime_days_in_month(const int month, const int year)
472 {
473  int days;
474 
475  /* The old code aborting if it was passed a parameter like BYMONTH=0
476  * Unfortunately it's not practical right now to pass an error all
477  * the way up the stack, so instead of aborting we're going to apply
478  * the GIGO principle and simply return '30 days' if we get an
479  * invalid month. Modern applications cannot tolerate crashing.
480  * assert(month > 0);
481  * assert(month <= 12);
482  */
483  if ((month < 1) || (month > 12)) {
484  return 30;
485  }
486 
487  days = _days_in_month[month];
488 
489  if (month == 2) {
490  days += (icaltime_is_leap_year(year) ? 1 : 0);
491  }
492 
493  return days;
494 }
495 
496 /* 1-> Sunday, 7->Saturday */
498 {
499  UTinstantInt jt;
500 
501  memset(&jt, 0, sizeof(UTinstantInt));
502 
503  jt.year = t.year;
504  jt.month = t.month;
505  jt.day = t.day;
506 
507  ical_juldat(&jt);
508 
509  return jt.weekday + 1;
510 }
511 
512 int icaltime_start_doy_week(const struct icaltimetype t, int fdow)
513 {
514  UTinstantInt jt;
515  int delta;
516 
517  memset(&jt, 0, sizeof(UTinstantInt));
518 
519  jt.year = t.year;
520  jt.month = t.month;
521  jt.day = t.day;
522 
523  ical_juldat(&jt);
524  ical_caldat(&jt);
525 
526  delta = jt.weekday - (fdow - 1);
527  if (delta < 0) {
528  delta += 7;
529  }
530  return jt.day_of_year - delta;
531 }
532 
534 {
535  unsigned int is_leap = (icaltime_is_leap_year(t.year) ? 1 : 0);
536 
537  if (t.month < 1 || t.month > 12) {
538  return 0;
539  }
540 
541  return days_in_year_passed_month[is_leap][t.month - 1] + t.day;
542 }
543 
544 struct icaltimetype icaltime_from_day_of_year(const int _doy, const int _year)
545 {
546  struct icaltimetype tt = icaltime_null_date();
547  unsigned int is_leap;
548  int month;
549  int doy = _doy;
550  int year = _year;
551 
552  is_leap = (icaltime_is_leap_year(year) ? 1 : 0);
553 
554  /* Zero and neg numbers represent days of the previous year */
555  if (doy < 1) {
556  year--;
557  is_leap = (icaltime_is_leap_year(year) ? 1 : 0);
558  doy += days_in_year_passed_month[is_leap][12];
559  } else if (doy > days_in_year_passed_month[is_leap][12]) {
560  /* Move on to the next year */
561  is_leap = (icaltime_is_leap_year(year) ? 1 : 0);
562  doy -= days_in_year_passed_month[is_leap][12];
563  year++;
564  }
565 
566  tt.year = year;
567 
568  for (month = 11; month >= 0; month--) {
569  if (doy > days_in_year_passed_month[is_leap][month]) {
570  tt.month = month + 1;
571  tt.day = doy - days_in_year_passed_month[is_leap][month];
572  break;
573  }
574  }
575 
576  return tt;
577 }
578 
580 {
581  struct icaltimetype t;
582 
583  memset(&t, 0, sizeof(struct icaltimetype));
584 
585  return t;
586 }
587 
589 {
590  struct icaltimetype t;
591 
592  memset(&t, 0, sizeof(struct icaltimetype));
593 
594  t.is_date = 1;
595 
596  /*
597  * Init to -1 to match what icalyacc.y used to do.
598  * Does anything depend on this?
599  */
600  t.hour = -1;
601  t.minute = -1;
602  t.second = -1;
603 
604  return t;
605 }
606 
608 {
609  // Note that we allow year, month and day to be zero to support null times
610  if (t.year < 0 || t.year > 9999 ||
611  t.month < 0 || t.month > 12 ||
612  t.day < 0 || t.day > 31 ||
613  t.is_date > 1 || t.is_date < 0) {
614  return false;
615  } else {
616  return true;
617  }
618 }
619 
620 bool icaltime_is_date(const struct icaltimetype t)
621 {
622  return (t.is_date != 0);
623 }
624 
625 bool icaltime_is_utc(const struct icaltimetype t)
626 {
627  return t.zone == icaltimezone_get_utc_timezone();
628 }
629 
631 {
632  if (t.second + t.minute + t.hour + t.day + t.month + t.year == 0) {
633  return true;
634  }
635 
636  return false;
637 }
638 
639 int icaltime_compare(const struct icaltimetype a_in, const struct icaltimetype b_in)
640 {
641  struct icaltimetype a, b;
642 
643  /* Ensure valid icaltimetypes, else the comparisons below mean nothing at all */
644  const bool a_is_valid = icaltime_is_valid_time(a_in);
645  const bool b_is_valid = icaltime_is_valid_time(b_in);
646  if (a_is_valid && !b_is_valid) {
647  return 1;
648  }
649  if (!a_is_valid) {
650  if (b_is_valid) {
651  return -1;
652  } else {
653  return 0;
654  }
655  }
656 
657  /* We only need to perform time zone conversion if times aren't in the same time zone
658  or neither of them is floating (zone equals NULL) */
659  if (a_in.zone != b_in.zone && a_in.zone != NULL && b_in.zone != NULL) {
662  } else {
663  a = a_in;
664  b = b_in;
665  }
666 
667  if (a.year > b.year) {
668  return 1;
669  } else if (a.year < b.year) {
670  return -1;
671  } else if (a.month > b.month) {
672  return 1;
673  } else if (a.month < b.month) {
674  return -1;
675  } else if (a.day > b.day) {
676  return 1;
677  } else if (a.day < b.day) {
678  return -1;
679  }
680 
681  /* if both are dates, we are done */
682  if (a.is_date && b.is_date) {
683  return 0;
684 
685  /* else, if only one is a date (and we already know the date part is equal),
686  then the other is greater */
687  } else if (b.is_date) {
688  return 1;
689  } else if (a.is_date) {
690  return -1;
691  } else if (a.hour > b.hour) {
692  return 1;
693  } else if (a.hour < b.hour) {
694  return -1;
695  } else if (a.minute > b.minute) {
696  return 1;
697  } else if (a.minute < b.minute) {
698  return -1;
699  } else if (a.second > b.second) {
700  return 1;
701  } else if (a.second < b.second) {
702  return -1;
703  }
704 
705  return 0;
706 }
707 
709  const struct icaltimetype b_in)
710 {
711  icaltimezone *tz;
712 
713  /* prefer timezone of one of the times, because the UTC can change days in some cases */
714  if (a_in.zone != NULL) {
715  tz = (icaltimezone *)a_in.zone;
716  } else if (b_in.zone != NULL) {
717  tz = (icaltimezone *)b_in.zone;
718  } else {
720  }
721 
722  return icaltime_compare_date_only_tz(a_in, b_in, tz);
723 }
724 
726  const struct icaltimetype b_in,
727  icaltimezone *tz)
728 {
729  struct icaltimetype a, b;
730 
731  a = icaltime_convert_to_zone(a_in, tz);
732  b = icaltime_convert_to_zone(b_in, tz);
733 
734  if (a.year > b.year) {
735  return 1;
736  } else if (a.year < b.year) {
737  return -1;
738  }
739 
740  if (a.month > b.month) {
741  return 1;
742  } else if (a.month < b.month) {
743  return -1;
744  }
745 
746  if (a.day > b.day) {
747  return 1;
748  } else if (a.day < b.day) {
749  return -1;
750  }
751 
752  return 0;
753 }
754 
756  const int days, const int hours,
757  const int minutes, const int seconds)
758 {
759  int second, minute, hour, day;
760  int minutes_overflow, hours_overflow, days_overflow = 0, years_overflow;
761  int days_in_month;
762 
763  if (icaltime_is_null_time(*tt)) { // do not attempt to adjust null times
764  return;
765  }
766 
767  /* If we are passed a date make sure to ignore hour minute and second */
768  if (tt->is_date) {
769  goto IS_DATE;
770  }
771 
772  /* Add on the seconds. */
773  second = tt->second + seconds;
774  tt->second = second % 60;
775  minutes_overflow = second / 60;
776  if (tt->second < 0) {
777  tt->second += 60;
778  minutes_overflow--;
779  }
780 
781  /* Add on the minutes. */
782  minute = tt->minute + minutes + minutes_overflow;
783  tt->minute = minute % 60;
784  hours_overflow = minute / 60;
785  if (tt->minute < 0) {
786  tt->minute += 60;
787  hours_overflow--;
788  }
789 
790  /* Add on the hours. */
791  hour = tt->hour + hours + hours_overflow;
792  tt->hour = hour % 24;
793  days_overflow = hour / 24;
794  if (tt->hour < 0) {
795  tt->hour += 24;
796  days_overflow--;
797  }
798 
799 IS_DATE:
800  /* Normalize the month. We do this before handling the day since we may
801  need to know what month it is to get the number of days in it.
802  Note that months are 1 to 12, so we have to be a bit careful. */
803  if (tt->month >= 13) {
804  years_overflow = (tt->month - 1) / 12;
805  tt->year += years_overflow;
806  tt->month -= years_overflow * 12;
807  } else if (tt->month <= 0) {
808  /* 0 to -11 is -1 year out, -12 to -23 is -2 years. */
809  years_overflow = (tt->month / 12) - 1;
810  tt->year += years_overflow;
811  tt->month -= years_overflow * 12;
812  }
813 
814  /* Add on the days. */
815  day = tt->day + days + days_overflow;
816  if (day > 0) {
817  for (;;) {
818  days_in_month = icaltime_days_in_month(tt->month, tt->year);
819  if (day <= days_in_month) {
820  break;
821  }
822 
823  tt->month++;
824  if (tt->month >= 13) {
825  tt->year++;
826  tt->month = 1;
827  }
828 
829  day -= days_in_month;
830  }
831  } else {
832  while (day <= 0) {
833  if (tt->month == 1) {
834  tt->year--;
835  tt->month = 12;
836  } else {
837  tt->month--;
838  }
839 
840  day += icaltime_days_in_month(tt->month, tt->year);
841  }
842  }
843  tt->day = day;
844 }
845 
847 {
848  struct icaltimetype ret = tt;
849 
850  /* If it's a date do nothing */
851  if (tt.is_date) {
852  return ret;
853  }
854 
855  if (tt.zone == zone) {
856  return ret;
857  }
858 
859  /* If it's a floating time we don't want to adjust the time */
860  if (tt.zone != NULL) {
862  }
863 
864  ret.zone = zone;
865 
866  return ret;
867 }
868 
870 {
871  return t.zone;
872 }
873 
874 const char *icaltime_get_tzid(const struct icaltimetype t)
875 {
876  if (t.zone != NULL) {
878  } else {
879  return NULL;
880  }
881 }
882 
884 {
885  /* If it's a date do nothing */
886  if (t->is_date) {
887  return *t;
888  }
889 
890  if (t->zone == zone) {
891  return *t;
892  }
893 
894  t->zone = zone;
895 
896  return *t;
897 }
int is_date
Definition: icaltime.h:98
int icaltime_days_in_year(const int year)
Definition: icaltime.c:460
void icaltimezone_convert_time(struct icaltimetype *tt, icaltimezone *from_zone, icaltimezone *to_zone)
Definition: icaltimezone.c:864
Common memory management routines.
Timezone handling routines.
struct icaltimetype icaltime_normalize(const struct icaltimetype tt)
Definition: icaltime.c:366
int second
Definition: icaltime.h:96
bool icaltime_is_utc(const struct icaltimetype t)
Definition: icaltime.c:625
Defines the data structure for representing date-times.
const icaltimezone * zone
Definition: icaltime.h:102
icaltime_t icaltime_as_timet_with_zone(const struct icaltimetype tt, const icaltimezone *zone)
Definition: icaltime.c:292
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
Definition: icalerror.c:90
struct icaltimetype icaltime_current_time_with_zone(const icaltimezone *zone)
Definition: icaltime.c:249
int icaltime_day_of_week(const struct icaltimetype t)
Definition: icaltime.c:497
int icaltime_compare(const struct icaltimetype a_in, const struct icaltimetype b_in)
Definition: icaltime.c:639
void icaltime_adjust(struct icaltimetype *tt, const int days, const int hours, const int minutes, const int seconds)
Definition: icaltime.c:755
Error handling for libical.
const char * icaltime_as_ical_string(const struct icaltimetype tt)
Definition: icaltime.c:332
int minute
Definition: icaltime.h:95
struct icaltimetype icaltime_from_day_of_year(const int _doy, const int _year)
Definition: icaltime.c:544
int icaltime_compare_date_only(const struct icaltimetype a_in, const struct icaltimetype b_in)
Definition: icaltime.c:708
struct icaltimetype icaltime_null_time(void)
Definition: icaltime.c:579
struct icaltimetype icaltime_set_timezone(struct icaltimetype *t, const icaltimezone *zone)
Definition: icaltime.c:883
const char * icaltime_get_tzid(const struct icaltimetype t)
Definition: icaltime.c:874
struct icaltimetype icaltime_null_date(void)
Definition: icaltime.c:588
struct icaltimetype icaltime_convert_to_zone(const struct icaltimetype tt, icaltimezone *zone)
Definition: icaltime.c:846
struct _icaltimezone icaltimezone
Definition: icaltimezone.h:29
bool icaltime_is_valid_time(const struct icaltimetype t)
Definition: icaltime.c:607
void * icalmemory_new_buffer(size_t size)
Creates new buffer with the specified size.
Definition: icalmemory.c:315
int icaltime_day_of_year(const struct icaltimetype t)
Definition: icaltime.c:533
struct icaltimetype icaltime_from_string(const char *str)
Definition: icaltime.c:374
const icaltimezone * icaltime_get_timezone(const struct icaltimetype t)
Definition: icaltime.c:869
bool icaltime_is_date(const struct icaltimetype t)
Definition: icaltime.c:620
icaltimezone * icaltimezone_get_utc_timezone(void)
struct icaltimetype icaltime_from_timet_with_zone(const icaltime_t tm, const bool is_date, const icaltimezone *zone)
Constructor.
Definition: icaltime.c:209
icaltime_t icaltime_as_timet(const struct icaltimetype tt)
Definition: icaltime.c:259
int icaltime_days_in_month(const int month, const int year)
Definition: icaltime.c:471
bool icaltime_is_null_time(const struct icaltimetype t)
Definition: icaltime.c:630
void icalmemory_add_tmp_buffer(void *buf)
Adds an externally allocated buffer to the ring.
Definition: icalmemory.c:158
int is_daylight
Definition: icaltime.h:100
struct icaltimetype icaltime_today(void)
Convenience constructor.
Definition: icaltime.c:254
int icaltime_compare_date_only_tz(const struct icaltimetype a_in, const struct icaltimetype b_in, icaltimezone *tz)
Definition: icaltime.c:725
char * icaltime_as_ical_string_r(const struct icaltimetype tt)
Definition: icaltime.c:341
const char * icaltimezone_get_tzid(icaltimezone *zone)
int icaltime_start_doy_week(const struct icaltimetype t, int fdow)
Definition: icaltime.c:512
bool icaltime_is_leap_year(const int year)
Definition: icaltime.c:451