1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-12-24 21:34:08 +03:00

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".
This commit is contained in:
Anders Wenhaug 2021-06-20 21:43:07 +02:00 committed by Anders Wenhaug
parent df8fd03a7d
commit 45eb4d2261
2 changed files with 105 additions and 12 deletions

View File

@ -429,18 +429,36 @@ char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
s = "left"; s = "left";
} }
if (d >= USEC_PER_YEAR) if (d >= USEC_PER_YEAR) {
snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s", usec_t years = d / USEC_PER_YEAR;
d / USEC_PER_YEAR, usec_t months = (d % USEC_PER_YEAR) / USEC_PER_MONTH;
(d % USEC_PER_YEAR) / USEC_PER_MONTH, s); snprintf(buf, l, USEC_FMT " %s " USEC_FMT " %s %s",
else if (d >= USEC_PER_MONTH) years,
snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s", years == 1 ? "year" : "years",
d / USEC_PER_MONTH, months,
(d % USEC_PER_MONTH) / USEC_PER_DAY, s); months == 1 ? "month" : "months",
else if (d >= USEC_PER_WEEK) s);
snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s", }
d / USEC_PER_WEEK, else if (d >= USEC_PER_MONTH) {
(d % USEC_PER_WEEK) / USEC_PER_DAY, s); 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) else if (d >= 2*USEC_PER_DAY)
snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s); snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
else if (d >= 25*USEC_PER_HOUR) else if (d >= 25*USEC_PER_HOUR)

View 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) { static void test_format_timestamp_utc_one(usec_t val, const char *result) {
char buf[FORMAT_TIMESTAMP_MAX]; char buf[FORMAT_TIMESTAMP_MAX];
const char *t; const char *t;
@ -539,6 +613,7 @@ int main(int argc, char *argv[]) {
test_usec_sub_signed(); test_usec_sub_signed();
test_usec_sub_unsigned(); test_usec_sub_unsigned();
test_format_timestamp(); test_format_timestamp();
test_format_timestamp_relative();
test_format_timestamp_utc(); test_format_timestamp_utc();
test_deserialize_dual_timestamp(); test_deserialize_dual_timestamp();
test_usec_shift_clock(); test_usec_shift_clock();