Coverage Report

Created: 2023-03-26 07:19

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