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 /// UNNEEDED by elogind
178 char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
179 return format_timestamp_internal(buf, l, t, true);
183 static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) {
190 if (t <= 0 || t == USEC_INFINITY)
193 sec = (time_t) (t / USEC_PER_SEC);
197 localtime_r(&sec, &tm);
199 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
201 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
202 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
208 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
209 return format_timestamp_internal_us(buf, l, t, false);
212 char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
213 return format_timestamp_internal_us(buf, l, t, true);
216 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
220 if (t <= 0 || t == USEC_INFINITY)
223 n = now(CLOCK_REALTIME);
232 if (d >= USEC_PER_YEAR)
233 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
235 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
236 else if (d >= USEC_PER_MONTH)
237 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
239 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
240 else if (d >= USEC_PER_WEEK)
241 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
243 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
244 else if (d >= 2*USEC_PER_DAY)
245 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
246 else if (d >= 25*USEC_PER_HOUR)
247 snprintf(buf, l, "1 day " USEC_FMT "h %s",
248 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
249 else if (d >= 6*USEC_PER_HOUR)
250 snprintf(buf, l, USEC_FMT "h %s",
251 d / USEC_PER_HOUR, s);
252 else if (d >= USEC_PER_HOUR)
253 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
255 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
256 else if (d >= 5*USEC_PER_MINUTE)
257 snprintf(buf, l, USEC_FMT "min %s",
258 d / USEC_PER_MINUTE, s);
259 else if (d >= USEC_PER_MINUTE)
260 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
262 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
263 else if (d >= USEC_PER_SEC)
264 snprintf(buf, l, USEC_FMT "s %s",
265 d / USEC_PER_SEC, s);
266 else if (d >= USEC_PER_MSEC)
267 snprintf(buf, l, USEC_FMT "ms %s",
268 d / USEC_PER_MSEC, s);
270 snprintf(buf, l, USEC_FMT"us %s",
273 snprintf(buf, l, "now");
279 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
280 static const struct {
284 { "y", USEC_PER_YEAR },
285 { "month", USEC_PER_MONTH },
286 { "w", USEC_PER_WEEK },
287 { "d", USEC_PER_DAY },
288 { "h", USEC_PER_HOUR },
289 { "min", USEC_PER_MINUTE },
290 { "s", USEC_PER_SEC },
291 { "ms", USEC_PER_MSEC },
297 bool something = false;
302 if (t == USEC_INFINITY) {
303 strncpy(p, "infinity", l-1);
309 strncpy(p, "0", l-1);
314 /* The result of this function can be parsed with parse_sec */
316 for (i = 0; i < ELEMENTSOF(table); i++) {
325 if (t < accuracy && something)
328 if (t < table[i].usec)
334 a = t / table[i].usec;
335 b = t % table[i].usec;
337 /* Let's see if we should shows this in dot notation */
338 if (t < USEC_PER_MINUTE && b > 0) {
343 for (cc = table[i].usec; cc > 1; cc /= 10)
346 for (cc = accuracy; cc > 1; cc /= 10) {
353 "%s"USEC_FMT".%0*llu%s",
357 (unsigned long long) b,
365 /* No? Then let's show it normally */
376 n = MIN((size_t) k, l);
389 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
395 if (!dual_timestamp_is_set(t))
398 fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
404 int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
405 unsigned long long a, b;
410 if (sscanf(value, "%llu %llu", &a, &b) != 2) {
411 log_debug("Failed to parse finish timestamp value %s.", value);
421 /// UNNEEDED by elogind
423 int parse_timestamp(const char *t, usec_t *usec) {
424 static const struct {
447 usec_t plus = 0, minus = 0, ret;
454 * 2012-09-22 16:34:22
455 * 2012-09-22 16:34 (seconds will be set to 0)
456 * 2012-09-22 (time will be set to 00:00:00)
457 * 16:34:22 (date will be set to today)
458 * 16:34 (date will be set to today, seconds to 0)
460 * yesterday (time is set to 00:00:00)
461 * today (time is set to 00:00:00)
462 * tomorrow (time is set to 00:00:00)
465 * @2147483647 (seconds since epoch)
473 assert_se(localtime_r(&x, &tm));
479 else if (streq(t, "today")) {
480 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
483 } else if (streq(t, "yesterday")) {
485 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
488 } else if (streq(t, "tomorrow")) {
490 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
493 } else if (t[0] == '+') {
494 r = parse_sec(t+1, &plus);
500 } else if (t[0] == '-') {
501 r = parse_sec(t+1, &minus);
507 } else if (t[0] == '@')
508 return parse_sec(t + 1, usec);
510 else if (endswith(t, " ago")) {
511 _cleanup_free_ char *z;
513 z = strndup(t, strlen(t) - 4);
517 r = parse_sec(z, &minus);
522 } else if (endswith(t, " left")) {
523 _cleanup_free_ char *z;
525 z = strndup(t, strlen(t) - 4);
529 r = parse_sec(z, &plus);
536 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
539 if (!startswith_no_case(t, day_nr[i].name))
542 skip = strlen(day_nr[i].name);
546 weekday = day_nr[i].nr;
552 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
557 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
562 k = strptime(t, "%y-%m-%d %H:%M", &tm);
569 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
576 k = strptime(t, "%y-%m-%d", &tm);
578 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
583 k = strptime(t, "%Y-%m-%d", &tm);
585 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
590 k = strptime(t, "%H:%M:%S", &tm);
595 k = strptime(t, "%H:%M", &tm);
605 if (x == (time_t) -1)
608 if (weekday >= 0 && tm.tm_wday != weekday)
611 ret = (usec_t) x * USEC_PER_SEC;
625 int parse_sec(const char *t, usec_t *usec) {
626 static const struct {
630 { "seconds", USEC_PER_SEC },
631 { "second", USEC_PER_SEC },
632 { "sec", USEC_PER_SEC },
633 { "s", USEC_PER_SEC },
634 { "minutes", USEC_PER_MINUTE },
635 { "minute", USEC_PER_MINUTE },
636 { "min", USEC_PER_MINUTE },
637 { "months", USEC_PER_MONTH },
638 { "month", USEC_PER_MONTH },
639 { "msec", USEC_PER_MSEC },
640 { "ms", USEC_PER_MSEC },
641 { "m", USEC_PER_MINUTE },
642 { "hours", USEC_PER_HOUR },
643 { "hour", USEC_PER_HOUR },
644 { "hr", USEC_PER_HOUR },
645 { "h", USEC_PER_HOUR },
646 { "days", USEC_PER_DAY },
647 { "day", USEC_PER_DAY },
648 { "d", USEC_PER_DAY },
649 { "weeks", USEC_PER_WEEK },
650 { "week", USEC_PER_WEEK },
651 { "w", USEC_PER_WEEK },
652 { "years", USEC_PER_YEAR },
653 { "year", USEC_PER_YEAR },
654 { "y", USEC_PER_YEAR },
657 { "", USEC_PER_SEC }, /* default is sec */
662 bool something = false;
669 p += strspn(p, WHITESPACE);
670 s = startswith(p, "infinity");
672 s += strspn(s, WHITESPACE);
676 *usec = USEC_INFINITY;
685 p += strspn(p, WHITESPACE);
695 l = strtoll(p, &e, 10);
707 z = strtoll(b, &e, 10);
722 e += strspn(e, WHITESPACE);
724 for (i = 0; i < ELEMENTSOF(table); i++)
725 if (startswith(e, table[i].suffix)) {
726 usec_t k = (usec_t) z * table[i].usec;
731 r += (usec_t) l * table[i].usec + k;
732 p = e + strlen(table[i].suffix);
738 if (i >= ELEMENTSOF(table))
748 int parse_nsec(const char *t, nsec_t *nsec) {
749 static const struct {
753 { "seconds", NSEC_PER_SEC },
754 { "second", NSEC_PER_SEC },
755 { "sec", NSEC_PER_SEC },
756 { "s", NSEC_PER_SEC },
757 { "minutes", NSEC_PER_MINUTE },
758 { "minute", NSEC_PER_MINUTE },
759 { "min", NSEC_PER_MINUTE },
760 { "months", NSEC_PER_MONTH },
761 { "month", NSEC_PER_MONTH },
762 { "msec", NSEC_PER_MSEC },
763 { "ms", NSEC_PER_MSEC },
764 { "m", NSEC_PER_MINUTE },
765 { "hours", NSEC_PER_HOUR },
766 { "hour", NSEC_PER_HOUR },
767 { "hr", NSEC_PER_HOUR },
768 { "h", NSEC_PER_HOUR },
769 { "days", NSEC_PER_DAY },
770 { "day", NSEC_PER_DAY },
771 { "d", NSEC_PER_DAY },
772 { "weeks", NSEC_PER_WEEK },
773 { "week", NSEC_PER_WEEK },
774 { "w", NSEC_PER_WEEK },
775 { "years", NSEC_PER_YEAR },
776 { "year", NSEC_PER_YEAR },
777 { "y", NSEC_PER_YEAR },
778 { "usec", NSEC_PER_USEC },
779 { "us", NSEC_PER_USEC },
782 { "", 1ULL }, /* default is nsec */
787 bool something = false;
794 p += strspn(p, WHITESPACE);
795 s = startswith(p, "infinity");
797 s += strspn(s, WHITESPACE);
801 *nsec = NSEC_INFINITY;
810 p += strspn(p, WHITESPACE);
820 l = strtoll(p, &e, 10);
832 z = strtoll(b, &e, 10);
847 e += strspn(e, WHITESPACE);
849 for (i = 0; i < ELEMENTSOF(table); i++)
850 if (startswith(e, table[i].suffix)) {
851 nsec_t k = (nsec_t) z * table[i].nsec;
856 r += (nsec_t) l * table[i].nsec + k;
857 p = e + strlen(table[i].suffix);
863 if (i >= ELEMENTSOF(table))
873 /// UNNEEDED by elogind
875 bool ntp_synced(void) {
876 struct timex txc = {};
878 if (adjtimex(&txc) < 0)
881 if (txc.status & STA_UNSYNC)
887 int get_timezones(char ***ret) {
888 _cleanup_fclose_ FILE *f = NULL;
889 _cleanup_strv_free_ char **zones = NULL;
890 size_t n_zones = 0, n_allocated = 0;
894 zones = strv_new("UTC", NULL);
901 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
905 FOREACH_LINE(l, f, return -errno) {
911 if (isempty(p) || *p == '#')
914 /* Skip over country code */
915 p += strcspn(p, WHITESPACE);
916 p += strspn(p, WHITESPACE);
918 /* Skip over coordinates */
919 p += strcspn(p, WHITESPACE);
920 p += strspn(p, WHITESPACE);
922 /* Found timezone name */
923 k = strcspn(p, WHITESPACE);
931 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
936 zones[n_zones++] = w;
937 zones[n_zones] = NULL;
942 } else if (errno != ENOENT)
951 bool timezone_is_valid(const char *name) {
956 if (!name || *name == 0 || *name == '/')
959 for (p = name; *p; p++) {
960 if (!(*p >= '0' && *p <= '9') &&
961 !(*p >= 'a' && *p <= 'z') &&
962 !(*p >= 'A' && *p <= 'Z') &&
963 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
979 t = strjoina("/usr/share/zoneinfo/", name);
980 if (stat(t, &st) < 0)
983 if (!S_ISREG(st.st_mode))
990 clockid_t clock_boottime_or_monotonic(void) {
991 static clockid_t clock = -1;
997 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
999 clock = CLOCK_MONOTONIC;
1002 clock = CLOCK_BOOTTIME;