diff options
| author | Manuel Bentele | 2020-10-23 15:18:01 +0200 |
|---|---|---|
| committer | Manuel Bentele | 2020-10-23 15:18:01 +0200 |
| commit | dbb41ce2b7f309d394054a6bd1e33afd578798a5 (patch) | |
| tree | 6a31092063d9f2fb5ac5720ec6759040e793c3d5 /utils/lib/timeutils.c | |
| parent | Set Linux kernel version to unknown if it is not detectable (diff) | |
| download | xloop-dbb41ce2b7f309d394054a6bd1e33afd578798a5.tar.gz xloop-dbb41ce2b7f309d394054a6bd1e33afd578798a5.tar.xz xloop-dbb41ce2b7f309d394054a6bd1e33afd578798a5.zip | |
Move the source code of all xloop components to the common 'src' directory
Diffstat (limited to 'utils/lib/timeutils.c')
| -rw-r--r-- | utils/lib/timeutils.c | 611 |
1 files changed, 0 insertions, 611 deletions
diff --git a/utils/lib/timeutils.c b/utils/lib/timeutils.c deleted file mode 100644 index 8b443cd..0000000 --- a/utils/lib/timeutils.c +++ /dev/null @@ -1,611 +0,0 @@ -/*** - First set of functions in this file are part of systemd, and were - copied to util-linux at August 2013. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with util-linux; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <assert.h> -#include <ctype.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <sys/time.h> - -#include "c.h" -#include "nls.h" -#include "strutils.h" -#include "timeutils.h" - -#define WHITESPACE " \t\n\r" - -#define streq(a,b) (strcmp((a),(b)) == 0) - -static int parse_sec(const char *t, usec_t *usec) -{ - static const struct { - const char *suffix; - usec_t usec; - } table[] = { - { "seconds", USEC_PER_SEC }, - { "second", USEC_PER_SEC }, - { "sec", USEC_PER_SEC }, - { "s", USEC_PER_SEC }, - { "minutes", USEC_PER_MINUTE }, - { "minute", USEC_PER_MINUTE }, - { "min", USEC_PER_MINUTE }, - { "months", USEC_PER_MONTH }, - { "month", USEC_PER_MONTH }, - { "msec", USEC_PER_MSEC }, - { "ms", USEC_PER_MSEC }, - { "m", USEC_PER_MINUTE }, - { "hours", USEC_PER_HOUR }, - { "hour", USEC_PER_HOUR }, - { "hr", USEC_PER_HOUR }, - { "h", USEC_PER_HOUR }, - { "days", USEC_PER_DAY }, - { "day", USEC_PER_DAY }, - { "d", USEC_PER_DAY }, - { "weeks", USEC_PER_WEEK }, - { "week", USEC_PER_WEEK }, - { "w", USEC_PER_WEEK }, - { "years", USEC_PER_YEAR }, - { "year", USEC_PER_YEAR }, - { "y", USEC_PER_YEAR }, - { "usec", 1ULL }, - { "us", 1ULL }, - { "", USEC_PER_SEC }, /* default is sec */ - }; - - const char *p; - usec_t r = 0; - int something = FALSE; - - assert(t); - assert(usec); - - p = t; - for (;;) { - long long l, z = 0; - char *e; - unsigned i, n = 0; - - p += strspn(p, WHITESPACE); - - if (*p == 0) { - if (!something) - return -EINVAL; - - break; - } - - errno = 0; - l = strtoll(p, &e, 10); - - if (errno > 0) - return -errno; - - if (l < 0) - return -ERANGE; - - if (*e == '.') { - char *b = e + 1; - - errno = 0; - z = strtoll(b, &e, 10); - if (errno > 0) - return -errno; - - if (z < 0) - return -ERANGE; - - if (e == b) - return -EINVAL; - - n = e - b; - - } else if (e == p) - return -EINVAL; - - e += strspn(e, WHITESPACE); - - for (i = 0; i < ARRAY_SIZE(table); i++) - if (startswith(e, table[i].suffix)) { - usec_t k = (usec_t) z * table[i].usec; - - for (; n > 0; n--) - k /= 10; - - r += (usec_t) l *table[i].usec + k; - p = e + strlen(table[i].suffix); - - something = TRUE; - break; - } - - if (i >= ARRAY_SIZE(table)) - return -EINVAL; - - } - - *usec = r; - - return 0; -} - -int parse_timestamp(const char *t, usec_t *usec) -{ - static const struct { - const char *name; - const int nr; - } day_nr[] = { - { "Sunday", 0 }, - { "Sun", 0 }, - { "Monday", 1 }, - { "Mon", 1 }, - { "Tuesday", 2 }, - { "Tue", 2 }, - { "Wednesday", 3 }, - { "Wed", 3 }, - { "Thursday", 4 }, - { "Thu", 4 }, - { "Friday", 5 }, - { "Fri", 5 }, - { "Saturday", 6 }, - { "Sat", 6 }, - }; - - const char *k; - struct tm tm, copy; - time_t x; - usec_t plus = 0, minus = 0, ret; - int r, weekday = -1; - unsigned i; - - /* - * Allowed syntaxes: - * - * 2012-09-22 16:34:22 - * 2012-09-22T16:34:22 - * 2012-09-22 16:34 (seconds will be set to 0) - * 2012-09-22 (time will be set to 00:00:00) - * 16:34:22 (date will be set to today) - * 16:34 (date will be set to today, seconds to 0) - * now - * yesterday (time is set to 00:00:00) - * today (time is set to 00:00:00) - * tomorrow (time is set to 00:00:00) - * +5min - * -5days - * - */ - - assert(t); - assert(usec); - - x = time(NULL); - localtime_r(&x, &tm); - tm.tm_isdst = -1; - - if (streq(t, "now")) - goto finish; - - else if (streq(t, "today")) { - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - - } else if (streq(t, "yesterday")) { - tm.tm_mday--; - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - - } else if (streq(t, "tomorrow")) { - tm.tm_mday++; - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - - } else if (t[0] == '+') { - - r = parse_sec(t + 1, &plus); - if (r < 0) - return r; - - goto finish; - } else if (t[0] == '-') { - - r = parse_sec(t + 1, &minus); - if (r < 0) - return r; - - goto finish; - - } else if (endswith(t, " ago")) { - char *z; - - z = strndup(t, strlen(t) - 4); - if (!z) - return -ENOMEM; - - r = parse_sec(z, &minus); - free(z); - if (r < 0) - return r; - - goto finish; - } - - for (i = 0; i < ARRAY_SIZE(day_nr); i++) { - size_t skip; - - if (!startswith_no_case(t, day_nr[i].name)) - continue; - - skip = strlen(day_nr[i].name); - if (t[skip] != ' ') - continue; - - weekday = day_nr[i].nr; - t += skip + 1; - break; - } - - copy = tm; - k = strptime(t, "%y-%m-%d %H:%M:%S", &tm); - if (k && *k == 0) - goto finish; - - tm = copy; - k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm); - if (k && *k == 0) - goto finish; - - tm = copy; - k = strptime(t, "%Y-%m-%dT%H:%M:%S", &tm); - if (k && *k == 0) - goto finish; - - tm = copy; - k = strptime(t, "%y-%m-%d %H:%M", &tm); - if (k && *k == 0) { - tm.tm_sec = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%Y-%m-%d %H:%M", &tm); - if (k && *k == 0) { - tm.tm_sec = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%y-%m-%d", &tm); - if (k && *k == 0) { - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%Y-%m-%d", &tm); - if (k && *k == 0) { - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%H:%M:%S", &tm); - if (k && *k == 0) - goto finish; - - tm = copy; - k = strptime(t, "%H:%M", &tm); - if (k && *k == 0) { - tm.tm_sec = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%Y%m%d%H%M%S", &tm); - if (k && *k == 0) { - tm.tm_sec = 0; - goto finish; - } - - return -EINVAL; - - finish: - x = mktime(&tm); - if (x == (time_t)-1) - return -EINVAL; - - if (weekday >= 0 && tm.tm_wday != weekday) - return -EINVAL; - - ret = (usec_t) x *USEC_PER_SEC; - - ret += plus; - if (ret > minus) - ret -= minus; - else - ret = 0; - - *usec = ret; - - return 0; -} - -/* Returns the difference in seconds between its argument and GMT. If if TP is - * invalid or no DST information is available default to UTC, that is, zero. - * tzset is called so, for example, 'TZ="UTC" hwclock' will work as expected. - * Derived from glibc/time/strftime_l.c - */ -int get_gmtoff(const struct tm *tp) -{ - if (tp->tm_isdst < 0) - return 0; - -#if HAVE_TM_GMTOFF - return tp->tm_gmtoff; -#else - struct tm tm; - struct tm gtm; - struct tm ltm = *tp; - time_t lt; - - tzset(); - lt = mktime(<m); - /* Check if mktime returning -1 is an error or a valid time_t */ - if (lt == (time_t) -1) { - if (! localtime_r(<, &tm) - || ((ltm.tm_sec ^ tm.tm_sec) - | (ltm.tm_min ^ tm.tm_min) - | (ltm.tm_hour ^ tm.tm_hour) - | (ltm.tm_mday ^ tm.tm_mday) - | (ltm.tm_mon ^ tm.tm_mon) - | (ltm.tm_year ^ tm.tm_year))) - return 0; - } - - if (! gmtime_r(<, >m)) - return 0; - - /* Calculate the GMT offset, that is, the difference between the - * TP argument (ltm) and GMT (gtm). - * - * Compute intervening leap days correctly even if year is negative. - * Take care to avoid int overflow in leap day calculations, but it's OK - * to assume that A and B are close to each other. - */ - int a4 = (ltm.tm_year >> 2) + (1900 >> 2) - ! (ltm.tm_year & 3); - int b4 = (gtm.tm_year >> 2) + (1900 >> 2) - ! (gtm.tm_year & 3); - int a100 = a4 / 25 - (a4 % 25 < 0); - int b100 = b4 / 25 - (b4 % 25 < 0); - int a400 = a100 >> 2; - int b400 = b100 >> 2; - int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); - - int years = ltm.tm_year - gtm.tm_year; - int days = (365 * years + intervening_leap_days - + (ltm.tm_yday - gtm.tm_yday)); - - return (60 * (60 * (24 * days + (ltm.tm_hour - gtm.tm_hour)) - + (ltm.tm_min - gtm.tm_min)) + (ltm.tm_sec - gtm.tm_sec)); -#endif -} - -static int format_iso_time(struct tm *tm, suseconds_t usec, int flags, char *buf, size_t bufsz) -{ - char *p = buf; - int len; - - if (flags & ISO_DATE) { - len = snprintf(p, bufsz, "%4ld-%.2d-%.2d", - tm->tm_year + (long) 1900, - tm->tm_mon + 1, tm->tm_mday); - if (len < 0 || (size_t) len > bufsz) - goto err; - bufsz -= len; - p += len; - } - - if ((flags & ISO_DATE) && (flags & ISO_TIME)) { - if (bufsz < 1) - goto err; - *p++ = (flags & ISO_T) ? 'T' : ' '; - bufsz--; - } - - if (flags & ISO_TIME) { - len = snprintf(p, bufsz, "%02d:%02d:%02d", tm->tm_hour, - tm->tm_min, tm->tm_sec); - if (len < 0 || (size_t) len > bufsz) - goto err; - bufsz -= len; - p += len; - } - - if (flags & ISO_DOTUSEC) { - len = snprintf(p, bufsz, ".%06ld", (long) usec); - if (len < 0 || (size_t) len > bufsz) - goto err; - bufsz -= len; - p += len; - - } else if (flags & ISO_COMMAUSEC) { - len = snprintf(p, bufsz, ",%06ld", (long) usec); - if (len < 0 || (size_t) len > bufsz) - goto err; - bufsz -= len; - p += len; - } - - if (flags & ISO_TIMEZONE) { - int tmin = get_gmtoff(tm) / 60; - int zhour = tmin / 60; - int zmin = abs(tmin % 60); - len = snprintf(p, bufsz, "%+03d:%02d", zhour,zmin); - if (len < 0 || (size_t) len > bufsz) - goto err; - } - return 0; - err: - warnx(_("format_iso_time: buffer overflow.")); - return -1; -} - -/* timeval to ISO 8601 */ -int strtimeval_iso(struct timeval *tv, int flags, char *buf, size_t bufsz) -{ - struct tm tm; - struct tm *rc; - - if (flags & ISO_GMTIME) - rc = gmtime_r(&tv->tv_sec, &tm); - else - rc = localtime_r(&tv->tv_sec, &tm); - - if (rc) - return format_iso_time(&tm, tv->tv_usec, flags, buf, bufsz); - - warnx(_("time %ld is out of range."), tv->tv_sec); - return -1; -} - -/* struct tm to ISO 8601 */ -int strtm_iso(struct tm *tm, int flags, char *buf, size_t bufsz) -{ - return format_iso_time(tm, 0, flags, buf, bufsz); -} - -/* time_t to ISO 8601 */ -int strtime_iso(const time_t *t, int flags, char *buf, size_t bufsz) -{ - struct tm tm; - struct tm *rc; - - if (flags & ISO_GMTIME) - rc = gmtime_r(t, &tm); - else - rc = localtime_r(t, &tm); - - if (rc) - return format_iso_time(&tm, 0, flags, buf, bufsz); - - warnx(_("time %ld is out of range."), (long)t); - return -1; -} - -/* relative time functions */ -static inline int time_is_thisyear(struct tm const *const tm, - struct tm const *const tmnow) -{ - return tm->tm_year == tmnow->tm_year; -} - -static inline int time_is_today(struct tm const *const tm, - struct tm const *const tmnow) -{ - return (tm->tm_yday == tmnow->tm_yday && - time_is_thisyear(tm, tmnow)); -} - -int strtime_short(const time_t *t, struct timeval *now, int flags, char *buf, size_t bufsz) -{ - struct tm tm, tmnow; - int rc = 0; - - if (now->tv_sec == 0) - gettimeofday(now, NULL); - - localtime_r(t, &tm); - localtime_r(&now->tv_sec, &tmnow); - - if (time_is_today(&tm, &tmnow)) { - rc = snprintf(buf, bufsz, "%02d:%02d", tm.tm_hour, tm.tm_min); - if (rc < 0 || (size_t) rc > bufsz) - return -1; - rc = 1; - - } else if (time_is_thisyear(&tm, &tmnow)) { - if (flags & UL_SHORTTIME_THISYEAR_HHMM) - rc = strftime(buf, bufsz, "%b%d/%H:%M", &tm); - else - rc = strftime(buf, bufsz, "%b%d", &tm); - } else - rc = strftime(buf, bufsz, "%Y-%b%d", &tm); - - return rc <= 0 ? -1 : 0; -} - -#ifndef HAVE_TIMEGM -time_t timegm(struct tm *tm) -{ - const char *zone = getenv("TZ"); - time_t ret; - - setenv("TZ", "", 1); - tzset(); - ret = mktime(tm); - if (zone) - setenv("TZ", zone, 1); - else - unsetenv("TZ"); - tzset(); - return ret; -} -#endif /* HAVE_TIMEGM */ - -#ifdef TEST_PROGRAM_TIMEUTILS - -int main(int argc, char *argv[]) -{ - struct timeval tv = { 0 }; - char buf[ISO_BUFSIZ]; - - if (argc < 2) { - fprintf(stderr, "usage: %s [<time> [<usec>]] | [--timestamp <str>]\n", argv[0]); - exit(EXIT_FAILURE); - } - - if (strcmp(argv[1], "--timestamp") == 0) { - usec_t usec; - - parse_timestamp(argv[2], &usec); - tv.tv_sec = (time_t) (usec / 1000000); - tv.tv_usec = usec % 1000000; - } else { - tv.tv_sec = strtos64_or_err(argv[1], "failed to parse <time>"); - if (argc == 3) - tv.tv_usec = strtos64_or_err(argv[2], "failed to parse <usec>"); - } - - strtimeval_iso(&tv, ISO_DATE, buf, sizeof(buf)); - printf("Date: '%s'\n", buf); - - strtimeval_iso(&tv, ISO_TIME, buf, sizeof(buf)); - printf("Time: '%s'\n", buf); - - strtimeval_iso(&tv, ISO_DATE | ISO_TIME | ISO_COMMAUSEC | ISO_T, - buf, sizeof(buf)); - printf("Full: '%s'\n", buf); - - strtimeval_iso(&tv, ISO_TIMESTAMP_DOT, buf, sizeof(buf)); - printf("Zone: '%s'\n", buf); - - return EXIT_SUCCESS; -} - -#endif /* TEST_PROGRAM_TIMEUTILS */ |
