clock_time.c (6272B)
1 /* Copyright (C) 2013-2023, 2025 Vincent Forest (vaplv@free.fr) 2 * 3 * The RSys library is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published 5 * by the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * The RSys library is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #define _POSIX_C_SOURCE 200112L /* snprintf support */ 17 #include "rsys.h" 18 19 #include <time.h> 20 21 #include "clock_time.h" 22 #include <string.h> 23 24 #define TIME_TO_NSEC(Time) ((Time)->nsec + (Time)->sec * 1000000000L) 25 #define NSEC_PER_USEC__ (int64_t)1000 26 #define NSEC_PER_MSEC__ ((int64_t)1000 * NSEC_PER_USEC__) 27 #define NSEC_PER_SEC__ ((int64_t)1000 * NSEC_PER_MSEC__) 28 #define NSEC_PER_MIN__ ((int64_t)60 * NSEC_PER_SEC__) 29 #define NSEC_PER_HOUR__ ((int64_t)60 * NSEC_PER_MIN__) 30 #define NSEC_PER_DAY__ ((int64_t)24 * NSEC_PER_HOUR__) 31 32 struct time* 33 time_current(struct time* t) 34 { 35 struct timespec time; 36 int err = 0; (void)err; 37 ASSERT(t); 38 39 err = clock_gettime(CLOCK_REALTIME, &time); 40 ASSERT(err == 0); 41 t->sec = (int64_t)time.tv_sec; 42 t->nsec = (int64_t)time.tv_nsec; 43 return t; 44 } 45 46 struct time* 47 time_sub(struct time* res, const struct time* a, const struct time* b) 48 { 49 ASSERT(res && a && b); 50 res->sec = a->sec - b->sec; 51 res->nsec = a->nsec - b->nsec; 52 if(res->nsec < 0) { 53 --res->sec; 54 res->nsec += 1000000000L; 55 } 56 return res; 57 } 58 59 struct time* 60 time_add(struct time* res, const struct time* a, const struct time* b) 61 { 62 ASSERT(res && a && b); 63 64 res->sec = a->sec + b->sec; 65 res->nsec = a->nsec + b->nsec; 66 if(res->nsec >= 1000000000L) { 67 ++res->sec; 68 res->nsec -= 1000000000L; 69 } 70 return res; 71 } 72 73 int64_t 74 time_val(const struct time* time, enum time_unit unit) 75 { 76 int64_t val = TIME_TO_NSEC(time); 77 switch(unit) { 78 case TIME_NSEC: 79 /* Do nothing. */ 80 break; 81 case TIME_USEC: 82 val /= NSEC_PER_USEC__; 83 break; 84 case TIME_MSEC: 85 val /= NSEC_PER_MSEC__; 86 break; 87 case TIME_SEC: 88 val /= NSEC_PER_SEC__; 89 break; 90 case TIME_MIN: 91 val /= NSEC_PER_MIN__; 92 break; 93 case TIME_HOUR: 94 val /= NSEC_PER_HOUR__; 95 break; 96 case TIME_DAY: 97 val /= NSEC_PER_DAY__; 98 break; 99 default: ASSERT(0); break; 100 } 101 return val; 102 } 103 104 void 105 time_dump 106 (const struct time* time, 107 int flag, 108 size_t* real_dump_len, 109 char* dump, 110 size_t max_dump_len) 111 { 112 size_t available_dump_space = max_dump_len; 113 int64_t time_nsec = 0; 114 char* dst = dump; 115 116 ASSERT(time && (!max_dump_len || dump)); 117 if(real_dump_len) *real_dump_len = 0; 118 if(max_dump_len > 0) dump[0] = '\0'; 119 if(!flag) return; 120 121 #define DUMP(Time, Suffix) \ 122 { \ 123 const int len = snprintf \ 124 (dst, available_dump_space, \ 125 "%li %s", (long)Time, Time > 1 ? Suffix "s ": Suffix " "); \ 126 ASSERT(len >= 0); \ 127 if(real_dump_len) { \ 128 *real_dump_len += (size_t)len; \ 129 } \ 130 if((size_t)len < available_dump_space) { \ 131 dst += len; \ 132 available_dump_space -= (size_t)len; \ 133 } else if(dst) { \ 134 available_dump_space = 0; \ 135 dst = NULL; \ 136 } \ 137 } (void) 0 138 139 time_nsec = TIME_TO_NSEC(time); 140 if(flag & TIME_DAY) { 141 const int64_t nb_days = time_nsec / NSEC_PER_DAY__; 142 if(nb_days) DUMP(nb_days, "day"); 143 time_nsec -= nb_days * NSEC_PER_DAY__; 144 } 145 if(flag & TIME_HOUR) { 146 const int64_t nb_hours = time_nsec / NSEC_PER_HOUR__; 147 if(nb_hours) DUMP(nb_hours, "hour"); 148 time_nsec -= nb_hours * NSEC_PER_HOUR__; 149 } 150 if(flag & TIME_MIN) { 151 const int64_t nb_mins = time_nsec / NSEC_PER_MIN__; 152 if(nb_mins) DUMP(nb_mins, "min"); 153 time_nsec -= nb_mins * NSEC_PER_MIN__; 154 } 155 if(flag & TIME_SEC) { 156 const int64_t nb_secs = time_nsec / NSEC_PER_SEC__; 157 if(nb_secs) DUMP(nb_secs, "sec"); 158 time_nsec -= nb_secs * NSEC_PER_SEC__; 159 } 160 if(flag & TIME_MSEC) { 161 const int64_t nb_msecs = time_nsec / NSEC_PER_MSEC__; 162 if(nb_msecs) DUMP(nb_msecs, "msec"); 163 time_nsec -= nb_msecs * NSEC_PER_MSEC__; 164 } 165 if(flag & TIME_USEC) { 166 const int64_t nb_usecs = time_nsec / NSEC_PER_USEC__; 167 if(nb_usecs) DUMP(nb_usecs, "usec"); 168 time_nsec -= nb_usecs * NSEC_PER_USEC__; 169 } 170 if(flag & TIME_NSEC) { 171 if(time_nsec) DUMP(time_nsec, "nsec"); 172 } 173 174 /* Remove last space */ 175 if(real_dump_len) *real_dump_len -= 1; 176 177 if(max_dump_len > 0) { 178 size_t dump_len = strlen(dump); 179 if(!dump_len && flag) { 180 if(flag & TIME_NSEC) { DUMP(0, "nsec"); 181 } else if(flag & TIME_USEC) { DUMP(0, "usec"); 182 } else if(flag & TIME_MSEC) { DUMP(0, "msec"); 183 } else if(flag & TIME_SEC) { DUMP(0, "sec"); 184 } else if(flag & TIME_MIN) { DUMP(0, "min"); 185 } else if(flag & TIME_HOUR) { DUMP(0, "hour"); 186 } else if(flag & TIME_DAY) { DUMP(0, "day"); 187 } 188 dump_len = strlen(dump); 189 } 190 /* Remove last space */ 191 if(dump[dump_len-1] == ' ') { 192 dump[dump_len-1] = '\0'; 193 } 194 } 195 #undef DUMP 196 } 197 198 #undef TIME_TO_NSEC 199 #undef NSEC_PER_USEC__ 200 #undef NSEC_PER_MSEC__ 201 #undef NSEC_PER_SEC__ 202 #undef NSEC_PER_MIN__ 203 #undef NSEC_PER_HOUR__ 204 #undef NSEC_PER_DAY__