1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "time-util.h"
28 usec_t now(clockid_t clock_id) {
31 assert_se(clock_gettime(clock_id, &ts) == 0);
33 return timespec_load(&ts);
36 dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
39 ts->realtime = now(CLOCK_REALTIME);
40 ts->monotonic = now(CLOCK_MONOTONIC);
45 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
54 delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
56 ts->monotonic = now(CLOCK_MONOTONIC);
58 if ((int64_t) ts->monotonic > delta)
59 ts->monotonic -= delta;
67 usec_t timespec_load(const struct timespec *ts) {
70 if (ts->tv_sec == (time_t) -1 &&
71 ts->tv_nsec == (long) -1)
74 if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
78 (usec_t) ts->tv_sec * USEC_PER_SEC +
79 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
82 struct timespec *timespec_store(struct timespec *ts, usec_t u) {
85 if (u == (usec_t) -1) {
86 ts->tv_sec = (time_t) -1;
87 ts->tv_nsec = (long) -1;
91 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
92 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
97 usec_t timeval_load(const struct timeval *tv) {
100 if (tv->tv_sec == (time_t) -1 &&
101 tv->tv_usec == (suseconds_t) -1)
104 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
108 (usec_t) tv->tv_sec * USEC_PER_SEC +
109 (usec_t) tv->tv_usec;
112 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
115 if (u == (usec_t) -1) {
116 tv->tv_sec = (time_t) -1;
117 tv->tv_usec = (suseconds_t) -1;
121 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
122 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
127 char *format_timestamp(char *buf, size_t l, usec_t t) {
137 sec = (time_t) (t / USEC_PER_SEC);
139 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) <= 0)
145 char *format_timestamp_pretty(char *buf, size_t l, usec_t t) {
148 n = now(CLOCK_REALTIME);
150 if (t <= 0 || t > n || t + USEC_PER_DAY*7 <= t)
155 if (d >= USEC_PER_YEAR)
156 snprintf(buf, l, "%llu years %llu months ago",
157 (unsigned long long) (d / USEC_PER_YEAR),
158 (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH));
159 else if (d >= USEC_PER_MONTH)
160 snprintf(buf, l, "%llu months %llu days ago",
161 (unsigned long long) (d / USEC_PER_MONTH),
162 (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY));
163 else if (d >= USEC_PER_WEEK)
164 snprintf(buf, l, "%llu weeks %llu days ago",
165 (unsigned long long) (d / USEC_PER_WEEK),
166 (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY));
167 else if (d >= 2*USEC_PER_DAY)
168 snprintf(buf, l, "%llu days ago", (unsigned long long) (d / USEC_PER_DAY));
169 else if (d >= 25*USEC_PER_HOUR)
170 snprintf(buf, l, "1 day %lluh ago",
171 (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR));
172 else if (d >= 6*USEC_PER_HOUR)
173 snprintf(buf, l, "%lluh ago",
174 (unsigned long long) (d / USEC_PER_HOUR));
175 else if (d >= USEC_PER_HOUR)
176 snprintf(buf, l, "%lluh %llumin ago",
177 (unsigned long long) (d / USEC_PER_HOUR),
178 (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE));
179 else if (d >= 5*USEC_PER_MINUTE)
180 snprintf(buf, l, "%llumin ago",
181 (unsigned long long) (d / USEC_PER_MINUTE));
182 else if (d >= USEC_PER_MINUTE)
183 snprintf(buf, l, "%llumin %llus ago",
184 (unsigned long long) (d / USEC_PER_MINUTE),
185 (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC));
186 else if (d >= USEC_PER_SEC)
187 snprintf(buf, l, "%llus ago",
188 (unsigned long long) (d / USEC_PER_SEC));
189 else if (d >= USEC_PER_MSEC)
190 snprintf(buf, l, "%llums ago",
191 (unsigned long long) (d / USEC_PER_MSEC));
193 snprintf(buf, l, "%lluus ago",
194 (unsigned long long) d);
196 snprintf(buf, l, "now");
202 char *format_timespan(char *buf, size_t l, usec_t t) {
203 static const struct {
207 { "w", USEC_PER_WEEK },
208 { "d", USEC_PER_DAY },
209 { "h", USEC_PER_HOUR },
210 { "min", USEC_PER_MINUTE },
211 { "s", USEC_PER_SEC },
212 { "ms", USEC_PER_MSEC },
222 if (t == (usec_t) -1)
231 /* The result of this function can be parsed with parse_usec */
233 for (i = 0; i < ELEMENTSOF(table); i++) {
237 if (t < table[i].usec)
243 k = snprintf(p, l, "%s%llu%s", p > buf ? " " : "", (unsigned long long) (t / table[i].usec), table[i].suffix);
244 n = MIN((size_t) k, l);
257 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
263 if (!dual_timestamp_is_set(t))
266 fprintf(f, "%s=%llu %llu\n",
268 (unsigned long long) t->realtime,
269 (unsigned long long) t->monotonic);
272 void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
273 unsigned long long a, b;
278 if (sscanf(value, "%lli %llu", &a, &b) != 2)
279 log_debug("Failed to parse finish timestamp value %s", value);
286 int parse_timestamp(const char *t, usec_t *usec) {
290 usec_t plus = 0, minus = 0, ret;
296 * 2012-09-22 16:34:22
297 * 2012-09-22 16:34 (seconds will be set to 0)
298 * 2012-09-22 (time will be set to 00:00:00)
299 * 16:34:22 (date will be set to today)
300 * 16:34 (date will be set to today, seconds to 0)
302 * yesterday (time is set to 00:00:00)
303 * today (time is set to 00:00:00)
304 * tomorrow (time is set to 00:00:00)
314 assert_se(localtime_r(&x, &tm));
319 else if (streq(t, "today")) {
320 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
323 } else if (streq(t, "yesterday")) {
325 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
328 } else if (streq(t, "tomorrow")) {
330 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
333 } else if (t[0] == '+') {
335 r = parse_usec(t+1, &plus);
340 } else if (t[0] == '-') {
342 r = parse_usec(t+1, &minus);
350 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
355 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
360 k = strptime(t, "%y-%m-%d %H:%M", &tm);
367 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
374 k = strptime(t, "%y-%m-%d", &tm);
376 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
381 k = strptime(t, "%Y-%m-%d", &tm);
383 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
388 k = strptime(t, "%H:%M:%S", &tm);
393 k = strptime(t, "%H:%M", &tm);
403 if (x == (time_t) -1)
406 ret = (usec_t) x * USEC_PER_SEC;
419 int parse_usec(const char *t, usec_t *usec) {
420 static const struct {
424 { "seconds", USEC_PER_SEC },
425 { "second", USEC_PER_SEC },
426 { "sec", USEC_PER_SEC },
427 { "s", USEC_PER_SEC },
428 { "minutes", USEC_PER_MINUTE },
429 { "minute", USEC_PER_MINUTE },
430 { "min", USEC_PER_MINUTE },
431 { "months", USEC_PER_MONTH },
432 { "month", USEC_PER_MONTH },
433 { "msec", USEC_PER_MSEC },
434 { "ms", USEC_PER_MSEC },
435 { "m", USEC_PER_MINUTE },
436 { "hours", USEC_PER_HOUR },
437 { "hour", USEC_PER_HOUR },
438 { "hr", USEC_PER_HOUR },
439 { "h", USEC_PER_HOUR },
440 { "days", USEC_PER_DAY },
441 { "day", USEC_PER_DAY },
442 { "d", USEC_PER_DAY },
443 { "weeks", USEC_PER_WEEK },
444 { "week", USEC_PER_WEEK },
445 { "w", USEC_PER_WEEK },
446 { "years", USEC_PER_YEAR },
447 { "year", USEC_PER_YEAR },
448 { "y", USEC_PER_YEAR },
451 { "", USEC_PER_SEC }, /* default is sec */
467 l = strtoll(p, &e, 10);
478 e += strspn(e, WHITESPACE);
480 for (i = 0; i < ELEMENTSOF(table); i++)
481 if (startswith(e, table[i].suffix)) {
482 r += (usec_t) l * table[i].usec;
483 p = e + strlen(table[i].suffix);
487 if (i >= ELEMENTSOF(table))
497 int parse_nsec(const char *t, nsec_t *nsec) {
498 static const struct {
502 { "seconds", NSEC_PER_SEC },
503 { "second", NSEC_PER_SEC },
504 { "sec", NSEC_PER_SEC },
505 { "s", NSEC_PER_SEC },
506 { "minutes", NSEC_PER_MINUTE },
507 { "minute", NSEC_PER_MINUTE },
508 { "min", NSEC_PER_MINUTE },
509 { "months", NSEC_PER_MONTH },
510 { "month", NSEC_PER_MONTH },
511 { "msec", NSEC_PER_MSEC },
512 { "ms", NSEC_PER_MSEC },
513 { "m", NSEC_PER_MINUTE },
514 { "hours", NSEC_PER_HOUR },
515 { "hour", NSEC_PER_HOUR },
516 { "hr", NSEC_PER_HOUR },
517 { "h", NSEC_PER_HOUR },
518 { "days", NSEC_PER_DAY },
519 { "day", NSEC_PER_DAY },
520 { "d", NSEC_PER_DAY },
521 { "weeks", NSEC_PER_WEEK },
522 { "week", NSEC_PER_WEEK },
523 { "w", NSEC_PER_WEEK },
524 { "years", NSEC_PER_YEAR },
525 { "year", NSEC_PER_YEAR },
526 { "y", NSEC_PER_YEAR },
527 { "usec", NSEC_PER_USEC },
528 { "us", NSEC_PER_USEC },
531 { "", 1ULL }, /* default is nsec */
547 l = strtoll(p, &e, 10);
558 e += strspn(e, WHITESPACE);
560 for (i = 0; i < ELEMENTSOF(table); i++)
561 if (startswith(e, table[i].suffix)) {
562 r += (nsec_t) l * table[i].nsec;
563 p = e + strlen(table[i].suffix);
567 if (i >= ELEMENTSOF(table))