#ifndef _CTRLSTATUS_FMT_H_ #define _CTRLSTATUS_FMT_H_ /* ctrlstatus_fmt.h — render a responder snapshot timestamp (epoch-millis) in * the EXACT wall-clock string the controller logger emits, so the test client's * `ctrlstatus` output is byte-comparable against ctrl-N.log (controller-status * task 6.3, Req 11.2/11.3). * * The tlog prefix (vendored tinylog, _tlog_root_default_format) is built inline * as: * * snprintf(... "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d]...", * tm->year, tm->mon, tm->mday, tm->hour, tm->min, tm->sec, * tm->usec / 1000, ...); * * where the broken-down time comes from gettimeofday() + localtime_r() — i.e. * LOCAL time, with sub-second precision rendered as zero-padded MILLISECONDS * (usec / 1000). tlog exposes no reusable formatter for callers, so this helper * REPLICATES that construction: localtime_r + strftime("%Y-%m-%d %H:%M:%S") * (byte-identical to "%.4d-%.2d-%.2d %.2d:%.2d:%.2d") then ",%03u" for the * millisecond fraction. Both the logger and this helper use local time, so the * rendered value matches the log line under the same TZ. */ #include #include #include #include /* Render `ms` (epoch milliseconds, e.g. xce_ctrlstatus_t.responder_time_ms) * into `buf` as local-time "YYYY-MM-DD HH:MM:SS,mmm". Needs at least 24 bytes. * Returns `buf` on success, NULL if buf is NULL / too small / time conversion * fails. */ static inline char* ctrlstatus_format_time_ms(uint64_t ms, char* buf, size_t n) { /* "YYYY-MM-DD HH:MM:SS,mmm" + NUL == 24 bytes. */ if (buf == NULL || n < 24) { return NULL; } time_t secs = (time_t)(ms / 1000u); unsigned msec = (unsigned)(ms % 1000u); struct tm tm; if (localtime_r(&secs, &tm) == NULL) { return NULL; } char datetime[20]; /* "YYYY-MM-DD HH:MM:SS" + NUL */ if (strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", &tm) == 0) { return NULL; } /* Match tlog's ",%.3d" millisecond fraction (zero-padded to 3 digits). */ if (snprintf(buf, n, "%s,%03u", datetime, msec) < 0) { return NULL; } return buf; } #endif /* _CTRLSTATUS_FMT_H_ */