Coverage Report

Created: 2026-04-12 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib/time-util.c
Line
Count
Source
1
/* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
2
3
#include "lib.h"
4
#include "time-util.h"
5
6
#include <time.h>
7
8
#define STRFTIME_MAX_BUFSIZE (1024*64)
9
10
void i_gettimeofday(struct timeval *tv_r)
11
0
{
12
0
  if (gettimeofday(tv_r, NULL) < 0)
13
0
    i_fatal("gettimeofday() failed: %m");
14
0
}
15
16
uint64_t i_nanoseconds(void)
17
0
{
18
0
  struct timespec ts;
19
20
0
  if (clock_gettime(CLOCK_REALTIME, &ts) < 0)
21
0
    i_fatal("clock_gettime() failed: %m");
22
0
  return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
23
0
}
24
25
int timeval_cmp(const struct timeval *tv1, const struct timeval *tv2)
26
0
{
27
0
  if (tv1->tv_sec < tv2->tv_sec)
28
0
    return -1;
29
0
  if (tv1->tv_sec > tv2->tv_sec)
30
0
    return 1;
31
0
  if (tv1->tv_usec < tv2->tv_usec)
32
0
    return -1;
33
0
  if (tv1->tv_usec > tv2->tv_usec)
34
0
    return 1;
35
0
  return 0;
36
0
}
37
38
int timeval_cmp_margin(const struct timeval *tv1, const struct timeval *tv2,
39
  unsigned int usec_margin)
40
0
{
41
0
  long long secs_diff, usecs_diff;
42
0
  int sec_margin, ret;
43
44
0
  if (tv1->tv_sec < tv2->tv_sec) {
45
0
    sec_margin = ((int)usec_margin / 1000000) + 1;
46
0
    secs_diff = (long long)tv2->tv_sec - (long long)tv1->tv_sec;
47
0
    if (secs_diff > sec_margin)
48
0
      return -1;
49
0
    usecs_diff = secs_diff * 1000000LL +
50
0
      (tv2->tv_usec - tv1->tv_usec);
51
0
    ret = -1;
52
0
  } else if (tv1->tv_sec > tv2->tv_sec) {
53
0
    sec_margin = ((int)usec_margin / 1000000) + 1;
54
0
    secs_diff = (long long)tv1->tv_sec - (long long)tv2->tv_sec;
55
0
    if (secs_diff > sec_margin)
56
0
      return 1;
57
0
    usecs_diff = secs_diff * 1000000LL +
58
0
      (tv1->tv_usec - tv2->tv_usec);
59
0
    ret = 1;
60
0
  } else if (tv1->tv_usec < tv2->tv_usec) {
61
0
    usecs_diff = tv2->tv_usec - tv1->tv_usec;
62
0
    ret = -1;
63
0
  } else {
64
0
    usecs_diff = tv1->tv_usec - tv2->tv_usec;
65
0
    ret = 1;
66
0
  }
67
0
  i_assert(usecs_diff >= 0);
68
0
  return (unsigned long long)usecs_diff > usec_margin ? ret : 0;
69
0
}
70
71
long long timeval_diff_usecs(const struct timeval *tv1,
72
           const struct timeval *tv2)
73
0
{
74
0
  time_t secs;
75
0
  suseconds_t usecs;
76
77
0
  secs = tv1->tv_sec - tv2->tv_sec;
78
0
  usecs = tv1->tv_usec - tv2->tv_usec;
79
0
  if (usecs < 0) {
80
0
    secs--;
81
0
    usecs += 1000000;
82
0
  }
83
0
  return ((long long)secs * 1000000LL) + usecs;
84
0
}
85
86
time_t time_to_local_day_start(time_t t)
87
0
{
88
0
  const struct tm *day_tm;
89
0
  struct tm tm;
90
0
  time_t new_start_time;
91
92
0
  day_tm = localtime(&t);
93
0
  i_zero(&tm);
94
0
  tm.tm_year = day_tm->tm_year;
95
0
  tm.tm_mon = day_tm->tm_mon;
96
0
  tm.tm_mday = day_tm->tm_mday;
97
0
  tm.tm_isdst = -1;
98
0
  new_start_time = mktime(&tm);
99
0
  i_assert(new_start_time != (time_t)-1);
100
0
  return new_start_time;
101
0
}
102
103
static const char *strftime_real(const char *fmt, const struct tm *tm)
104
0
{
105
0
  size_t bufsize = strlen(fmt) + 32;
106
0
  char *buf = t_buffer_get(bufsize);
107
0
  size_t ret;
108
109
0
  while ((ret = strftime(buf, bufsize, fmt, tm)) == 0) {
110
0
    bufsize *= 2;
111
0
    i_assert(bufsize <= STRFTIME_MAX_BUFSIZE);
112
0
    buf = t_buffer_get(bufsize);
113
0
  }
114
0
  t_buffer_alloc(ret + 1);
115
0
  return buf;
116
0
}
117
118
const char *t_strftime(const char *fmt, const struct tm *tm)
119
0
{
120
0
  return strftime_real(fmt, tm);
121
0
}
122
123
const char *t_strflocaltime(const char *fmt, time_t t)
124
0
{
125
0
  return strftime_real(fmt, localtime(&t));
126
0
}
127
128
const char *t_strfgmtime(const char *fmt, time_t t)
129
0
{
130
0
  return strftime_real(fmt, gmtime(&t));
131
0
}
132
133
int str_to_timeval(const char *str, struct timeval *tv_r)
134
0
{
135
0
  tv_r->tv_usec = 0;
136
137
0
  const char *p = strchr(str, '.');
138
0
  if (p == NULL)
139
0
    return str_to_time(str, &tv_r->tv_sec);
140
141
0
  int ret;
142
0
  T_BEGIN {
143
0
    ret = str_to_time(t_strdup_until(str, p++), &tv_r->tv_sec);
144
0
  } T_END;
145
0
  if (ret < 0 || p[0] == '\0')
146
0
    return -1;
147
148
0
  unsigned int len = strlen(p);
149
0
  if (len > 6)
150
0
    return -1; /* we don't support sub-microseconds */
151
0
  char usecs_str[7] = "000000";
152
0
  memcpy(usecs_str, p, len);
153
154
0
  unsigned int usec;
155
0
  if (str_to_uint(usecs_str, &usec) < 0)
156
0
    return -1;
157
0
  tv_r->tv_usec = usec;
158
0
  return 0;
159
0
}