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 int 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);
418 int parse_timestamp(const char *t, usec_t *usec) {
419 static const struct {
442 usec_t plus = 0, minus = 0, ret;
449 * 2012-09-22 16:34:22
450 * 2012-09-22 16:34 (seconds will be set to 0)
451 * 2012-09-22 (time will be set to 00:00:00)
452 * 16:34:22 (date will be set to today)
453 * 16:34 (date will be set to today, seconds to 0)
455 * yesterday (time is set to 00:00:00)
456 * today (time is set to 00:00:00)
457 * tomorrow (time is set to 00:00:00)
460 * @2147483647 (seconds since epoch)
468 assert_se(localtime_r(&x, &tm));
474 else if (streq(t, "today")) {
475 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
478 } else if (streq(t, "yesterday")) {
480 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
483 } else if (streq(t, "tomorrow")) {
485 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
488 } else if (t[0] == '+') {
489 r = parse_sec(t+1, &plus);
495 } else if (t[0] == '-') {
496 r = parse_sec(t+1, &minus);
502 } else if (t[0] == '@')
503 return parse_sec(t + 1, usec);
505 else if (endswith(t, " ago")) {
506 _cleanup_free_ char *z;
508 z = strndup(t, strlen(t) - 4);
512 r = parse_sec(z, &minus);
517 } else if (endswith(t, " left")) {
518 _cleanup_free_ char *z;
520 z = strndup(t, strlen(t) - 4);
524 r = parse_sec(z, &plus);
531 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
534 if (!startswith_no_case(t, day_nr[i].name))
537 skip = strlen(day_nr[i].name);
541 weekday = day_nr[i].nr;
547 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
552 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
557 k = strptime(t, "%y-%m-%d %H:%M", &tm);
564 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
571 k = strptime(t, "%y-%m-%d", &tm);
573 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
578 k = strptime(t, "%Y-%m-%d", &tm);
580 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
585 k = strptime(t, "%H:%M:%S", &tm);
590 k = strptime(t, "%H:%M", &tm);
600 if (x == (time_t) -1)
603 if (weekday >= 0 && tm.tm_wday != weekday)
606 ret = (usec_t) x * USEC_PER_SEC;
619 int parse_sec(const char *t, usec_t *usec) {
620 static const struct {
624 { "seconds", USEC_PER_SEC },
625 { "second", USEC_PER_SEC },
626 { "sec", USEC_PER_SEC },
627 { "s", USEC_PER_SEC },
628 { "minutes", USEC_PER_MINUTE },
629 { "minute", USEC_PER_MINUTE },
630 { "min", USEC_PER_MINUTE },
631 { "months", USEC_PER_MONTH },
632 { "month", USEC_PER_MONTH },
633 { "msec", USEC_PER_MSEC },
634 { "ms", USEC_PER_MSEC },
635 { "m", USEC_PER_MINUTE },
636 { "hours", USEC_PER_HOUR },
637 { "hour", USEC_PER_HOUR },
638 { "hr", USEC_PER_HOUR },
639 { "h", USEC_PER_HOUR },
640 { "days", USEC_PER_DAY },
641 { "day", USEC_PER_DAY },
642 { "d", USEC_PER_DAY },
643 { "weeks", USEC_PER_WEEK },
644 { "week", USEC_PER_WEEK },
645 { "w", USEC_PER_WEEK },
646 { "years", USEC_PER_YEAR },
647 { "year", USEC_PER_YEAR },
648 { "y", USEC_PER_YEAR },
651 { "", USEC_PER_SEC }, /* default is sec */
656 bool something = false;
663 p += strspn(p, WHITESPACE);
664 s = startswith(p, "infinity");
666 s += strspn(s, WHITESPACE);
670 *usec = USEC_INFINITY;
679 p += strspn(p, WHITESPACE);
689 l = strtoll(p, &e, 10);
701 z = strtoll(b, &e, 10);
716 e += strspn(e, WHITESPACE);
718 for (i = 0; i < ELEMENTSOF(table); i++)
719 if (startswith(e, table[i].suffix)) {
720 usec_t k = (usec_t) z * table[i].usec;
725 r += (usec_t) l * table[i].usec + k;
726 p = e + strlen(table[i].suffix);
732 if (i >= ELEMENTSOF(table))
742 int parse_nsec(const char *t, nsec_t *nsec) {
743 static const struct {
747 { "seconds", NSEC_PER_SEC },
748 { "second", NSEC_PER_SEC },
749 { "sec", NSEC_PER_SEC },
750 { "s", NSEC_PER_SEC },
751 { "minutes", NSEC_PER_MINUTE },
752 { "minute", NSEC_PER_MINUTE },
753 { "min", NSEC_PER_MINUTE },
754 { "months", NSEC_PER_MONTH },
755 { "month", NSEC_PER_MONTH },
756 { "msec", NSEC_PER_MSEC },
757 { "ms", NSEC_PER_MSEC },
758 { "m", NSEC_PER_MINUTE },
759 { "hours", NSEC_PER_HOUR },
760 { "hour", NSEC_PER_HOUR },
761 { "hr", NSEC_PER_HOUR },
762 { "h", NSEC_PER_HOUR },
763 { "days", NSEC_PER_DAY },
764 { "day", NSEC_PER_DAY },
765 { "d", NSEC_PER_DAY },
766 { "weeks", NSEC_PER_WEEK },
767 { "week", NSEC_PER_WEEK },
768 { "w", NSEC_PER_WEEK },
769 { "years", NSEC_PER_YEAR },
770 { "year", NSEC_PER_YEAR },
771 { "y", NSEC_PER_YEAR },
772 { "usec", NSEC_PER_USEC },
773 { "us", NSEC_PER_USEC },
776 { "", 1ULL }, /* default is nsec */
781 bool something = false;
788 p += strspn(p, WHITESPACE);
789 s = startswith(p, "infinity");
791 s += strspn(s, WHITESPACE);
795 *nsec = NSEC_INFINITY;
804 p += strspn(p, WHITESPACE);
814 l = strtoll(p, &e, 10);
826 z = strtoll(b, &e, 10);
841 e += strspn(e, WHITESPACE);
843 for (i = 0; i < ELEMENTSOF(table); i++)
844 if (startswith(e, table[i].suffix)) {
845 nsec_t k = (nsec_t) z * table[i].nsec;
850 r += (nsec_t) l * table[i].nsec + k;
851 p = e + strlen(table[i].suffix);
857 if (i >= ELEMENTSOF(table))
867 bool ntp_synced(void) {
868 struct timex txc = {};
870 if (adjtimex(&txc) < 0)
873 if (txc.status & STA_UNSYNC)
879 int get_timezones(char ***ret) {
880 _cleanup_fclose_ FILE *f = NULL;
881 _cleanup_strv_free_ char **zones = NULL;
882 size_t n_zones = 0, n_allocated = 0;
886 zones = strv_new("UTC", NULL);
893 f = fopen("/usr/share/zoneinfo/zone.tab", "re");
897 FOREACH_LINE(l, f, return -errno) {
903 if (isempty(p) || *p == '#')
906 /* Skip over country code */
907 p += strcspn(p, WHITESPACE);
908 p += strspn(p, WHITESPACE);
910 /* Skip over coordinates */
911 p += strcspn(p, WHITESPACE);
912 p += strspn(p, WHITESPACE);
914 /* Found timezone name */
915 k = strcspn(p, WHITESPACE);
923 if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
928 zones[n_zones++] = w;
929 zones[n_zones] = NULL;
934 } else if (errno != ENOENT)
943 bool timezone_is_valid(const char *name) {
948 if (!name || *name == 0 || *name == '/')
951 for (p = name; *p; p++) {
952 if (!(*p >= '0' && *p <= '9') &&
953 !(*p >= 'a' && *p <= 'z') &&
954 !(*p >= 'A' && *p <= 'Z') &&
955 !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
971 t = strjoina("/usr/share/zoneinfo/", name);
972 if (stat(t, &st) < 0)
975 if (!S_ISREG(st.st_mode))
981 clockid_t clock_boottime_or_monotonic(void) {
982 static clockid_t clock = -1;
988 fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
990 clock = CLOCK_MONOTONIC;
993 clock = CLOCK_BOOTTIME;