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) {
49 if (u == (usec_t) -1) {
50 ts->realtime = ts->monotonic = (usec_t) -1;
59 delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
61 ts->monotonic = now(CLOCK_MONOTONIC);
63 if ((int64_t) ts->monotonic > delta)
64 ts->monotonic -= delta;
72 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
76 if (u == (usec_t) -1) {
77 ts->realtime = ts->monotonic = (usec_t) -1;
82 delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
84 ts->realtime = now(CLOCK_REALTIME);
85 if ((int64_t) ts->realtime > delta)
86 ts->realtime -= delta;
93 usec_t timespec_load(const struct timespec *ts) {
96 if (ts->tv_sec == (time_t) -1 &&
97 ts->tv_nsec == (long) -1)
100 if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
104 (usec_t) ts->tv_sec * USEC_PER_SEC +
105 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
108 struct timespec *timespec_store(struct timespec *ts, usec_t u) {
111 if (u == (usec_t) -1) {
112 ts->tv_sec = (time_t) -1;
113 ts->tv_nsec = (long) -1;
117 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
118 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
123 usec_t timeval_load(const struct timeval *tv) {
126 if (tv->tv_sec == (time_t) -1 &&
127 tv->tv_usec == (suseconds_t) -1)
130 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
134 (usec_t) tv->tv_sec * USEC_PER_SEC +
135 (usec_t) tv->tv_usec;
138 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
141 if (u == (usec_t) -1) {
142 tv->tv_sec = (time_t) -1;
143 tv->tv_usec = (suseconds_t) -1;
147 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
148 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
153 char *format_timestamp(char *buf, size_t l, usec_t t) {
163 sec = (time_t) (t / USEC_PER_SEC);
165 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) <= 0)
171 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
174 n = now(CLOCK_REALTIME);
176 if (t <= 0 || t > n || t + USEC_PER_DAY*7 <= t)
181 if (d >= USEC_PER_YEAR)
182 snprintf(buf, l, "%llu years %llu months ago",
183 (unsigned long long) (d / USEC_PER_YEAR),
184 (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH));
185 else if (d >= USEC_PER_MONTH)
186 snprintf(buf, l, "%llu months %llu days ago",
187 (unsigned long long) (d / USEC_PER_MONTH),
188 (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY));
189 else if (d >= USEC_PER_WEEK)
190 snprintf(buf, l, "%llu weeks %llu days ago",
191 (unsigned long long) (d / USEC_PER_WEEK),
192 (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY));
193 else if (d >= 2*USEC_PER_DAY)
194 snprintf(buf, l, "%llu days ago", (unsigned long long) (d / USEC_PER_DAY));
195 else if (d >= 25*USEC_PER_HOUR)
196 snprintf(buf, l, "1 day %lluh ago",
197 (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR));
198 else if (d >= 6*USEC_PER_HOUR)
199 snprintf(buf, l, "%lluh ago",
200 (unsigned long long) (d / USEC_PER_HOUR));
201 else if (d >= USEC_PER_HOUR)
202 snprintf(buf, l, "%lluh %llumin ago",
203 (unsigned long long) (d / USEC_PER_HOUR),
204 (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE));
205 else if (d >= 5*USEC_PER_MINUTE)
206 snprintf(buf, l, "%llumin ago",
207 (unsigned long long) (d / USEC_PER_MINUTE));
208 else if (d >= USEC_PER_MINUTE)
209 snprintf(buf, l, "%llumin %llus ago",
210 (unsigned long long) (d / USEC_PER_MINUTE),
211 (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC));
212 else if (d >= USEC_PER_SEC)
213 snprintf(buf, l, "%llus ago",
214 (unsigned long long) (d / USEC_PER_SEC));
215 else if (d >= USEC_PER_MSEC)
216 snprintf(buf, l, "%llums ago",
217 (unsigned long long) (d / USEC_PER_MSEC));
219 snprintf(buf, l, "%lluus ago",
220 (unsigned long long) d);
222 snprintf(buf, l, "now");
228 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
229 static const struct {
233 { "y", USEC_PER_YEAR },
234 { "month", USEC_PER_MONTH },
235 { "w", USEC_PER_WEEK },
236 { "d", USEC_PER_DAY },
237 { "h", USEC_PER_HOUR },
238 { "min", USEC_PER_MINUTE },
239 { "s", USEC_PER_SEC },
240 { "ms", USEC_PER_MSEC },
246 bool something = false;
251 if (t == (usec_t) -1)
260 /* The result of this function can be parsed with parse_sec */
262 for (i = 0; i < ELEMENTSOF(table); i++) {
271 if (t < accuracy && something)
274 if (t < table[i].usec)
280 a = t / table[i].usec;
281 b = t % table[i].usec;
283 /* Let's see if we should shows this in dot notation */
284 if (t < USEC_PER_MINUTE && b > 0) {
289 for (cc = table[i].usec; cc > 1; cc /= 10)
292 for (cc = accuracy; cc > 1; cc /= 10) {
301 (unsigned long long) a,
303 (unsigned long long) b,
311 /* No? Then let's show it normally */
316 (unsigned long long) a,
322 n = MIN((size_t) k, l);
335 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
341 if (!dual_timestamp_is_set(t))
344 fprintf(f, "%s=%llu %llu\n",
346 (unsigned long long) t->realtime,
347 (unsigned long long) t->monotonic);
350 void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
351 unsigned long long a, b;
356 if (sscanf(value, "%lli %llu", &a, &b) != 2)
357 log_debug("Failed to parse finish timestamp value %s", value);
364 int parse_timestamp(const char *t, usec_t *usec) {
365 static const struct {
388 usec_t plus = 0, minus = 0, ret;
395 * 2012-09-22 16:34:22
396 * 2012-09-22 16:34 (seconds will be set to 0)
397 * 2012-09-22 (time will be set to 00:00:00)
398 * 16:34:22 (date will be set to today)
399 * 16:34 (date will be set to today, seconds to 0)
401 * yesterday (time is set to 00:00:00)
402 * today (time is set to 00:00:00)
403 * tomorrow (time is set to 00:00:00)
413 assert_se(localtime_r(&x, &tm));
419 else if (streq(t, "today")) {
420 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
423 } else if (streq(t, "yesterday")) {
425 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
428 } else if (streq(t, "tomorrow")) {
430 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
433 } else if (t[0] == '+') {
435 r = parse_sec(t+1, &plus);
440 } else if (t[0] == '-') {
442 r = parse_sec(t+1, &minus);
448 } else if (endswith(t, " ago")) {
449 _cleanup_free_ char *z;
451 z = strndup(t, strlen(t) - 4);
455 r = parse_sec(z, &minus);
462 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
465 if (!startswith_no_case(t, day_nr[i].name))
468 skip = strlen(day_nr[i].name);
472 weekday = day_nr[i].nr;
478 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
483 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
488 k = strptime(t, "%y-%m-%d %H:%M", &tm);
495 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
502 k = strptime(t, "%y-%m-%d", &tm);
504 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
509 k = strptime(t, "%Y-%m-%d", &tm);
511 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
516 k = strptime(t, "%H:%M:%S", &tm);
521 k = strptime(t, "%H:%M", &tm);
531 if (x == (time_t) -1)
534 if (weekday >= 0 && tm.tm_wday != weekday)
537 ret = (usec_t) x * USEC_PER_SEC;
550 int parse_sec(const char *t, usec_t *usec) {
551 static const struct {
555 { "seconds", USEC_PER_SEC },
556 { "second", USEC_PER_SEC },
557 { "sec", USEC_PER_SEC },
558 { "s", USEC_PER_SEC },
559 { "minutes", USEC_PER_MINUTE },
560 { "minute", USEC_PER_MINUTE },
561 { "min", USEC_PER_MINUTE },
562 { "months", USEC_PER_MONTH },
563 { "month", USEC_PER_MONTH },
564 { "msec", USEC_PER_MSEC },
565 { "ms", USEC_PER_MSEC },
566 { "m", USEC_PER_MINUTE },
567 { "hours", USEC_PER_HOUR },
568 { "hour", USEC_PER_HOUR },
569 { "hr", USEC_PER_HOUR },
570 { "h", USEC_PER_HOUR },
571 { "days", USEC_PER_DAY },
572 { "day", USEC_PER_DAY },
573 { "d", USEC_PER_DAY },
574 { "weeks", USEC_PER_WEEK },
575 { "week", USEC_PER_WEEK },
576 { "w", USEC_PER_WEEK },
577 { "years", USEC_PER_YEAR },
578 { "year", USEC_PER_YEAR },
579 { "y", USEC_PER_YEAR },
582 { "", USEC_PER_SEC }, /* default is sec */
587 bool something = false;
598 p += strspn(p, WHITESPACE);
608 l = strtoll(p, &e, 10);
620 z = strtoll(b, &e, 10);
635 e += strspn(e, WHITESPACE);
637 for (i = 0; i < ELEMENTSOF(table); i++)
638 if (startswith(e, table[i].suffix)) {
639 usec_t k = (usec_t) z * table[i].usec;
644 r += (usec_t) l * table[i].usec + k;
645 p = e + strlen(table[i].suffix);
651 if (i >= ELEMENTSOF(table))
661 int parse_nsec(const char *t, nsec_t *nsec) {
662 static const struct {
666 { "seconds", NSEC_PER_SEC },
667 { "second", NSEC_PER_SEC },
668 { "sec", NSEC_PER_SEC },
669 { "s", NSEC_PER_SEC },
670 { "minutes", NSEC_PER_MINUTE },
671 { "minute", NSEC_PER_MINUTE },
672 { "min", NSEC_PER_MINUTE },
673 { "months", NSEC_PER_MONTH },
674 { "month", NSEC_PER_MONTH },
675 { "msec", NSEC_PER_MSEC },
676 { "ms", NSEC_PER_MSEC },
677 { "m", NSEC_PER_MINUTE },
678 { "hours", NSEC_PER_HOUR },
679 { "hour", NSEC_PER_HOUR },
680 { "hr", NSEC_PER_HOUR },
681 { "h", NSEC_PER_HOUR },
682 { "days", NSEC_PER_DAY },
683 { "day", NSEC_PER_DAY },
684 { "d", NSEC_PER_DAY },
685 { "weeks", NSEC_PER_WEEK },
686 { "week", NSEC_PER_WEEK },
687 { "w", NSEC_PER_WEEK },
688 { "years", NSEC_PER_YEAR },
689 { "year", NSEC_PER_YEAR },
690 { "y", NSEC_PER_YEAR },
691 { "usec", NSEC_PER_USEC },
692 { "us", NSEC_PER_USEC },
695 { "", 1ULL }, /* default is nsec */
700 bool something = false;
711 p += strspn(p, WHITESPACE);
721 l = strtoll(p, &e, 10);
733 z = strtoll(b, &e, 10);
748 e += strspn(e, WHITESPACE);
750 for (i = 0; i < ELEMENTSOF(table); i++)
751 if (startswith(e, table[i].suffix)) {
752 nsec_t k = (nsec_t) z * table[i].nsec;
757 r += (nsec_t) l * table[i].nsec + k;
758 p = e + strlen(table[i].suffix);
764 if (i >= ELEMENTSOF(table))