static void test_format_timestamp_utc_one(usec_t val, const char *result) { char buf[FORMAT_TIMESTAMP_MAX]; const char *t; t = format_timestamp_utc(buf, sizeof(buf), val); assert_se(streq_ptr(t, result)); }
static void test_format_timestamp(void) { unsigned i; log_info("/* %s */", __func__); for (i = 0; i < 100; i++) { char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)]; usec_t x, y; random_bytes(&x, sizeof(x)); x = x % (2147483600 * USEC_PER_SEC) + 1; assert_se(format_timestamp(buf, sizeof(buf), x)); log_info("%s", buf); assert_se(parse_timestamp(buf, &y) >= 0); assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC); assert_se(format_timestamp_utc(buf, sizeof(buf), x)); log_info("%s", buf); assert_se(parse_timestamp(buf, &y) >= 0); assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC); assert_se(format_timestamp_us(buf, sizeof(buf), x)); log_info("%s", buf); assert_se(parse_timestamp(buf, &y) >= 0); assert_se(x == y); assert_se(format_timestamp_us_utc(buf, sizeof(buf), x)); log_info("%s", buf); assert_se(parse_timestamp(buf, &y) >= 0); assert_se(x == y); assert_se(format_timestamp_relative(buf, sizeof(buf), x)); log_info("%s", buf); assert_se(parse_timestamp(buf, &y) >= 0); /* The two calls above will run with a slightly different local time. Make sure we are in the same * range however, but give enough leeway that this is unlikely to explode. And of course, * format_timestamp_relative() scales the accuracy with the distance from the current time up to one * month, cover for that too. */ assert_se(y > x ? y - x : x - y <= USEC_PER_MONTH + USEC_PER_DAY); } }
static int output_timestamp_realtime(FILE *f, sd_journal *j, OutputMode mode, OutputFlags flags, const char *realtime) { char buf[MAX(FORMAT_TIMESTAMP_MAX, 64)]; struct tm *(*gettime_r)(const time_t *, struct tm *); struct tm tm; uint64_t x; time_t t; int r; assert(f); assert(j); if (realtime) r = safe_atou64(realtime, &x); if (!realtime || r < 0 || !VALID_REALTIME(x)) r = sd_journal_get_realtime_usec(j, &x); if (r < 0) return log_error_errno(r, "Failed to get realtime timestamp: %m"); if (IN_SET(mode, OUTPUT_SHORT_FULL, OUTPUT_WITH_UNIT)) { const char *k; if (flags & OUTPUT_UTC) k = format_timestamp_utc(buf, sizeof(buf), x); else k = format_timestamp(buf, sizeof(buf), x); if (!k) { log_error("Failed to format timestamp: %"PRIu64, x); return -EINVAL; } } else { char usec[7]; gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r; t = (time_t) (x / USEC_PER_SEC); switch (mode) { case OUTPUT_SHORT_UNIX: xsprintf(buf, "%10"PRI_TIME".%06"PRIu64, t, x % USEC_PER_SEC); break; case OUTPUT_SHORT_ISO: if (strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm)) <= 0) { log_error("Failed to format ISO time"); return -EINVAL; } break; case OUTPUT_SHORT_ISO_PRECISE: /* No usec in strftime, so we leave space and copy over */ if (strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S.xxxxxx%z", gettime_r(&t, &tm)) <= 0) { log_error("Failed to format ISO-precise time"); return -EINVAL; } xsprintf(usec, "%06"PRI_USEC, x % USEC_PER_SEC); memcpy(buf + 20, usec, 6); break; case OUTPUT_SHORT: case OUTPUT_SHORT_PRECISE: if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm)) <= 0) { log_error("Failed to format syslog time"); return -EINVAL; } if (mode == OUTPUT_SHORT_PRECISE) { size_t k; assert(sizeof(buf) > strlen(buf)); k = sizeof(buf) - strlen(buf); r = snprintf(buf + strlen(buf), k, ".%06"PRIu64, x % USEC_PER_SEC); if (r <= 0 || (size_t) r >= k) { /* too long? */ log_error("Failed to format precise time"); return -EINVAL; } } break; default: assert_not_reached("Unknown time format"); } } fputs(buf, f); return (int) strlen(buf); }