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 /// UNNEEDED by elogind
72 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
76 if (u == USEC_INFINITY) {
77 ts->realtime = ts->monotonic = USEC_INFINITY;
82 delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
84 ts->realtime = now(CLOCK_REALTIME);
85 if ((int64_t) ts->realtime > delta)
86 ts->realtime -= delta;
94 usec_t timespec_load(const struct timespec *ts) {
97 if (ts->tv_sec == (time_t) -1 &&
98 ts->tv_nsec == (long) -1)
101 if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
102 return USEC_INFINITY;
105 (usec_t) ts->tv_sec * USEC_PER_SEC +
106 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
109 struct timespec *timespec_store(struct timespec *ts, usec_t u) {
112 if (u == USEC_INFINITY) {
113 ts->tv_sec = (time_t) -1;
114 ts->tv_nsec = (long) -1;
118 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
119 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
124 usec_t timeval_load(const struct timeval *tv) {
127 if (tv->tv_sec == (time_t) -1 &&
128 tv->tv_usec == (suseconds_t) -1)
129 return USEC_INFINITY;
131 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
132 return USEC_INFINITY;
135 (usec_t) tv->tv_sec * USEC_PER_SEC +
136 (usec_t) tv->tv_usec;
139 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
142 if (u == USEC_INFINITY) {
143 tv->tv_sec = (time_t) -1;
144 tv->tv_usec = (suseconds_t) -1;
146 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
147 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
153 static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) {
160 if (t <= 0 || t == USEC_INFINITY)
163 sec = (time_t) (t / USEC_PER_SEC);
168 localtime_r(&sec, &tm);
169 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
175 char *format_timestamp(char *buf, size_t l, usec_t t) {
176 return format_timestamp_internal(buf, l, t, false);
179 /// UNNEEDED by elogind
181 char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
182 return format_timestamp_internal(buf, l, t, true);
186 static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) {
193 if (t <= 0 || t == USEC_INFINITY)
196 sec = (time_t) (t / USEC_PER_SEC);
200 localtime_r(&sec, &tm);
202 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
204 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
205 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
211 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
212 return format_timestamp_internal_us(buf, l, t, false);
215 /// UNNEEDED by elogind
217 char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
218 return format_timestamp_internal_us(buf, l, t, true);
222 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
226 if (t <= 0 || t == USEC_INFINITY)
229 n = now(CLOCK_REALTIME);
238 if (d >= USEC_PER_YEAR)
239 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
241 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
242 else if (d >= USEC_PER_MONTH)
243 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
245 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
246 else if (d >= USEC_PER_WEEK)
247 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
249 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
250 else if (d >= 2*USEC_PER_DAY)
251 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
252 else if (d >= 25*USEC_PER_HOUR)
253 snprintf(buf, l, "1 day " USEC_FMT "h %s",
254 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
255 else if (d >= 6*USEC_PER_HOUR)
256 snprintf(buf, l, USEC_FMT "h %s",
257 d / USEC_PER_HOUR, s);
258 else if (d >= USEC_PER_HOUR)
259 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
261 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
262 else if (d >= 5*USEC_PER_MINUTE)
263 snprintf(buf, l, USEC_FMT "min %s",
264 d / USEC_PER_MINUTE, s);
265 else if (d >= USEC_PER_MINUTE)
266 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
268 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
269 else if (d >= USEC_PER_SEC)
270 snprintf(buf, l, USEC_FMT "s %s",
271 d / USEC_PER_SEC, s);
272 else if (d >= USEC_PER_MSEC)
273 snprintf(buf, l, USEC_FMT "ms %s",
274 d / USEC_PER_MSEC, s);
276 snprintf(buf, l, USEC_FMT"us %s",
279 snprintf(buf, l, "now");
285 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
286 static const struct {
290 { "y", USEC_PER_YEAR },
291 { "month", USEC_PER_MONTH },
292 { "w", USEC_PER_WEEK },
293 { "d", USEC_PER_DAY },
294 { "h", USEC_PER_HOUR },
295 { "min", USEC_PER_MINUTE },
296 { "s", USEC_PER_SEC },
297 { "ms", USEC_PER_MSEC },
303 bool something = false;
308 if (t == USEC_INFINITY) {
309 strncpy(p, "infinity", l-1);
315 strncpy(p, "0", l-1);
320 /* The result of this function can be parsed with parse_sec */
322 for (i = 0; i < ELEMENTSOF(table); i++) {
331 if (t < accuracy && something)
334 if (t < table[i].usec)
340 a = t / table[i].usec;
341 b = t % table[i].usec;
343 /* Let's see if we should shows this in dot notation */
344 if (t < USEC_PER_MINUTE && b > 0) {
349 for (cc = table[i].usec; cc > 1; cc /= 10)
352 for (cc = accuracy; cc > 1; cc /= 10) {
359 "%s"USEC_FMT".%0*llu%s",
363 (unsigned long long) b,
371 /* No? Then let's show it normally */
382 n = MIN((size_t) k, l);
395 /// UNNEEDED by elogind
397 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
403 if (!dual_timestamp_is_set(t))
406 fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
412 int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
413 unsigned long long a, b;
418 if (sscanf(value, "%llu %llu", &a, &b) != 2) {
419 log_debug("Failed to parse finish timestamp value %s.", value);
429 int parse_timestamp(const char *t, usec_t *usec) {
430 static const struct {
453 usec_t plus = 0, minus = 0, ret;
460 * 2012-09-22 16:34:22
461 * 2012-09-22 16:34 (seconds will be set to 0)
462 * 2012-09-22 (time will be set to 00:00:00)
463 * 16:34:22 (date will be set to today)
464 * 16:34 (date will be set to today, seconds to 0)
466 * yesterday (time is set to 00:00:00)
467 * today (time is set to 00:00:00)
468 * tomorrow (time is set to 00:00:00)
471 * @2147483647 (seconds since epoch)
479 assert_se(localtime_r(&x, &tm));
485 else if (streq(t, "today")) {
486 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
489 } else if (streq(t, "yesterday")) {
491 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
494 } else if (streq(t, "tomorrow")) {
496 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
499 } else if (t[0] == '+') {
500 r = parse_sec(t+1, &plus);
506 } else if (t[0] == '-') {
507 r = parse_sec(t+1, &minus);
513 } else if (t[0] == '@')
514 return parse_sec(t + 1, usec);
516 else if (endswith(t, " ago")) {
517 _cleanup_free_ char *z;
519 z = strndup(t, strlen(t) - 4);
523 r = parse_sec(z, &minus);
528 } else if (endswith(t, " left")) {
529 _cleanup_free_ char *z;
531 z = strndup(t, strlen(t) - 4);
535 r = parse_sec(z, &plus);
542 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
545 if (!startswith_no_case(t, day_nr[i].name))
548 skip = strlen(day_nr[i].name);
552 weekday = day_nr[i].nr;
558 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
563 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
568 k = strptime(t, "%y-%m-%d %H:%M", &tm);
575 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
582 k = strptime(t, "%y-%m-%d", &tm);
584 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
589 k = strptime(t, "%Y-%m-%d", &tm);
591 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
596 k = strptime(t, "%H:%M:%S", &tm);
601 k = strptime(t, "%H:%M", &tm);
611 if (x == (time_t) -1)
614 if (weekday >= 0 && tm.tm_wday != weekday)
617 ret = (usec_t) x * USEC_PER_SEC;
631 int parse_sec(const char *t, usec_t *usec) {
632 static const struct {
636 { "seconds", USEC_PER_SEC },
637 { "second", USEC_PER_SEC },
638 { "sec", USEC_PER_SEC },
639 { "s", USEC_PER_SEC },
640 { "minutes", USEC_PER_MINUTE },
641 { "minute", USEC_PER_MINUTE },
642 { "min", USEC_PER_MINUTE },
643 { "months", USEC_PER_MONTH },
644 { "month", USEC_PER_MONTH },
645 { "msec", USEC_PER_MSEC },
646 { "ms", USEC_PER_MSEC },
647 { "m", USEC_PER_MINUTE },
648 { "hours", USEC_PER_HOUR },
649 { "hour", USEC_PER_HOUR },
650 { "hr", USEC_PER_HOUR },
651 { "h", USEC_PER_HOUR },
652 { "days", USEC_PER_DAY },
653 { "day", USEC_PER_DAY },
654 { "d", USEC_PER_DAY },
655 { "weeks", USEC_PER_WEEK },
656 { "week", USEC_PER_WEEK },
657 { "w", USEC_PER_WEEK },
658 { "years", USEC_PER_YEAR },
659 { "year", USEC_PER_YEAR },
660 { "y", USEC_PER_YEAR },
663 { "", USEC_PER_SEC }, /* default is sec */
668 bool something = false;
675 p += strspn(p, WHITESPACE);
676 s = startswith(p, "infinity");
678 s += strspn(s, WHITESPACE);
682 *usec = USEC_INFINITY;
691 p += strspn(p, WHITESPACE);
701 l = strtoll(p, &e, 10);
713 z = strtoll(b, &e, 10);
728 e += strspn(e, WHITESPACE);
730 for (i = 0; i < ELEMENTSOF(table); i++)
731 if (startswith(e, table[i].suffix)) {
732 usec_t k = (usec_t) z * table[i].usec;
737 r += (usec_t) l * table[i].usec + k;
738 p = e + strlen(table[i].suffix);
744 if (i >= ELEMENTSOF(table))
754 int parse_nsec(const char *t, nsec_t *nsec) {
755 static const struct {
759 { "seconds", NSEC_PER_SEC },
760 { "second", NSEC_PER_SEC },
761 { "sec", NSEC_PER_SEC },
762 { "s", NSEC_PER_SEC },
763 { "minutes", NSEC_PER_MINUTE },
764 { "minute", NSEC_PER_MINUTE },
765 { "min", NSEC_PER_MINUTE },
766 { "months", NSEC_PER_MONTH },
767 { "month", NSEC_PER_MONTH },
768 { "msec", NSEC_PER_MSEC },
769 { "ms", NSEC_PER_MSEC },
770 { "m", NSEC_PER_MINUTE },
771 { "hours", NSEC_PER_HOUR },
772 { "hour", NSEC_PER_HOUR },
773 { "hr", NSEC_PER_HOUR },
774 { "h", NSEC_PER_HOUR },
775 { "days", NSEC_PER_DAY },
776 { "day", NSEC_PER_DAY },
777 { "d", NSEC_PER_DAY },
778 { "weeks", NSEC_PER_WEEK },
779 { "week", NSEC_PER_WEEK },
780 { "w", NSEC_PER_WEEK },
781 { "years", NSEC_PER_YEAR },
782 { "year", NSEC_PER_YEAR },
783 { "y", NSEC_PER_YEAR },
784 { "usec", NSEC_PER_USEC },
785 { "us", NSEC_PER_USEC },
788 { "", 1ULL }, /* default is nsec */
793 bool something = false;
800 p += strspn(p, WHITESPACE);
801 s = startswith(p, "infinity");
803 s += strspn(s, WHITESPACE);
807 *nsec = NSEC_INFINITY;
816 p += strspn(p, WHITESPACE);
826 l = strtoll(p, &e, 10);
838 z = strtoll(b, &e, 10);
853 e += strspn(e, WHITESPACE);
855 for (i = 0; i < ELEMENTSOF(table); i++)
856 if (startswith(e, table[i].suffix)) {
857 nsec_t k = (nsec_t) z * table[i].nsec;
862 r += (nsec_t) l * table[i].nsec + k;
863 p = e + strlen(table[i].suffix);
869 if (i >= ELEMENTSOF(table))
879 /// UNNEEDED by elogind
881 bool ntp_synced(void) {
882 struct timex txc = {};
884 if (adjtimex(&txc) < 0)
887 if (txc.status & STA_UNSYNC)
893 int get_timezones(char ***ret) {
894 _cleanup_fclose_ FILE *f = NULL;
895 _cleanup_strv_free_ char **zones = NULL;
896 size_t n_zones = 0, n_allocated = 0;
900 zones = strv_new("UTC", NULL);
907 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
911 FOREACH_LINE(l, f, return -errno) {
917 if (isempty(p) || *p == '#')
920 /* Skip over country code */
921 p += strcspn(p, WHITESPACE);
922 p += strspn(p, WHITESPACE);
924 /* Skip over coordinates */
925 p += strcspn(p, WHITESPACE);
926 p += strspn(p, WHITESPACE);
928 /* Found timezone name */
929 k = strcspn(p, WHITESPACE);
937 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
942 zones[n_zones++] = w;
943 zones[n_zones] = NULL;
948 } else if (errno != ENOENT)
957 bool timezone_is_valid(const char *name) {
962 if (!name || *name == 0 || *name == '/')
965 for (p = name; *p; p++) {
966 if (!(*p >= '0' && *p <= '9') &&
967 !(*p >= 'a' && *p <= 'z') &&
968 !(*p >= 'A' && *p <= 'Z') &&
969 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
985 t = strjoina("/usr/share/zoneinfo/", name);
986 if (stat(t, &st) < 0)
989 if (!S_ISREG(st.st_mode))
995 clockid_t clock_boottime_or_monotonic(void) {
996 static clockid_t clock = -1;
1002 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1004 clock = CLOCK_MONOTONIC;
1007 clock = CLOCK_BOOTTIME;