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) {
300 strncpy(p, "infinity", l-1);
306 strncpy(p, "0", l-1);
311 /* The result of this function can be parsed with parse_sec */
313 for (i = 0; i < ELEMENTSOF(table); i++) {
322 if (t < accuracy && something)
325 if (t < table[i].usec)
331 a = t / table[i].usec;
332 b = t % table[i].usec;
334 /* Let's see if we should shows this in dot notation */
335 if (t < USEC_PER_MINUTE && b > 0) {
340 for (cc = table[i].usec; cc > 1; cc /= 10)
343 for (cc = accuracy; cc > 1; cc /= 10) {
350 "%s"USEC_FMT".%0*llu%s",
354 (unsigned long long) b,
362 /* No? Then let's show it normally */
373 n = MIN((size_t) k, l);
386 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
392 if (!dual_timestamp_is_set(t))
395 fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
401 void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
402 unsigned long long a, b;
407 if (sscanf(value, "%llu %llu", &a, &b) != 2)
408 log_debug("Failed to parse finish timestamp value %s", value);
415 int parse_timestamp(const char *t, usec_t *usec) {
416 static const struct {
439 usec_t plus = 0, minus = 0, ret;
446 * 2012-09-22 16:34:22
447 * 2012-09-22 16:34 (seconds will be set to 0)
448 * 2012-09-22 (time will be set to 00:00:00)
449 * 16:34:22 (date will be set to today)
450 * 16:34 (date will be set to today, seconds to 0)
452 * yesterday (time is set to 00:00:00)
453 * today (time is set to 00:00:00)
454 * tomorrow (time is set to 00:00:00)
457 * @2147483647 (seconds since epoch)
465 assert_se(localtime_r(&x, &tm));
471 else if (streq(t, "today")) {
472 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
475 } else if (streq(t, "yesterday")) {
477 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
480 } else if (streq(t, "tomorrow")) {
482 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
485 } else if (t[0] == '+') {
486 r = parse_sec(t+1, &plus);
492 } else if (t[0] == '-') {
493 r = parse_sec(t+1, &minus);
499 } else if (t[0] == '@')
500 return parse_sec(t + 1, usec);
502 else if (endswith(t, " ago")) {
503 _cleanup_free_ char *z;
505 z = strndup(t, strlen(t) - 4);
509 r = parse_sec(z, &minus);
514 } else if (endswith(t, " left")) {
515 _cleanup_free_ char *z;
517 z = strndup(t, strlen(t) - 4);
521 r = parse_sec(z, &plus);
528 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
531 if (!startswith_no_case(t, day_nr[i].name))
534 skip = strlen(day_nr[i].name);
538 weekday = day_nr[i].nr;
544 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
549 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
554 k = strptime(t, "%y-%m-%d %H:%M", &tm);
561 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
568 k = strptime(t, "%y-%m-%d", &tm);
570 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
575 k = strptime(t, "%Y-%m-%d", &tm);
577 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
582 k = strptime(t, "%H:%M:%S", &tm);
587 k = strptime(t, "%H:%M", &tm);
597 if (x == (time_t) -1)
600 if (weekday >= 0 && tm.tm_wday != weekday)
603 ret = (usec_t) x * USEC_PER_SEC;
616 int parse_sec(const char *t, usec_t *usec) {
617 static const struct {
621 { "seconds", USEC_PER_SEC },
622 { "second", USEC_PER_SEC },
623 { "sec", USEC_PER_SEC },
624 { "s", USEC_PER_SEC },
625 { "minutes", USEC_PER_MINUTE },
626 { "minute", USEC_PER_MINUTE },
627 { "min", USEC_PER_MINUTE },
628 { "months", USEC_PER_MONTH },
629 { "month", USEC_PER_MONTH },
630 { "msec", USEC_PER_MSEC },
631 { "ms", USEC_PER_MSEC },
632 { "m", USEC_PER_MINUTE },
633 { "hours", USEC_PER_HOUR },
634 { "hour", USEC_PER_HOUR },
635 { "hr", USEC_PER_HOUR },
636 { "h", USEC_PER_HOUR },
637 { "days", USEC_PER_DAY },
638 { "day", USEC_PER_DAY },
639 { "d", USEC_PER_DAY },
640 { "weeks", USEC_PER_WEEK },
641 { "week", USEC_PER_WEEK },
642 { "w", USEC_PER_WEEK },
643 { "years", USEC_PER_YEAR },
644 { "year", USEC_PER_YEAR },
645 { "y", USEC_PER_YEAR },
648 { "", USEC_PER_SEC }, /* default is sec */
653 bool something = false;
660 p += strspn(p, WHITESPACE);
661 s = startswith(p, "infinity");
663 s += strspn(s, WHITESPACE);
667 *usec = USEC_INFINITY;
676 p += strspn(p, WHITESPACE);
686 l = strtoll(p, &e, 10);
698 z = strtoll(b, &e, 10);
713 e += strspn(e, WHITESPACE);
715 for (i = 0; i < ELEMENTSOF(table); i++)
716 if (startswith(e, table[i].suffix)) {
717 usec_t k = (usec_t) z * table[i].usec;
722 r += (usec_t) l * table[i].usec + k;
723 p = e + strlen(table[i].suffix);
729 if (i >= ELEMENTSOF(table))
739 int parse_nsec(const char *t, nsec_t *nsec) {
740 static const struct {
744 { "seconds", NSEC_PER_SEC },
745 { "second", NSEC_PER_SEC },
746 { "sec", NSEC_PER_SEC },
747 { "s", NSEC_PER_SEC },
748 { "minutes", NSEC_PER_MINUTE },
749 { "minute", NSEC_PER_MINUTE },
750 { "min", NSEC_PER_MINUTE },
751 { "months", NSEC_PER_MONTH },
752 { "month", NSEC_PER_MONTH },
753 { "msec", NSEC_PER_MSEC },
754 { "ms", NSEC_PER_MSEC },
755 { "m", NSEC_PER_MINUTE },
756 { "hours", NSEC_PER_HOUR },
757 { "hour", NSEC_PER_HOUR },
758 { "hr", NSEC_PER_HOUR },
759 { "h", NSEC_PER_HOUR },
760 { "days", NSEC_PER_DAY },
761 { "day", NSEC_PER_DAY },
762 { "d", NSEC_PER_DAY },
763 { "weeks", NSEC_PER_WEEK },
764 { "week", NSEC_PER_WEEK },
765 { "w", NSEC_PER_WEEK },
766 { "years", NSEC_PER_YEAR },
767 { "year", NSEC_PER_YEAR },
768 { "y", NSEC_PER_YEAR },
769 { "usec", NSEC_PER_USEC },
770 { "us", NSEC_PER_USEC },
773 { "", 1ULL }, /* default is nsec */
778 bool something = false;
785 p += strspn(p, WHITESPACE);
786 s = startswith(p, "infinity");
788 s += strspn(s, WHITESPACE);
792 *nsec = NSEC_INFINITY;
801 p += strspn(p, WHITESPACE);
811 l = strtoll(p, &e, 10);
823 z = strtoll(b, &e, 10);
838 e += strspn(e, WHITESPACE);
840 for (i = 0; i < ELEMENTSOF(table); i++)
841 if (startswith(e, table[i].suffix)) {
842 nsec_t k = (nsec_t) z * table[i].nsec;
847 r += (nsec_t) l * table[i].nsec + k;
848 p = e + strlen(table[i].suffix);
854 if (i >= ELEMENTSOF(table))
864 bool ntp_synced(void) {
865 struct timex txc = {};
867 if (adjtimex(&txc) < 0)
870 if (txc.status & STA_UNSYNC)
876 int get_timezones(char ***ret) {
877 _cleanup_fclose_ FILE *f = NULL;
878 _cleanup_strv_free_ char **zones = NULL;
879 size_t n_zones = 0, n_allocated = 0;
883 zones = strv_new("UTC", NULL);
890 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
894 FOREACH_LINE(l, f, return -errno) {
900 if (isempty(p) || *p == '#')
903 /* Skip over country code */
904 p += strcspn(p, WHITESPACE);
905 p += strspn(p, WHITESPACE);
907 /* Skip over coordinates */
908 p += strcspn(p, WHITESPACE);
909 p += strspn(p, WHITESPACE);
911 /* Found timezone name */
912 k = strcspn(p, WHITESPACE);
920 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
925 zones[n_zones++] = w;
926 zones[n_zones] = NULL;
931 } else if (errno != ENOENT)
940 bool timezone_is_valid(const char *name) {
945 if (!name || *name == 0 || *name == '/')
948 for (p = name; *p; p++) {
949 if (!(*p >= '0' && *p <= '9') &&
950 !(*p >= 'a' && *p <= 'z') &&
951 !(*p >= 'A' && *p <= 'Z') &&
952 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
968 t = strjoina("/usr/share/zoneinfo/", name);
969 if (stat(t, &st) < 0)
972 if (!S_ISREG(st.st_mode))
978 clockid_t clock_boottime_or_monotonic(void) {
979 static clockid_t clock = -1;
985 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
987 clock = CLOCK_MONOTONIC;
990 clock = CLOCK_BOOTTIME;