8d419f
From 5f59cc1593eaa251161061fe9a4ac4afb1592e6e Mon Sep 17 00:00:00 2001
8d419f
From: Frantisek Sumsal <frantisek@sumsal.cz>
8d419f
Date: Mon, 21 Feb 2022 13:08:20 +0100
8d419f
Subject: [PATCH] time-util: introduce TIMESTAMP_UNIX
8d419f
8d419f
Allow formatting timestamps as number of seconds since the Epoch for easier
8d419f
machine parsing.
8d419f
8d419f
Fixes: #22567
8d419f
8d419f
```
8d419f
$ systemctl show systemd-journald | grep Timestamp
8d419f
WatchdogTimestampMonotonic=0
8d419f
ExecMainStartTimestamp=Sat 2021-12-11 15:25:57 CET
8d419f
ExecMainStartTimestampMonotonic=13030408
8d419f
ExecMainExitTimestampMonotonic=0
8d419f
StateChangeTimestamp=Sat 2021-12-11 15:25:57 CET
8d419f
StateChangeTimestampMonotonic=13049273
8d419f
InactiveExitTimestamp=Sat 2021-12-11 15:25:57 CET
8d419f
InactiveExitTimestampMonotonic=13030430
8d419f
ActiveEnterTimestamp=Sat 2021-12-11 15:25:57 CET
8d419f
ActiveEnterTimestampMonotonic=13049273
8d419f
ActiveExitTimestamp=Sat 2021-12-11 15:25:57 CET
8d419f
ActiveExitTimestampMonotonic=12997236
8d419f
InactiveEnterTimestamp=Sat 2021-12-11 15:25:57 CET
8d419f
InactiveEnterTimestampMonotonic=13028890
8d419f
ConditionTimestamp=Sat 2021-12-11 15:25:57 CET
8d419f
ConditionTimestampMonotonic=13029539
8d419f
AssertTimestamp=Sat 2021-12-11 15:25:57 CET
8d419f
AssertTimestampMonotonic=13029540
8d419f
8d419f
$ systemctl show --timestamp=unix systemd-journald | grep Timestamp
8d419f
WatchdogTimestampMonotonic=0
8d419f
ExecMainStartTimestamp=@1639232757
8d419f
ExecMainStartTimestampMonotonic=13030408
8d419f
ExecMainExitTimestampMonotonic=0
8d419f
StateChangeTimestamp=@1639232757
8d419f
StateChangeTimestampMonotonic=13049273
8d419f
InactiveExitTimestamp=@1639232757
8d419f
InactiveExitTimestampMonotonic=13030430
8d419f
ActiveEnterTimestamp=@1639232757
8d419f
ActiveEnterTimestampMonotonic=13049273
8d419f
ActiveExitTimestamp=@1639232757
8d419f
ActiveExitTimestampMonotonic=12997236
8d419f
InactiveEnterTimestamp=@1639232757
8d419f
InactiveEnterTimestampMonotonic=13028890
8d419f
ConditionTimestamp=@1639232757
8d419f
ConditionTimestampMonotonic=13029539
8d419f
AssertTimestamp=@1639232757
8d419f
AssertTimestampMonotonic=13029540
8d419f
```
8d419f
8d419f
(cherry picked from commit ed4a5b434517eeebc508379476cf112704e7981c)
8d419f
8d419f
Related: #2017035
8d419f
---
8d419f
 src/basic/time-util.c     | 11 +++++++++++
8d419f
 src/basic/time-util.h     |  1 +
8d419f
 src/test/test-time-util.c |  5 +++++
8d419f
 3 files changed, 17 insertions(+)
8d419f
8d419f
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
8d419f
index b659d6905d..c0841af8f3 100644
8d419f
--- a/src/basic/time-util.c
8d419f
+++ b/src/basic/time-util.c
8d419f
@@ -320,11 +320,13 @@ char *format_timestamp_style(
8d419f
         time_t sec;
8d419f
         size_t n;
8d419f
         bool utc = false, us = false;
8d419f
+        int r;
8d419f
 
8d419f
         assert(buf);
8d419f
 
8d419f
         switch (style) {
8d419f
                 case TIMESTAMP_PRETTY:
8d419f
+                case TIMESTAMP_UNIX:
8d419f
                         break;
8d419f
                 case TIMESTAMP_US:
8d419f
                         us = true;
8d419f
@@ -350,6 +352,14 @@ char *format_timestamp_style(
8d419f
         if (t <= 0 || t == USEC_INFINITY)
8d419f
                 return NULL; /* Timestamp is unset */
8d419f
 
8d419f
+        if (style == TIMESTAMP_UNIX) {
8d419f
+                r = snprintf(buf, l, "@" USEC_FMT, t / USEC_PER_SEC);  /* round down µs → s */
8d419f
+                if (r < 0 || (size_t) r >= l)
8d419f
+                        return NULL; /* Doesn't fit */
8d419f
+
8d419f
+                return buf;
8d419f
+        }
8d419f
+
8d419f
         /* Let's not format times with years > 9999 */
8d419f
         if (t > USEC_TIMESTAMP_FORMATTABLE_MAX) {
8d419f
                 assert(l >= STRLEN("--- XXXX-XX-XX XX:XX:XX") + 1);
8d419f
@@ -1632,6 +1642,7 @@ static const char* const timestamp_style_table[_TIMESTAMP_STYLE_MAX] = {
8d419f
         [TIMESTAMP_US] = "us",
8d419f
         [TIMESTAMP_UTC] = "utc",
8d419f
         [TIMESTAMP_US_UTC] = "us+utc",
8d419f
+        [TIMESTAMP_UNIX] = "unix",
8d419f
 };
8d419f
 
8d419f
 /* Use the macro for enum → string to allow for aliases */
8d419f
diff --git a/src/basic/time-util.h b/src/basic/time-util.h
8d419f
index 895af88299..01a72026e3 100644
8d419f
--- a/src/basic/time-util.h
8d419f
+++ b/src/basic/time-util.h
8d419f
@@ -34,6 +34,7 @@ typedef enum TimestampStyle {
8d419f
         TIMESTAMP_US,
8d419f
         TIMESTAMP_UTC,
8d419f
         TIMESTAMP_US_UTC,
8d419f
+        TIMESTAMP_UNIX,
8d419f
         _TIMESTAMP_STYLE_MAX,
8d419f
         _TIMESTAMP_STYLE_INVALID = -EINVAL,
8d419f
 } TimestampStyle;
8d419f
diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c
8d419f
index 554693834b..799d271a44 100644
8d419f
--- a/src/test/test-time-util.c
8d419f
+++ b/src/test/test-time-util.c
8d419f
@@ -325,6 +325,11 @@ TEST(format_timestamp) {
8d419f
                 assert_se(parse_timestamp(buf, &y) >= 0);
8d419f
                 assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
8d419f
 
8d419f
+                assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UNIX));
8d419f
+                log_debug("%s", buf);
8d419f
+                assert_se(parse_timestamp(buf, &y) >= 0);
8d419f
+                assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC);
8d419f
+
8d419f
                 assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC));
8d419f
                 log_debug("%s", buf);
8d419f
                 assert_se(parse_timestamp(buf, &y) >= 0);