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 || u <= 0) {
53 ts->realtime = ts->monotonic = u;
59 delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
60 ts->monotonic = now(CLOCK_MONOTONIC);
62 if ((int64_t) ts->monotonic > delta)
63 ts->monotonic -= delta;
70 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
74 if (u == USEC_INFINITY) {
75 ts->realtime = ts->monotonic = USEC_INFINITY;
80 delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
82 ts->realtime = now(CLOCK_REALTIME);
83 if ((int64_t) ts->realtime > delta)
84 ts->realtime -= delta;
91 usec_t timespec_load(const struct timespec *ts) {
94 if (ts->tv_sec == (time_t) -1 &&
95 ts->tv_nsec == (long) -1)
98 if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
102 (usec_t) ts->tv_sec * USEC_PER_SEC +
103 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
106 struct timespec *timespec_store(struct timespec *ts, usec_t u) {
109 if (u == USEC_INFINITY) {
110 ts->tv_sec = (time_t) -1;
111 ts->tv_nsec = (long) -1;
115 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
116 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
121 usec_t timeval_load(const struct timeval *tv) {
124 if (tv->tv_sec == (time_t) -1 &&
125 tv->tv_usec == (suseconds_t) -1)
126 return USEC_INFINITY;
128 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
129 return USEC_INFINITY;
132 (usec_t) tv->tv_sec * USEC_PER_SEC +
133 (usec_t) tv->tv_usec;
136 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
139 if (u == USEC_INFINITY) {
140 tv->tv_sec = (time_t) -1;
141 tv->tv_usec = (suseconds_t) -1;
143 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
144 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
150 static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) {
157 if (t <= 0 || t == USEC_INFINITY)
160 sec = (time_t) (t / USEC_PER_SEC);
165 localtime_r(&sec, &tm);
166 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
172 char *format_timestamp(char *buf, size_t l, usec_t t) {
173 return format_timestamp_internal(buf, l, t, false);
176 char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
177 return format_timestamp_internal(buf, l, t, true);
180 static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) {
187 if (t <= 0 || t == USEC_INFINITY)
190 sec = (time_t) (t / USEC_PER_SEC);
194 localtime_r(&sec, &tm);
196 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
198 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
199 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
205 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
206 return format_timestamp_internal_us(buf, l, t, false);
209 char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
210 return format_timestamp_internal_us(buf, l, t, true);
213 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
217 if (t <= 0 || t == USEC_INFINITY)
220 n = now(CLOCK_REALTIME);
229 if (d >= USEC_PER_YEAR)
230 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
232 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
233 else if (d >= USEC_PER_MONTH)
234 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
236 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
237 else if (d >= USEC_PER_WEEK)
238 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
240 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
241 else if (d >= 2*USEC_PER_DAY)
242 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
243 else if (d >= 25*USEC_PER_HOUR)
244 snprintf(buf, l, "1 day " USEC_FMT "h %s",
245 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
246 else if (d >= 6*USEC_PER_HOUR)
247 snprintf(buf, l, USEC_FMT "h %s",
248 d / USEC_PER_HOUR, s);
249 else if (d >= USEC_PER_HOUR)
250 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
252 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
253 else if (d >= 5*USEC_PER_MINUTE)
254 snprintf(buf, l, USEC_FMT "min %s",
255 d / USEC_PER_MINUTE, s);
256 else if (d >= USEC_PER_MINUTE)
257 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
259 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
260 else if (d >= USEC_PER_SEC)
261 snprintf(buf, l, USEC_FMT "s %s",
262 d / USEC_PER_SEC, s);
263 else if (d >= USEC_PER_MSEC)
264 snprintf(buf, l, USEC_FMT "ms %s",
265 d / USEC_PER_MSEC, s);
267 snprintf(buf, l, USEC_FMT"us %s",
270 snprintf(buf, l, "now");
276 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
277 static const struct {
281 { "y", USEC_PER_YEAR },
282 { "month", USEC_PER_MONTH },
283 { "w", USEC_PER_WEEK },
284 { "d", USEC_PER_DAY },
285 { "h", USEC_PER_HOUR },
286 { "min", USEC_PER_MINUTE },
287 { "s", USEC_PER_SEC },
288 { "ms", USEC_PER_MSEC },
294 bool something = false;
299 if (t == USEC_INFINITY || t <= 0) {
300 strncpy(p, t == USEC_INFINITY ? "infinity" : "0", l);
305 /* The result of this function can be parsed with parse_sec */
307 for (i = 0; i < ELEMENTSOF(table); i++) {
316 if (t < accuracy && something)
319 if (t < table[i].usec)
325 a = t / table[i].usec;
326 b = t % table[i].usec;
328 /* Let's see if we should shows this in dot notation */
329 if (t < USEC_PER_MINUTE && b > 0) {
334 for (cc = table[i].usec; cc > 1; cc /= 10)
337 for (cc = accuracy; cc > 1; cc /= 10) {
344 "%s"USEC_FMT".%0*llu%s",
348 (unsigned long long) b,
356 /* No? Then let's show it normally */
367 n = MIN((size_t) k, l);
380 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
386 if (!dual_timestamp_is_set(t))
389 fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
395 void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
396 unsigned long long a, b;
401 if (sscanf(value, "%llu %llu", &a, &b) != 2)
402 log_debug("Failed to parse finish timestamp value %s", value);
409 int parse_timestamp(const char *t, usec_t *usec) {
410 static const struct {
433 usec_t plus = 0, minus = 0, ret;
440 * 2012-09-22 16:34:22
441 * 2012-09-22 16:34 (seconds will be set to 0)
442 * 2012-09-22 (time will be set to 00:00:00)
443 * 16:34:22 (date will be set to today)
444 * 16:34 (date will be set to today, seconds to 0)
446 * yesterday (time is set to 00:00:00)
447 * today (time is set to 00:00:00)
448 * tomorrow (time is set to 00:00:00)
451 * @2147483647 (seconds since epoch)
459 assert_se(localtime_r(&x, &tm));
465 else if (streq(t, "today")) {
466 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
469 } else if (streq(t, "yesterday")) {
471 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
474 } else if (streq(t, "tomorrow")) {
476 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
479 } else if (t[0] == '+') {
480 r = parse_sec(t+1, &plus);
486 } else if (t[0] == '-') {
487 r = parse_sec(t+1, &minus);
493 } else if (t[0] == '@')
494 return parse_sec(t + 1, usec);
496 else if (endswith(t, " ago")) {
497 _cleanup_free_ char *z;
499 z = strndup(t, strlen(t) - 4);
503 r = parse_sec(z, &minus);
508 } else if (endswith(t, " left")) {
509 _cleanup_free_ char *z;
511 z = strndup(t, strlen(t) - 4);
515 r = parse_sec(z, &plus);
522 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
525 if (!startswith_no_case(t, day_nr[i].name))
528 skip = strlen(day_nr[i].name);
532 weekday = day_nr[i].nr;
538 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
543 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
548 k = strptime(t, "%y-%m-%d %H:%M", &tm);
555 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
562 k = strptime(t, "%y-%m-%d", &tm);
564 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
569 k = strptime(t, "%Y-%m-%d", &tm);
571 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
576 k = strptime(t, "%H:%M:%S", &tm);
581 k = strptime(t, "%H:%M", &tm);
591 if (x == (time_t) -1)
594 if (weekday >= 0 && tm.tm_wday != weekday)
597 ret = (usec_t) x * USEC_PER_SEC;
610 int parse_sec(const char *t, usec_t *usec) {
611 static const struct {
615 { "seconds", USEC_PER_SEC },
616 { "second", USEC_PER_SEC },
617 { "sec", USEC_PER_SEC },
618 { "s", USEC_PER_SEC },
619 { "minutes", USEC_PER_MINUTE },
620 { "minute", USEC_PER_MINUTE },
621 { "min", USEC_PER_MINUTE },
622 { "months", USEC_PER_MONTH },
623 { "month", USEC_PER_MONTH },
624 { "msec", USEC_PER_MSEC },
625 { "ms", USEC_PER_MSEC },
626 { "m", USEC_PER_MINUTE },
627 { "hours", USEC_PER_HOUR },
628 { "hour", USEC_PER_HOUR },
629 { "hr", USEC_PER_HOUR },
630 { "h", USEC_PER_HOUR },
631 { "days", USEC_PER_DAY },
632 { "day", USEC_PER_DAY },
633 { "d", USEC_PER_DAY },
634 { "weeks", USEC_PER_WEEK },
635 { "week", USEC_PER_WEEK },
636 { "w", USEC_PER_WEEK },
637 { "years", USEC_PER_YEAR },
638 { "year", USEC_PER_YEAR },
639 { "y", USEC_PER_YEAR },
642 { "", USEC_PER_SEC }, /* default is sec */
647 bool something = false;
654 p += strspn(p, WHITESPACE);
655 s = startswith(p, "infinity");
657 s += strspn(s, WHITESPACE);
661 *usec = USEC_INFINITY;
670 p += strspn(p, WHITESPACE);
680 l = strtoll(p, &e, 10);
692 z = strtoll(b, &e, 10);
707 e += strspn(e, WHITESPACE);
709 for (i = 0; i < ELEMENTSOF(table); i++)
710 if (startswith(e, table[i].suffix)) {
711 usec_t k = (usec_t) z * table[i].usec;
716 r += (usec_t) l * table[i].usec + k;
717 p = e + strlen(table[i].suffix);
723 if (i >= ELEMENTSOF(table))
733 int parse_nsec(const char *t, nsec_t *nsec) {
734 static const struct {
738 { "seconds", NSEC_PER_SEC },
739 { "second", NSEC_PER_SEC },
740 { "sec", NSEC_PER_SEC },
741 { "s", NSEC_PER_SEC },
742 { "minutes", NSEC_PER_MINUTE },
743 { "minute", NSEC_PER_MINUTE },
744 { "min", NSEC_PER_MINUTE },
745 { "months", NSEC_PER_MONTH },
746 { "month", NSEC_PER_MONTH },
747 { "msec", NSEC_PER_MSEC },
748 { "ms", NSEC_PER_MSEC },
749 { "m", NSEC_PER_MINUTE },
750 { "hours", NSEC_PER_HOUR },
751 { "hour", NSEC_PER_HOUR },
752 { "hr", NSEC_PER_HOUR },
753 { "h", NSEC_PER_HOUR },
754 { "days", NSEC_PER_DAY },
755 { "day", NSEC_PER_DAY },
756 { "d", NSEC_PER_DAY },
757 { "weeks", NSEC_PER_WEEK },
758 { "week", NSEC_PER_WEEK },
759 { "w", NSEC_PER_WEEK },
760 { "years", NSEC_PER_YEAR },
761 { "year", NSEC_PER_YEAR },
762 { "y", NSEC_PER_YEAR },
763 { "usec", NSEC_PER_USEC },
764 { "us", NSEC_PER_USEC },
767 { "", 1ULL }, /* default is nsec */
772 bool something = false;
779 p += strspn(p, WHITESPACE);
780 s = startswith(p, "infinity");
782 s += strspn(s, WHITESPACE);
786 *nsec = NSEC_INFINITY;
795 p += strspn(p, WHITESPACE);
805 l = strtoll(p, &e, 10);
817 z = strtoll(b, &e, 10);
832 e += strspn(e, WHITESPACE);
834 for (i = 0; i < ELEMENTSOF(table); i++)
835 if (startswith(e, table[i].suffix)) {
836 nsec_t k = (nsec_t) z * table[i].nsec;
841 r += (nsec_t) l * table[i].nsec + k;
842 p = e + strlen(table[i].suffix);
848 if (i >= ELEMENTSOF(table))
858 bool ntp_synced(void) {
859 struct timex txc = {};
861 if (adjtimex(&txc) < 0)
864 if (txc.status & STA_UNSYNC)
870 int get_timezones(char ***ret) {
871 _cleanup_fclose_ FILE *f = NULL;
872 _cleanup_strv_free_ char **zones = NULL;
873 size_t n_zones = 0, n_allocated = 0;
877 zones = strv_new("UTC", NULL);
884 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
888 FOREACH_LINE(l, f, return -errno) {
894 if (isempty(p) || *p == '#')
897 /* Skip over country code */
898 p += strcspn(p, WHITESPACE);
899 p += strspn(p, WHITESPACE);
901 /* Skip over coordinates */
902 p += strcspn(p, WHITESPACE);
903 p += strspn(p, WHITESPACE);
905 /* Found timezone name */
906 k = strcspn(p, WHITESPACE);
914 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
919 zones[n_zones++] = w;
920 zones[n_zones] = NULL;
925 } else if (errno != ENOENT)
934 bool timezone_is_valid(const char *name) {
939 if (!name || *name == 0 || *name == '/')
942 for (p = name; *p; p++) {
943 if (!(*p >= '0' && *p <= '9') &&
944 !(*p >= 'a' && *p <= 'z') &&
945 !(*p >= 'A' && *p <= 'Z') &&
946 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
962 t = strappenda("/usr/share/zoneinfo/", name);
963 if (stat(t, &st) < 0)
966 if (!S_ISREG(st.st_mode))
972 clockid_t clock_boottime_or_monotonic(void) {
973 static clockid_t clock = -1;
979 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
981 clock = CLOCK_MONOTONIC;
984 clock = CLOCK_BOOTTIME;