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 dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) {
97 if (u == USEC_INFINITY) {
98 ts->realtime = ts->monotonic = USEC_INFINITY;
101 ts->realtime = now(CLOCK_REALTIME);
102 ts->monotonic = now(CLOCK_MONOTONIC);
104 delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u;
106 if ((int64_t) ts->realtime > delta)
107 ts->realtime -= delta;
111 if ((int64_t) ts->monotonic > delta)
112 ts->monotonic -= delta;
120 usec_t timespec_load(const struct timespec *ts) {
123 if (ts->tv_sec == (time_t) -1 &&
124 ts->tv_nsec == (long) -1)
125 return USEC_INFINITY;
127 if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
128 return USEC_INFINITY;
131 (usec_t) ts->tv_sec * USEC_PER_SEC +
132 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
135 struct timespec *timespec_store(struct timespec *ts, usec_t u) {
138 if (u == USEC_INFINITY) {
139 ts->tv_sec = (time_t) -1;
140 ts->tv_nsec = (long) -1;
144 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
145 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
150 usec_t timeval_load(const struct timeval *tv) {
153 if (tv->tv_sec == (time_t) -1 &&
154 tv->tv_usec == (suseconds_t) -1)
155 return USEC_INFINITY;
157 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
158 return USEC_INFINITY;
161 (usec_t) tv->tv_sec * USEC_PER_SEC +
162 (usec_t) tv->tv_usec;
165 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
168 if (u == USEC_INFINITY) {
169 tv->tv_sec = (time_t) -1;
170 tv->tv_usec = (suseconds_t) -1;
172 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
173 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
179 static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) {
186 if (t <= 0 || t == USEC_INFINITY)
189 sec = (time_t) (t / USEC_PER_SEC);
194 localtime_r(&sec, &tm);
195 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
201 char *format_timestamp(char *buf, size_t l, usec_t t) {
202 return format_timestamp_internal(buf, l, t, false);
205 /// UNNEEDED by elogind
207 char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
208 return format_timestamp_internal(buf, l, t, true);
212 static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) {
219 if (t <= 0 || t == USEC_INFINITY)
222 sec = (time_t) (t / USEC_PER_SEC);
226 localtime_r(&sec, &tm);
228 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
230 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
231 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
237 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
238 return format_timestamp_internal_us(buf, l, t, false);
241 /// UNNEEDED by elogind
243 char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
244 return format_timestamp_internal_us(buf, l, t, true);
248 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
252 if (t <= 0 || t == USEC_INFINITY)
255 n = now(CLOCK_REALTIME);
264 if (d >= USEC_PER_YEAR)
265 snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
267 (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
268 else if (d >= USEC_PER_MONTH)
269 snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
271 (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
272 else if (d >= USEC_PER_WEEK)
273 snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
275 (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
276 else if (d >= 2*USEC_PER_DAY)
277 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
278 else if (d >= 25*USEC_PER_HOUR)
279 snprintf(buf, l, "1 day " USEC_FMT "h %s",
280 (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
281 else if (d >= 6*USEC_PER_HOUR)
282 snprintf(buf, l, USEC_FMT "h %s",
283 d / USEC_PER_HOUR, s);
284 else if (d >= USEC_PER_HOUR)
285 snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
287 (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
288 else if (d >= 5*USEC_PER_MINUTE)
289 snprintf(buf, l, USEC_FMT "min %s",
290 d / USEC_PER_MINUTE, s);
291 else if (d >= USEC_PER_MINUTE)
292 snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
294 (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
295 else if (d >= USEC_PER_SEC)
296 snprintf(buf, l, USEC_FMT "s %s",
297 d / USEC_PER_SEC, s);
298 else if (d >= USEC_PER_MSEC)
299 snprintf(buf, l, USEC_FMT "ms %s",
300 d / USEC_PER_MSEC, s);
302 snprintf(buf, l, USEC_FMT"us %s",
305 snprintf(buf, l, "now");
311 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
312 static const struct {
316 { "y", USEC_PER_YEAR },
317 { "month", USEC_PER_MONTH },
318 { "w", USEC_PER_WEEK },
319 { "d", USEC_PER_DAY },
320 { "h", USEC_PER_HOUR },
321 { "min", USEC_PER_MINUTE },
322 { "s", USEC_PER_SEC },
323 { "ms", USEC_PER_MSEC },
329 bool something = false;
334 if (t == USEC_INFINITY) {
335 strncpy(p, "infinity", l-1);
341 strncpy(p, "0", l-1);
346 /* The result of this function can be parsed with parse_sec */
348 for (i = 0; i < ELEMENTSOF(table); i++) {
357 if (t < accuracy && something)
360 if (t < table[i].usec)
366 a = t / table[i].usec;
367 b = t % table[i].usec;
369 /* Let's see if we should shows this in dot notation */
370 if (t < USEC_PER_MINUTE && b > 0) {
375 for (cc = table[i].usec; cc > 1; cc /= 10)
378 for (cc = accuracy; cc > 1; cc /= 10) {
385 "%s"USEC_FMT".%0*llu%s",
389 (unsigned long long) b,
397 /* No? Then let's show it normally */
408 n = MIN((size_t) k, l);
421 /// UNNEEDED by elogind
423 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
429 if (!dual_timestamp_is_set(t))
432 fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n",
438 int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
439 unsigned long long a, b;
444 if (sscanf(value, "%llu %llu", &a, &b) != 2) {
445 log_debug("Failed to parse finish timestamp value %s.", value);
455 int parse_timestamp(const char *t, usec_t *usec) {
456 static const struct {
479 usec_t plus = 0, minus = 0, ret;
486 * 2012-09-22 16:34:22
487 * 2012-09-22 16:34 (seconds will be set to 0)
488 * 2012-09-22 (time will be set to 00:00:00)
489 * 16:34:22 (date will be set to today)
490 * 16:34 (date will be set to today, seconds to 0)
492 * yesterday (time is set to 00:00:00)
493 * today (time is set to 00:00:00)
494 * tomorrow (time is set to 00:00:00)
497 * @2147483647 (seconds since epoch)
505 assert_se(localtime_r(&x, &tm));
511 else if (streq(t, "today")) {
512 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
515 } else if (streq(t, "yesterday")) {
517 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
520 } else if (streq(t, "tomorrow")) {
522 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
525 } else if (t[0] == '+') {
526 r = parse_sec(t+1, &plus);
532 } else if (t[0] == '-') {
533 r = parse_sec(t+1, &minus);
539 } else if (t[0] == '@')
540 return parse_sec(t + 1, usec);
542 else if (endswith(t, " ago")) {
543 _cleanup_free_ char *z;
545 z = strndup(t, strlen(t) - 4);
549 r = parse_sec(z, &minus);
554 } else if (endswith(t, " left")) {
555 _cleanup_free_ char *z;
557 z = strndup(t, strlen(t) - 4);
561 r = parse_sec(z, &plus);
568 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
571 if (!startswith_no_case(t, day_nr[i].name))
574 skip = strlen(day_nr[i].name);
578 weekday = day_nr[i].nr;
584 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
589 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
594 k = strptime(t, "%y-%m-%d %H:%M", &tm);
601 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
608 k = strptime(t, "%y-%m-%d", &tm);
610 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
615 k = strptime(t, "%Y-%m-%d", &tm);
617 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
622 k = strptime(t, "%H:%M:%S", &tm);
627 k = strptime(t, "%H:%M", &tm);
637 if (x == (time_t) -1)
640 if (weekday >= 0 && tm.tm_wday != weekday)
643 ret = (usec_t) x * USEC_PER_SEC;
657 int parse_sec(const char *t, usec_t *usec) {
658 static const struct {
662 { "seconds", USEC_PER_SEC },
663 { "second", USEC_PER_SEC },
664 { "sec", USEC_PER_SEC },
665 { "s", USEC_PER_SEC },
666 { "minutes", USEC_PER_MINUTE },
667 { "minute", USEC_PER_MINUTE },
668 { "min", USEC_PER_MINUTE },
669 { "months", USEC_PER_MONTH },
670 { "month", USEC_PER_MONTH },
671 { "msec", USEC_PER_MSEC },
672 { "ms", USEC_PER_MSEC },
673 { "m", USEC_PER_MINUTE },
674 { "hours", USEC_PER_HOUR },
675 { "hour", USEC_PER_HOUR },
676 { "hr", USEC_PER_HOUR },
677 { "h", USEC_PER_HOUR },
678 { "days", USEC_PER_DAY },
679 { "day", USEC_PER_DAY },
680 { "d", USEC_PER_DAY },
681 { "weeks", USEC_PER_WEEK },
682 { "week", USEC_PER_WEEK },
683 { "w", USEC_PER_WEEK },
684 { "years", USEC_PER_YEAR },
685 { "year", USEC_PER_YEAR },
686 { "y", USEC_PER_YEAR },
689 { "", USEC_PER_SEC }, /* default is sec */
694 bool something = false;
701 p += strspn(p, WHITESPACE);
702 s = startswith(p, "infinity");
704 s += strspn(s, WHITESPACE);
708 *usec = USEC_INFINITY;
717 p += strspn(p, WHITESPACE);
727 l = strtoll(p, &e, 10);
739 z = strtoll(b, &e, 10);
754 e += strspn(e, WHITESPACE);
756 for (i = 0; i < ELEMENTSOF(table); i++)
757 if (startswith(e, table[i].suffix)) {
758 usec_t k = (usec_t) z * table[i].usec;
763 r += (usec_t) l * table[i].usec + k;
764 p = e + strlen(table[i].suffix);
770 if (i >= ELEMENTSOF(table))
780 int parse_nsec(const char *t, nsec_t *nsec) {
781 static const struct {
785 { "seconds", NSEC_PER_SEC },
786 { "second", NSEC_PER_SEC },
787 { "sec", NSEC_PER_SEC },
788 { "s", NSEC_PER_SEC },
789 { "minutes", NSEC_PER_MINUTE },
790 { "minute", NSEC_PER_MINUTE },
791 { "min", NSEC_PER_MINUTE },
792 { "months", NSEC_PER_MONTH },
793 { "month", NSEC_PER_MONTH },
794 { "msec", NSEC_PER_MSEC },
795 { "ms", NSEC_PER_MSEC },
796 { "m", NSEC_PER_MINUTE },
797 { "hours", NSEC_PER_HOUR },
798 { "hour", NSEC_PER_HOUR },
799 { "hr", NSEC_PER_HOUR },
800 { "h", NSEC_PER_HOUR },
801 { "days", NSEC_PER_DAY },
802 { "day", NSEC_PER_DAY },
803 { "d", NSEC_PER_DAY },
804 { "weeks", NSEC_PER_WEEK },
805 { "week", NSEC_PER_WEEK },
806 { "w", NSEC_PER_WEEK },
807 { "years", NSEC_PER_YEAR },
808 { "year", NSEC_PER_YEAR },
809 { "y", NSEC_PER_YEAR },
810 { "usec", NSEC_PER_USEC },
811 { "us", NSEC_PER_USEC },
814 { "", 1ULL }, /* default is nsec */
819 bool something = false;
826 p += strspn(p, WHITESPACE);
827 s = startswith(p, "infinity");
829 s += strspn(s, WHITESPACE);
833 *nsec = NSEC_INFINITY;
842 p += strspn(p, WHITESPACE);
852 l = strtoll(p, &e, 10);
864 z = strtoll(b, &e, 10);
879 e += strspn(e, WHITESPACE);
881 for (i = 0; i < ELEMENTSOF(table); i++)
882 if (startswith(e, table[i].suffix)) {
883 nsec_t k = (nsec_t) z * table[i].nsec;
888 r += (nsec_t) l * table[i].nsec + k;
889 p = e + strlen(table[i].suffix);
895 if (i >= ELEMENTSOF(table))
905 /// UNNEEDED by elogind
907 bool ntp_synced(void) {
908 struct timex txc = {};
910 if (adjtimex(&txc) < 0)
913 if (txc.status & STA_UNSYNC)
919 int get_timezones(char ***ret) {
920 _cleanup_fclose_ FILE *f = NULL;
921 _cleanup_strv_free_ char **zones = NULL;
922 size_t n_zones = 0, n_allocated = 0;
926 zones = strv_new("UTC", NULL);
933 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
937 FOREACH_LINE(l, f, return -errno) {
943 if (isempty(p) || *p == '#')
946 /* Skip over country code */
947 p += strcspn(p, WHITESPACE);
948 p += strspn(p, WHITESPACE);
950 /* Skip over coordinates */
951 p += strcspn(p, WHITESPACE);
952 p += strspn(p, WHITESPACE);
954 /* Found timezone name */
955 k = strcspn(p, WHITESPACE);
963 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
968 zones[n_zones++] = w;
969 zones[n_zones] = NULL;
974 } else if (errno != ENOENT)
983 bool timezone_is_valid(const char *name) {
988 if (!name || *name == 0 || *name == '/')
991 for (p = name; *p; p++) {
992 if (!(*p >= '0' && *p <= '9') &&
993 !(*p >= 'a' && *p <= 'z') &&
994 !(*p >= 'A' && *p <= 'Z') &&
995 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
1011 t = strjoina("/usr/share/zoneinfo/", name);
1012 if (stat(t, &st) < 0)
1015 if (!S_ISREG(st.st_mode))
1022 clockid_t clock_boottime_or_monotonic(void) {
1023 static clockid_t clock = -1;
1029 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
1031 clock = CLOCK_MONOTONIC;
1034 clock = CLOCK_BOOTTIME;