blob: e67c687a92193ea7f28b230f67562349deefd6fd (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "utc-mktime.h"
static int tm_cmp(const struct tm *tm1, const struct tm *tm2)
{
int diff;
if ((diff = tm1->tm_year - tm2->tm_year) != 0)
return diff;
if ((diff = tm1->tm_mon - tm2->tm_mon) != 0)
return diff;
if ((diff = tm1->tm_mday - tm2->tm_mday) != 0)
return diff;
if ((diff = tm1->tm_hour - tm2->tm_hour) != 0)
return diff;
if ((diff = tm1->tm_min - tm2->tm_min) != 0)
return diff;
return tm1->tm_sec - tm2->tm_sec;
}
static inline void adjust_leap_second(struct tm *tm)
{
if (tm->tm_sec == 60)
tm->tm_sec = 59;
}
#ifdef HAVE_TIMEGM
/* Normalization done by timegm is considered a failure here, since it means
* the timestamp is not valid as-is. Leap second 60 is adjusted to 59 before
* this though. */
time_t utc_mktime(const struct tm *tm)
{
struct tm leap_adj_tm = *tm;
adjust_leap_second(&leap_adj_tm);
struct tm tmp = leap_adj_tm;
time_t t;
t = timegm(&tmp);
if (tm_cmp(&leap_adj_tm, &tmp) != 0)
return (time_t)-1;
return t;
}
#else
time_t utc_mktime(const struct tm *tm)
{
struct tm leap_adj_tm = *tm;
adjust_leap_second(&leap_adj_tm);
const struct tm *try_tm;
time_t t;
int bits, dir;
/* we'll do a binary search across the entire valid time_t range.
when gmtime()'s output matches the tm parameter, we've found the
correct time_t value. this also means that if tm contains invalid
values, -1 is returned. */
#ifdef TIME_T_SIGNED
t = 0;
#else
t = (time_t)1 << (TIME_T_MAX_BITS - 1);
#endif
for (bits = TIME_T_MAX_BITS - 2;; bits--) {
try_tm = gmtime(&t);
dir = tm_cmp(&leap_adj_tm, try_tm);
if (dir == 0)
return t;
if (bits < 0)
break;
if (dir < 0)
t -= (time_t)1 << bits;
else
t += (time_t)1 << bits;
}
return (time_t)-1;
}
#endif
|