mirror of
https://github.com/systemd/systemd.git
synced 2025-03-31 14:50:15 +03:00
basic/time-util: add function to format timestamps with different styles
Instead of a multiple fixed format helper functions, add an enum and a single helper, so that it's easier to extend in the future.
This commit is contained in:
parent
caf6bd166f
commit
7b3eb5c97e
@ -23,6 +23,7 @@
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "time-util.h"
|
||||
@ -282,12 +283,11 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) {
|
||||
return tv;
|
||||
}
|
||||
|
||||
static char *format_timestamp_internal(
|
||||
char *format_timestamp_style(
|
||||
char *buf,
|
||||
size_t l,
|
||||
usec_t t,
|
||||
bool utc,
|
||||
bool us) {
|
||||
TimestampStyle style) {
|
||||
|
||||
/* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our
|
||||
* generated timestamps may be parsed with parse_timestamp(), and always read the same. */
|
||||
@ -304,9 +304,27 @@ static char *format_timestamp_internal(
|
||||
struct tm tm;
|
||||
time_t sec;
|
||||
size_t n;
|
||||
bool utc = false, us = false;
|
||||
|
||||
assert(buf);
|
||||
|
||||
switch (style) {
|
||||
case TIMESTAMP_PRETTY:
|
||||
break;
|
||||
case TIMESTAMP_US:
|
||||
us = true;
|
||||
break;
|
||||
case TIMESTAMP_UTC:
|
||||
utc = true;
|
||||
break;
|
||||
case TIMESTAMP_US_UTC:
|
||||
us = true;
|
||||
utc = true;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (l < (size_t) (3 + /* week day */
|
||||
1 + 10 + /* space and date */
|
||||
1 + 8 + /* space and time */
|
||||
@ -380,22 +398,6 @@ static char *format_timestamp_internal(
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *format_timestamp(char *buf, size_t l, usec_t t) {
|
||||
return format_timestamp_internal(buf, l, t, false, false);
|
||||
}
|
||||
|
||||
char *format_timestamp_utc(char *buf, size_t l, usec_t t) {
|
||||
return format_timestamp_internal(buf, l, t, true, false);
|
||||
}
|
||||
|
||||
char *format_timestamp_us(char *buf, size_t l, usec_t t) {
|
||||
return format_timestamp_internal(buf, l, t, false, true);
|
||||
}
|
||||
|
||||
char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) {
|
||||
return format_timestamp_internal(buf, l, t, true, true);
|
||||
}
|
||||
|
||||
char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
|
||||
const char *s;
|
||||
usec_t n, d;
|
||||
@ -1568,3 +1570,27 @@ int time_change_fd(void) {
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
static const char* const timestamp_style_table[_TIMESTAMP_STYLE_MAX] = {
|
||||
[TIMESTAMP_PRETTY] = "pretty",
|
||||
[TIMESTAMP_US] = "us",
|
||||
[TIMESTAMP_UTC] = "utc",
|
||||
[TIMESTAMP_US_UTC] = "us+utc",
|
||||
};
|
||||
|
||||
/* Use the macro for enum → string to allow for aliases */
|
||||
_DEFINE_STRING_TABLE_LOOKUP_TO_STRING(timestamp_style, TimestampStyle,);
|
||||
|
||||
/* For the string → enum mapping we use the generic implementation, but also support two aliases */
|
||||
TimestampStyle timestamp_style_from_string(const char *s) {
|
||||
TimestampStyle t;
|
||||
|
||||
t = (TimestampStyle) string_table_lookup(timestamp_style_table, ELEMENTSOF(timestamp_style_table), s);
|
||||
if (t >= 0)
|
||||
return t;
|
||||
if (streq_ptr(s, "µs"))
|
||||
return TIMESTAMP_US;
|
||||
if (streq_ptr(s, "µs+uts"))
|
||||
return TIMESTAMP_US_UTC;
|
||||
return t;
|
||||
}
|
||||
|
@ -29,6 +29,15 @@ typedef struct triple_timestamp {
|
||||
usec_t boottime;
|
||||
} triple_timestamp;
|
||||
|
||||
typedef enum TimestampStyle {
|
||||
TIMESTAMP_PRETTY,
|
||||
TIMESTAMP_US,
|
||||
TIMESTAMP_UTC,
|
||||
TIMESTAMP_US_UTC,
|
||||
_TIMESTAMP_STYLE_MAX,
|
||||
_TIMESTAMP_STYLE_INVALID = -1,
|
||||
} TimestampStyle;
|
||||
|
||||
#define USEC_INFINITY ((usec_t) UINT64_MAX)
|
||||
#define NSEC_INFINITY ((nsec_t) UINT64_MAX)
|
||||
|
||||
@ -107,13 +116,14 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u);
|
||||
usec_t timeval_load(const struct timeval *tv) _pure_;
|
||||
struct timeval *timeval_store(struct timeval *tv, usec_t u);
|
||||
|
||||
char *format_timestamp(char *buf, size_t l, usec_t t);
|
||||
char *format_timestamp_utc(char *buf, size_t l, usec_t t);
|
||||
char *format_timestamp_us(char *buf, size_t l, usec_t t);
|
||||
char *format_timestamp_us_utc(char *buf, size_t l, usec_t t);
|
||||
char *format_timestamp_style(char *buf, size_t l, usec_t t, TimestampStyle style);
|
||||
char *format_timestamp_relative(char *buf, size_t l, usec_t t);
|
||||
char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy);
|
||||
|
||||
static inline char *format_timestamp(char *buf, size_t l, usec_t t) {
|
||||
return format_timestamp_style(buf, l, t, TIMESTAMP_PRETTY);
|
||||
}
|
||||
|
||||
int parse_timestamp(const char *t, usec_t *usec);
|
||||
|
||||
int parse_sec(const char *t, usec_t *usec);
|
||||
@ -185,3 +195,6 @@ static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
|
||||
#endif
|
||||
|
||||
int time_change_fd(void);
|
||||
|
||||
const char* timestamp_style_to_string(TimestampStyle t) _const_;
|
||||
TimestampStyle timestamp_style_from_string(const char *s) _pure_;
|
||||
|
@ -265,7 +265,7 @@ get_parent:
|
||||
static char *format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) {
|
||||
|
||||
if (arg_utc)
|
||||
return format_timestamp_utc(buf, l, t);
|
||||
return format_timestamp_style(buf, l, t, TIMESTAMP_UTC);
|
||||
|
||||
return format_timestamp(buf, l, t);
|
||||
}
|
||||
|
@ -1335,7 +1335,7 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas
|
||||
if (d->type == TABLE_TIMESTAMP)
|
||||
ret = format_timestamp(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
|
||||
else if (d->type == TABLE_TIMESTAMP_UTC)
|
||||
ret = format_timestamp_utc(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
|
||||
ret = format_timestamp_style(p, FORMAT_TIMESTAMP_MAX, d->timestamp, TIMESTAMP_UTC);
|
||||
else
|
||||
ret = format_timestamp_relative(p, FORMAT_TIMESTAMP_MAX, d->timestamp);
|
||||
if (!ret)
|
||||
|
@ -368,7 +368,7 @@ static int output_timestamp_realtime(FILE *f, sd_journal *j, OutputMode mode, Ou
|
||||
const char *k;
|
||||
|
||||
if (flags & OUTPUT_UTC)
|
||||
k = format_timestamp_utc(buf, sizeof(buf), x);
|
||||
k = format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC);
|
||||
else
|
||||
k = format_timestamp(buf, sizeof(buf), x);
|
||||
if (!k)
|
||||
@ -685,8 +685,8 @@ static int output_verbose(
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get cursor: %m");
|
||||
|
||||
timestamp = flags & OUTPUT_UTC ? format_timestamp_us_utc(ts, sizeof ts, realtime)
|
||||
: format_timestamp_us(ts, sizeof ts, realtime);
|
||||
timestamp = format_timestamp_style(ts, sizeof ts, realtime,
|
||||
flags & OUTPUT_UTC ? TIMESTAMP_US_UTC : TIMESTAMP_US);
|
||||
fprintf(f, "%s [%s]\n",
|
||||
timestamp ?: "(no timestamp)",
|
||||
cursor);
|
||||
|
@ -58,7 +58,7 @@ static void test_next(const char *input, const char *new_tz, usec_t after, usec_
|
||||
|
||||
u = after;
|
||||
r = calendar_spec_next_usec(c, after, &u);
|
||||
printf("At: %s\n", r < 0 ? strerror_safe(r) : format_timestamp_us(buf, sizeof buf, u));
|
||||
printf("At: %s\n", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US));
|
||||
if (expect != (usec_t)-1)
|
||||
assert_se(r >= 0 && u == expect);
|
||||
else
|
||||
@ -83,7 +83,7 @@ static void test_timestamp(void) {
|
||||
|
||||
x = now(CLOCK_REALTIME);
|
||||
|
||||
assert_se(format_timestamp_us(buf, sizeof(buf), x));
|
||||
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US));
|
||||
printf("%s\n", buf);
|
||||
assert_se(calendar_spec_from_string(buf, &c) >= 0);
|
||||
assert_se(calendar_spec_to_string(c, &t) >= 0);
|
||||
@ -104,11 +104,11 @@ static void test_hourly_bug_4031(void) {
|
||||
n = now(CLOCK_REALTIME);
|
||||
assert_se((r = calendar_spec_next_usec(c, n, &u)) >= 0);
|
||||
|
||||
printf("Now: %s (%"PRIu64")\n", format_timestamp_us(buf, sizeof buf, n), n);
|
||||
printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_us(buf, sizeof buf, u), u);
|
||||
printf("Now: %s (%"PRIu64")\n", format_timestamp_style(buf, sizeof buf, n, TIMESTAMP_US), n);
|
||||
printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US), u);
|
||||
|
||||
assert_se((r = calendar_spec_next_usec(c, u, &w)) >= 0);
|
||||
printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_us(zaf, sizeof zaf, w), w);
|
||||
printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_style(zaf, sizeof zaf, w, TIMESTAMP_US), w);
|
||||
|
||||
assert_se(n < u);
|
||||
assert_se(u <= n + USEC_PER_HOUR);
|
||||
|
@ -11,7 +11,7 @@ static void test_should_pass(const char *p) {
|
||||
|
||||
log_info("Test: %s", p);
|
||||
assert_se(parse_timestamp(p, &t) >= 0);
|
||||
assert_se(format_timestamp_us(buf, sizeof(buf), t));
|
||||
assert_se(format_timestamp_style(buf, sizeof(buf), t, TIMESTAMP_US));
|
||||
log_info("\"%s\" → \"%s\"", p, buf);
|
||||
|
||||
assert_se(parse_timestamp(buf, &q) >= 0);
|
||||
@ -19,7 +19,7 @@ static void test_should_pass(const char *p) {
|
||||
char tmp[FORMAT_TIMESTAMP_MAX];
|
||||
|
||||
log_error("round-trip failed: \"%s\" → \"%s\"",
|
||||
buf, format_timestamp_us(tmp, sizeof(tmp), q));
|
||||
buf, format_timestamp_style(tmp, sizeof(tmp), q, TIMESTAMP_US));
|
||||
}
|
||||
assert_se(q == t);
|
||||
|
||||
|
@ -333,17 +333,17 @@ static void test_format_timestamp(void) {
|
||||
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));
|
||||
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC));
|
||||
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));
|
||||
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US));
|
||||
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));
|
||||
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US_UTC));
|
||||
log_info("%s", buf);
|
||||
assert_se(parse_timestamp(buf, &y) >= 0);
|
||||
assert_se(x == y);
|
||||
@ -364,7 +364,7 @@ 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);
|
||||
t = format_timestamp_style(buf, sizeof(buf), val, TIMESTAMP_UTC);
|
||||
assert_se(streq_ptr(t, result));
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ static int clock_state_update(
|
||||
if (tx.status & STA_NANO)
|
||||
tx.time.tv_usec /= 1000;
|
||||
t = timeval_load(&tx.time);
|
||||
ts = format_timestamp_us_utc(buf, sizeof(buf), t);
|
||||
ts = format_timestamp_style(buf, sizeof(buf), t, TIMESTAMP_US_UTC);
|
||||
if (!ts)
|
||||
strcpy(buf, "unrepresentable");
|
||||
log_info("adjtime state %d status %x time %s", sp->adjtime_state, tx.status, ts);
|
||||
|
@ -611,7 +611,7 @@ static int dir_cleanup(
|
||||
/* Follows spelling in stat(1). */
|
||||
log_debug("Directory \"%s\": modify time %s is too new.",
|
||||
sub_path,
|
||||
format_timestamp_us(a, sizeof(a), age));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -620,7 +620,7 @@ static int dir_cleanup(
|
||||
char a[FORMAT_TIMESTAMP_MAX];
|
||||
log_debug("Directory \"%s\": access time %s is too new.",
|
||||
sub_path,
|
||||
format_timestamp_us(a, sizeof(a), age));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -672,7 +672,7 @@ static int dir_cleanup(
|
||||
/* Follows spelling in stat(1). */
|
||||
log_debug("File \"%s\": modify time %s is too new.",
|
||||
sub_path,
|
||||
format_timestamp_us(a, sizeof(a), age));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -681,7 +681,7 @@ static int dir_cleanup(
|
||||
char a[FORMAT_TIMESTAMP_MAX];
|
||||
log_debug("File \"%s\": access time %s is too new.",
|
||||
sub_path,
|
||||
format_timestamp_us(a, sizeof(a), age));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -690,7 +690,7 @@ static int dir_cleanup(
|
||||
char a[FORMAT_TIMESTAMP_MAX];
|
||||
log_debug("File \"%s\": change time %s is too new.",
|
||||
sub_path,
|
||||
format_timestamp_us(a, sizeof(a), age));
|
||||
format_timestamp_style(a, sizeof(a), age, TIMESTAMP_US));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -713,8 +713,8 @@ finish:
|
||||
|
||||
log_debug("Restoring access and modification time on \"%s\": %s, %s",
|
||||
p,
|
||||
format_timestamp_us(a, sizeof(a), age1),
|
||||
format_timestamp_us(b, sizeof(b), age2));
|
||||
format_timestamp_style(a, sizeof(a), age1, TIMESTAMP_US),
|
||||
format_timestamp_style(b, sizeof(b), age2, TIMESTAMP_US));
|
||||
|
||||
/* Restore original directory timestamps */
|
||||
if (futimens(dirfd(d), (struct timespec[]) {
|
||||
@ -2228,7 +2228,7 @@ static int clean_item_instance(Item *i, const char* instance) {
|
||||
log_debug("Cleanup threshold for %s \"%s\" is %s",
|
||||
mountpoint ? "mount point" : "directory",
|
||||
instance,
|
||||
format_timestamp_us(timestamp, sizeof(timestamp), cutoff));
|
||||
format_timestamp_style(timestamp, sizeof(timestamp), cutoff, TIMESTAMP_US));
|
||||
|
||||
return dir_cleanup(i, instance, d, &s, cutoff, s.st_dev, mountpoint,
|
||||
MAX_DEPTH, i->keep_first_level);
|
||||
|
Loading…
x
Reference in New Issue
Block a user