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/>.
24 #include <sys/timex.h>
27 #include "time-util.h"
29 usec_t now(clockid_t clock_id) {
32 assert_se(clock_gettime(clock_id, &ts) == 0);
34 return timespec_load(&ts);
37 dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
40 ts->realtime = now(CLOCK_REALTIME);
41 ts->monotonic = now(CLOCK_MONOTONIC);
46 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
50 if (u == (usec_t) -1) {
51 ts->realtime = ts->monotonic = (usec_t) -1;
60 delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
62 ts->monotonic = now(CLOCK_MONOTONIC);
64 if ((int64_t) ts->monotonic > delta)
65 ts->monotonic -= delta;
73 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
77 if (u == (usec_t) -1) {
78 ts->realtime = ts->monotonic = (usec_t) -1;
83 delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
85 ts->realtime = now(CLOCK_REALTIME);
86 if ((int64_t) ts->realtime > delta)
87 ts->realtime -= delta;
94 usec_t timespec_load(const struct timespec *ts) {
97 if (ts->tv_sec == (time_t) -1 &&
98 ts->tv_nsec == (long) -1)
101 if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
105 (usec_t) ts->tv_sec * USEC_PER_SEC +
106 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
109 struct timespec *timespec_store(struct timespec *ts, usec_t u) {
112 if (u == (usec_t) -1) {
113 ts->tv_sec = (time_t) -1;
114 ts->tv_nsec = (long) -1;
118 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
119 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
124 usec_t timeval_load(const struct timeval *tv) {
127 if (tv->tv_sec == (time_t) -1 &&
128 tv->tv_usec == (suseconds_t) -1)
131 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
135 (usec_t) tv->tv_sec * USEC_PER_SEC +
136 (usec_t) tv->tv_usec;
139 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
142 if (u == (usec_t) -1) {
143 tv->tv_sec = (time_t) -1;
144 tv->tv_usec = (suseconds_t) -1;
148 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
149 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
154 char *format_timestamp(char *buf, size_t l, usec_t t) {
161 if (t <= 0 || t == (usec_t) -1)
164 sec = (time_t) (t / USEC_PER_SEC);
166 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) <= 0)
172 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
179 if (t <= 0 || t == (usec_t) -1)
182 sec = (time_t) (t / USEC_PER_SEC);
183 localtime_r(&sec, &tm);
185 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
187 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", t % USEC_PER_SEC);
188 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
194 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
198 n = now(CLOCK_REALTIME);
200 if (t <= 0 || (t == (usec_t) -1))
211 if (d >= USEC_PER_YEAR)
212 snprintf(buf, l, "%llu years %llu months %s",
213 (unsigned long long) (d / USEC_PER_YEAR),
214 (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH), s);
215 else if (d >= USEC_PER_MONTH)
216 snprintf(buf, l, "%llu months %llu days %s",
217 (unsigned long long) (d / USEC_PER_MONTH),
218 (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY), s);
219 else if (d >= USEC_PER_WEEK)
220 snprintf(buf, l, "%llu weeks %llu days %s",
221 (unsigned long long) (d / USEC_PER_WEEK),
222 (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY), s);
223 else if (d >= 2*USEC_PER_DAY)
224 snprintf(buf, l, "%llu days %s", (unsigned long long) (d / USEC_PER_DAY), s);
225 else if (d >= 25*USEC_PER_HOUR)
226 snprintf(buf, l, "1 day %lluh %s",
227 (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR), s);
228 else if (d >= 6*USEC_PER_HOUR)
229 snprintf(buf, l, "%lluh %s",
230 (unsigned long long) (d / USEC_PER_HOUR), s);
231 else if (d >= USEC_PER_HOUR)
232 snprintf(buf, l, "%lluh %llumin %s",
233 (unsigned long long) (d / USEC_PER_HOUR),
234 (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE), s);
235 else if (d >= 5*USEC_PER_MINUTE)
236 snprintf(buf, l, "%llumin %s",
237 (unsigned long long) (d / USEC_PER_MINUTE), s);
238 else if (d >= USEC_PER_MINUTE)
239 snprintf(buf, l, "%llumin %llus %s",
240 (unsigned long long) (d / USEC_PER_MINUTE),
241 (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC), s);
242 else if (d >= USEC_PER_SEC)
243 snprintf(buf, l, "%llus %s",
244 (unsigned long long) (d / USEC_PER_SEC), s);
245 else if (d >= USEC_PER_MSEC)
246 snprintf(buf, l, "%llums %s",
247 (unsigned long long) (d / USEC_PER_MSEC), s);
249 snprintf(buf, l, "%lluus %s",
250 (unsigned long long) d, s);
252 snprintf(buf, l, "now");
258 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
259 static const struct {
263 { "y", USEC_PER_YEAR },
264 { "month", USEC_PER_MONTH },
265 { "w", USEC_PER_WEEK },
266 { "d", USEC_PER_DAY },
267 { "h", USEC_PER_HOUR },
268 { "min", USEC_PER_MINUTE },
269 { "s", USEC_PER_SEC },
270 { "ms", USEC_PER_MSEC },
276 bool something = false;
281 if (t == (usec_t) -1)
290 /* The result of this function can be parsed with parse_sec */
292 for (i = 0; i < ELEMENTSOF(table); i++) {
301 if (t < accuracy && something)
304 if (t < table[i].usec)
310 a = t / table[i].usec;
311 b = t % table[i].usec;
313 /* Let's see if we should shows this in dot notation */
314 if (t < USEC_PER_MINUTE && b > 0) {
319 for (cc = table[i].usec; cc > 1; cc /= 10)
322 for (cc = accuracy; cc > 1; cc /= 10) {
331 (unsigned long long) a,
333 (unsigned long long) b,
341 /* No? Then let's show it normally */
346 (unsigned long long) a,
352 n = MIN((size_t) k, l);
365 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
371 if (!dual_timestamp_is_set(t))
374 fprintf(f, "%s=%llu %llu\n",
376 (unsigned long long) t->realtime,
377 (unsigned long long) t->monotonic);
380 void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
381 unsigned long long a, b;
386 if (sscanf(value, "%lli %llu", &a, &b) != 2)
387 log_debug("Failed to parse finish timestamp value %s", value);
394 int parse_timestamp(const char *t, usec_t *usec) {
395 static const struct {
418 usec_t plus = 0, minus = 0, ret;
425 * 2012-09-22 16:34:22
426 * 2012-09-22 16:34 (seconds will be set to 0)
427 * 2012-09-22 (time will be set to 00:00:00)
428 * 16:34:22 (date will be set to today)
429 * 16:34 (date will be set to today, seconds to 0)
431 * yesterday (time is set to 00:00:00)
432 * today (time is set to 00:00:00)
433 * tomorrow (time is set to 00:00:00)
443 assert_se(localtime_r(&x, &tm));
449 else if (streq(t, "today")) {
450 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
453 } else if (streq(t, "yesterday")) {
455 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
458 } else if (streq(t, "tomorrow")) {
460 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
463 } else if (t[0] == '+') {
465 r = parse_sec(t+1, &plus);
470 } else if (t[0] == '-') {
472 r = parse_sec(t+1, &minus);
478 } else if (endswith(t, " ago")) {
479 _cleanup_free_ char *z;
481 z = strndup(t, strlen(t) - 4);
485 r = parse_sec(z, &minus);
490 } else if (endswith(t, " left")) {
491 _cleanup_free_ char *z;
493 z = strndup(t, strlen(t) - 4);
497 r = parse_sec(z, &plus);
504 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
507 if (!startswith_no_case(t, day_nr[i].name))
510 skip = strlen(day_nr[i].name);
514 weekday = day_nr[i].nr;
520 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
525 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
530 k = strptime(t, "%y-%m-%d %H:%M", &tm);
537 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
544 k = strptime(t, "%y-%m-%d", &tm);
546 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
551 k = strptime(t, "%Y-%m-%d", &tm);
553 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
558 k = strptime(t, "%H:%M:%S", &tm);
563 k = strptime(t, "%H:%M", &tm);
573 if (x == (time_t) -1)
576 if (weekday >= 0 && tm.tm_wday != weekday)
579 ret = (usec_t) x * USEC_PER_SEC;
592 int parse_sec(const char *t, usec_t *usec) {
593 static const struct {
597 { "seconds", USEC_PER_SEC },
598 { "second", USEC_PER_SEC },
599 { "sec", USEC_PER_SEC },
600 { "s", USEC_PER_SEC },
601 { "minutes", USEC_PER_MINUTE },
602 { "minute", USEC_PER_MINUTE },
603 { "min", USEC_PER_MINUTE },
604 { "months", USEC_PER_MONTH },
605 { "month", USEC_PER_MONTH },
606 { "msec", USEC_PER_MSEC },
607 { "ms", USEC_PER_MSEC },
608 { "m", USEC_PER_MINUTE },
609 { "hours", USEC_PER_HOUR },
610 { "hour", USEC_PER_HOUR },
611 { "hr", USEC_PER_HOUR },
612 { "h", USEC_PER_HOUR },
613 { "days", USEC_PER_DAY },
614 { "day", USEC_PER_DAY },
615 { "d", USEC_PER_DAY },
616 { "weeks", USEC_PER_WEEK },
617 { "week", USEC_PER_WEEK },
618 { "w", USEC_PER_WEEK },
619 { "years", USEC_PER_YEAR },
620 { "year", USEC_PER_YEAR },
621 { "y", USEC_PER_YEAR },
624 { "", USEC_PER_SEC }, /* default is sec */
629 bool something = false;
640 p += strspn(p, WHITESPACE);
650 l = strtoll(p, &e, 10);
662 z = strtoll(b, &e, 10);
677 e += strspn(e, WHITESPACE);
679 for (i = 0; i < ELEMENTSOF(table); i++)
680 if (startswith(e, table[i].suffix)) {
681 usec_t k = (usec_t) z * table[i].usec;
686 r += (usec_t) l * table[i].usec + k;
687 p = e + strlen(table[i].suffix);
693 if (i >= ELEMENTSOF(table))
703 int parse_nsec(const char *t, nsec_t *nsec) {
704 static const struct {
708 { "seconds", NSEC_PER_SEC },
709 { "second", NSEC_PER_SEC },
710 { "sec", NSEC_PER_SEC },
711 { "s", NSEC_PER_SEC },
712 { "minutes", NSEC_PER_MINUTE },
713 { "minute", NSEC_PER_MINUTE },
714 { "min", NSEC_PER_MINUTE },
715 { "months", NSEC_PER_MONTH },
716 { "month", NSEC_PER_MONTH },
717 { "msec", NSEC_PER_MSEC },
718 { "ms", NSEC_PER_MSEC },
719 { "m", NSEC_PER_MINUTE },
720 { "hours", NSEC_PER_HOUR },
721 { "hour", NSEC_PER_HOUR },
722 { "hr", NSEC_PER_HOUR },
723 { "h", NSEC_PER_HOUR },
724 { "days", NSEC_PER_DAY },
725 { "day", NSEC_PER_DAY },
726 { "d", NSEC_PER_DAY },
727 { "weeks", NSEC_PER_WEEK },
728 { "week", NSEC_PER_WEEK },
729 { "w", NSEC_PER_WEEK },
730 { "years", NSEC_PER_YEAR },
731 { "year", NSEC_PER_YEAR },
732 { "y", NSEC_PER_YEAR },
733 { "usec", NSEC_PER_USEC },
734 { "us", NSEC_PER_USEC },
737 { "", 1ULL }, /* default is nsec */
742 bool something = false;
753 p += strspn(p, WHITESPACE);
763 l = strtoll(p, &e, 10);
775 z = strtoll(b, &e, 10);
790 e += strspn(e, WHITESPACE);
792 for (i = 0; i < ELEMENTSOF(table); i++)
793 if (startswith(e, table[i].suffix)) {
794 nsec_t k = (nsec_t) z * table[i].nsec;
799 r += (nsec_t) l * table[i].nsec + k;
800 p = e + strlen(table[i].suffix);
806 if (i >= ELEMENTSOF(table))
816 bool ntp_synced(void) {
817 struct timex txc = {};
819 if (adjtimex(&txc) < 0)
822 if (txc.status & STA_UNSYNC)