diff options
-rw-r--r-- | src/basic/time-util.c | 32 | ||||
-rw-r--r-- | src/basic/time-util.h | 7 | ||||
-rw-r--r-- | src/shared/format-table.c | 13 | ||||
-rw-r--r-- | src/shared/format-table.h | 1 | ||||
-rw-r--r-- | src/test/test-time-util.c | 68 |
5 files changed, 102 insertions, 19 deletions
diff --git a/src/basic/time-util.c b/src/basic/time-util.c index b700f364ef..bae62ce411 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -418,7 +418,7 @@ char *format_timestamp_style( return buf; } -char *format_timestamp_relative(char *buf, size_t l, usec_t t) { +char* format_timestamp_relative_full(char *buf, size_t l, usec_t t, bool implicit_left) { const char *s; usec_t n, d; @@ -428,17 +428,17 @@ char *format_timestamp_relative(char *buf, size_t l, usec_t t) { n = now(CLOCK_REALTIME); if (n > t) { d = n - t; - s = "ago"; + s = " ago"; } else { d = t - n; - s = "left"; + s = implicit_left ? "" : " left"; } if (d >= USEC_PER_YEAR) { usec_t years = d / USEC_PER_YEAR; usec_t months = (d % USEC_PER_YEAR) / USEC_PER_MONTH; - (void) snprintf(buf, l, USEC_FMT " %s " USEC_FMT " %s %s", + (void) snprintf(buf, l, USEC_FMT " %s " USEC_FMT " %s%s", years, years == 1 ? "year" : "years", months, @@ -448,7 +448,7 @@ char *format_timestamp_relative(char *buf, size_t l, usec_t t) { usec_t months = d / USEC_PER_MONTH; usec_t days = (d % USEC_PER_MONTH) / USEC_PER_DAY; - (void) snprintf(buf, l, USEC_FMT " %s " USEC_FMT " %s %s", + (void) snprintf(buf, l, USEC_FMT " %s " USEC_FMT " %s%s", months, months == 1 ? "month" : "months", days, @@ -458,39 +458,39 @@ char *format_timestamp_relative(char *buf, size_t l, usec_t t) { usec_t weeks = d / USEC_PER_WEEK; usec_t days = (d % USEC_PER_WEEK) / USEC_PER_DAY; - (void) snprintf(buf, l, USEC_FMT " %s " USEC_FMT " %s %s", + (void) 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) - (void) snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s); + (void) snprintf(buf, l, USEC_FMT " days%s", d / USEC_PER_DAY,s); else if (d >= 25*USEC_PER_HOUR) - (void) snprintf(buf, l, "1 day " USEC_FMT "h %s", + (void) snprintf(buf, l, "1 day " USEC_FMT "h%s", (d - USEC_PER_DAY) / USEC_PER_HOUR, s); else if (d >= 6*USEC_PER_HOUR) - (void) snprintf(buf, l, USEC_FMT "h %s", + (void) snprintf(buf, l, USEC_FMT "h%s", d / USEC_PER_HOUR, s); else if (d >= USEC_PER_HOUR) - (void) snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s", + (void) snprintf(buf, l, USEC_FMT "h " USEC_FMT "min%s", d / USEC_PER_HOUR, (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s); else if (d >= 5*USEC_PER_MINUTE) - (void) snprintf(buf, l, USEC_FMT "min %s", + (void) snprintf(buf, l, USEC_FMT "min%s", d / USEC_PER_MINUTE, s); else if (d >= USEC_PER_MINUTE) - (void) snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s", + (void) snprintf(buf, l, USEC_FMT "min " USEC_FMT "s%s", d / USEC_PER_MINUTE, (d % USEC_PER_MINUTE) / USEC_PER_SEC, s); else if (d >= USEC_PER_SEC) - (void) snprintf(buf, l, USEC_FMT "s %s", + (void) snprintf(buf, l, USEC_FMT "s%s", d / USEC_PER_SEC, s); else if (d >= USEC_PER_MSEC) - (void) snprintf(buf, l, USEC_FMT "ms %s", + (void) snprintf(buf, l, USEC_FMT "ms%s", d / USEC_PER_MSEC, s); else if (d > 0) - (void) snprintf(buf, l, USEC_FMT"us %s", + (void) snprintf(buf, l, USEC_FMT"us%s", d, s); else (void) snprintf(buf, l, "now"); @@ -499,7 +499,7 @@ char *format_timestamp_relative(char *buf, size_t l, usec_t t) { return buf; } -char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { +char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { static const struct { const char *suffix; usec_t usec; diff --git a/src/basic/time-util.h b/src/basic/time-util.h index c5ae0c98d4..0ed19d04ad 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -124,10 +124,15 @@ struct timeval* timeval_store(struct timeval *tv, usec_t u); #define TIMEVAL_STORE(u) timeval_store(&(struct timeval) {}, (u)) char* format_timestamp_style(char *buf, size_t l, usec_t t, TimestampStyle style) _warn_unused_result_; -char* format_timestamp_relative(char *buf, size_t l, usec_t t) _warn_unused_result_; +char* format_timestamp_relative_full(char *buf, size_t l, usec_t t, bool implicit_left) _warn_unused_result_; char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) _warn_unused_result_; _warn_unused_result_ +static inline char* format_timestamp_relative(char *buf, size_t l, usec_t t) { + return format_timestamp_relative_full(buf, l, t, false); +} + +_warn_unused_result_ static inline char* format_timestamp(char *buf, size_t l, usec_t t) { return format_timestamp_style(buf, l, t, TIMESTAMP_PRETTY); } diff --git a/src/shared/format-table.c b/src/shared/format-table.c index ee45d4fd9e..351a5ede11 100644 --- a/src/shared/format-table.c +++ b/src/shared/format-table.c @@ -297,6 +297,7 @@ static size_t table_data_size(TableDataType type, const void *data) { case TABLE_TIMESTAMP: case TABLE_TIMESTAMP_UTC: case TABLE_TIMESTAMP_RELATIVE: + case TABLE_TIMESTAMP_LEFT: case TABLE_TIMESTAMP_DATE: case TABLE_TIMESPAN: case TABLE_TIMESPAN_MSEC: @@ -896,6 +897,7 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) { case TABLE_TIMESTAMP: case TABLE_TIMESTAMP_UTC: case TABLE_TIMESTAMP_RELATIVE: + case TABLE_TIMESTAMP_LEFT: case TABLE_TIMESTAMP_DATE: case TABLE_TIMESPAN: case TABLE_TIMESPAN_MSEC: @@ -1304,6 +1306,7 @@ static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t case TABLE_TIMESTAMP: case TABLE_TIMESTAMP_UTC: case TABLE_TIMESTAMP_RELATIVE: + case TABLE_TIMESTAMP_LEFT: case TABLE_TIMESTAMP_DATE: return CMP(a->timestamp, b->timestamp); @@ -1537,11 +1540,14 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas case TABLE_TIMESTAMP: case TABLE_TIMESTAMP_UTC: case TABLE_TIMESTAMP_RELATIVE: + case TABLE_TIMESTAMP_LEFT: case TABLE_TIMESTAMP_DATE: { _cleanup_free_ char *p = NULL; char *ret; - p = new(char, d->type == TABLE_TIMESTAMP_RELATIVE ? FORMAT_TIMESTAMP_RELATIVE_MAX : FORMAT_TIMESTAMP_MAX); + p = new(char, + IN_SET(d->type, TABLE_TIMESTAMP_RELATIVE, TABLE_TIMESTAMP_LEFT) ? + FORMAT_TIMESTAMP_RELATIVE_MAX : FORMAT_TIMESTAMP_MAX); if (!p) return NULL; @@ -1552,7 +1558,9 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas else if (d->type == TABLE_TIMESTAMP_DATE) ret = format_timestamp_style(p, FORMAT_TIMESTAMP_MAX, d->timestamp, TIMESTAMP_DATE); else - ret = format_timestamp_relative(p, FORMAT_TIMESTAMP_RELATIVE_MAX, d->timestamp); + ret = format_timestamp_relative_full( + p, FORMAT_TIMESTAMP_RELATIVE_MAX, d->timestamp, + /* implicit_left= */ d->type == TABLE_TIMESTAMP_LEFT); if (!ret) return "-"; @@ -2589,6 +2597,7 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) { case TABLE_TIMESTAMP: case TABLE_TIMESTAMP_UTC: case TABLE_TIMESTAMP_RELATIVE: + case TABLE_TIMESTAMP_LEFT: case TABLE_TIMESTAMP_DATE: if (d->timestamp == USEC_INFINITY) return json_variant_new_null(ret); diff --git a/src/shared/format-table.h b/src/shared/format-table.h index 97255f5aef..5a2b366b59 100644 --- a/src/shared/format-table.h +++ b/src/shared/format-table.h @@ -23,6 +23,7 @@ typedef enum TableDataType { TABLE_TIMESTAMP, TABLE_TIMESTAMP_UTC, TABLE_TIMESTAMP_RELATIVE, + TABLE_TIMESTAMP_LEFT, TABLE_TIMESTAMP_DATE, TABLE_TIMESPAN, TABLE_TIMESPAN_MSEC, diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c index 0fb76391fd..dee012fa2e 100644 --- a/src/test/test-time-util.c +++ b/src/test/test-time-util.c @@ -401,6 +401,74 @@ TEST(FORMAT_TIMESTAMP) { } } +TEST(format_timestamp_relative_full) { + char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)]; + usec_t x; + + /* Years and months */ + x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 1*USEC_PER_MONTH); + assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, true)); + log_debug("%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_full(buf, sizeof(buf), x, true)); + log_debug("%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_full(buf, sizeof(buf), x, true)); + log_debug("%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_full(buf, sizeof(buf), x, true)); + log_debug("%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_full(buf, sizeof(buf), x, true)); + log_debug("%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_full(buf, sizeof(buf), x, true)); + log_debug("%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_full(buf, sizeof(buf), x, true)); + log_debug("%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_full(buf, sizeof(buf), x, true)); + log_debug("%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_full(buf, sizeof(buf), x, true)); + log_debug("%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_full(buf, sizeof(buf), x, true)); + log_debug("%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_full(buf, sizeof(buf), x, true)); + log_debug("%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_full(buf, sizeof(buf), x, true)); + log_debug("%s", buf); + assert_se(streq(buf, "2 weeks 2 days ago")); +} + TEST(format_timestamp_relative) { char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)]; usec_t x; |