Allow formatting timestamps as number of seconds since the Epoch for easier
machine parsing.
Fixes: #22567
```
$ systemctl show systemd-journald | grep Timestamp
WatchdogTimestampMonotonic=0
ExecMainStartTimestamp=Sat 2021-12-11 15:25:57 CET
ExecMainStartTimestampMonotonic=
13030408
ExecMainExitTimestampMonotonic=0
StateChangeTimestamp=Sat 2021-12-11 15:25:57 CET
StateChangeTimestampMonotonic=
13049273
InactiveExitTimestamp=Sat 2021-12-11 15:25:57 CET
InactiveExitTimestampMonotonic=
13030430
ActiveEnterTimestamp=Sat 2021-12-11 15:25:57 CET
ActiveEnterTimestampMonotonic=
13049273
ActiveExitTimestamp=Sat 2021-12-11 15:25:57 CET
ActiveExitTimestampMonotonic=
12997236
InactiveEnterTimestamp=Sat 2021-12-11 15:25:57 CET
InactiveEnterTimestampMonotonic=
13028890
ConditionTimestamp=Sat 2021-12-11 15:25:57 CET
ConditionTimestampMonotonic=
13029539
AssertTimestamp=Sat 2021-12-11 15:25:57 CET
AssertTimestampMonotonic=
13029540
$ systemctl show --timestamp=unix systemd-journald | grep Timestamp
WatchdogTimestampMonotonic=0
ExecMainStartTimestamp=@
1639232757
ExecMainStartTimestampMonotonic=
13030408
ExecMainExitTimestampMonotonic=0
StateChangeTimestamp=@
1639232757
StateChangeTimestampMonotonic=
13049273
InactiveExitTimestamp=@
1639232757
InactiveExitTimestampMonotonic=
13030430
ActiveEnterTimestamp=@
1639232757
ActiveEnterTimestampMonotonic=
13049273
ActiveExitTimestamp=@
1639232757
ActiveExitTimestampMonotonic=
12997236
InactiveEnterTimestamp=@
1639232757
InactiveEnterTimestampMonotonic=
13028890
ConditionTimestamp=@
1639232757
ConditionTimestampMonotonic=
13029539
AssertTimestamp=@
1639232757
AssertTimestampMonotonic=
13029540
```
time_t sec;
size_t n;
bool utc = false, us = false;
+ int r;
assert(buf);
switch (style) {
case TIMESTAMP_PRETTY:
+ case TIMESTAMP_UNIX:
break;
case TIMESTAMP_US:
us = true;
if (t <= 0 || t == USEC_INFINITY)
return NULL; /* Timestamp is unset */
+ if (style == TIMESTAMP_UNIX) {
+ r = snprintf(buf, l, "@" USEC_FMT, t / USEC_PER_SEC); /* round down µs → s */
+ if (r < 0 || (size_t) r >= l)
+ return NULL; /* Doesn't fit */
+
+ return buf;
+ }
+
/* Let's not format times with years > 9999 */
if (t > USEC_TIMESTAMP_FORMATTABLE_MAX) {
assert(l >= STRLEN("--- XXXX-XX-XX XX:XX:XX") + 1);
[TIMESTAMP_US] = "us",
[TIMESTAMP_UTC] = "utc",
[TIMESTAMP_US_UTC] = "us+utc",
+ [TIMESTAMP_UNIX] = "unix",
};
/* Use the macro for enum → string to allow for aliases */
TIMESTAMP_US,
TIMESTAMP_UTC,
TIMESTAMP_US_UTC,
+ TIMESTAMP_UNIX,
_TIMESTAMP_STYLE_MAX,
_TIMESTAMP_STYLE_INVALID = -EINVAL,
} TimestampStyle;
assert_se(parse_timestamp(buf, &y) >= 0);
assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
+ assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UNIX));
+ log_debug("%s", buf);
+ assert_se(parse_timestamp(buf, &y) >= 0);
+ assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
+
assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC));
log_debug("%s", buf);
assert_se(parse_timestamp(buf, &y) >= 0);