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)
254 /* The result of this function can be parsed with parse_sec */
256 for (i = 0; i < ELEMENTSOF(table); i++) {
262 if (t == 0 || t < accuracy) {
272 if (t < table[i].usec)
278 a = t / table[i].usec;
279 b = t % table[i].usec;
281 /* Let's see if we should shows this in dot notation */
282 if (t < USEC_PER_MINUTE && b > 0) {
287 for (cc = table[i].usec; cc > 1; cc /= 10)
290 for (cc = accuracy; cc > 1; cc /= 10) {
299 (unsigned long long) a,
301 (unsigned long long) b,
309 /* No? Then let's show it normally */
314 (unsigned long long) a,
320 n = MIN((size_t) k, l);
334 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
340 if (!dual_timestamp_is_set(t))
343 fprintf(f, "%s=%llu %llu\n",
345 (unsigned long long) t->realtime,
346 (unsigned long long) t->monotonic);
349 void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
350 unsigned long long a, b;
355 if (sscanf(value, "%lli %llu", &a, &b) != 2)
356 log_debug("Failed to parse finish timestamp value %s", value);
363 int parse_timestamp(const char *t, usec_t *usec) {
364 static const struct {
387 usec_t plus = 0, minus = 0, ret;
394 * 2012-09-22 16:34:22
395 * 2012-09-22 16:34 (seconds will be set to 0)
396 * 2012-09-22 (time will be set to 00:00:00)
397 * 16:34:22 (date will be set to today)
398 * 16:34 (date will be set to today, seconds to 0)
400 * yesterday (time is set to 00:00:00)
401 * today (time is set to 00:00:00)
402 * tomorrow (time is set to 00:00:00)
412 assert_se(localtime_r(&x, &tm));
418 else if (streq(t, "today")) {
419 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
422 } else if (streq(t, "yesterday")) {
424 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
427 } else if (streq(t, "tomorrow")) {
429 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
432 } else if (t[0] == '+') {
434 r = parse_sec(t+1, &plus);
439 } else if (t[0] == '-') {
441 r = parse_sec(t+1, &minus);
447 } else if (endswith(t, " ago")) {
448 _cleanup_free_ char *z;
450 z = strndup(t, strlen(t) - 4);
454 r = parse_sec(z, &minus);
461 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
464 if (!startswith_no_case(t, day_nr[i].name))
467 skip = strlen(day_nr[i].name);
471 weekday = day_nr[i].nr;
477 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
482 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
487 k = strptime(t, "%y-%m-%d %H:%M", &tm);
494 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
501 k = strptime(t, "%y-%m-%d", &tm);
503 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
508 k = strptime(t, "%Y-%m-%d", &tm);
510 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
515 k = strptime(t, "%H:%M:%S", &tm);
520 k = strptime(t, "%H:%M", &tm);
530 if (x == (time_t) -1)
533 if (weekday >= 0 && tm.tm_wday != weekday)
536 ret = (usec_t) x * USEC_PER_SEC;
549 int parse_sec(const char *t, usec_t *usec) {
550 static const struct {
554 { "seconds", USEC_PER_SEC },
555 { "second", USEC_PER_SEC },
556 { "sec", USEC_PER_SEC },
557 { "s", USEC_PER_SEC },
558 { "minutes", USEC_PER_MINUTE },
559 { "minute", USEC_PER_MINUTE },
560 { "min", USEC_PER_MINUTE },
561 { "months", USEC_PER_MONTH },
562 { "month", USEC_PER_MONTH },
563 { "msec", USEC_PER_MSEC },
564 { "ms", USEC_PER_MSEC },
565 { "m", USEC_PER_MINUTE },
566 { "hours", USEC_PER_HOUR },
567 { "hour", USEC_PER_HOUR },
568 { "hr", USEC_PER_HOUR },
569 { "h", USEC_PER_HOUR },
570 { "days", USEC_PER_DAY },
571 { "day", USEC_PER_DAY },
572 { "d", USEC_PER_DAY },
573 { "weeks", USEC_PER_WEEK },
574 { "week", USEC_PER_WEEK },
575 { "w", USEC_PER_WEEK },
576 { "years", USEC_PER_YEAR },
577 { "year", USEC_PER_YEAR },
578 { "y", USEC_PER_YEAR },
581 { "", USEC_PER_SEC }, /* default is sec */
586 bool something = false;
597 p += strspn(p, WHITESPACE);
607 l = strtoll(p, &e, 10);
619 z = strtoll(b, &e, 10);
634 e += strspn(e, WHITESPACE);
636 for (i = 0; i < ELEMENTSOF(table); i++)
637 if (startswith(e, table[i].suffix)) {
638 usec_t k = (usec_t) z * table[i].usec;
643 r += (usec_t) l * table[i].usec + k;
644 p = e + strlen(table[i].suffix);
650 if (i >= ELEMENTSOF(table))
660 int parse_nsec(const char *t, nsec_t *nsec) {
661 static const struct {
665 { "seconds", NSEC_PER_SEC },
666 { "second", NSEC_PER_SEC },
667 { "sec", NSEC_PER_SEC },
668 { "s", NSEC_PER_SEC },
669 { "minutes", NSEC_PER_MINUTE },
670 { "minute", NSEC_PER_MINUTE },
671 { "min", NSEC_PER_MINUTE },
672 { "months", NSEC_PER_MONTH },
673 { "month", NSEC_PER_MONTH },
674 { "msec", NSEC_PER_MSEC },
675 { "ms", NSEC_PER_MSEC },
676 { "m", NSEC_PER_MINUTE },
677 { "hours", NSEC_PER_HOUR },
678 { "hour", NSEC_PER_HOUR },
679 { "hr", NSEC_PER_HOUR },
680 { "h", NSEC_PER_HOUR },
681 { "days", NSEC_PER_DAY },
682 { "day", NSEC_PER_DAY },
683 { "d", NSEC_PER_DAY },
684 { "weeks", NSEC_PER_WEEK },
685 { "week", NSEC_PER_WEEK },
686 { "w", NSEC_PER_WEEK },
687 { "years", NSEC_PER_YEAR },
688 { "year", NSEC_PER_YEAR },
689 { "y", NSEC_PER_YEAR },
690 { "usec", NSEC_PER_USEC },
691 { "us", NSEC_PER_USEC },
694 { "", 1ULL }, /* default is nsec */
699 bool something = false;
710 p += strspn(p, WHITESPACE);
720 l = strtoll(p, &e, 10);
732 z = strtoll(b, &e, 10);
747 e += strspn(e, WHITESPACE);
749 for (i = 0; i < ELEMENTSOF(table); i++)
750 if (startswith(e, table[i].suffix)) {
751 nsec_t k = (nsec_t) z * table[i].nsec;
756 r += (nsec_t) l * table[i].nsec + k;
757 p = e + strlen(table[i].suffix);
763 if (i >= ELEMENTSOF(table))