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/>.
26 #include "time-util.h"
28 usec_t now(clockid_t clock_id) {
31 assert_se(clock_gettime(clock_id, &ts) == 0);
33 return timespec_load(&ts);
36 dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
39 ts->realtime = now(CLOCK_REALTIME);
40 ts->monotonic = now(CLOCK_MONOTONIC);
45 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
49 if (u == (usec_t) -1) {
50 ts->realtime = ts->monotonic = (usec_t) -1;
59 delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
61 ts->monotonic = now(CLOCK_MONOTONIC);
63 if ((int64_t) ts->monotonic > delta)
64 ts->monotonic -= delta;
72 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
76 if (u == (usec_t) -1) {
77 ts->realtime = ts->monotonic = (usec_t) -1;
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;
93 usec_t timespec_load(const struct timespec *ts) {
96 if (ts->tv_sec == (time_t) -1 &&
97 ts->tv_nsec == (long) -1)
100 if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
104 (usec_t) ts->tv_sec * USEC_PER_SEC +
105 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
108 struct timespec *timespec_store(struct timespec *ts, usec_t u) {
111 if (u == (usec_t) -1) {
112 ts->tv_sec = (time_t) -1;
113 ts->tv_nsec = (long) -1;
117 ts->tv_sec = (time_t) (u / USEC_PER_SEC);
118 ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
123 usec_t timeval_load(const struct timeval *tv) {
126 if (tv->tv_sec == (time_t) -1 &&
127 tv->tv_usec == (suseconds_t) -1)
130 if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
134 (usec_t) tv->tv_sec * USEC_PER_SEC +
135 (usec_t) tv->tv_usec;
138 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
141 if (u == (usec_t) -1) {
142 tv->tv_sec = (time_t) -1;
143 tv->tv_usec = (suseconds_t) -1;
147 tv->tv_sec = (time_t) (u / USEC_PER_SEC);
148 tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
153 char *format_timestamp(char *buf, size_t l, usec_t t) {
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_relative(char *buf, size_t l, usec_t t) {
174 n = now(CLOCK_REALTIME);
176 if (t <= 0 || t > n || t + USEC_PER_DAY*7 <= t)
181 if (d >= USEC_PER_YEAR)
182 snprintf(buf, l, "%llu years %llu months ago",
183 (unsigned long long) (d / USEC_PER_YEAR),
184 (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH));
185 else if (d >= USEC_PER_MONTH)
186 snprintf(buf, l, "%llu months %llu days ago",
187 (unsigned long long) (d / USEC_PER_MONTH),
188 (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY));
189 else if (d >= USEC_PER_WEEK)
190 snprintf(buf, l, "%llu weeks %llu days ago",
191 (unsigned long long) (d / USEC_PER_WEEK),
192 (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY));
193 else if (d >= 2*USEC_PER_DAY)
194 snprintf(buf, l, "%llu days ago", (unsigned long long) (d / USEC_PER_DAY));
195 else if (d >= 25*USEC_PER_HOUR)
196 snprintf(buf, l, "1 day %lluh ago",
197 (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR));
198 else if (d >= 6*USEC_PER_HOUR)
199 snprintf(buf, l, "%lluh ago",
200 (unsigned long long) (d / USEC_PER_HOUR));
201 else if (d >= USEC_PER_HOUR)
202 snprintf(buf, l, "%lluh %llumin ago",
203 (unsigned long long) (d / USEC_PER_HOUR),
204 (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE));
205 else if (d >= 5*USEC_PER_MINUTE)
206 snprintf(buf, l, "%llumin ago",
207 (unsigned long long) (d / USEC_PER_MINUTE));
208 else if (d >= USEC_PER_MINUTE)
209 snprintf(buf, l, "%llumin %llus ago",
210 (unsigned long long) (d / USEC_PER_MINUTE),
211 (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC));
212 else if (d >= USEC_PER_SEC)
213 snprintf(buf, l, "%llus ago",
214 (unsigned long long) (d / USEC_PER_SEC));
215 else if (d >= USEC_PER_MSEC)
216 snprintf(buf, l, "%llums ago",
217 (unsigned long long) (d / USEC_PER_MSEC));
219 snprintf(buf, l, "%lluus ago",
220 (unsigned long long) d);
222 snprintf(buf, l, "now");
228 char *format_timespan(char *buf, size_t l, usec_t t) {
229 static const struct {
233 { "y", USEC_PER_YEAR },
234 { "month", USEC_PER_MONTH },
235 { "w", USEC_PER_WEEK },
236 { "d", USEC_PER_DAY },
237 { "h", USEC_PER_HOUR },
238 { "min", USEC_PER_MINUTE },
239 { "s", USEC_PER_SEC },
240 { "ms", USEC_PER_MSEC },
250 if (t == (usec_t) -1)
259 /* The result of this function can be parsed with parse_usec */
261 for (i = 0; i < ELEMENTSOF(table); i++) {
265 if (t < table[i].usec)
271 k = snprintf(p, l, "%s%llu%s", p > buf ? " " : "", (unsigned long long) (t / table[i].usec), table[i].suffix);
272 n = MIN((size_t) k, l);
285 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
291 if (!dual_timestamp_is_set(t))
294 fprintf(f, "%s=%llu %llu\n",
296 (unsigned long long) t->realtime,
297 (unsigned long long) t->monotonic);
300 void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
301 unsigned long long a, b;
306 if (sscanf(value, "%lli %llu", &a, &b) != 2)
307 log_debug("Failed to parse finish timestamp value %s", value);
314 int parse_timestamp(const char *t, usec_t *usec) {
315 static const struct {
338 usec_t plus = 0, minus = 0, ret;
345 * 2012-09-22 16:34:22
346 * 2012-09-22 16:34 (seconds will be set to 0)
347 * 2012-09-22 (time will be set to 00:00:00)
348 * 16:34:22 (date will be set to today)
349 * 16:34 (date will be set to today, seconds to 0)
351 * yesterday (time is set to 00:00:00)
352 * today (time is set to 00:00:00)
353 * tomorrow (time is set to 00:00:00)
363 assert_se(localtime_r(&x, &tm));
369 else if (streq(t, "today")) {
370 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
373 } else if (streq(t, "yesterday")) {
375 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
378 } else if (streq(t, "tomorrow")) {
380 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
383 } else if (t[0] == '+') {
385 r = parse_usec(t+1, &plus);
390 } else if (t[0] == '-') {
392 r = parse_usec(t+1, &minus);
398 } else if (endswith(t, " ago")) {
399 _cleanup_free_ char *z;
401 z = strndup(t, strlen(t) - 4);
405 r = parse_usec(z, &minus);
412 for (i = 0; i < ELEMENTSOF(day_nr); i++) {
415 if (!startswith_no_case(t, day_nr[i].name))
418 skip = strlen(day_nr[i].name);
422 weekday = day_nr[i].nr;
428 k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
433 k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
438 k = strptime(t, "%y-%m-%d %H:%M", &tm);
445 k = strptime(t, "%Y-%m-%d %H:%M", &tm);
452 k = strptime(t, "%y-%m-%d", &tm);
454 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
459 k = strptime(t, "%Y-%m-%d", &tm);
461 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
466 k = strptime(t, "%H:%M:%S", &tm);
471 k = strptime(t, "%H:%M", &tm);
481 if (x == (time_t) -1)
484 if (weekday >= 0 && tm.tm_wday != weekday)
487 ret = (usec_t) x * USEC_PER_SEC;
500 int parse_usec(const char *t, usec_t *usec) {
501 static const struct {
505 { "seconds", USEC_PER_SEC },
506 { "second", USEC_PER_SEC },
507 { "sec", USEC_PER_SEC },
508 { "s", USEC_PER_SEC },
509 { "minutes", USEC_PER_MINUTE },
510 { "minute", USEC_PER_MINUTE },
511 { "min", USEC_PER_MINUTE },
512 { "months", USEC_PER_MONTH },
513 { "month", USEC_PER_MONTH },
514 { "msec", USEC_PER_MSEC },
515 { "ms", USEC_PER_MSEC },
516 { "m", USEC_PER_MINUTE },
517 { "hours", USEC_PER_HOUR },
518 { "hour", USEC_PER_HOUR },
519 { "hr", USEC_PER_HOUR },
520 { "h", USEC_PER_HOUR },
521 { "days", USEC_PER_DAY },
522 { "day", USEC_PER_DAY },
523 { "d", USEC_PER_DAY },
524 { "weeks", USEC_PER_WEEK },
525 { "week", USEC_PER_WEEK },
526 { "w", USEC_PER_WEEK },
527 { "years", USEC_PER_YEAR },
528 { "year", USEC_PER_YEAR },
529 { "y", USEC_PER_YEAR },
532 { "", USEC_PER_SEC }, /* default is sec */
548 l = strtoll(p, &e, 10);
559 e += strspn(e, WHITESPACE);
561 for (i = 0; i < ELEMENTSOF(table); i++)
562 if (startswith(e, table[i].suffix)) {
563 r += (usec_t) l * table[i].usec;
564 p = e + strlen(table[i].suffix);
568 if (i >= ELEMENTSOF(table))
578 int parse_nsec(const char *t, nsec_t *nsec) {
579 static const struct {
583 { "seconds", NSEC_PER_SEC },
584 { "second", NSEC_PER_SEC },
585 { "sec", NSEC_PER_SEC },
586 { "s", NSEC_PER_SEC },
587 { "minutes", NSEC_PER_MINUTE },
588 { "minute", NSEC_PER_MINUTE },
589 { "min", NSEC_PER_MINUTE },
590 { "months", NSEC_PER_MONTH },
591 { "month", NSEC_PER_MONTH },
592 { "msec", NSEC_PER_MSEC },
593 { "ms", NSEC_PER_MSEC },
594 { "m", NSEC_PER_MINUTE },
595 { "hours", NSEC_PER_HOUR },
596 { "hour", NSEC_PER_HOUR },
597 { "hr", NSEC_PER_HOUR },
598 { "h", NSEC_PER_HOUR },
599 { "days", NSEC_PER_DAY },
600 { "day", NSEC_PER_DAY },
601 { "d", NSEC_PER_DAY },
602 { "weeks", NSEC_PER_WEEK },
603 { "week", NSEC_PER_WEEK },
604 { "w", NSEC_PER_WEEK },
605 { "years", NSEC_PER_YEAR },
606 { "year", NSEC_PER_YEAR },
607 { "y", NSEC_PER_YEAR },
608 { "usec", NSEC_PER_USEC },
609 { "us", NSEC_PER_USEC },
612 { "", 1ULL }, /* default is nsec */
628 l = strtoll(p, &e, 10);
639 e += strspn(e, WHITESPACE);
641 for (i = 0; i < ELEMENTSOF(table); i++)
642 if (startswith(e, table[i].suffix)) {
643 r += (nsec_t) l * table[i].nsec;
644 p = e + strlen(table[i].suffix);
648 if (i >= ELEMENTSOF(table))