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 static 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_utc(char *buf, size_t l, usec_t t) {
182 return format_timestamp_internal(buf, l, t, true);
185 static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) {
192 if (t <= 0 || t == USEC_INFINITY)
195 sec = (time_t) (t / USEC_PER_SEC);
199 localtime_r(&sec, &tm);
201 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
203 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
204 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
210 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
211 return format_timestamp_internal_us(buf, l, t, false);
214 char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
215 return format_timestamp_internal_us(buf, l, t, true);
218 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
222 n = now(CLOCK_REALTIME);
224 if (t <= 0 || (t == USEC_INFINITY))
235 if (d >= USEC_PER_YEAR)
236 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
238 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
239 else if (d >= USEC_PER_MONTH)
240 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
242 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
243 else if (d >= USEC_PER_WEEK)
244 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
246 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
247 else if (d >= 2*USEC_PER_DAY)
248 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
249 else if (d >= 25*USEC_PER_HOUR)
250 snprintf(buf, l, "1 day " USEC_FMT "h %s",
251 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
252 else if (d >= 6*USEC_PER_HOUR)
253 snprintf(buf, l, USEC_FMT "h %s",
254 d / USEC_PER_HOUR, s);
255 else if (d >= USEC_PER_HOUR)
256 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
258 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
259 else if (d >= 5*USEC_PER_MINUTE)
260 snprintf(buf, l, USEC_FMT "min %s",
261 d / USEC_PER_MINUTE, s);
262 else if (d >= USEC_PER_MINUTE)
263 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
265 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
266 else if (d >= USEC_PER_SEC)
267 snprintf(buf, l, USEC_FMT "s %s",
268 d / USEC_PER_SEC, s);
269 else if (d >= USEC_PER_MSEC)
270 snprintf(buf, l, USEC_FMT "ms %s",
271 d / USEC_PER_MSEC, s);
273 snprintf(buf, l, USEC_FMT"us %s",
276 snprintf(buf, l, "now");
282 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
283 static const struct {
287 { "y", USEC_PER_YEAR },
288 { "month", USEC_PER_MONTH },
289 { "w", USEC_PER_WEEK },
290 { "d", USEC_PER_DAY },
291 { "h", USEC_PER_HOUR },
292 { "min", USEC_PER_MINUTE },
293 { "s", USEC_PER_SEC },
294 { "ms", USEC_PER_MSEC },
300 bool something = false;
305 if (t == USEC_INFINITY || t <= 0) {
306 strncpy(p, t == USEC_INFINITY ? "infinity" : "0", l);
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;
789 p += strspn(p, WHITESPACE);
799 l = strtoll(p, &e, 10);
811 z = strtoll(b, &e, 10);
826 e += strspn(e, WHITESPACE);
828 for (i = 0; i < ELEMENTSOF(table); i++)
829 if (startswith(e, table[i].suffix)) {
830 nsec_t k = (nsec_t) z * table[i].nsec;
835 r += (nsec_t) l * table[i].nsec + k;
836 p = e + strlen(table[i].suffix);
842 if (i >= ELEMENTSOF(table))
852 bool ntp_synced(void) {
853 struct timex txc = {};
855 if (adjtimex(&txc) < 0)
858 if (txc.status & STA_UNSYNC)
864 int get_timezones(char ***ret) {
865 _cleanup_fclose_ FILE *f = NULL;
866 _cleanup_strv_free_ char **zones = NULL;
867 size_t n_zones = 0, n_allocated = 0;
871 zones = strv_new("UTC", NULL);
878 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
882 FOREACH_LINE(l, f, return -errno) {
888 if (isempty(p) || *p == '#')
891 /* Skip over country code */
892 p += strcspn(p, WHITESPACE);
893 p += strspn(p, WHITESPACE);
895 /* Skip over coordinates */
896 p += strcspn(p, WHITESPACE);
897 p += strspn(p, WHITESPACE);
899 /* Found timezone name */
900 k = strcspn(p, WHITESPACE);
908 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
913 zones[n_zones++] = w;
914 zones[n_zones] = NULL;
919 } else if (errno != ENOENT)
928 bool timezone_is_valid(const char *name) {
933 if (!name || *name == 0 || *name == '/')
936 for (p = name; *p; p++) {
937 if (!(*p >= '0' && *p <= '9') &&
938 !(*p >= 'a' && *p <= 'z') &&
939 !(*p >= 'A' && *p <= 'Z') &&
940 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
956 t = strappenda("/usr/share/zoneinfo/", name);
957 if (stat(t, &st) < 0)
960 if (!S_ISREG(st.st_mode))
966 clockid_t clock_boottime_or_monotonic(void) {
967 static clockid_t clock = -1;
973 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
975 clock = CLOCK_MONOTONIC;
978 clock = CLOCK_BOOTTIME;