]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
time-util: don't use plural units indiscriminately 19981/head
authorAnders Wenhaug <awenhaug@gmail.com>
Sun, 20 Jun 2021 19:43:07 +0000 (21:43 +0200)
committerAnders Wenhaug <anders@wenhaug.no>
Sun, 20 Jun 2021 19:54:37 +0000 (21:54 +0200)
format_timestamp_relative currently returns the plural form of
years and months no matter the quantity, and in many cases (for
durations > 1 week) this is the same with days.

This patch changes this so that the function takes the quantity into account,
returning "1 month 1 week ago" instead of "1 months 1 weeks ago".

src/basic/time-util.c
src/test/test-time-util.c

index 26a6762b179588ea196248799766b6a552a7a33b..3063b7581a38b75ab050b78041b91480a199aa50 100644 (file)
@@ -429,18 +429,36 @@ char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
                 s = "left";
         }
 
-        if (d >= USEC_PER_YEAR)
-                snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
-                         d / USEC_PER_YEAR,
-                         (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
-        else if (d >= USEC_PER_MONTH)
-                snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
-                         d / USEC_PER_MONTH,
-                         (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
-        else if (d >= USEC_PER_WEEK)
-                snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
-                         d / USEC_PER_WEEK,
-                         (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
+        if (d >= USEC_PER_YEAR) {
+                usec_t years = d / USEC_PER_YEAR;
+                usec_t months = (d % USEC_PER_YEAR) / USEC_PER_MONTH;
+                snprintf(buf, l, USEC_FMT " %s " USEC_FMT " %s %s",
+                         years,
+                         years == 1 ? "year" : "years",
+                         months,
+                         months == 1 ? "month" : "months",
+                         s);
+        }
+        else if (d >= USEC_PER_MONTH) {
+                usec_t months = d / USEC_PER_MONTH;
+                usec_t days = (d % USEC_PER_MONTH) / USEC_PER_DAY;
+                snprintf(buf, l, USEC_FMT " %s " USEC_FMT " %s %s",
+                         months,
+                         months == 1 ? "month" : "months",
+                         days,
+                         days == 1 ? "day" : "days",
+                         s);
+        }
+        else if (d >= USEC_PER_WEEK) {
+                usec_t weeks = d / USEC_PER_WEEK;
+                usec_t days = (d % USEC_PER_WEEK) / USEC_PER_DAY;
+                snprintf(buf, l, USEC_FMT " %s " USEC_FMT " %s %s",
+                         weeks,
+                         weeks == 1 ? "week" : "weeks",
+                         days,
+                         days == 1 ? "day" : "days",
+                         s);
+        }
         else if (d >= 2*USEC_PER_DAY)
                 snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
         else if (d >= 25*USEC_PER_HOUR)
index cc391e81a051ff91e7134e48ffb1c64c7c769266..a40cc523142f51c24171f61df4d8cd26a85677b5 100644 (file)
@@ -360,6 +360,80 @@ static void test_format_timestamp(void) {
         }
 }
 
+static void test_format_timestamp_relative(void) {
+        log_info("/* %s */", __func__);
+
+        char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)];
+        usec_t x;
+
+        /* Only testing timestamps in the past so we don't need to add some delta to account for time passing
+         * by while we are running the tests (unless we're running on potatoes and 24 hours somehow passes
+         * between our call to now() and format_timestamp_relative's call to now()). */
+
+        /* Years and months */
+        x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 1*USEC_PER_MONTH);
+        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
+        log_info("%s", buf);
+        assert_se(streq(buf, "1 year 1 month ago"));
+
+        x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 2*USEC_PER_MONTH);
+        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
+        log_info("%s", buf);
+        assert_se(streq(buf, "1 year 2 months ago"));
+
+        x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 1*USEC_PER_MONTH);
+        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
+        log_info("%s", buf);
+        assert_se(streq(buf, "2 years 1 month ago"));
+
+        x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 2*USEC_PER_MONTH);
+        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
+        log_info("%s", buf);
+        assert_se(streq(buf, "2 years 2 months ago"));
+
+        /* Months and days */
+        x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 1*USEC_PER_DAY);
+        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
+        log_info("%s", buf);
+        assert_se(streq(buf, "1 month 1 day ago"));
+
+        x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 2*USEC_PER_DAY);
+        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
+        log_info("%s", buf);
+        assert_se(streq(buf, "1 month 2 days ago"));
+
+        x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 1*USEC_PER_DAY);
+        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
+        log_info("%s", buf);
+        assert_se(streq(buf, "2 months 1 day ago"));
+
+        x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 2*USEC_PER_DAY);
+        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
+        log_info("%s", buf);
+        assert_se(streq(buf, "2 months 2 days ago"));
+
+        /* Weeks and days */
+        x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 1*USEC_PER_DAY);
+        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
+        log_info("%s", buf);
+        assert_se(streq(buf, "1 week 1 day ago"));
+
+        x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 2*USEC_PER_DAY);
+        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
+        log_info("%s", buf);
+        assert_se(streq(buf, "1 week 2 days ago"));
+
+        x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 1*USEC_PER_DAY);
+        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
+        log_info("%s", buf);
+        assert_se(streq(buf, "2 weeks 1 day ago"));
+
+        x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 2*USEC_PER_DAY);
+        assert_se(format_timestamp_relative(buf, sizeof(buf), x));
+        log_info("%s", buf);
+        assert_se(streq(buf, "2 weeks 2 days ago"));
+}
+
 static void test_format_timestamp_utc_one(usec_t val, const char *result) {
         char buf[FORMAT_TIMESTAMP_MAX];
         const char *t;
@@ -539,6 +613,7 @@ int main(int argc, char *argv[]) {
         test_usec_sub_signed();
         test_usec_sub_unsigned();
         test_format_timestamp();
+        test_format_timestamp_relative();
         test_format_timestamp_utc();
         test_deserialize_dual_timestamp();
         test_usec_shift_clock();