date: add --date=elapsed and %aX/%cX placeholders
PATCH 1/1 date: add --date=elapsed and %aX/%cX placeholders
From: Israel Roldan <[email protected]>
The --date=human format and the %cr/%ch placeholders both produce a localized English phrase that hides the precise amount of time that has passed. A commit shown as "2 days ago" may in reality be 1 day 3 hours, or 1 day 23 hours. Switching to %ct and a calculator solves the problem but is not glance-friendly.
Add an uptime(1)-style elapsed-time format:
--date=elapsed --date=elapsed-pad 39s 39s 8h 7m 48s 08h 07m 48s 1y 11M 5d 13h 5m 13s 01y 11M 05d 13h 05m 13s
The placeholder letter is X because the obvious choice E is already used for the mailmap-respecting email variants (%aE, %cE, %gE).
---
[RFC PATCH] date: add --date=elapsed and %aX/%cX placeholders
Motivation
==========
The --date=human format and the %cr/%ch placeholders both produce a localized English phrase that hides the precise amount of time that has passed. A commit shown as "2 days ago" may in reality be 1 day 3 hours, or 1 day 23 hours. Switching to %ct and a calculator solves the problem but is not glance-friendly.
The closest external tool that solves the same problem is git-log-compact by Kyle J. McKay (2016), which the maintainer declined to merge into Git core because it was a heavyweight change to the oneline output rather than a date format.
What this patch adds
====================
A new date format --date=elapsed and --date=elapsed-pad modelled on uptime(1):
seconds --date=elapsed --date=elapsed-pad
39 "39s" "39s"
984 "16m 24s" "16m 24s"
29268 "8h 7m 48s" "08h 07m 48s"
3024000 "1M 5d 0s" "01M 05d 00h 00m 00s"
60527113 "1y 11M 5d 13h 5m 13s" "01y 11M 05d 13h 05m 13s"
The padded variant zero-pads every emitted unit to at least two digits.
A commit timestamp that is in the future is reported as "0s", not the localized phrase "in the future" that show_date_relative() emits.
Months are fixed at 30 days and years at 365 days, matching the uptime(1) convention. They are consistent, and the same approximations are already in use by Git's own show_date_relative() for the relative-time format.
Two new pretty-format placeholders, %aX (author) and %cX (committer):
git log --format='%h (%aX) %s'
13c7afec21 (1d 2h 9s) The 8th batch
8c7817c361 (1y 3d 19h 5m 10s) Merge branch 'rj/meson-libexecdir-fix' 0e521a41b5 (11y 17d 21h 8m 40s) Merge branch 'et/http-proxyauth'
The placeholders mirror %ch and %cr, which also ignore the caller's --date= and emit a fixed shape.
Open questions
==============
Q1. The placeholder letter. The natural mnemonic is E (Elapsed), but %aE, %cE and %gE are already taken (mailmap-respecting email variants). This patch uses X as a free letter. Would the maintainer prefer a different letter? I am not attached to X.
Q2. Should --date=elapsed-pad be its own format name, or a separate --date=elapsed plus a flag? Which mirrors --date=human / --date=human-local / --date=iso / --date=iso-local.
Q3. The "future timestamp" behaviour. This patch clamps a future timestamp to "0s". An alternative would be to keep the relative format's "in the future" wording.
Q4. %aX/%cX are hard-coded compact; padded output requires %ad/%cd together with --date=elapsed-pad. Should a paired %aY/%cY for padded also exist, or is the asymmetry acceptable?
Patch
=====
The patch modifies the existing date_mode_type enum, adds a new show_date_elapsed() helper in date.c, wires it through show_date() and parse_date_format(), exposes two placeholders via format_person_part() in pretty.c, handles the new format in builtin/blame.c for column width, updates the documentation, and adds tests for both the date helper and the pretty-format placeholder equivalence.
The full patch is attached below.
Testing
=======
$ make DEVELOPER=1 && cd t &&
prove --no-color ./t0006-date.sh ./t4205-log-pretty-formats.sh ./t0006-date.sh ................ ok ./t4205-log-pretty-formats.sh .. ok All tests successful.
The full test suite (1054 test files, 33832 tests) also passes on this machine.
Thanks for your time. I am happy to iterate on any of the open questions before posting a non-RFC version.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2368%2Fairvzxf%2Ffeature%2Fdate-elapsed-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2368/airvzxf/feature/date-elapsed-v1
Pull-Request: https://github.com/git/git/pull/2368
Documentation/pretty-formats.adoc | 4 ++ Documentation/rev-list-options.adoc | 13 ++++ builtin/blame.c | 8 +++ contrib/completion/git-completion.bash | 2 +- date.c | 88 +++++++++++++++++++++++++- date.h | 4 +- pretty.c | 3 + t/helper/test-date.c | 19 +++++- t/t0006-date.sh | 43 +++++++++++++ t/t4205-log-pretty-formats.sh | 6 ++ 10 files changed, 186 insertions(+), 4 deletions(-)
Documentation/pretty-formats.adoc +4 -0
@@ -233,6 +233,8 @@ The placeholders are: +%as+:: author date, short format (`YYYY-MM-DD`) +%ah+:: author date, human style (like the `--date=human` option of linkgit:git-rev-list[1]) ++%aX+:: author date, elapsed (like the `--date=elapsed` option of + linkgit:git-rev-list[1]) +%cn+:: committer name +%cN+:: committer name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
@@ -251,6 +253,8 @@ The placeholders are: +%cs+:: committer date, short format (`YYYY-MM-DD`) +%ch+:: committer date, human style (like the `--date=human` option of linkgit:git-rev-list[1]) ++%cX+:: committer date, elapsed (like the `--date=elapsed` option of + linkgit:git-rev-list[1]) +%d+:: ref names, like the --decorate option of linkgit:git-log[1] +%D+:: ref names without the " (", ")" wrapping. +%(count)+:: the number of a patch within a patch series. Used only in
Documentation/rev-list-options.adoc +13 -0
@@ -1174,6 +1174,19 @@ omitted. 1970). As with `--raw`, this is always in UTC and therefore `-local` has no effect. +`--date=elapsed` shows the elapsed time between the commit and now, +in a compact, script-friendly, `uptime(1)`-style format. Only the +non-zero leading units are emitted, separated by single spaces. For +example "39s", "16m 24s", "8h 7m 48s", "12M 30d 13h 25m 43s", +"1y 11M 5d 13h 5m 13s". A commit timestamp that is in the future +is reported as "0s". Months are fixed at 30 days and years at 365 +days, matching the `uptime(1)` convention. + +`--date=elapsed-pad` is like `--date=elapsed`, but every emitted +unit is at least two digits wide, zero-padded on the left, so +that columns line up across rows. For example "16m 24s", +"08h 07m 48s", "01M 05d 00h 00m 00s", "01y 11M 05d 13h 05m 13s". + `--date=format:<format>` feeds the _<format>_ to your system `strftime`, except for `%s`, `%z`, and `%Z`, which are handled internally. Use `--date=format:%c` to show the date in your system locale's
builtin/blame.c +8 -0
@@ -1123,6 +1123,14 @@ parse_done:/* If the year is shown, no time is shown */ blame_date_width =sizeof ("Thu Oct 19 16:00" );break ; +case DATE_ELAPSED : +case DATE_ELAPSED_PAD : +/* +* Maximum display width of the elapsed time format, +* e.g. "99y 99M 99d 99h 99m 99s" -- a safe upper bound. +*/ + blame_date_width =sizeof ("99y 99M 99d 99h 99m 99s" ); +break ;case DATE_NORMAL : blame_date_width =sizeof ("Thu Oct 19 16:00:04 2006 -0700" );break ;
contrib/completion/git-completion.bash +1 -1
@@ -2231,7 +2231,7 @@ __git_log_show_options=" __git_diff_merges_opts="off none on first-parent 1 separate m combined c dense-combined cc remerge r" __git_log_pretty_formats="oneline short medium full fuller reference email raw format: tformat: mboxrd" -__git_log_date_formats="relative iso8601 iso8601-strict rfc2822 short local default human raw unix auto: format:" +__git_log_date_formats="relative iso8601 iso8601-strict rfc2822 short local default human raw unix elapsed auto: format:" # Complete porcelain (i.e. not git-rev-list) options and at least some # option arguments accepted by git-log. Note that this same set of options
date.c +87 -1
112 lines not on this page · raw message
date.h +3 -1
@@ -17,7 +17,9 @@ enum date_mode_type {DATE_RFC2822 ,DATE_STRFTIME ,DATE_RAW , -DATE_UNIX +DATE_UNIX , +DATE_ELAPSED , +DATE_ELAPSED_PAD }; struct date_mode {
pretty.c +3 -0
@@ -848,6 +848,9 @@ static size_t format_person_part(struct strbuf *sb, char part,case 'h' :/* date, human */ strbuf_addstr (sb,show_ident_date (&s,DATE_MODE (HUMAN )));return placeholder_len; +case 'X' :/* date, elapsed */ +strbuf_addstr (sb,show_ident_date (&s,DATE_MODE (ELAPSED ))); +return placeholder_len;case 's' :strbuf_addstr (sb,show_ident_date (&s,DATE_MODE (SHORT )));return placeholder_len;
t/helper/test-date.c +18 -1
@@ -11,7 +11,9 @@ static const char *const usage_msg = "\n"" test-tool date timestamp [date]...\n" " test-tool date getnanos [start-nanos]\n" " test-tool date is64bit\n" -" test-tool date time_t-is64bit\n" ; +" test-tool date time_t-is64bit\n" +" test-tool date elapsed [time_t]...\n" +" test-tool date elapsed-pad [time_t]...\n" ;static void show_relative_dates (const char **argv) {
@@ -33,6 +35,17 @@ static void show_human_dates(const char **argv) } } +static void show_elapsed_dates (const char **argv,int pad) +{ +for (; *argv; argv++) { +time_t t =atoi (*argv); +struct date_mode mode =DATE_MODE (ELAPSED ); +if (pad) + mode =DATE_MODE (ELAPSED_PAD ); +printf ("%s -> %s\n" , *argv,show_date (t,0 , mode)); + } +} +static void show_dates (const char **argv,const char *format) {struct date_mode mode =DATE_MODE_INIT ;
@@ -115,6 +128,10 @@ int cmd__date(int argc UNUSED, const char **argv)show_relative_dates (argv+1 ); else if (!strcmp(*argv, "human"))show_human_dates (argv+1 ); + else if (!strcmp(*argv, "elapsed")) +show_elapsed_dates (argv+1 ,0 ); + else if (!strcmp(*argv, "elapsed-pad")) +show_elapsed_dates (argv+1 ,1 ); else if (skip_prefix(*argv, "show:", &x))show_dates (argv+1 , x); else if (!strcmp(*argv, "parse"))
t/t0006-date.sh +43 -0
47 lines not on this page · raw message
t/t4205-log-pretty-formats.sh +6 -0
@@ -557,6 +557,12 @@ test_expect_success '--date=human %ad%cd is the same as %ah%ch' ' test_cmp expected actual ' +test_expect_success '--date=elapsed %ad%cd is the same as %aX%cX' ' + git log --format=%ad%n%cd --date=elapsed >expected && + git log --format=%aX%n%cX >actual && + test_cmp expected actual +' + # get new digests (with no abbreviations) test_expect_success 'set up log decoration tests' ' head1=$(git rev-parse --verify HEAD~0) &&
base-commit: 13c7afec212fc97ce257d15601659314c6673d6c
Signature · 1 line
gitgitgadget