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>
27 #include "time-util.h"
29 usec_t now(clockid_t clock_id) {
32 assert_se(clock_gettime(clock_id, &ts) == 0);
34 return timespec_load(&ts);
37 dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
40 ts->realtime = now(CLOCK_REALTIME);
41 ts->monotonic = now(CLOCK_MONOTONIC);
46 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
50 if (u == (usec_t) -1) {
51 ts->realtime = ts->monotonic = (usec_t) -1;
60 delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
62 ts->monotonic = now(CLOCK_MONOTONIC);
64 if ((int64_t) ts->monotonic > delta)
65 ts->monotonic -= delta;
73 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
77 if (u == (usec_t) -1) {
78 ts->realtime = ts->monotonic = (usec_t) -1;
83 delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
85 ts->realtime = now(CLOCK_REALTIME);
86 if ((int64_t) ts->realtime > delta)
87 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)
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_t) -1) {
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)
131 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
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_t) -1) {
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 char *format_timestamp(char *buf, size_t l, usec_t t) {
160 if (t <= 0 || t == (usec_t) -1)
163 sec = (time_t) (t / USEC_PER_SEC);
165 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) <= 0)
171 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
178 if (t <= 0 || t == (usec_t) -1)
181 sec = (time_t) (t / USEC_PER_SEC);
182 localtime_r(&sec, &tm);
184 if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
186 snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", t % USEC_PER_SEC);
187 if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
193 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
197 n = now(CLOCK_REALTIME);
199 if (t <= 0 || (t == (usec_t) -1))
210 if (d >= USEC_PER_YEAR)
211 snprintf(buf, l, "%llu years %llu months %s",
212 (unsigned long long) (d / USEC_PER_YEAR),
213 (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH), s);
214 else if (d >= USEC_PER_MONTH)
215 snprintf(buf, l, "%llu months %llu days %s",
216 (unsigned long long) (d / USEC_PER_MONTH),
217 (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY), s);
218 else if (d >= USEC_PER_WEEK)
219 snprintf(buf, l, "%llu weeks %llu days %s",
220 (unsigned long long) (d / USEC_PER_WEEK),
221 (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY), s);
222 else if (d >= 2*USEC_PER_DAY)
223 snprintf(buf, l, "%llu days %s", (unsigned long long) (d / USEC_PER_DAY), s);
224 else if (d >= 25*USEC_PER_HOUR)
225 snprintf(buf, l, "1 day %lluh %s",
226 (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR), s);
227 else if (d >= 6*USEC_PER_HOUR)
228 snprintf(buf, l, "%lluh %s",
229 (unsigned long long) (d / USEC_PER_HOUR), s);
230 else if (d >= USEC_PER_HOUR)
231 snprintf(buf, l, "%lluh %llumin %s",
232 (unsigned long long) (d / USEC_PER_HOUR),
233 (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE), s);
234 else if (d >= 5*USEC_PER_MINUTE)
235 snprintf(buf, l, "%llumin %s",
236 (unsigned long long) (d / USEC_PER_MINUTE), s);
237 else if (d >= USEC_PER_MINUTE)
238 snprintf(buf, l, "%llumin %llus %s",
239 (unsigned long long) (d / USEC_PER_MINUTE),
240 (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC), s);
241 else if (d >= USEC_PER_SEC)
242 snprintf(buf, l, "%llus %s",
243 (unsigned long long) (d / USEC_PER_SEC), s);
244 else if (d >= USEC_PER_MSEC)
245 snprintf(buf, l, "%llums %s",
246 (unsigned long long) (d / USEC_PER_MSEC), s);
248 snprintf(buf, l, "%lluus %s",
249 (unsigned long long) d, s);
251 snprintf(buf, l, "now");
257 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
258 static const struct {
262 { "y", USEC_PER_YEAR },
263 { "month", USEC_PER_MONTH },
264 { "w", USEC_PER_WEEK },
265 { "d", USEC_PER_DAY },
266 { "h", USEC_PER_HOUR },
267 { "min", USEC_PER_MINUTE },
268 { "s", USEC_PER_SEC },
269 { "ms", USEC_PER_MSEC },
275 bool something = false;
280 if (t == (usec_t) -1)
289 /* The result of this function can be parsed with parse_sec */
291 for (i = 0; i < ELEMENTSOF(table); i++) {
300 if (t < accuracy && something)
303 if (t < table[i].usec)
309 a = t / table[i].usec;
310 b = t % table[i].usec;
312 /* Let's see if we should shows this in dot notation */
313 if (t < USEC_PER_MINUTE && b > 0) {
318 for (cc = table[i].usec; cc > 1; cc /= 10)
321 for (cc = accuracy; cc > 1; cc /= 10) {
330 (unsigned long long) a,
332 (unsigned long long) b,
340 /* No? Then let's show it normally */
345 (unsigned long long) a,
351 n = MIN((size_t) k, l);
364 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
370 if (!dual_timestamp_is_set(t))
373 fprintf(f, "%s=%llu %llu\n",
375 (unsigned long long) t->realtime,
376 (unsigned long long) t->monotonic);
379 void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
380 unsigned long long a, b;
385 if (sscanf(value, "%llu %llu", &a, &b) != 2)
386 log_debug("Failed to parse finish timestamp value %s", value);
393 int parse_timestamp(const char *t, usec_t *usec) {
394 static const struct {
417 usec_t plus = 0, minus = 0, ret;
424 * 2012-09-22 16:34:22
425 * 2012-09-22 16:34 (seconds will be set to 0)
426 * 2012-09-22 (time will be set to 00:00:00)
427 * 16:34:22 (date will be set to today)
428 * 16:34 (date will be set to today, seconds to 0)
430 * yesterday (time is set to 00:00:00)
431 * today (time is set to 00:00:00)
432 * tomorrow (time is set to 00:00:00)
435 * @2147483647 (seconds since epoch)
443 assert_se(localtime_r(&x, &tm));
449 else if (streq(t, "today")) {
450 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
453 } else if (streq(t, "yesterday")) {
455 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
458 } else if (streq(t, "tomorrow")) {
460 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
463 } else if (t[0] == '+') {
464 r = parse_sec(t+1, &plus);
470 } else if (t[0] == '-') {
471 r = parse_sec(t+1, &minus);
477 } else if (t[0] == '@')
478 return parse_sec(t + 1, usec);
480 else if (endswith(t, " ago")) {
481 _cleanup_free_ char *z;
483 z = strndup(t, strlen(t) - 4);
487 r = parse_sec(z, &minus);
492 } else if (endswith(t, " left")) {
493 _cleanup_free_ char *z;
495 z = strndup(t, strlen(t) - 4);
499 r = parse_sec(z, &plus);
506 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
509 if (!startswith_no_case(t, day_nr[i].name))
512 skip = strlen(day_nr[i].name);
516 weekday = day_nr[i].nr;
522 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
527 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
532 k = strptime(t, "%y-%m-%d %H:%M", &tm);
539 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
546 k = strptime(t, "%y-%m-%d", &tm);
548 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
553 k = strptime(t, "%Y-%m-%d", &tm);
555 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
560 k = strptime(t, "%H:%M:%S", &tm);
565 k = strptime(t, "%H:%M", &tm);
575 if (x == (time_t) -1)
578 if (weekday >= 0 && tm.tm_wday != weekday)
581 ret = (usec_t) x * USEC_PER_SEC;
594 int parse_sec(const char *t, usec_t *usec) {
595 static const struct {
599 { "seconds", USEC_PER_SEC },
600 { "second", USEC_PER_SEC },
601 { "sec", USEC_PER_SEC },
602 { "s", USEC_PER_SEC },
603 { "minutes", USEC_PER_MINUTE },
604 { "minute", USEC_PER_MINUTE },
605 { "min", USEC_PER_MINUTE },
606 { "months", USEC_PER_MONTH },
607 { "month", USEC_PER_MONTH },
608 { "msec", USEC_PER_MSEC },
609 { "ms", USEC_PER_MSEC },
610 { "m", USEC_PER_MINUTE },
611 { "hours", USEC_PER_HOUR },
612 { "hour", USEC_PER_HOUR },
613 { "hr", USEC_PER_HOUR },
614 { "h", USEC_PER_HOUR },
615 { "days", USEC_PER_DAY },
616 { "day", USEC_PER_DAY },
617 { "d", USEC_PER_DAY },
618 { "weeks", USEC_PER_WEEK },
619 { "week", USEC_PER_WEEK },
620 { "w", USEC_PER_WEEK },
621 { "years", USEC_PER_YEAR },
622 { "year", USEC_PER_YEAR },
623 { "y", USEC_PER_YEAR },
626 { "", USEC_PER_SEC }, /* default is sec */
631 bool something = false;
642 p += strspn(p, WHITESPACE);
652 l = strtoll(p, &e, 10);
664 z = strtoll(b, &e, 10);
679 e += strspn(e, WHITESPACE);
681 for (i = 0; i < ELEMENTSOF(table); i++)
682 if (startswith(e, table[i].suffix)) {
683 usec_t k = (usec_t) z * table[i].usec;
688 r += (usec_t) l * table[i].usec + k;
689 p = e + strlen(table[i].suffix);
695 if (i >= ELEMENTSOF(table))
705 int parse_nsec(const char *t, nsec_t *nsec) {
706 static const struct {
710 { "seconds", NSEC_PER_SEC },
711 { "second", NSEC_PER_SEC },
712 { "sec", NSEC_PER_SEC },
713 { "s", NSEC_PER_SEC },
714 { "minutes", NSEC_PER_MINUTE },
715 { "minute", NSEC_PER_MINUTE },
716 { "min", NSEC_PER_MINUTE },
717 { "months", NSEC_PER_MONTH },
718 { "month", NSEC_PER_MONTH },
719 { "msec", NSEC_PER_MSEC },
720 { "ms", NSEC_PER_MSEC },
721 { "m", NSEC_PER_MINUTE },
722 { "hours", NSEC_PER_HOUR },
723 { "hour", NSEC_PER_HOUR },
724 { "hr", NSEC_PER_HOUR },
725 { "h", NSEC_PER_HOUR },
726 { "days", NSEC_PER_DAY },
727 { "day", NSEC_PER_DAY },
728 { "d", NSEC_PER_DAY },
729 { "weeks", NSEC_PER_WEEK },
730 { "week", NSEC_PER_WEEK },
731 { "w", NSEC_PER_WEEK },
732 { "years", NSEC_PER_YEAR },
733 { "year", NSEC_PER_YEAR },
734 { "y", NSEC_PER_YEAR },
735 { "usec", NSEC_PER_USEC },
736 { "us", NSEC_PER_USEC },
739 { "", 1ULL }, /* default is nsec */
744 bool something = false;
755 p += strspn(p, WHITESPACE);
765 l = strtoll(p, &e, 10);
777 z = strtoll(b, &e, 10);
792 e += strspn(e, WHITESPACE);
794 for (i = 0; i < ELEMENTSOF(table); i++)
795 if (startswith(e, table[i].suffix)) {
796 nsec_t k = (nsec_t) z * table[i].nsec;
801 r += (nsec_t) l * table[i].nsec + k;
802 p = e + strlen(table[i].suffix);
808 if (i >= ELEMENTSOF(table))
818 bool ntp_synced(void) {
819 struct timex txc = {};
821 if (adjtimex(&txc) < 0)
824 if (txc.status & STA_UNSYNC)