Libical API Documentation 4.0 STABLE VERSION [Visit the v3.0 documentation]
Loading...
Searching...
No Matches
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
44
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*/
60static 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
65static 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 */
83static 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 /* 32-bit time_t cannot represent any instant after
108 2038-01-19T03:14:07 UTC (INT32_MAX seconds since the epoch). */
109 if (tm->tm_year == 138 &&
110 (tm->tm_mon > 0 ||
111 tm->tm_mday > 19 ||
112 (tm->tm_mday == 19 &&
113 (tm->tm_hour > 3 ||
114 (tm->tm_hour == 3 &&
115 (tm->tm_min > 14 ||
116 (tm->tm_min == 14 && tm->tm_sec > 7))))))) {
117 return false;
118 }
119
120#else
121 /* We don't support years >= 10000, because the function has not been tested at this range. */
122 if (tm->tm_year >= 8100) {
123 return false;
124 }
125#endif /* SIZEOF_ICALTIME_T */
126
127 /*
128 * calculate elapsed days since start of the epoch (midnight Jan
129 * 1st, 1970 UTC) 17 = number of leap years between 1900 and 1970
130 * (number of leap days to subtract)
131 */
132
133 tim = (icaltime_t)((tm->tm_year - 70) * 365 + ((tm->tm_year - 1) / 4) - 17);
134
135 /* adjust: no leap days every 100 years, except every 400 years. */
136
137 febs = (tm->tm_year - 100) - ((tm->tm_mon <= 1) ? 1 : 0);
138 tim -= febs / 100;
139 tim += febs / 400;
140
141 /* add number of days elapsed in the current year */
142
143 tim += days[tm->tm_mon];
144
145 /* check and adjust for leap years */
146
147 if ((tm->tm_year & 3) == 0 && tm->tm_mon > 1) {
148 tim += 1;
149 }
150
151 /* elapsed days to current date */
152
153 tim += tm->tm_mday;
154
155 /* calculate elapsed hours since start of the epoch */
156
157 tim = tim * 24 + tm->tm_hour;
158
159 /* calculate elapsed minutes since start of the epoch */
160
161 tim = tim * 60 + tm->tm_min;
162
163 /* adjust per time zone specification */
164
165 tim -= tzm;
166
167 /* calculate elapsed seconds since start of the epoch */
168
169 tim = tim * 60 + tm->tm_sec;
170
171 /* return number of seconds since start of the epoch */
172
173 if (out_time_t) {
174 *out_time_t = tim;
175 }
176
177 return true;
178}
179
180/*
181 * Code adapted from Python 2.4.1 sources (Lib/calendar.py).
182 */
183static icaltime_t icaltime_timegm(const struct tm *tm)
184{
185 int year;
186 icaltime_t days;
187 icaltime_t hours;
188 icaltime_t minutes;
189 icaltime_t seconds;
190
191 /* Validate the tm structure by passing it through make_time() */
192 if (!make_time(tm, 0, NULL)) {
193 /* we have some invalid data in the tm struct */
194 return 0;
195 }
196
197 year = 1900 + tm->tm_year;
198 int idays = (365 * (year - 1970) + icaltime_leap_days(1970, year));
199 days = (icaltime_t)idays;
200 days += days_in_year_passed_month[0][tm->tm_mon];
201
202 if (tm->tm_mon > 1 && icaltime_is_leap_year(year)) {
203 ++days;
204 }
205
206 days += tm->tm_mday - 1;
207 hours = days * 24 + tm->tm_hour;
208 minutes = hours * 60 + tm->tm_min;
209 seconds = minutes * 60 + tm->tm_sec;
210
211 return seconds;
212}
213
214struct icaltimetype icaltime_from_timet_with_zone(const icaltime_t tm, const bool is_date,
215 const icaltimezone *zone)
216{
217 struct icaltimetype tt;
218 struct tm t;
219 icaltimezone *utc_zone;
220
222
223 /* Convert the icaltime_t to a struct tm in UTC time. We can trust gmtime for this. */
224 memset(&t, 0, sizeof(struct tm));
225 if (!icalgmtime_r(&tm, &t)) {
226 return is_date ? icaltime_null_date() : icaltime_null_time(); //NOLINT(readability-implicit-bool-conversion)
227 }
228
229 tt.year = t.tm_year + 1900;
230 tt.month = t.tm_mon + 1;
231 tt.day = t.tm_mday;
232 tt.hour = t.tm_hour;
233 tt.minute = t.tm_min;
234 tt.second = t.tm_sec;
235 tt.is_date = 0;
236 tt.is_daylight = 0;
237 tt.zone = (zone == NULL) ? NULL : utc_zone;
238
239 /* Use our timezone functions to convert to the required timezone. */
240 icaltimezone_convert_time(&tt, utc_zone, (icaltimezone *)zone);
241
242 tt.is_date = (int)is_date;
243
244 /* If it is a DATE value, make sure hour, minute & second are 0. */
245 if (is_date) {
246 tt.hour = 0;
247 tt.minute = 0;
248 tt.second = 0;
249 }
250
251 return tt;
252}
253
255{
256 return icaltime_from_timet_with_zone(icaltime(NULL), false, zone);
257}
258
260{
261 return icaltime_from_timet_with_zone(icaltime(NULL), true, NULL);
262}
263
264icaltime_t icaltime_as_timet(const struct icaltimetype tt)
265{
266 struct tm stm;
267 icaltime_t t = (icaltime_t)-1;
268
269 /* If the time is the special null time, return 0. */
270 if (icaltime_is_null_time(tt)) {
271 return 0;
272 }
273
274 /* Copy the icaltimetype to a struct tm. */
275 memset(&stm, 0, sizeof(struct tm));
276
277 if (icaltime_is_date(tt)) {
278 stm.tm_sec = stm.tm_min = stm.tm_hour = 0;
279 } else {
280 stm.tm_sec = tt.second;
281 stm.tm_min = tt.minute;
282 stm.tm_hour = tt.hour;
283 }
284
285 stm.tm_mday = tt.day;
286 stm.tm_mon = tt.month - 1;
287 stm.tm_year = tt.year - 1900;
288 stm.tm_isdst = -1;
289
290 if (!make_time(&stm, 0, &t)) {
291 t = ((icaltime_t)-1);
292 }
293
294 return t;
295}
296
297icaltime_t icaltime_as_timet_with_zone(const struct icaltimetype tt, const icaltimezone *zone)
298{
299 icaltimezone *utc_zone;
300 struct tm stm;
301 icaltime_t t;
302 struct icaltimetype local_tt;
303
305
306 /* Return 0 if the time is the special null time or a bad time */
308 return 0;
309 }
310
311 local_tt = tt;
312
313 /* Clear the is_date flag, so we can convert the time. */
314 local_tt.is_date = 0;
315
316 /* Use our timezone functions to convert to UTC. */
317 if (tt.zone != utc_zone) {
318 icaltimezone_convert_time(&local_tt, (icaltimezone *)zone, utc_zone);
319 }
320
321 /* Copy the icaltimetype to a struct tm. */
322 memset(&stm, 0, sizeof(struct tm));
323
324 stm.tm_sec = local_tt.second;
325 stm.tm_min = local_tt.minute;
326 stm.tm_hour = local_tt.hour;
327 stm.tm_mday = local_tt.day;
328 stm.tm_mon = local_tt.month - 1;
329 stm.tm_year = local_tt.year - 1900;
330 stm.tm_isdst = -1;
331
332 t = icaltime_timegm(&stm);
333
334 return t;
335}
336
337const char *icaltime_as_ical_string(const struct icaltimetype tt)
338{
339 char *buf;
340
343 return buf;
344}
345
347{
348 size_t size = 17;
349 char *buf = icalmemory_new_buffer(size);
350
351 if (tt.is_date) {
352 snprintf(buf, size, "%04d%02d%02d", tt.year, tt.month, tt.day);
353 } else {
354#pragma GCC diagnostic push
355#pragma GCC diagnostic ignored "-Wformat-nonliteral"
356 const char *fmt;
357
358 if (icaltime_is_utc(tt)) {
359 fmt = "%04d%02d%02dT%02d%02d%02dZ";
360 } else {
361 fmt = "%04d%02d%02dT%02d%02d%02d";
362 }
363 snprintf(buf, size, fmt, tt.year, tt.month, tt.day, tt.hour, tt.minute, tt.second);
364#pragma GCC diagnostic pop
365 }
366
367 return buf;
368}
369
370/* Implementation note: we call icaltime_adjust() with no adjustment. */
372{
373 struct icaltimetype ret = tt;
374
375 icaltime_adjust(&ret, 0, 0, 0, 0);
376 return ret;
377}
378
380{
381 struct icaltimetype tt = icaltime_null_time();
382 size_t size;
383
384 icalerror_check_arg_re(str != 0, "str", icaltime_null_time());
385
386 size = strlen(str);
387
388 if ((size == 15) || (size == 19)) { /* floating time with/without separators */
389 tt.is_date = 0;
390 } else if ((size == 16) || (size == 20)) { /* UTC time, ends in 'Z' */
391 if ((str[size - 1] != 'Z')) {
392 goto FAIL;
393 }
394
396 tt.is_date = 0;
397 } else if ((size == 8) || (size == 10)) { /* A DATE */
398 tt.is_date = 1;
399 } else { /* error */
400 goto FAIL;
401 }
402
403 // NOLINTBEGIN(bugprone-unchecked-string-to-number-conversion)
404 if (tt.is_date == 1) {
405 if (size == 10) {
406 char dsep1, dsep2;
407
408 if (sscanf(str, "%04d%c%02d%c%02d",
409 &tt.year, &dsep1, &tt.month, &dsep2, &tt.day) < 5) {
410 goto FAIL;
411 }
412
413 if ((dsep1 != '-') || (dsep2 != '-')) {
414 goto FAIL;
415 }
416 } else if (sscanf(str, "%04d%02d%02d", &tt.year, &tt.month, &tt.day) < 3) {
417 goto FAIL;
418 }
419 } else {
420 if (size > 16) {
421 char dsep1, dsep2, tsep, tsep1, tsep2;
422
423 if (sscanf(str, "%04d%c%02d%c%02d%c%02d%c%02d%c%02d",
424 &tt.year, &dsep1, &tt.month, &dsep2, &tt.day, &tsep,
425 &tt.hour, &tsep1, &tt.minute, &tsep2, &tt.second) < 11) {
426 goto FAIL;
427 }
428
429 if ((tsep != 'T') ||
430 (dsep1 != '-') || (dsep2 != '-') ||
431 (tsep1 != ':') || (tsep2 != ':')) {
432 goto FAIL;
433 }
434
435 } else {
436 char tsep;
437
438 if (sscanf(str, "%04d%02d%02d%c%02d%02d%02d",
439 &tt.year, &tt.month, &tt.day, &tsep,
440 &tt.hour, &tt.minute, &tt.second) < 7) {
441 goto FAIL;
442 }
443
444 if (tsep != 'T') {
445 goto FAIL;
446 }
447 }
448 }
449 // NOLINTEND(bugprone-unchecked-string-to-number-conversion)
450
451 return tt;
452
453FAIL:
455 return icaltime_null_time();
456}
457
459{
460 if (year <= 1752) {
461 return (year % 4 == 0);
462 } else {
463 return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); //NOLINT(readability-implicit-bool-conversion)
464 }
465}
466
468{
470 return 366;
471 } else {
472 return 365;
473 }
474}
475
476static const int _days_in_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
477
478int icaltime_days_in_month(const int month, const int year)
479{
480 int days;
481
482 /* The old code aborting if it was passed a parameter like BYMONTH=0
483 * Unfortunately it's not practical right now to pass an error all
484 * the way up the stack, so instead of aborting we're going to apply
485 * the GIGO principle and simply return '30 days' if we get an
486 * invalid month. Modern applications cannot tolerate crashing.
487 * assert(month > 0);
488 * assert(month <= 12);
489 */
490 if ((month < 1) || (month > 12)) {
491 return 30;
492 }
493
494 days = _days_in_month[month];
495
496 if (month == 2) {
497 days += (int)icaltime_is_leap_year(year);
498 }
499
500 return days;
501}
502
503/* 1-> Sunday, 7->Saturday */
505{
506 UTinstantInt jt;
507
508 memset(&jt, 0, sizeof(UTinstantInt));
509
510 jt.year = t.year;
511 jt.month = t.month;
512 jt.day = t.day;
513
514 ical_juldat(&jt);
515
516 return jt.weekday + 1;
517}
518
519int icaltime_start_doy_week(const struct icaltimetype t, int fdow)
520{
521 UTinstantInt jt;
522 int delta;
523
524 memset(&jt, 0, sizeof(UTinstantInt));
525
526 jt.year = t.year;
527 jt.month = t.month;
528 jt.day = t.day;
529
530 ical_juldat(&jt);
531 ical_caldat(&jt);
532
533 delta = jt.weekday - (fdow - 1);
534 if (delta < 0) {
535 delta += 7;
536 }
537 return jt.day_of_year - delta;
538}
539
541{
542 if (t.month < 1 || t.month > 12) {
543 return 0;
544 }
545
546 return days_in_year_passed_month[icaltime_is_leap_year(t.year)][t.month - 1] + t.day;
547}
548
549struct icaltimetype icaltime_from_day_of_year(const int _doy, const int _year)
550{
551 struct icaltimetype tt = icaltime_null_date();
552 bool is_leap;
553 int month;
554 int doy = _doy;
555 int year = _year;
556
557 is_leap = icaltime_is_leap_year(year);
558
559 /* Zero and neg numbers represent days of the previous year */
560 if (doy < 1) {
561 year--;
562 is_leap = icaltime_is_leap_year(year);
563 doy += days_in_year_passed_month[is_leap][12];
564 } else if (doy > days_in_year_passed_month[is_leap][12]) {
565 /* Move on to the next year */
566 is_leap = icaltime_is_leap_year(year);
567 doy -= days_in_year_passed_month[is_leap][12];
568 year++;
569 }
570
571 tt.year = year;
572
573 for (month = 11; month >= 0; month--) {
574 if (doy > days_in_year_passed_month[is_leap][month]) {
575 tt.month = month + 1;
576 tt.day = doy - days_in_year_passed_month[is_leap][month];
577 break;
578 }
579 }
580
581 return tt;
582}
583
585{
586 struct icaltimetype t;
587
588 memset(&t, 0, sizeof(struct icaltimetype));
589
590 return t;
591}
592
594{
595 struct icaltimetype t;
596
597 memset(&t, 0, sizeof(struct icaltimetype));
598
599 t.is_date = 1;
600
601 /*
602 * Init to -1 to match what icalyacc.y used to do.
603 * Does anything depend on this?
604 */
605 t.hour = -1;
606 t.minute = -1;
607 t.second = -1;
608
609 return t;
610}
611
613{
614 // Note that we allow year, month and day to be zero to support null times
615 if (t.year < 0 || t.year > 9999 ||
616 t.month < 0 || t.month > 12 ||
617 t.day < 0 || t.day > 31 ||
618 t.is_date > 1 || t.is_date < 0) {
619 return false;
620 }
621
622 // If this is a datetime also validate the time members
623 if (!t.is_date &&
624 (t.second < 0 ||
625 t.second > 59 ||
626 t.minute < 0 || t.minute > 59 ||
627 t.hour < 0 || t.hour > 23)) {
628 return false;
629 }
630
631 return true;
632}
633
634bool icaltime_is_date(const struct icaltimetype t)
635{
636 return (t.is_date != 0);
637}
638
639bool icaltime_is_utc(const struct icaltimetype t)
640{
642}
643
645{
646 if (t.second + t.minute + t.hour + t.day + t.month + t.year == 0) {
647 return true;
648 }
649
650 return false;
651}
652
653int icaltime_compare(const struct icaltimetype a_in, const struct icaltimetype b_in)
654{
655 struct icaltimetype a, b;
656
657 /* Ensure valid icaltimetypes, else the comparisons below mean nothing at all */
658 const bool a_is_valid = icaltime_is_valid_time(a_in);
659 const bool b_is_valid = icaltime_is_valid_time(b_in);
660 if (a_is_valid && !b_is_valid) {
661 return 1;
662 }
663 if (!a_is_valid) {
664 if (b_is_valid) {
665 return -1;
666 } else {
667 return 0;
668 }
669 }
670
671 /* We only need to perform time zone conversion if times aren't in the same time zone
672 or neither of them is floating (zone equals NULL) */
673 if (a_in.zone != b_in.zone && a_in.zone != NULL && b_in.zone != NULL) {
676 } else {
677 a = a_in;
678 b = b_in;
679 }
680
681 if (a.year > b.year) {
682 return 1;
683 } else if (a.year < b.year) {
684 return -1;
685 } else if (a.month > b.month) {
686 return 1;
687 } else if (a.month < b.month) {
688 return -1;
689 } else if (a.day > b.day) {
690 return 1;
691 } else if (a.day < b.day) {
692 return -1;
693 }
694
695 /* if both are dates, we are done */
696 if (a.is_date && b.is_date) {
697 return 0;
698
699 /* else, if only one is a date (and we already know the date part is equal),
700 then the other is greater */
701 } else if (b.is_date) {
702 return 1;
703 } else if (a.is_date) {
704 return -1;
705 } else if (a.hour > b.hour) {
706 return 1;
707 } else if (a.hour < b.hour) {
708 return -1;
709 } else if (a.minute > b.minute) {
710 return 1;
711 } else if (a.minute < b.minute) {
712 return -1;
713 } else if (a.second > b.second) {
714 return 1;
715 } else if (a.second < b.second) {
716 return -1;
717 }
718
719 return 0;
720}
721
723 const struct icaltimetype b_in)
724{
725 icaltimezone *tz;
726
727 /* prefer timezone of one of the times, because the UTC can change days in some cases */
728 if (a_in.zone != NULL) {
729 tz = (icaltimezone *)a_in.zone;
730 } else if (b_in.zone != NULL) {
731 tz = (icaltimezone *)b_in.zone;
732 } else {
734 }
735
736 return icaltime_compare_date_only_tz(a_in, b_in, tz);
737}
738
740 const struct icaltimetype b_in,
741 icaltimezone *tz)
742{
743 struct icaltimetype a, b;
744
745 a = icaltime_convert_to_zone(a_in, tz);
746 b = icaltime_convert_to_zone(b_in, tz);
747
748 if (a.year > b.year) {
749 return 1;
750 } else if (a.year < b.year) {
751 return -1;
752 }
753
754 if (a.month > b.month) {
755 return 1;
756 } else if (a.month < b.month) {
757 return -1;
758 }
759
760 if (a.day > b.day) {
761 return 1;
762 } else if (a.day < b.day) {
763 return -1;
764 }
765
766 return 0;
767}
768
770 const int days, const int hours,
771 const int minutes, const int seconds)
772{
773 int second, minute, hour, day;
774 int minutes_overflow, hours_overflow, days_overflow = 0, years_overflow;
775 int days_in_month;
776
777 if (icaltime_is_null_time(*tt)) { // do not attempt to adjust null times
778 return;
779 }
780
781 /* If we are passed a date make sure to ignore hour minute and second */
782 if (tt->is_date) {
783 goto IS_DATE;
784 }
785
786 /* Add on the seconds. */
787 second = tt->second + seconds;
788 tt->second = second % 60;
789 minutes_overflow = second / 60;
790 if (tt->second < 0) {
791 tt->second += 60;
792 minutes_overflow--;
793 }
794
795 /* Add on the minutes. */
796 minute = tt->minute + minutes + minutes_overflow;
797 tt->minute = minute % 60;
798 hours_overflow = minute / 60;
799 if (tt->minute < 0) {
800 tt->minute += 60;
801 hours_overflow--;
802 }
803
804 /* Add on the hours. */
805 hour = tt->hour + hours + hours_overflow;
806 tt->hour = hour % 24;
807 days_overflow = hour / 24;
808 if (tt->hour < 0) {
809 tt->hour += 24;
810 days_overflow--;
811 }
812
813IS_DATE:
814 /* Normalize the month. We do this before handling the day since we may
815 need to know what month it is to get the number of days in it.
816 Note that months are 1 to 12, so we have to be a bit careful. */
817 if (tt->month >= 13) {
818 years_overflow = (tt->month - 1) / 12;
819 tt->year += years_overflow;
820 tt->month -= years_overflow * 12;
821 } else if (tt->month <= 0) {
822 /* 0 to -11 is -1 year out, -12 to -23 is -2 years. */
823 years_overflow = (tt->month / 12) - 1;
824 tt->year += years_overflow;
825 tt->month -= years_overflow * 12;
826 }
827
828 /* Add on the days. */
829 day = tt->day + days + days_overflow;
830 if (day > 0) {
831 for (;;) {
832 days_in_month = icaltime_days_in_month(tt->month, tt->year);
833 if (day <= days_in_month) {
834 break;
835 }
836
837 tt->month++;
838 if (tt->month >= 13) {
839 tt->year++;
840 tt->month = 1;
841 }
842
843 day -= days_in_month;
844 }
845 } else {
846 while (day <= 0) {
847 if (tt->month == 1) {
848 tt->year--;
849 tt->month = 12;
850 } else {
851 tt->month--;
852 }
853
855 }
856 }
857 tt->day = day;
858}
859
861{
862 struct icaltimetype ret = tt;
863
864 /* If it's a date do nothing */
865 if (tt.is_date) {
866 return ret;
867 }
868
869 if (tt.zone == zone) {
870 return ret;
871 }
872
873 /* If it's a floating time we don't want to adjust the time */
874 if (tt.zone != NULL) {
876 }
877
878 ret.zone = zone;
879
880 return ret;
881}
882
884{
885 return t.zone;
886}
887
888const char *icaltime_get_tzid(const struct icaltimetype t)
889{
890 if (t.zone != NULL) {
892 } else {
893 return NULL;
894 }
895}
896
898{
899 /* If it's a date do nothing */
900 if (t->is_date) {
901 return *t;
902 }
903
904 if (t->zone == zone) {
905 return *t;
906 }
907
908 t->zone = zone;
909
910 return *t;
911}
const char * str
Definition icalenums.c:29
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
Definition icalerror.c:90
Error handling for libical.
@ ICAL_MALFORMEDDATA_ERROR
Definition icalerror.h:59
void * icalmemory_new_buffer(size_t size)
Creates new buffer with the specified size.
Definition icalmemory.c:315
void icalmemory_add_tmp_buffer(void *buf)
Adds an externally allocated buffer to the ring.
Definition icalmemory.c:158
Common memory management routines.
struct icaltimetype icaltime_from_timet_with_zone(const icaltime_t tm, const bool is_date, const icaltimezone *zone)
Constructor.
Definition icaltime.c:214
bool icaltime_is_date(const struct icaltimetype t)
Definition icaltime.c:634
struct icaltimetype icaltime_from_string(const char *str)
Definition icaltime.c:379
const char * icaltime_get_tzid(const struct icaltimetype t)
Definition icaltime.c:888
struct icaltimetype icaltime_current_time_with_zone(const icaltimezone *zone)
Definition icaltime.c:254
int icaltime_day_of_year(const struct icaltimetype t)
Definition icaltime.c:540
int icaltime_start_doy_week(const struct icaltimetype t, int fdow)
Definition icaltime.c:519
bool icaltime_is_leap_year(const int year)
Definition icaltime.c:458
const icaltimezone * icaltime_get_timezone(const struct icaltimetype t)
Definition icaltime.c:883
int icaltime_day_of_week(const struct icaltimetype t)
Definition icaltime.c:504
struct icaltimetype icaltime_from_day_of_year(const int _doy, const int _year)
Definition icaltime.c:549
struct icaltimetype icaltime_today(void)
Convenience constructor.
Definition icaltime.c:259
struct icaltimetype icaltime_null_date(void)
Definition icaltime.c:593
bool icaltime_is_valid_time(const struct icaltimetype t)
Definition icaltime.c:612
const char * icaltime_as_ical_string(const struct icaltimetype tt)
Definition icaltime.c:337
int icaltime_days_in_month(const int month, const int year)
Definition icaltime.c:478
bool icaltime_is_utc(const struct icaltimetype t)
Definition icaltime.c:639
struct icaltimetype icaltime_convert_to_zone(const struct icaltimetype tt, icaltimezone *zone)
Definition icaltime.c:860
int icaltime_compare_date_only(const struct icaltimetype a_in, const struct icaltimetype b_in)
Definition icaltime.c:722
int icaltime_days_in_year(const int year)
Definition icaltime.c:467
bool icaltime_is_null_time(const struct icaltimetype t)
Definition icaltime.c:644
icaltime_t icaltime_as_timet_with_zone(const struct icaltimetype tt, const icaltimezone *zone)
Definition icaltime.c:297
struct icaltimetype icaltime_normalize(const struct icaltimetype tt)
Definition icaltime.c:371
icaltime_t icaltime_as_timet(const struct icaltimetype tt)
Definition icaltime.c:264
int icaltime_compare(const struct icaltimetype a_in, const struct icaltimetype b_in)
Definition icaltime.c:653
struct icaltimetype icaltime_set_timezone(struct icaltimetype *t, const icaltimezone *zone)
Definition icaltime.c:897
void icaltime_adjust(struct icaltimetype *tt, const int days, const int hours, const int minutes, const int seconds)
Definition icaltime.c:769
struct icaltimetype icaltime_null_time(void)
Definition icaltime.c:584
int icaltime_compare_date_only_tz(const struct icaltimetype a_in, const struct icaltimetype b_in, icaltimezone *tz)
Definition icaltime.c:739
char * icaltime_as_ical_string_r(const struct icaltimetype tt)
Definition icaltime.c:346
Defines the data structure for representing date-times.
struct icaltimetype icaltime_from_timet_with_zone(const icaltime_t tm, const bool is_date, const icaltimezone *zone)
Constructor.
Definition icaltime.c:214
bool icaltime_is_leap_year(const int year)
Definition icaltime.c:458
struct icaltimetype icaltime_null_date(void)
Definition icaltime.c:593
void icaltime_adjust(struct icaltimetype *tt, const int days, const int hours, const int minutes, const int seconds)
Definition icaltime.c:769
const char * icaltimezone_get_tzid(icaltimezone *zone)
icaltimezone * icaltimezone_get_utc_timezone(void)
void icaltimezone_convert_time(struct icaltimetype *tt, icaltimezone *from_zone, icaltimezone *to_zone)
Timezone handling routines.
struct _icaltimezone icaltimezone
int is_daylight
Definition icaltime.h:100
const icaltimezone * zone
Definition icaltime.h:102