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;
146 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
147 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
153 char *format_timestamp(char *buf, size_t l, usec_t t) {
160 if (t <= 0 || t == (usec_t) -1)
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_us(char *buf, size_t l, usec_t t) {
178 if (t <= 0 || t == (usec_t) -1)
181 sec = (time_t) (t / USEC_PER_SEC);
182 localtime_r(&sec, &tm);
184 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
186 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", t % USEC_PER_SEC);
187 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
193 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
197 n = now(CLOCK_REALTIME);
199 if (t <= 0 || (t == (usec_t) -1))
210 if (d >= USEC_PER_YEAR)
211 snprintf(buf, l, "%llu years %llu months %s",
212 (unsigned long long) (d / USEC_PER_YEAR),
213 (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH), s);
214 else if (d >= USEC_PER_MONTH)
215 snprintf(buf, l, "%llu months %llu days %s",
216 (unsigned long long) (d / USEC_PER_MONTH),
217 (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY), s);
218 else if (d >= USEC_PER_WEEK)
219 snprintf(buf, l, "%llu weeks %llu days %s",
220 (unsigned long long) (d / USEC_PER_WEEK),
221 (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY), s);
222 else if (d >= 2*USEC_PER_DAY)
223 snprintf(buf, l, "%llu days %s", (unsigned long long) (d / USEC_PER_DAY), s);
224 else if (d >= 25*USEC_PER_HOUR)
225 snprintf(buf, l, "1 day %lluh %s",
226 (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR), s);
227 else if (d >= 6*USEC_PER_HOUR)
228 snprintf(buf, l, "%lluh %s",
229 (unsigned long long) (d / USEC_PER_HOUR), s);
230 else if (d >= USEC_PER_HOUR)
231 snprintf(buf, l, "%lluh %llumin %s",
232 (unsigned long long) (d / USEC_PER_HOUR),
233 (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE), s);
234 else if (d >= 5*USEC_PER_MINUTE)
235 snprintf(buf, l, "%llumin %s",
236 (unsigned long long) (d / USEC_PER_MINUTE), s);
237 else if (d >= USEC_PER_MINUTE)
238 snprintf(buf, l, "%llumin %llus %s",
239 (unsigned long long) (d / USEC_PER_MINUTE),
240 (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC), s);
241 else if (d >= USEC_PER_SEC)
242 snprintf(buf, l, "%llus %s",
243 (unsigned long long) (d / USEC_PER_SEC), s);
244 else if (d >= USEC_PER_MSEC)
245 snprintf(buf, l, "%llums %s",
246 (unsigned long long) (d / USEC_PER_MSEC), s);
248 snprintf(buf, l, "%lluus %s",
249 (unsigned long long) d, s);
251 snprintf(buf, l, "now");
257 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
258 static const struct {
262 { "y", USEC_PER_YEAR },
263 { "month", USEC_PER_MONTH },
264 { "w", USEC_PER_WEEK },
265 { "d", USEC_PER_DAY },
266 { "h", USEC_PER_HOUR },
267 { "min", USEC_PER_MINUTE },
268 { "s", USEC_PER_SEC },
269 { "ms", USEC_PER_MSEC },
275 bool something = false;
280 if (t == (usec_t) -1)
289 /* The result of this function can be parsed with parse_sec */
291 for (i = 0; i < ELEMENTSOF(table); i++) {
300 if (t < accuracy && something)
303 if (t < table[i].usec)
309 a = t / table[i].usec;
310 b = t % table[i].usec;
312 /* Let's see if we should shows this in dot notation */
313 if (t < USEC_PER_MINUTE && b > 0) {
318 for (cc = table[i].usec; cc > 1; cc /= 10)
321 for (cc = accuracy; cc > 1; cc /= 10) {
330 (unsigned long long) a,
332 (unsigned long long) b,
340 /* No? Then let's show it normally */
345 (unsigned long long) a,
351 n = MIN((size_t) k, l);
364 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
370 if (!dual_timestamp_is_set(t))
373 fprintf(f, "%s=%llu %llu\n",
375 (unsigned long long) t->realtime,
376 (unsigned long long) t->monotonic);
379 void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
380 unsigned long long a, b;
385 if (sscanf(value, "%llu %llu", &a, &b) != 2)
386 log_debug("Failed to parse finish timestamp value %s", value);
393 int parse_timestamp(const char *t, usec_t *usec) {
394 static const struct {
417 usec_t plus = 0, minus = 0, ret;
424 * 2012-09-22 16:34:22
425 * 2012-09-22 16:34 (seconds will be set to 0)
426 * 2012-09-22 (time will be set to 00:00:00)
427 * 16:34:22 (date will be set to today)
428 * 16:34 (date will be set to today, seconds to 0)
430 * yesterday (time is set to 00:00:00)
431 * today (time is set to 00:00:00)
432 * tomorrow (time is set to 00:00:00)
442 assert_se(localtime_r(&x, &tm));
448 else if (streq(t, "today")) {
449 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
452 } else if (streq(t, "yesterday")) {
454 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
457 } else if (streq(t, "tomorrow")) {
459 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
462 } else if (t[0] == '+') {
464 r = parse_sec(t+1, &plus);
469 } else if (t[0] == '-') {
471 r = parse_sec(t+1, &minus);
477 } else if (endswith(t, " ago")) {
478 _cleanup_free_ char *z;
480 z = strndup(t, strlen(t) - 4);
484 r = parse_sec(z, &minus);
489 } else if (endswith(t, " left")) {
490 _cleanup_free_ char *z;
492 z = strndup(t, strlen(t) - 4);
496 r = parse_sec(z, &plus);
503 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
506 if (!startswith_no_case(t, day_nr[i].name))
509 skip = strlen(day_nr[i].name);
513 weekday = day_nr[i].nr;
519 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
524 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
529 k = strptime(t, "%y-%m-%d %H:%M", &tm);
536 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
543 k = strptime(t, "%y-%m-%d", &tm);
545 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
550 k = strptime(t, "%Y-%m-%d", &tm);
552 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
557 k = strptime(t, "%H:%M:%S", &tm);
562 k = strptime(t, "%H:%M", &tm);
572 if (x == (time_t) -1)
575 if (weekday >= 0 && tm.tm_wday != weekday)
578 ret = (usec_t) x * USEC_PER_SEC;
591 int parse_sec(const char *t, usec_t *usec) {
592 static const struct {
596 { "seconds", USEC_PER_SEC },
597 { "second", USEC_PER_SEC },
598 { "sec", USEC_PER_SEC },
599 { "s", USEC_PER_SEC },
600 { "minutes", USEC_PER_MINUTE },
601 { "minute", USEC_PER_MINUTE },
602 { "min", USEC_PER_MINUTE },
603 { "months", USEC_PER_MONTH },
604 { "month", USEC_PER_MONTH },
605 { "msec", USEC_PER_MSEC },
606 { "ms", USEC_PER_MSEC },
607 { "m", USEC_PER_MINUTE },
608 { "hours", USEC_PER_HOUR },
609 { "hour", USEC_PER_HOUR },
610 { "hr", USEC_PER_HOUR },
611 { "h", USEC_PER_HOUR },
612 { "days", USEC_PER_DAY },
613 { "day", USEC_PER_DAY },
614 { "d", USEC_PER_DAY },
615 { "weeks", USEC_PER_WEEK },
616 { "week", USEC_PER_WEEK },
617 { "w", USEC_PER_WEEK },
618 { "years", USEC_PER_YEAR },
619 { "year", USEC_PER_YEAR },
620 { "y", USEC_PER_YEAR },
623 { "", USEC_PER_SEC }, /* default is sec */
628 bool something = false;
639 p += strspn(p, WHITESPACE);
649 l = strtoll(p, &e, 10);
661 z = strtoll(b, &e, 10);
676 e += strspn(e, WHITESPACE);
678 for (i = 0; i < ELEMENTSOF(table); i++)
679 if (startswith(e, table[i].suffix)) {
680 usec_t k = (usec_t) z * table[i].usec;
685 r += (usec_t) l * table[i].usec + k;
686 p = e + strlen(table[i].suffix);
692 if (i >= ELEMENTSOF(table))
702 int parse_nsec(const char *t, nsec_t *nsec) {
703 static const struct {
707 { "seconds", NSEC_PER_SEC },
708 { "second", NSEC_PER_SEC },
709 { "sec", NSEC_PER_SEC },
710 { "s", NSEC_PER_SEC },
711 { "minutes", NSEC_PER_MINUTE },
712 { "minute", NSEC_PER_MINUTE },
713 { "min", NSEC_PER_MINUTE },
714 { "months", NSEC_PER_MONTH },
715 { "month", NSEC_PER_MONTH },
716 { "msec", NSEC_PER_MSEC },
717 { "ms", NSEC_PER_MSEC },
718 { "m", NSEC_PER_MINUTE },
719 { "hours", NSEC_PER_HOUR },
720 { "hour", NSEC_PER_HOUR },
721 { "hr", NSEC_PER_HOUR },
722 { "h", NSEC_PER_HOUR },
723 { "days", NSEC_PER_DAY },
724 { "day", NSEC_PER_DAY },
725 { "d", NSEC_PER_DAY },
726 { "weeks", NSEC_PER_WEEK },
727 { "week", NSEC_PER_WEEK },
728 { "w", NSEC_PER_WEEK },
729 { "years", NSEC_PER_YEAR },
730 { "year", NSEC_PER_YEAR },
731 { "y", NSEC_PER_YEAR },
732 { "usec", NSEC_PER_USEC },
733 { "us", NSEC_PER_USEC },
736 { "", 1ULL }, /* default is nsec */
741 bool something = false;
752 p += strspn(p, WHITESPACE);
762 l = strtoll(p, &e, 10);
774 z = strtoll(b, &e, 10);
789 e += strspn(e, WHITESPACE);
791 for (i = 0; i < ELEMENTSOF(table); i++)
792 if (startswith(e, table[i].suffix)) {
793 nsec_t k = (nsec_t) z * table[i].nsec;
798 r += (nsec_t) l * table[i].nsec + k;
799 p = e + strlen(table[i].suffix);
805 if (i >= ELEMENTSOF(table))
815 bool ntp_synced(void) {
816 struct timex txc = {};
818 if (adjtimex(&txc) < 0)
821 if (txc.status & STA_UNSYNC)