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 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_us(char *buf, size_t l, usec_t t, bool utc) {
188 if (t <= 0 || t == USEC_INFINITY)
191 sec = (time_t) (t / USEC_PER_SEC);
195 localtime_r(&sec, &tm);
197 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
199 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
200 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
206 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
210 n = now(CLOCK_REALTIME);
212 if (t <= 0 || (t == USEC_INFINITY))
223 if (d >= USEC_PER_YEAR)
224 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
226 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
227 else if (d >= USEC_PER_MONTH)
228 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
230 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
231 else if (d >= USEC_PER_WEEK)
232 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
234 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
235 else if (d >= 2*USEC_PER_DAY)
236 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
237 else if (d >= 25*USEC_PER_HOUR)
238 snprintf(buf, l, "1 day " USEC_FMT "h %s",
239 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
240 else if (d >= 6*USEC_PER_HOUR)
241 snprintf(buf, l, USEC_FMT "h %s",
242 d / USEC_PER_HOUR, s);
243 else if (d >= USEC_PER_HOUR)
244 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
246 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
247 else if (d >= 5*USEC_PER_MINUTE)
248 snprintf(buf, l, USEC_FMT "min %s",
249 d / USEC_PER_MINUTE, s);
250 else if (d >= USEC_PER_MINUTE)
251 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
253 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
254 else if (d >= USEC_PER_SEC)
255 snprintf(buf, l, USEC_FMT "s %s",
256 d / USEC_PER_SEC, s);
257 else if (d >= USEC_PER_MSEC)
258 snprintf(buf, l, USEC_FMT "ms %s",
259 d / USEC_PER_MSEC, s);
261 snprintf(buf, l, USEC_FMT"us %s",
264 snprintf(buf, l, "now");
270 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
271 static const struct {
275 { "y", USEC_PER_YEAR },
276 { "month", USEC_PER_MONTH },
277 { "w", USEC_PER_WEEK },
278 { "d", USEC_PER_DAY },
279 { "h", USEC_PER_HOUR },
280 { "min", USEC_PER_MINUTE },
281 { "s", USEC_PER_SEC },
282 { "ms", USEC_PER_MSEC },
288 bool something = false;
293 if (t == USEC_INFINITY || t <= 0) {
294 strncpy(p, t == USEC_INFINITY ? "infinity" : "0", l);
299 /* The result of this function can be parsed with parse_sec */
301 for (i = 0; i < ELEMENTSOF(table); i++) {
310 if (t < accuracy && something)
313 if (t < table[i].usec)
319 a = t / table[i].usec;
320 b = t % table[i].usec;
322 /* Let's see if we should shows this in dot notation */
323 if (t < USEC_PER_MINUTE && b > 0) {
328 for (cc = table[i].usec; cc > 1; cc /= 10)
331 for (cc = accuracy; cc > 1; cc /= 10) {
338 "%s"USEC_FMT".%0*llu%s",
342 (unsigned long long) b,
350 /* No? Then let's show it normally */
361 n = MIN((size_t) k, l);
374 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
380 if (!dual_timestamp_is_set(t))
383 fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
389 void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
390 unsigned long long a, b;
395 if (sscanf(value, "%llu %llu", &a, &b) != 2)
396 log_debug("Failed to parse finish timestamp value %s", value);
403 int parse_timestamp(const char *t, usec_t *usec) {
404 static const struct {
427 usec_t plus = 0, minus = 0, ret;
434 * 2012-09-22 16:34:22
435 * 2012-09-22 16:34 (seconds will be set to 0)
436 * 2012-09-22 (time will be set to 00:00:00)
437 * 16:34:22 (date will be set to today)
438 * 16:34 (date will be set to today, seconds to 0)
440 * yesterday (time is set to 00:00:00)
441 * today (time is set to 00:00:00)
442 * tomorrow (time is set to 00:00:00)
445 * @2147483647 (seconds since epoch)
453 assert_se(localtime_r(&x, &tm));
459 else if (streq(t, "today")) {
460 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
463 } else if (streq(t, "yesterday")) {
465 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
468 } else if (streq(t, "tomorrow")) {
470 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
473 } else if (t[0] == '+') {
474 r = parse_sec(t+1, &plus);
480 } else if (t[0] == '-') {
481 r = parse_sec(t+1, &minus);
487 } else if (t[0] == '@')
488 return parse_sec(t + 1, usec);
490 else if (endswith(t, " ago")) {
491 _cleanup_free_ char *z;
493 z = strndup(t, strlen(t) - 4);
497 r = parse_sec(z, &minus);
502 } else if (endswith(t, " left")) {
503 _cleanup_free_ char *z;
505 z = strndup(t, strlen(t) - 4);
509 r = parse_sec(z, &plus);
516 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
519 if (!startswith_no_case(t, day_nr[i].name))
522 skip = strlen(day_nr[i].name);
526 weekday = day_nr[i].nr;
532 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
537 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
542 k = strptime(t, "%y-%m-%d %H:%M", &tm);
549 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
556 k = strptime(t, "%y-%m-%d", &tm);
558 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
563 k = strptime(t, "%Y-%m-%d", &tm);
565 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
570 k = strptime(t, "%H:%M:%S", &tm);
575 k = strptime(t, "%H:%M", &tm);
585 if (x == (time_t) -1)
588 if (weekday >= 0 && tm.tm_wday != weekday)
591 ret = (usec_t) x * USEC_PER_SEC;
604 int parse_sec(const char *t, usec_t *usec) {
605 static const struct {
609 { "seconds", USEC_PER_SEC },
610 { "second", USEC_PER_SEC },
611 { "sec", USEC_PER_SEC },
612 { "s", USEC_PER_SEC },
613 { "minutes", USEC_PER_MINUTE },
614 { "minute", USEC_PER_MINUTE },
615 { "min", USEC_PER_MINUTE },
616 { "months", USEC_PER_MONTH },
617 { "month", USEC_PER_MONTH },
618 { "msec", USEC_PER_MSEC },
619 { "ms", USEC_PER_MSEC },
620 { "m", USEC_PER_MINUTE },
621 { "hours", USEC_PER_HOUR },
622 { "hour", USEC_PER_HOUR },
623 { "hr", USEC_PER_HOUR },
624 { "h", USEC_PER_HOUR },
625 { "days", USEC_PER_DAY },
626 { "day", USEC_PER_DAY },
627 { "d", USEC_PER_DAY },
628 { "weeks", USEC_PER_WEEK },
629 { "week", USEC_PER_WEEK },
630 { "w", USEC_PER_WEEK },
631 { "years", USEC_PER_YEAR },
632 { "year", USEC_PER_YEAR },
633 { "y", USEC_PER_YEAR },
636 { "", USEC_PER_SEC }, /* default is sec */
641 bool something = false;
648 p += strspn(p, WHITESPACE);
649 s = startswith(p, "infinity");
651 s += strspn(s, WHITESPACE);
655 *usec = USEC_INFINITY;
664 p += strspn(p, WHITESPACE);
674 l = strtoll(p, &e, 10);
686 z = strtoll(b, &e, 10);
701 e += strspn(e, WHITESPACE);
703 for (i = 0; i < ELEMENTSOF(table); i++)
704 if (startswith(e, table[i].suffix)) {
705 usec_t k = (usec_t) z * table[i].usec;
710 r += (usec_t) l * table[i].usec + k;
711 p = e + strlen(table[i].suffix);
717 if (i >= ELEMENTSOF(table))
727 int parse_nsec(const char *t, nsec_t *nsec) {
728 static const struct {
732 { "seconds", NSEC_PER_SEC },
733 { "second", NSEC_PER_SEC },
734 { "sec", NSEC_PER_SEC },
735 { "s", NSEC_PER_SEC },
736 { "minutes", NSEC_PER_MINUTE },
737 { "minute", NSEC_PER_MINUTE },
738 { "min", NSEC_PER_MINUTE },
739 { "months", NSEC_PER_MONTH },
740 { "month", NSEC_PER_MONTH },
741 { "msec", NSEC_PER_MSEC },
742 { "ms", NSEC_PER_MSEC },
743 { "m", NSEC_PER_MINUTE },
744 { "hours", NSEC_PER_HOUR },
745 { "hour", NSEC_PER_HOUR },
746 { "hr", NSEC_PER_HOUR },
747 { "h", NSEC_PER_HOUR },
748 { "days", NSEC_PER_DAY },
749 { "day", NSEC_PER_DAY },
750 { "d", NSEC_PER_DAY },
751 { "weeks", NSEC_PER_WEEK },
752 { "week", NSEC_PER_WEEK },
753 { "w", NSEC_PER_WEEK },
754 { "years", NSEC_PER_YEAR },
755 { "year", NSEC_PER_YEAR },
756 { "y", NSEC_PER_YEAR },
757 { "usec", NSEC_PER_USEC },
758 { "us", NSEC_PER_USEC },
761 { "", 1ULL }, /* default is nsec */
766 bool something = false;
777 p += strspn(p, WHITESPACE);
787 l = strtoll(p, &e, 10);
799 z = strtoll(b, &e, 10);
814 e += strspn(e, WHITESPACE);
816 for (i = 0; i < ELEMENTSOF(table); i++)
817 if (startswith(e, table[i].suffix)) {
818 nsec_t k = (nsec_t) z * table[i].nsec;
823 r += (nsec_t) l * table[i].nsec + k;
824 p = e + strlen(table[i].suffix);
830 if (i >= ELEMENTSOF(table))
840 bool ntp_synced(void) {
841 struct timex txc = {};
843 if (adjtimex(&txc) < 0)
846 if (txc.status & STA_UNSYNC)
852 int get_timezones(char ***ret) {
853 _cleanup_fclose_ FILE *f = NULL;
854 _cleanup_strv_free_ char **zones = NULL;
855 size_t n_zones = 0, n_allocated = 0;
859 zones = strv_new("UTC", NULL);
866 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
870 FOREACH_LINE(l, f, return -errno) {
876 if (isempty(p) || *p == '#')
879 /* Skip over country code */
880 p += strcspn(p, WHITESPACE);
881 p += strspn(p, WHITESPACE);
883 /* Skip over coordinates */
884 p += strcspn(p, WHITESPACE);
885 p += strspn(p, WHITESPACE);
887 /* Found timezone name */
888 k = strcspn(p, WHITESPACE);
896 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
901 zones[n_zones++] = w;
902 zones[n_zones] = NULL;
907 } else if (errno != ENOENT)
916 bool timezone_is_valid(const char *name) {
921 if (!name || *name == 0 || *name == '/')
924 for (p = name; *p; p++) {
925 if (!(*p >= '0' && *p <= '9') &&
926 !(*p >= 'a' && *p <= 'z') &&
927 !(*p >= 'A' && *p <= 'Z') &&
928 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
944 t = strappenda("/usr/share/zoneinfo/", name);
945 if (stat(t, &st) < 0)
948 if (!S_ISREG(st.st_mode))
954 clockid_t clock_boottime_or_monotonic(void) {
955 static clockid_t clock = -1;
961 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
963 clock = CLOCK_MONOTONIC;
966 clock = CLOCK_BOOTTIME;