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(char *buf, size_t l, usec_t t) {
162 if (t <= 0 || t == USEC_INFINITY)
165 sec = (time_t) (t / USEC_PER_SEC);
167 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) <= 0)
173 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
180 if (t <= 0 || t == USEC_INFINITY)
183 sec = (time_t) (t / USEC_PER_SEC);
184 localtime_r(&sec, &tm);
186 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
188 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
189 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
195 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
199 n = now(CLOCK_REALTIME);
201 if (t <= 0 || (t == USEC_INFINITY))
212 if (d >= USEC_PER_YEAR)
213 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
215 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
216 else if (d >= USEC_PER_MONTH)
217 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
219 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
220 else if (d >= USEC_PER_WEEK)
221 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
223 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
224 else if (d >= 2*USEC_PER_DAY)
225 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
226 else if (d >= 25*USEC_PER_HOUR)
227 snprintf(buf, l, "1 day " USEC_FMT "h %s",
228 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
229 else if (d >= 6*USEC_PER_HOUR)
230 snprintf(buf, l, USEC_FMT "h %s",
231 d / USEC_PER_HOUR, s);
232 else if (d >= USEC_PER_HOUR)
233 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
235 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
236 else if (d >= 5*USEC_PER_MINUTE)
237 snprintf(buf, l, USEC_FMT "min %s",
238 d / USEC_PER_MINUTE, s);
239 else if (d >= USEC_PER_MINUTE)
240 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
242 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
243 else if (d >= USEC_PER_SEC)
244 snprintf(buf, l, USEC_FMT "s %s",
245 d / USEC_PER_SEC, s);
246 else if (d >= USEC_PER_MSEC)
247 snprintf(buf, l, USEC_FMT "ms %s",
248 d / USEC_PER_MSEC, s);
250 snprintf(buf, l, USEC_FMT"us %s",
253 snprintf(buf, l, "now");
259 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
260 static const struct {
264 { "y", USEC_PER_YEAR },
265 { "month", USEC_PER_MONTH },
266 { "w", USEC_PER_WEEK },
267 { "d", USEC_PER_DAY },
268 { "h", USEC_PER_HOUR },
269 { "min", USEC_PER_MINUTE },
270 { "s", USEC_PER_SEC },
271 { "ms", USEC_PER_MSEC },
277 bool something = false;
282 if (t == USEC_INFINITY || t <= 0) {
283 strncpy(p, t == USEC_INFINITY ? "infinity" : "0", l);
288 /* The result of this function can be parsed with parse_sec */
290 for (i = 0; i < ELEMENTSOF(table); i++) {
299 if (t < accuracy && something)
302 if (t < table[i].usec)
308 a = t / table[i].usec;
309 b = t % table[i].usec;
311 /* Let's see if we should shows this in dot notation */
312 if (t < USEC_PER_MINUTE && b > 0) {
317 for (cc = table[i].usec; cc > 1; cc /= 10)
320 for (cc = accuracy; cc > 1; cc /= 10) {
327 "%s"USEC_FMT".%0*llu%s",
331 (unsigned long long) b,
339 /* No? Then let's show it normally */
350 n = MIN((size_t) k, l);
363 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
369 if (!dual_timestamp_is_set(t))
372 fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
378 void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
379 unsigned long long a, b;
384 if (sscanf(value, "%llu %llu", &a, &b) != 2)
385 log_debug("Failed to parse finish timestamp value %s", value);
392 int parse_timestamp(const char *t, usec_t *usec) {
393 static const struct {
416 usec_t plus = 0, minus = 0, ret;
423 * 2012-09-22 16:34:22
424 * 2012-09-22 16:34 (seconds will be set to 0)
425 * 2012-09-22 (time will be set to 00:00:00)
426 * 16:34:22 (date will be set to today)
427 * 16:34 (date will be set to today, seconds to 0)
429 * yesterday (time is set to 00:00:00)
430 * today (time is set to 00:00:00)
431 * tomorrow (time is set to 00:00:00)
434 * @2147483647 (seconds since epoch)
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] == '+') {
463 r = parse_sec(t+1, &plus);
469 } else if (t[0] == '-') {
470 r = parse_sec(t+1, &minus);
476 } else if (t[0] == '@')
477 return parse_sec(t + 1, usec);
479 else if (endswith(t, " ago")) {
480 _cleanup_free_ char *z;
482 z = strndup(t, strlen(t) - 4);
486 r = parse_sec(z, &minus);
491 } else if (endswith(t, " left")) {
492 _cleanup_free_ char *z;
494 z = strndup(t, strlen(t) - 4);
498 r = parse_sec(z, &plus);
505 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
508 if (!startswith_no_case(t, day_nr[i].name))
511 skip = strlen(day_nr[i].name);
515 weekday = day_nr[i].nr;
521 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
526 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
531 k = strptime(t, "%y-%m-%d %H:%M", &tm);
538 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
545 k = strptime(t, "%y-%m-%d", &tm);
547 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
552 k = strptime(t, "%Y-%m-%d", &tm);
554 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
559 k = strptime(t, "%H:%M:%S", &tm);
564 k = strptime(t, "%H:%M", &tm);
574 if (x == (time_t) -1)
577 if (weekday >= 0 && tm.tm_wday != weekday)
580 ret = (usec_t) x * USEC_PER_SEC;
593 int parse_sec(const char *t, usec_t *usec) {
594 static const struct {
598 { "seconds", USEC_PER_SEC },
599 { "second", USEC_PER_SEC },
600 { "sec", USEC_PER_SEC },
601 { "s", USEC_PER_SEC },
602 { "minutes", USEC_PER_MINUTE },
603 { "minute", USEC_PER_MINUTE },
604 { "min", USEC_PER_MINUTE },
605 { "months", USEC_PER_MONTH },
606 { "month", USEC_PER_MONTH },
607 { "msec", USEC_PER_MSEC },
608 { "ms", USEC_PER_MSEC },
609 { "m", USEC_PER_MINUTE },
610 { "hours", USEC_PER_HOUR },
611 { "hour", USEC_PER_HOUR },
612 { "hr", USEC_PER_HOUR },
613 { "h", USEC_PER_HOUR },
614 { "days", USEC_PER_DAY },
615 { "day", USEC_PER_DAY },
616 { "d", USEC_PER_DAY },
617 { "weeks", USEC_PER_WEEK },
618 { "week", USEC_PER_WEEK },
619 { "w", USEC_PER_WEEK },
620 { "years", USEC_PER_YEAR },
621 { "year", USEC_PER_YEAR },
622 { "y", USEC_PER_YEAR },
625 { "", USEC_PER_SEC }, /* default is sec */
630 bool something = false;
637 p += strspn(p, WHITESPACE);
638 s = startswith(p, "infinity");
640 s += strspn(s, WHITESPACE);
644 *usec = USEC_INFINITY;
653 p += strspn(p, WHITESPACE);
663 l = strtoll(p, &e, 10);
675 z = strtoll(b, &e, 10);
690 e += strspn(e, WHITESPACE);
692 for (i = 0; i < ELEMENTSOF(table); i++)
693 if (startswith(e, table[i].suffix)) {
694 usec_t k = (usec_t) z * table[i].usec;
699 r += (usec_t) l * table[i].usec + k;
700 p = e + strlen(table[i].suffix);
706 if (i >= ELEMENTSOF(table))
716 int parse_nsec(const char *t, nsec_t *nsec) {
717 static const struct {
721 { "seconds", NSEC_PER_SEC },
722 { "second", NSEC_PER_SEC },
723 { "sec", NSEC_PER_SEC },
724 { "s", NSEC_PER_SEC },
725 { "minutes", NSEC_PER_MINUTE },
726 { "minute", NSEC_PER_MINUTE },
727 { "min", NSEC_PER_MINUTE },
728 { "months", NSEC_PER_MONTH },
729 { "month", NSEC_PER_MONTH },
730 { "msec", NSEC_PER_MSEC },
731 { "ms", NSEC_PER_MSEC },
732 { "m", NSEC_PER_MINUTE },
733 { "hours", NSEC_PER_HOUR },
734 { "hour", NSEC_PER_HOUR },
735 { "hr", NSEC_PER_HOUR },
736 { "h", NSEC_PER_HOUR },
737 { "days", NSEC_PER_DAY },
738 { "day", NSEC_PER_DAY },
739 { "d", NSEC_PER_DAY },
740 { "weeks", NSEC_PER_WEEK },
741 { "week", NSEC_PER_WEEK },
742 { "w", NSEC_PER_WEEK },
743 { "years", NSEC_PER_YEAR },
744 { "year", NSEC_PER_YEAR },
745 { "y", NSEC_PER_YEAR },
746 { "usec", NSEC_PER_USEC },
747 { "us", NSEC_PER_USEC },
750 { "", 1ULL }, /* default is nsec */
755 bool something = false;
766 p += strspn(p, WHITESPACE);
776 l = strtoll(p, &e, 10);
788 z = strtoll(b, &e, 10);
803 e += strspn(e, WHITESPACE);
805 for (i = 0; i < ELEMENTSOF(table); i++)
806 if (startswith(e, table[i].suffix)) {
807 nsec_t k = (nsec_t) z * table[i].nsec;
812 r += (nsec_t) l * table[i].nsec + k;
813 p = e + strlen(table[i].suffix);
819 if (i >= ELEMENTSOF(table))
829 bool ntp_synced(void) {
830 struct timex txc = {};
832 if (adjtimex(&txc) < 0)
835 if (txc.status & STA_UNSYNC)
841 int get_timezones(char ***ret) {
842 _cleanup_fclose_ FILE *f = NULL;
843 _cleanup_strv_free_ char **zones = NULL;
844 size_t n_zones = 0, n_allocated = 0;
848 zones = strv_new("UTC", NULL);
855 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
859 FOREACH_LINE(l, f, return -errno) {
865 if (isempty(p) || *p == '#')
868 /* Skip over country code */
869 p += strcspn(p, WHITESPACE);
870 p += strspn(p, WHITESPACE);
872 /* Skip over coordinates */
873 p += strcspn(p, WHITESPACE);
874 p += strspn(p, WHITESPACE);
876 /* Found timezone name */
877 k = strcspn(p, WHITESPACE);
885 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
890 zones[n_zones++] = w;
891 zones[n_zones] = NULL;
896 } else if (errno != ENOENT)
905 bool timezone_is_valid(const char *name) {
910 if (!name || *name == 0 || *name == '/')
913 for (p = name; *p; p++) {
914 if (!(*p >= '0' && *p <= '9') &&
915 !(*p >= 'a' && *p <= 'z') &&
916 !(*p >= 'A' && *p <= 'Z') &&
917 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
933 t = strappenda("/usr/share/zoneinfo/", name);
934 if (stat(t, &st) < 0)
937 if (!S_ISREG(st.st_mode))
943 clockid_t clock_boottime_or_monotonic(void) {
944 static clockid_t clock = -1;
950 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
952 clock = CLOCK_MONOTONIC;
955 clock = CLOCK_BOOTTIME;