X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fdaemon%2Futils_time.c;h=86476ea63b4cd95728cfd843a48b52d26859d979;hb=a9e50e9e30ecde17e167e271060c8183bfcbf407;hp=6603c15e89f161afc832a5e2cd8ef08b335564ea;hpb=f14feb1eddfe5760a64640b98ab7bbc5c493f614;p=collectd.git diff --git a/src/daemon/utils_time.c b/src/daemon/utils_time.c index 6603c15e..a807c7f9 100644 --- a/src/daemon/utils_time.c +++ b/src/daemon/utils_time.c @@ -1,6 +1,6 @@ /** * collectd - src/utils_time.c - * Copyright (C) 2010 Florian octo Forster + * Copyright (C) 2010-2015 Florian octo Forster * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -21,84 +21,214 @@ * DEALINGS IN THE SOFTWARE. * * Authors: - * Florian octo Forster + * Florian octo Forster **/ #include "collectd.h" -#include "utils_time.h" -#include "plugin.h" + #include "common.h" +#include "plugin.h" +#include "utils_time.h" + +#ifndef DEFAULT_MOCK_TIME +#define DEFAULT_MOCK_TIME 1542455354518929408ULL +#endif +#ifdef MOCK_TIME +cdtime_t cdtime_mock = (cdtime_t)MOCK_TIME; + +cdtime_t cdtime(void) { return cdtime_mock; } +#else /* !MOCK_TIME */ #if HAVE_CLOCK_GETTIME -cdtime_t cdtime (void) /* {{{ */ +cdtime_t cdtime(void) /* {{{ */ { int status; - struct timespec ts = { 0, 0 }; - - status = clock_gettime (CLOCK_REALTIME, &ts); - if (status != 0) - { - char errbuf[1024]; - ERROR ("cdtime: clock_gettime failed: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); - return (0); + struct timespec ts = {0, 0}; + + status = clock_gettime(CLOCK_REALTIME, &ts); + if (status != 0) { + ERROR("cdtime: clock_gettime failed: %s", STRERRNO); + return 0; } - return (TIMESPEC_TO_CDTIME_T (&ts)); + return TIMESPEC_TO_CDTIME_T(&ts); } /* }}} cdtime_t cdtime */ -#else +#else /* !HAVE_CLOCK_GETTIME */ /* Work around for Mac OS X which doesn't have clock_gettime(2). *sigh* */ -cdtime_t cdtime (void) /* {{{ */ +cdtime_t cdtime(void) /* {{{ */ { int status; - struct timeval tv = { 0, 0 }; - - status = gettimeofday (&tv, /* struct timezone = */ NULL); - if (status != 0) - { - char errbuf[1024]; - ERROR ("cdtime: gettimeofday failed: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); - return (0); + struct timeval tv = {0, 0}; + + status = gettimeofday(&tv, /* struct timezone = */ NULL); + if (status != 0) { + ERROR("cdtime: gettimeofday failed: %s", STRERRNO); + return 0; } - return (TIMEVAL_TO_CDTIME_T (&tv)); + return TIMEVAL_TO_CDTIME_T(&tv); } /* }}} cdtime_t cdtime */ #endif +#endif + +/********************************************************************** + Time retrieval functions +***********************************************************************/ -size_t cdtime_to_iso8601 (char *s, size_t max, cdtime_t t) /* {{{ */ +static int get_utc_time(cdtime_t t, struct tm *t_tm, long *nsec) /* {{{ */ { - struct timespec t_spec; - struct tm t_tm; + struct timespec t_spec = CDTIME_T_TO_TIMESPEC(t); + NORMALIZE_TIMESPEC(t_spec); + + if (gmtime_r(&t_spec.tv_sec, t_tm) == NULL) { + int status = errno; + ERROR("get_utc_time: gmtime_r failed: %s", STRERRNO); + return status; + } - size_t len; + *nsec = t_spec.tv_nsec; + return 0; +} /* }}} int get_utc_time */ - CDTIME_T_TO_TIMESPEC (t, &t_spec); - NORMALIZE_TIMESPEC (t_spec); +static int get_local_time(cdtime_t t, struct tm *t_tm, long *nsec) /* {{{ */ +{ + struct timespec t_spec = CDTIME_T_TO_TIMESPEC(t); + NORMALIZE_TIMESPEC(t_spec); - if (localtime_r ((time_t *)&t_spec.tv_sec, &t_tm) == NULL) { - char errbuf[1024]; - ERROR ("cdtime_to_iso8601: localtime_r failed: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); - return (0); + if (localtime_r(&t_spec.tv_sec, t_tm) == NULL) { + int status = errno; + ERROR("get_local_time: localtime_r failed: %s", STRERRNO); + return status; } - len = strftime (s, max, "%Y-%m-%dT%H:%M:%S", &t_tm); - if (len == 0) - return 0; + *nsec = t_spec.tv_nsec; + return 0; +} /* }}} int get_local_time */ + +/********************************************************************** + Formatting functions +***********************************************************************/ + +static const char zulu_zone[] = "Z"; - if (max - len > 2) { - int n = snprintf (s + len, max - len, ".%09i", (int)t_spec.tv_nsec); - len += (n < max - len) ? n : max - len; +/* format_zone reads time zone information from "extern long timezone", exported + * by , and formats it according to RFC 3339. This differs from + * strftime()'s "%z" format by including a colon between hour and minute. */ +static int format_zone(char *buffer, size_t buffer_size, + struct tm const *tm) /* {{{ */ +{ + char tmp[7]; + size_t sz; + + if ((buffer == NULL) || (buffer_size < 7)) + return EINVAL; + + sz = strftime(tmp, sizeof(tmp), "%z", tm); + if (sz == 0) + return ENOMEM; + if (sz != 5) { + DEBUG("format_zone: strftime(\"%%z\") = \"%s\", want \"+hhmm\"", tmp); + sstrncpy(buffer, tmp, buffer_size); + return 0; } - if (max - len > 3) { - int n = strftime (s + len, max - len, "%z", &t_tm); - len += (n < max - len) ? n : max - len; + buffer[0] = tmp[0]; + buffer[1] = tmp[1]; + buffer[2] = tmp[2]; + buffer[3] = ':'; + buffer[4] = tmp[3]; + buffer[5] = tmp[4]; + buffer[6] = 0; + + return 0; +} /* }}} int format_zone */ + +int format_rfc3339(char *buffer, size_t buffer_size, struct tm const *t_tm, + long nsec, _Bool print_nano, char const *zone) /* {{{ */ +{ + int len; + char *pos = buffer; + size_t size_left = buffer_size; + + if ((len = strftime(pos, size_left, "%Y-%m-%dT%H:%M:%S", t_tm)) == 0) + return ENOMEM; + pos += len; + size_left -= len; + + if (print_nano) { + if ((len = snprintf(pos, size_left, ".%09ld", nsec)) == 0) + return ENOMEM; + pos += len; + size_left -= len; } - s[max - 1] = '\0'; - return len; -} /* }}} size_t cdtime_to_iso8601 */ + sstrncpy(pos, zone, size_left); + return 0; +} /* }}} int format_rfc3339 */ + +int format_rfc3339_utc(char *buffer, size_t buffer_size, cdtime_t t, + _Bool print_nano) /* {{{ */ +{ + struct tm t_tm; + long nsec = 0; + int status; + + if ((status = get_utc_time(t, &t_tm, &nsec)) != 0) + return status; /* The error should have already be reported. */ + + return format_rfc3339(buffer, buffer_size, &t_tm, nsec, print_nano, + zulu_zone); +} /* }}} int format_rfc3339_utc */ + +int format_rfc3339_local(char *buffer, size_t buffer_size, cdtime_t t, + _Bool print_nano) /* {{{ */ +{ + struct tm t_tm; + long nsec = 0; + int status; + char zone[7]; /* +00:00 */ + + if ((status = get_local_time(t, &t_tm, &nsec)) != 0) + return status; /* The error should have already be reported. */ + + if ((status = format_zone(zone, sizeof(zone), &t_tm)) != 0) + return status; + + return format_rfc3339(buffer, buffer_size, &t_tm, nsec, print_nano, zone); +} /* }}} int format_rfc3339_local */ + +/********************************************************************** + Public functions +***********************************************************************/ + +int rfc3339(char *buffer, size_t buffer_size, cdtime_t t) /* {{{ */ +{ + if (buffer_size < RFC3339_SIZE) + return ENOMEM; + + return format_rfc3339_utc(buffer, buffer_size, t, 0); +} /* }}} int rfc3339 */ + +int rfc3339nano(char *buffer, size_t buffer_size, cdtime_t t) /* {{{ */ +{ + if (buffer_size < RFC3339NANO_SIZE) + return ENOMEM; + + return format_rfc3339_utc(buffer, buffer_size, t, 1); +} /* }}} int rfc3339nano */ + +int rfc3339_local(char *buffer, size_t buffer_size, cdtime_t t) /* {{{ */ +{ + if (buffer_size < RFC3339_SIZE) + return ENOMEM; + + return format_rfc3339_local(buffer, buffer_size, t, 0); +} /* }}} int rfc3339 */ + +int rfc3339nano_local(char *buffer, size_t buffer_size, cdtime_t t) /* {{{ */ +{ + if (buffer_size < RFC3339NANO_SIZE) + return ENOMEM; -/* vim: set sw=2 sts=2 et fdm=marker : */ + return format_rfc3339_local(buffer, buffer_size, t, 1); +} /* }}} int rfc3339nano */