diff options
author | Anders Wenhaug <awenhaug@gmail.com> | 2021-06-20 21:43:07 +0200 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2021-07-20 17:53:34 +0200 |
commit | f3f4ace8ea15ada14495a92b24e207769955b1e5 (patch) | |
tree | 00f6c59767613fba39782290ebf5f38dfff61e75 | |
parent | 8e00d92fc27df97c1fe578c35c82e096d0aa1670 (diff) | |
download | systemd-f3f4ace8ea15ada14495a92b24e207769955b1e5.tar.gz |
time-util: don't use plural units indiscriminately
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".
(cherry picked from commit 45eb4d2261ed0d943fd503a6d79ee3b7b7558c09)
(cherry picked from commit e74329ce9fa7ccb025960f9b220dff9e556a80e5)
-rw-r--r-- | src/basic/time-util.c | 42 | ||||
-rw-r--r-- | src/test/test-time-util.c | 75 |
2 files changed, 105 insertions, 12 deletions
diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 5318d6378d..c32608edbb 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -430,18 +430,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) diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c index cc391e81a0..a40cc52314 100644 --- a/src/test/test-time-util.c +++ b/src/test/test-time-util.c @@ -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(); |