/src/dovecot/src/lib/time-util.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "time-util.h" |
5 | | |
6 | | #include <time.h> |
7 | | |
8 | | #define STRFTIME_MAX_BUFSIZE (1024*64) |
9 | | |
10 | | void i_gettimeofday(struct timeval *tv_r) |
11 | 1 | { |
12 | 1 | if (gettimeofday(tv_r, NULL) < 0) |
13 | 0 | i_fatal("gettimeofday() failed: %m"); |
14 | 1 | } |
15 | | |
16 | | uint64_t i_nanoseconds(void) |
17 | 0 | { |
18 | 0 | struct timespec ts; |
19 | |
|
20 | 0 | if (clock_gettime(CLOCK_REALTIME, &ts) < 0) |
21 | 0 | i_fatal("clock_gettime() failed: %m"); |
22 | 0 | return ts.tv_sec * 1000000000ULL + ts.tv_nsec; |
23 | 0 | } |
24 | | |
25 | | int timeval_cmp(const struct timeval *tv1, const struct timeval *tv2) |
26 | 0 | { |
27 | 0 | if (tv1->tv_sec < tv2->tv_sec) |
28 | 0 | return -1; |
29 | 0 | if (tv1->tv_sec > tv2->tv_sec) |
30 | 0 | return 1; |
31 | 0 | if (tv1->tv_usec < tv2->tv_usec) |
32 | 0 | return -1; |
33 | 0 | if (tv1->tv_usec > tv2->tv_usec) |
34 | 0 | return 1; |
35 | 0 | return 0; |
36 | 0 | } |
37 | | |
38 | | int timeval_cmp_margin(const struct timeval *tv1, const struct timeval *tv2, |
39 | | unsigned int usec_margin) |
40 | 0 | { |
41 | 0 | long long secs_diff, usecs_diff; |
42 | 0 | int sec_margin, ret; |
43 | |
|
44 | 0 | if (tv1->tv_sec < tv2->tv_sec) { |
45 | 0 | sec_margin = ((int)usec_margin / 1000000) + 1; |
46 | 0 | secs_diff = (long long)tv2->tv_sec - (long long)tv1->tv_sec; |
47 | 0 | if (secs_diff > sec_margin) |
48 | 0 | return -1; |
49 | 0 | usecs_diff = secs_diff * 1000000LL + |
50 | 0 | (tv2->tv_usec - tv1->tv_usec); |
51 | 0 | ret = -1; |
52 | 0 | } else if (tv1->tv_sec > tv2->tv_sec) { |
53 | 0 | sec_margin = ((int)usec_margin / 1000000) + 1; |
54 | 0 | secs_diff = (long long)tv1->tv_sec - (long long)tv2->tv_sec; |
55 | 0 | if (secs_diff > sec_margin) |
56 | 0 | return 1; |
57 | 0 | usecs_diff = secs_diff * 1000000LL + |
58 | 0 | (tv1->tv_usec - tv2->tv_usec); |
59 | 0 | ret = 1; |
60 | 0 | } else if (tv1->tv_usec < tv2->tv_usec) { |
61 | 0 | usecs_diff = tv2->tv_usec - tv1->tv_usec; |
62 | 0 | ret = -1; |
63 | 0 | } else { |
64 | 0 | usecs_diff = tv1->tv_usec - tv2->tv_usec; |
65 | 0 | ret = 1; |
66 | 0 | } |
67 | 0 | i_assert(usecs_diff >= 0); |
68 | 0 | return (unsigned long long)usecs_diff > usec_margin ? ret : 0; |
69 | 0 | } |
70 | | |
71 | | int timeval_diff_msecs(const struct timeval *tv1, const struct timeval *tv2) |
72 | 0 | { |
73 | 0 | long long diff = timeval_diff_usecs(tv1, tv2) / 1000LL; |
74 | | #ifdef DEBUG |
75 | | /* FIXME v2.4: Remove the ifdef */ |
76 | | i_assert(diff <= INT_MAX); |
77 | | #endif |
78 | 0 | return (int)diff; |
79 | 0 | } |
80 | | |
81 | | long long timeval_diff_usecs(const struct timeval *tv1, |
82 | | const struct timeval *tv2) |
83 | 0 | { |
84 | 0 | time_t secs; |
85 | 0 | int usecs; |
86 | |
|
87 | 0 | secs = tv1->tv_sec - tv2->tv_sec; |
88 | 0 | usecs = tv1->tv_usec - tv2->tv_usec; |
89 | 0 | if (usecs < 0) { |
90 | 0 | secs--; |
91 | 0 | usecs += 1000000; |
92 | 0 | } |
93 | 0 | return ((long long)secs * 1000000LL) + usecs; |
94 | 0 | } |
95 | | |
96 | | time_t time_to_local_day_start(time_t t) |
97 | 0 | { |
98 | 0 | const struct tm *day_tm; |
99 | 0 | struct tm tm; |
100 | 0 | time_t new_start_time; |
101 | |
|
102 | 0 | day_tm = localtime(&t); |
103 | 0 | i_zero(&tm); |
104 | 0 | tm.tm_year = day_tm->tm_year; |
105 | 0 | tm.tm_mon = day_tm->tm_mon; |
106 | 0 | tm.tm_mday = day_tm->tm_mday; |
107 | 0 | tm.tm_isdst = -1; |
108 | 0 | new_start_time = mktime(&tm); |
109 | 0 | i_assert(new_start_time != (time_t)-1); |
110 | 0 | return new_start_time; |
111 | 0 | } |
112 | | |
113 | | static const char *strftime_real(const char *fmt, const struct tm *tm) |
114 | 0 | { |
115 | 0 | size_t bufsize = strlen(fmt) + 32; |
116 | 0 | char *buf = t_buffer_get(bufsize); |
117 | 0 | size_t ret; |
118 | |
|
119 | 0 | while ((ret = strftime(buf, bufsize, fmt, tm)) == 0) { |
120 | 0 | bufsize *= 2; |
121 | 0 | i_assert(bufsize <= STRFTIME_MAX_BUFSIZE); |
122 | 0 | buf = t_buffer_get(bufsize); |
123 | 0 | } |
124 | 0 | t_buffer_alloc(ret + 1); |
125 | 0 | return buf; |
126 | 0 | } |
127 | | |
128 | | const char *t_strftime(const char *fmt, const struct tm *tm) |
129 | 0 | { |
130 | 0 | return strftime_real(fmt, tm); |
131 | 0 | } |
132 | | |
133 | | const char *t_strflocaltime(const char *fmt, time_t t) |
134 | 0 | { |
135 | 0 | return strftime_real(fmt, localtime(&t)); |
136 | 0 | } |
137 | | |
138 | | const char *t_strfgmtime(const char *fmt, time_t t) |
139 | 0 | { |
140 | 0 | return strftime_real(fmt, gmtime(&t)); |
141 | 0 | } |
142 | | |
143 | | int str_to_timeval(const char *str, struct timeval *tv_r) |
144 | 0 | { |
145 | 0 | tv_r->tv_usec = 0; |
146 | |
|
147 | 0 | const char *p = strchr(str, '.'); |
148 | 0 | if (p == NULL) |
149 | 0 | return str_to_time(str, &tv_r->tv_sec); |
150 | | |
151 | 0 | int ret; |
152 | 0 | T_BEGIN { |
153 | 0 | ret = str_to_time(t_strdup_until(str, p++), &tv_r->tv_sec); |
154 | 0 | } T_END; |
155 | 0 | if (ret < 0 || p[0] == '\0') |
156 | 0 | return -1; |
157 | | |
158 | 0 | unsigned int len = strlen(p); |
159 | 0 | if (len > 6) |
160 | 0 | return -1; /* we don't support sub-microseconds */ |
161 | 0 | char usecs_str[7] = "000000"; |
162 | 0 | memcpy(usecs_str, p, len); |
163 | |
|
164 | 0 | unsigned int usec; |
165 | 0 | if (str_to_uint(usecs_str, &usec) < 0) |
166 | 0 | return -1; |
167 | 0 | tv_r->tv_usec = usec; |
168 | 0 | return 0; |
169 | 0 | } |