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>
25 #include <sys/timerfd.h>
28 #include "time-util.h"
31 usec_t now(clockid_t clock_id) {
34 assert_se(clock_gettime(clock_id, &ts) == 0);
36 return timespec_load(&ts);
39 dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
42 ts->realtime = now(CLOCK_REALTIME);
43 ts->monotonic = now(CLOCK_MONOTONIC);
48 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
52 if (u == USEC_INFINITY) {
53 ts->realtime = ts->monotonic = USEC_INFINITY;
62 delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
64 ts->monotonic = now(CLOCK_MONOTONIC);
66 if ((int64_t) ts->monotonic > delta)
67 ts->monotonic -= delta;
75 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
79 if (u == USEC_INFINITY) {
80 ts->realtime = ts->monotonic = USEC_INFINITY;
85 delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
87 ts->realtime = now(CLOCK_REALTIME);
88 if ((int64_t) ts->realtime > delta)
89 ts->realtime -= delta;
96 usec_t timespec_load(const struct timespec *ts) {
99 if (ts->tv_sec == (time_t) -1 &&
100 ts->tv_nsec == (long) -1)
101 return USEC_INFINITY;
103 if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
104 return USEC_INFINITY;
107 (usec_t) ts->tv_sec * USEC_PER_SEC +
108 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
111 struct timespec *timespec_store(struct timespec *ts, usec_t u) {
114 if (u == USEC_INFINITY) {
115 ts->tv_sec = (time_t) -1;
116 ts->tv_nsec = (long) -1;
120 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
121 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
126 usec_t timeval_load(const struct timeval *tv) {
129 if (tv->tv_sec == (time_t) -1 &&
130 tv->tv_usec == (suseconds_t) -1)
131 return USEC_INFINITY;
133 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
134 return USEC_INFINITY;
137 (usec_t) tv->tv_sec * USEC_PER_SEC +
138 (usec_t) tv->tv_usec;
141 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
144 if (u == USEC_INFINITY) {
145 tv->tv_sec = (time_t) -1;
146 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);
155 static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) {
162 if (t <= 0 || t == USEC_INFINITY)
165 sec = (time_t) (t / USEC_PER_SEC);
170 localtime_r(&sec, &tm);
171 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
177 char *format_timestamp(char *buf, size_t l, usec_t t) {
178 return format_timestamp_internal(buf, l, t, false);
181 char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
182 return format_timestamp_internal(buf, l, t, true);
185 static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) {
192 if (t <= 0 || t == USEC_INFINITY)
195 sec = (time_t) (t / USEC_PER_SEC);
199 localtime_r(&sec, &tm);
201 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
203 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
204 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
210 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
211 return format_timestamp_internal_us(buf, l, t, false);
214 char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
215 return format_timestamp_internal_us(buf, l, t, true);
218 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
222 if (t <= 0 || t == USEC_INFINITY)
225 n = now(CLOCK_REALTIME);
234 if (d >= USEC_PER_YEAR)
235 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
237 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
238 else if (d >= USEC_PER_MONTH)
239 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
241 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
242 else if (d >= USEC_PER_WEEK)
243 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
245 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
246 else if (d >= 2*USEC_PER_DAY)
247 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
248 else if (d >= 25*USEC_PER_HOUR)
249 snprintf(buf, l, "1 day " USEC_FMT "h %s",
250 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
251 else if (d >= 6*USEC_PER_HOUR)
252 snprintf(buf, l, USEC_FMT "h %s",
253 d / USEC_PER_HOUR, s);
254 else if (d >= USEC_PER_HOUR)
255 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
257 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
258 else if (d >= 5*USEC_PER_MINUTE)
259 snprintf(buf, l, USEC_FMT "min %s",
260 d / USEC_PER_MINUTE, s);
261 else if (d >= USEC_PER_MINUTE)
262 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
264 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
265 else if (d >= USEC_PER_SEC)
266 snprintf(buf, l, USEC_FMT "s %s",
267 d / USEC_PER_SEC, s);
268 else if (d >= USEC_PER_MSEC)
269 snprintf(buf, l, USEC_FMT "ms %s",
270 d / USEC_PER_MSEC, s);
272 snprintf(buf, l, USEC_FMT"us %s",
275 snprintf(buf, l, "now");
281 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
282 static const struct {
286 { "y", USEC_PER_YEAR },
287 { "month", USEC_PER_MONTH },
288 { "w", USEC_PER_WEEK },
289 { "d", USEC_PER_DAY },
290 { "h", USEC_PER_HOUR },
291 { "min", USEC_PER_MINUTE },
292 { "s", USEC_PER_SEC },
293 { "ms", USEC_PER_MSEC },
299 bool something = false;
304 if (t == USEC_INFINITY || t <= 0) {
305 strncpy(p, t == USEC_INFINITY ? "infinity" : "0", l);
310 /* The result of this function can be parsed with parse_sec */
312 for (i = 0; i < ELEMENTSOF(table); i++) {
321 if (t < accuracy && something)
324 if (t < table[i].usec)
330 a = t / table[i].usec;
331 b = t % table[i].usec;
333 /* Let's see if we should shows this in dot notation */
334 if (t < USEC_PER_MINUTE && b > 0) {
339 for (cc = table[i].usec; cc > 1; cc /= 10)
342 for (cc = accuracy; cc > 1; cc /= 10) {
349 "%s"USEC_FMT".%0*llu%s",
353 (unsigned long long) b,
361 /* No? Then let's show it normally */
372 n = MIN((size_t) k, l);
385 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
391 if (!dual_timestamp_is_set(t))
394 fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
400 void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
401 unsigned long long a, b;
406 if (sscanf(value, "%llu %llu", &a, &b) != 2)
407 log_debug("Failed to parse finish timestamp value %s", value);
414 int parse_timestamp(const char *t, usec_t *usec) {
415 static const struct {
438 usec_t plus = 0, minus = 0, ret;
445 * 2012-09-22 16:34:22
446 * 2012-09-22 16:34 (seconds will be set to 0)
447 * 2012-09-22 (time will be set to 00:00:00)
448 * 16:34:22 (date will be set to today)
449 * 16:34 (date will be set to today, seconds to 0)
451 * yesterday (time is set to 00:00:00)
452 * today (time is set to 00:00:00)
453 * tomorrow (time is set to 00:00:00)
456 * @2147483647 (seconds since epoch)
464 assert_se(localtime_r(&x, &tm));
470 else if (streq(t, "today")) {
471 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
474 } else if (streq(t, "yesterday")) {
476 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
479 } else if (streq(t, "tomorrow")) {
481 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
484 } else if (t[0] == '+') {
485 r = parse_sec(t+1, &plus);
491 } else if (t[0] == '-') {
492 r = parse_sec(t+1, &minus);
498 } else if (t[0] == '@')
499 return parse_sec(t + 1, usec);
501 else if (endswith(t, " ago")) {
502 _cleanup_free_ char *z;
504 z = strndup(t, strlen(t) - 4);
508 r = parse_sec(z, &minus);
513 } else if (endswith(t, " left")) {
514 _cleanup_free_ char *z;
516 z = strndup(t, strlen(t) - 4);
520 r = parse_sec(z, &plus);
527 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
530 if (!startswith_no_case(t, day_nr[i].name))
533 skip = strlen(day_nr[i].name);
537 weekday = day_nr[i].nr;
543 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
548 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
553 k = strptime(t, "%y-%m-%d %H:%M", &tm);
560 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
567 k = strptime(t, "%y-%m-%d", &tm);
569 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
574 k = strptime(t, "%Y-%m-%d", &tm);
576 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
581 k = strptime(t, "%H:%M:%S", &tm);
586 k = strptime(t, "%H:%M", &tm);
596 if (x == (time_t) -1)
599 if (weekday >= 0 && tm.tm_wday != weekday)
602 ret = (usec_t) x * USEC_PER_SEC;
615 int parse_sec(const char *t, usec_t *usec) {
616 static const struct {
620 { "seconds", USEC_PER_SEC },
621 { "second", USEC_PER_SEC },
622 { "sec", USEC_PER_SEC },
623 { "s", USEC_PER_SEC },
624 { "minutes", USEC_PER_MINUTE },
625 { "minute", USEC_PER_MINUTE },
626 { "min", USEC_PER_MINUTE },
627 { "months", USEC_PER_MONTH },
628 { "month", USEC_PER_MONTH },
629 { "msec", USEC_PER_MSEC },
630 { "ms", USEC_PER_MSEC },
631 { "m", USEC_PER_MINUTE },
632 { "hours", USEC_PER_HOUR },
633 { "hour", USEC_PER_HOUR },
634 { "hr", USEC_PER_HOUR },
635 { "h", USEC_PER_HOUR },
636 { "days", USEC_PER_DAY },
637 { "day", USEC_PER_DAY },
638 { "d", USEC_PER_DAY },
639 { "weeks", USEC_PER_WEEK },
640 { "week", USEC_PER_WEEK },
641 { "w", USEC_PER_WEEK },
642 { "years", USEC_PER_YEAR },
643 { "year", USEC_PER_YEAR },
644 { "y", USEC_PER_YEAR },
647 { "", USEC_PER_SEC }, /* default is sec */
652 bool something = false;
659 p += strspn(p, WHITESPACE);
660 s = startswith(p, "infinity");
662 s += strspn(s, WHITESPACE);
666 *usec = USEC_INFINITY;
675 p += strspn(p, WHITESPACE);
685 l = strtoll(p, &e, 10);
697 z = strtoll(b, &e, 10);
712 e += strspn(e, WHITESPACE);
714 for (i = 0; i < ELEMENTSOF(table); i++)
715 if (startswith(e, table[i].suffix)) {
716 usec_t k = (usec_t) z * table[i].usec;
721 r += (usec_t) l * table[i].usec + k;
722 p = e + strlen(table[i].suffix);
728 if (i >= ELEMENTSOF(table))
738 int parse_nsec(const char *t, nsec_t *nsec) {
739 static const struct {
743 { "seconds", NSEC_PER_SEC },
744 { "second", NSEC_PER_SEC },
745 { "sec", NSEC_PER_SEC },
746 { "s", NSEC_PER_SEC },
747 { "minutes", NSEC_PER_MINUTE },
748 { "minute", NSEC_PER_MINUTE },
749 { "min", NSEC_PER_MINUTE },
750 { "months", NSEC_PER_MONTH },
751 { "month", NSEC_PER_MONTH },
752 { "msec", NSEC_PER_MSEC },
753 { "ms", NSEC_PER_MSEC },
754 { "m", NSEC_PER_MINUTE },
755 { "hours", NSEC_PER_HOUR },
756 { "hour", NSEC_PER_HOUR },
757 { "hr", NSEC_PER_HOUR },
758 { "h", NSEC_PER_HOUR },
759 { "days", NSEC_PER_DAY },
760 { "day", NSEC_PER_DAY },
761 { "d", NSEC_PER_DAY },
762 { "weeks", NSEC_PER_WEEK },
763 { "week", NSEC_PER_WEEK },
764 { "w", NSEC_PER_WEEK },
765 { "years", NSEC_PER_YEAR },
766 { "year", NSEC_PER_YEAR },
767 { "y", NSEC_PER_YEAR },
768 { "usec", NSEC_PER_USEC },
769 { "us", NSEC_PER_USEC },
772 { "", 1ULL }, /* default is nsec */
777 bool something = false;
784 p += strspn(p, WHITESPACE);
785 s = startswith(p, "infinity");
787 s += strspn(s, WHITESPACE);
791 *nsec = NSEC_INFINITY;
800 p += strspn(p, WHITESPACE);
810 l = strtoll(p, &e, 10);
822 z = strtoll(b, &e, 10);
837 e += strspn(e, WHITESPACE);
839 for (i = 0; i < ELEMENTSOF(table); i++)
840 if (startswith(e, table[i].suffix)) {
841 nsec_t k = (nsec_t) z * table[i].nsec;
846 r += (nsec_t) l * table[i].nsec + k;
847 p = e + strlen(table[i].suffix);
853 if (i >= ELEMENTSOF(table))
863 bool ntp_synced(void) {
864 struct timex txc = {};
866 if (adjtimex(&txc) < 0)
869 if (txc.status & STA_UNSYNC)
875 int get_timezones(char ***ret) {
876 _cleanup_fclose_ FILE *f = NULL;
877 _cleanup_strv_free_ char **zones = NULL;
878 size_t n_zones = 0, n_allocated = 0;
882 zones = strv_new("UTC", NULL);
889 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
893 FOREACH_LINE(l, f, return -errno) {
899 if (isempty(p) || *p == '#')
902 /* Skip over country code */
903 p += strcspn(p, WHITESPACE);
904 p += strspn(p, WHITESPACE);
906 /* Skip over coordinates */
907 p += strcspn(p, WHITESPACE);
908 p += strspn(p, WHITESPACE);
910 /* Found timezone name */
911 k = strcspn(p, WHITESPACE);
919 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
924 zones[n_zones++] = w;
925 zones[n_zones] = NULL;
930 } else if (errno != ENOENT)
939 bool timezone_is_valid(const char *name) {
944 if (!name || *name == 0 || *name == '/')
947 for (p = name; *p; p++) {
948 if (!(*p >= '0' && *p <= '9') &&
949 !(*p >= 'a' && *p <= 'z') &&
950 !(*p >= 'A' && *p <= 'Z') &&
951 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
967 t = strappenda("/usr/share/zoneinfo/", name);
968 if (stat(t, &st) < 0)
971 if (!S_ISREG(st.st_mode))
977 clockid_t clock_boottime_or_monotonic(void) {
978 static clockid_t clock = -1;
984 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
986 clock = CLOCK_MONOTONIC;
989 clock = CLOCK_BOOTTIME;