summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnders Wenhaug <awenhaug@gmail.com>2021-06-20 21:43:07 +0200
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2021-07-20 17:53:34 +0200
commitf3f4ace8ea15ada14495a92b24e207769955b1e5 (patch)
tree00f6c59767613fba39782290ebf5f38dfff61e75
parent8e00d92fc27df97c1fe578c35c82e096d0aa1670 (diff)
downloadsystemd-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.c42
-rw-r--r--src/test/test-time-util.c75
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();