]> git.ipfire.org Git - thirdparty/util-linux.git/blame - lib/time-util.c
lib/strutils: move *swith() functions to private library
[thirdparty/util-linux.git] / lib / time-util.c
CommitLineData
2659a49e
SK
1/***
2 First set of functions in this file are part of systemd, and were
3 copied to util-linux at August 2013.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with util-linux; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <assert.h>
22#include <ctype.h>
23#include <string.h>
24#include <time.h>
25
26#include "c.h"
27#include "time-util.h"
28
29#define WHITESPACE " \t\n\r"
30
31#define streq(a,b) (strcmp((a),(b)) == 0)
32
2659a49e
SK
33static int parse_sec(const char *t, usec_t *usec)
34{
35 static const struct {
36 const char *suffix;
37 usec_t usec;
38 } table[] = {
39 { "seconds", USEC_PER_SEC },
40 { "second", USEC_PER_SEC },
41 { "sec", USEC_PER_SEC },
42 { "s", USEC_PER_SEC },
43 { "minutes", USEC_PER_MINUTE },
44 { "minute", USEC_PER_MINUTE },
45 { "min", USEC_PER_MINUTE },
46 { "months", USEC_PER_MONTH },
47 { "month", USEC_PER_MONTH },
48 { "msec", USEC_PER_MSEC },
49 { "ms", USEC_PER_MSEC },
50 { "m", USEC_PER_MINUTE },
51 { "hours", USEC_PER_HOUR },
52 { "hour", USEC_PER_HOUR },
53 { "hr", USEC_PER_HOUR },
54 { "h", USEC_PER_HOUR },
55 { "days", USEC_PER_DAY },
56 { "day", USEC_PER_DAY },
57 { "d", USEC_PER_DAY },
58 { "weeks", USEC_PER_WEEK },
59 { "week", USEC_PER_WEEK },
60 { "w", USEC_PER_WEEK },
61 { "years", USEC_PER_YEAR },
62 { "year", USEC_PER_YEAR },
63 { "y", USEC_PER_YEAR },
64 { "usec", 1ULL },
65 { "us", 1ULL },
66 { "", USEC_PER_SEC }, /* default is sec */
67 };
68
69 const char *p;
70 usec_t r = 0;
71 int something = FALSE;
72
73 assert(t);
74 assert(usec);
75
76 p = t;
77 for (;;) {
78 long long l, z = 0;
79 char *e;
80 unsigned i, n = 0;
81
82 p += strspn(p, WHITESPACE);
83
84 if (*p == 0) {
85 if (!something)
86 return -EINVAL;
87
88 break;
89 }
90
91 errno = 0;
92 l = strtoll(p, &e, 10);
93
94 if (errno > 0)
95 return -errno;
96
97 if (l < 0)
98 return -ERANGE;
99
100 if (*e == '.') {
101 char *b = e + 1;
102
103 errno = 0;
104 z = strtoll(b, &e, 10);
105 if (errno > 0)
106 return -errno;
107
108 if (z < 0)
109 return -ERANGE;
110
111 if (e == b)
112 return -EINVAL;
113
114 n = e - b;
115
116 } else if (e == p)
117 return -EINVAL;
118
119 e += strspn(e, WHITESPACE);
120
121 for (i = 0; i < ARRAY_SIZE(table); i++)
122 if (startswith(e, table[i].suffix)) {
123 usec_t k = (usec_t) z * table[i].usec;
124
125 for (; n > 0; n--)
126 k /= 10;
127
128 r += (usec_t) l *table[i].usec + k;
129 p = e + strlen(table[i].suffix);
130
131 something = TRUE;
132 break;
133 }
134
135 if (i >= ARRAY_SIZE(table))
136 return -EINVAL;
137
138 }
139
140 *usec = r;
141
142 return 0;
143}
144
145int parse_timestamp(const char *t, usec_t *usec)
146{
147 static const struct {
148 const char *name;
149 const int nr;
150 } day_nr[] = {
151 { "Sunday", 0 },
152 { "Sun", 0 },
153 { "Monday", 1 },
154 { "Mon", 1 },
155 { "Tuesday", 2 },
156 { "Tue", 2 },
157 { "Wednesday", 3 },
158 { "Wed", 3 },
159 { "Thursday", 4 },
160 { "Thu", 4 },
161 { "Friday", 5 },
162 { "Fri", 5 },
163 { "Saturday", 6 },
164 { "Sat", 6 },
165 };
166
167 const char *k;
168 struct tm tm, copy;
169 time_t x;
170 usec_t plus = 0, minus = 0, ret;
171 int r, weekday = -1;
172 unsigned i;
173
174 /*
175 * Allowed syntaxes:
176 *
177 * 2012-09-22 16:34:22
178 * 2012-09-22 16:34 (seconds will be set to 0)
179 * 2012-09-22 (time will be set to 00:00:00)
180 * 16:34:22 (date will be set to today)
181 * 16:34 (date will be set to today, seconds to 0)
182 * now
183 * yesterday (time is set to 00:00:00)
184 * today (time is set to 00:00:00)
185 * tomorrow (time is set to 00:00:00)
186 * +5min
187 * -5days
188 *
189 */
190
191 assert(t);
192 assert(usec);
193
194 x = time(NULL);
195 localtime_r(&x, &tm);
196 tm.tm_isdst = -1;
197
198 if (streq(t, "now"))
199 goto finish;
200
201 else if (streq(t, "today")) {
202 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
203 goto finish;
204
205 } else if (streq(t, "yesterday")) {
206 tm.tm_mday--;
207 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
208 goto finish;
209
210 } else if (streq(t, "tomorrow")) {
211 tm.tm_mday++;
212 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
213 goto finish;
214
215 } else if (t[0] == '+') {
216
217 r = parse_sec(t + 1, &plus);
218 if (r < 0)
219 return r;
220
221 goto finish;
222 } else if (t[0] == '-') {
223
224 r = parse_sec(t + 1, &minus);
225 if (r < 0)
226 return r;
227
228 goto finish;
229
230 } else if (endswith(t, " ago")) {
231 char *z;
232
233 z = strndup(t, strlen(t) - 4);
234 if (!z)
235 return -ENOMEM;
236
237 r = parse_sec(z, &minus);
238 if (r < 0)
239 return r;
240
241 goto finish;
242 }
243
244 for (i = 0; i < ARRAY_SIZE(day_nr); i++) {
245 size_t skip;
246
247 if (!startswith_no_case(t, day_nr[i].name))
248 continue;
249
250 skip = strlen(day_nr[i].name);
251 if (t[skip] != ' ')
252 continue;
253
254 weekday = day_nr[i].nr;
255 t += skip + 1;
256 break;
257 }
258
259 copy = tm;
260 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
261 if (k && *k == 0)
262 goto finish;
263
264 tm = copy;
265 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
266 if (k && *k == 0)
267 goto finish;
268
269 tm = copy;
270 k = strptime(t, "%y-%m-%d %H:%M", &tm);
271 if (k && *k == 0) {
272 tm.tm_sec = 0;
273 goto finish;
274 }
275
276 tm = copy;
277 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
278 if (k && *k == 0) {
279 tm.tm_sec = 0;
280 goto finish;
281 }
282
283 tm = copy;
284 k = strptime(t, "%y-%m-%d", &tm);
285 if (k && *k == 0) {
286 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
287 goto finish;
288 }
289
290 tm = copy;
291 k = strptime(t, "%Y-%m-%d", &tm);
292 if (k && *k == 0) {
293 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
294 goto finish;
295 }
296
297 tm = copy;
298 k = strptime(t, "%H:%M:%S", &tm);
299 if (k && *k == 0)
300 goto finish;
301
302 tm = copy;
303 k = strptime(t, "%H:%M", &tm);
304 if (k && *k == 0) {
305 tm.tm_sec = 0;
306 goto finish;
307 }
308
309 return -EINVAL;
310
311 finish:
312 x = mktime(&tm);
313 if (x == (time_t)-1)
314 return -EINVAL;
315
316 if (weekday >= 0 && tm.tm_wday != weekday)
317 return -EINVAL;
318
319 ret = (usec_t) x *USEC_PER_SEC;
320
321 ret += plus;
322 if (ret > minus)
323 ret -= minus;
324 else
325 ret = 0;
326
327 *usec = ret;
328
329 return 0;
330}