summaryrefslogtreecommitdiffstats
path: root/src/lib/time-util.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib/time-util.c169
1 files changed, 169 insertions, 0 deletions
diff --git a/src/lib/time-util.c b/src/lib/time-util.c
new file mode 100644
index 0000000..3f4cd01
--- /dev/null
+++ b/src/lib/time-util.c
@@ -0,0 +1,169 @@
+/* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "time-util.h"
+
+#include <time.h>
+
+#define STRFTIME_MAX_BUFSIZE (1024*64)
+
+void i_gettimeofday(struct timeval *tv_r)
+{
+ if (gettimeofday(tv_r, NULL) < 0)
+ i_fatal("gettimeofday() failed: %m");
+}
+
+uint64_t i_nanoseconds(void)
+{
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_REALTIME, &ts) < 0)
+ i_fatal("clock_gettime() failed: %m");
+ return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+}
+
+int timeval_cmp(const struct timeval *tv1, const struct timeval *tv2)
+{
+ if (tv1->tv_sec < tv2->tv_sec)
+ return -1;
+ if (tv1->tv_sec > tv2->tv_sec)
+ return 1;
+ if (tv1->tv_usec < tv2->tv_usec)
+ return -1;
+ if (tv1->tv_usec > tv2->tv_usec)
+ return 1;
+ return 0;
+}
+
+int timeval_cmp_margin(const struct timeval *tv1, const struct timeval *tv2,
+ unsigned int usec_margin)
+{
+ long long secs_diff, usecs_diff;
+ int sec_margin, ret;
+
+ if (tv1->tv_sec < tv2->tv_sec) {
+ sec_margin = ((int)usec_margin / 1000000) + 1;
+ secs_diff = (long long)tv2->tv_sec - (long long)tv1->tv_sec;
+ if (secs_diff > sec_margin)
+ return -1;
+ usecs_diff = secs_diff * 1000000LL +
+ (tv2->tv_usec - tv1->tv_usec);
+ ret = -1;
+ } else if (tv1->tv_sec > tv2->tv_sec) {
+ sec_margin = ((int)usec_margin / 1000000) + 1;
+ secs_diff = (long long)tv1->tv_sec - (long long)tv2->tv_sec;
+ if (secs_diff > sec_margin)
+ return 1;
+ usecs_diff = secs_diff * 1000000LL +
+ (tv1->tv_usec - tv2->tv_usec);
+ ret = 1;
+ } else if (tv1->tv_usec < tv2->tv_usec) {
+ usecs_diff = tv2->tv_usec - tv1->tv_usec;
+ ret = -1;
+ } else {
+ usecs_diff = tv1->tv_usec - tv2->tv_usec;
+ ret = 1;
+ }
+ i_assert(usecs_diff >= 0);
+ return (unsigned long long)usecs_diff > usec_margin ? ret : 0;
+}
+
+int timeval_diff_msecs(const struct timeval *tv1, const struct timeval *tv2)
+{
+ long long diff = timeval_diff_usecs(tv1, tv2) / 1000LL;
+#ifdef DEBUG
+ /* FIXME v2.4: Remove the ifdef */
+ i_assert(diff <= INT_MAX);
+#endif
+ return (int)diff;
+}
+
+long long timeval_diff_usecs(const struct timeval *tv1,
+ const struct timeval *tv2)
+{
+ time_t secs;
+ int usecs;
+
+ secs = tv1->tv_sec - tv2->tv_sec;
+ usecs = tv1->tv_usec - tv2->tv_usec;
+ if (usecs < 0) {
+ secs--;
+ usecs += 1000000;
+ }
+ return ((long long)secs * 1000000LL) + usecs;
+}
+
+time_t time_to_local_day_start(time_t t)
+{
+ const struct tm *day_tm;
+ struct tm tm;
+ time_t new_start_time;
+
+ day_tm = localtime(&t);
+ i_zero(&tm);
+ tm.tm_year = day_tm->tm_year;
+ tm.tm_mon = day_tm->tm_mon;
+ tm.tm_mday = day_tm->tm_mday;
+ tm.tm_isdst = -1;
+ new_start_time = mktime(&tm);
+ i_assert(new_start_time != (time_t)-1);
+ return new_start_time;
+}
+
+static const char *strftime_real(const char *fmt, const struct tm *tm)
+{
+ size_t bufsize = strlen(fmt) + 32;
+ char *buf = t_buffer_get(bufsize);
+ size_t ret;
+
+ while ((ret = strftime(buf, bufsize, fmt, tm)) == 0) {
+ bufsize *= 2;
+ i_assert(bufsize <= STRFTIME_MAX_BUFSIZE);
+ buf = t_buffer_get(bufsize);
+ }
+ t_buffer_alloc(ret + 1);
+ return buf;
+}
+
+const char *t_strftime(const char *fmt, const struct tm *tm)
+{
+ return strftime_real(fmt, tm);
+}
+
+const char *t_strflocaltime(const char *fmt, time_t t)
+{
+ return strftime_real(fmt, localtime(&t));
+}
+
+const char *t_strfgmtime(const char *fmt, time_t t)
+{
+ return strftime_real(fmt, gmtime(&t));
+}
+
+int str_to_timeval(const char *str, struct timeval *tv_r)
+{
+ tv_r->tv_usec = 0;
+
+ const char *p = strchr(str, '.');
+ if (p == NULL)
+ return str_to_time(str, &tv_r->tv_sec);
+
+ int ret;
+ T_BEGIN {
+ ret = str_to_time(t_strdup_until(str, p++), &tv_r->tv_sec);
+ } T_END;
+ if (ret < 0 || p[0] == '\0')
+ return -1;
+
+ unsigned int len = strlen(p);
+ if (len > 6)
+ return -1; /* we don't support sub-microseconds */
+ char usecs_str[7] = "000000";
+ memcpy(usecs_str, p, len);
+
+ unsigned int usec;
+ if (str_to_uint(usecs_str, &usec) < 0)
+ return -1;
+ tv_r->tv_usec = usec;
+ return 0;
+}