{"thread":{"id":"50135","subject":"[PATCH 2/3] Add 'human' date format documentation","startedAt":"2018-12-31T00:31:53Z","lastAt":"2019-01-29T03:50:27Z","messageCount":56,"participants":["Stephen P. Smith","Junio C Hamano","Stephen & Linda Smith","Jeff King","Philip Oakley","Stephen P Smith","Johannes Sixt","SZEDER Gábor"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"365999","messageId":"20181231003150.8031-3-ischis2@cox.net","threadId":"50135","inReplyTo":"20181231003150.8031-1-ischis2@cox.net","subject":"[PATCH 2/3] Add 'human' date format documentation","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2018-12-31T00:31:49Z","receivedAt":"2018-12-31T00:31:53Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Display date and time information in a format similar to how people\nwrite dates in other contexts. If the year isn't specified then, the\nreader infers the date is given is in the current year.\n\nBy not displaying the redundant information, the reader concentrates\non the information that is different. The patch reports relative dates\nbased on information inferred from the date on the machine running the\ngit command at the time the command is executed.\n\nWhile the format is more useful to humans by dropping inferred\ninformation, there is nothing that makes it actually human. If the\n'relative' date format wasn't already implemented then using\n'relative' would have been appropriate.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n Documentation/rev-list-options.txt | 8 ++++++++\n 1 file changed, 8 insertions(+)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex bab5f50b17..b491c3b999 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -835,6 +835,14 @@ Note that the `-local` option does not affect the seconds-since-epoch\n value (which is always measured in UTC), but does switch the accompanying\n timezone value.\n +\n+`--date=human` shows the timezone if it matches the current time-zone,\n+and doesn't print the whole date if that matches (ie skip printing\n+year for dates that are \"this year\", but also skip the whole date\n+itself if it's in the last few days and we can just say what weekday\n+it was).\n++\n+`--date=auto` defaults to human if we're using the pager.\n++\n `--date=unix` shows the date as a Unix epoch timestamp (seconds since\n 1970).  As with `--raw`, this is always in UTC and therefore `-local`\n has no effect.\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"366000","messageId":"20181231003150.8031-1-ischis2@cox.net","threadId":"50135","inReplyTo":null,"subject":"[PATCH 0/3] Add 'human' date format","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2018-12-31T00:31:47Z","receivedAt":"2018-12-31T00:32:26Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Added documentation and tests for the previously submitted patch.  The\nprevious patch was rebased and the conflict in cache.h was resolved.\n\nRange diff for Linus' original code:\n\n1:  74e8221b52 ! 1:  dd8ea66414 Add 'human' date format\n    @@ -26,6 +26,10 @@\n     \n         Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>\n         Signed-off-by: Junio C Hamano <gitster@pobox.com>\n    +    Rebased lt/date-human to git version 2.20.1 and resolved a conflict.\n    +\n    +    Intentionally did not change logic or add documentation/tests to the\n    +    original commit so that the sign-offs would still be legitimate.\n     \n      diff --git a/builtin/blame.c b/builtin/blame.c\n      --- a/builtin/blame.c\n    @@ -46,13 +50,13 @@\n      --- a/cache.h\n      +++ b/cache.h\n     @@\n    - struct date_mode {\n    - \tenum date_mode_type {\n    - \t\tDATE_NORMAL = 0,\n    -+\t\tDATE_HUMAN,\n    - \t\tDATE_RELATIVE,\n    - \t\tDATE_SHORT,\n    - \t\tDATE_ISO8601,\n    + \n    + enum date_mode_type {\n    + \tDATE_NORMAL = 0,\n    ++\tDATE_HUMAN,\n    + \tDATE_RELATIVE,\n    + \tDATE_SHORT,\n    + \tDATE_ISO8601,\n     \n      diff --git a/date.c b/date.c\n      --- a/date.c\n\n\nLinus Torvalds (1):\n  Add 'human' date format\n\nStephen P. Smith (2):\n  Add 'human' date format documentation\n  t0006-date.sh: add `human` date format tests.\n\n Documentation/rev-list-options.txt |   8 ++\n builtin/blame.c                    |   4 +\n cache.h                            |   1 +\n date.c                             | 130 ++++++++++++++++++++++++-----\n t/t0006-date.sh                    |  24 ++++++\n t/t4202-log.sh                     |  24 ++++++\n t/t7007-show.sh                    |  25 ++++++\n 7 files changed, 196 insertions(+), 20 deletions(-)\n\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"366001","messageId":"20181231003150.8031-4-ischis2@cox.net","threadId":"50135","inReplyTo":"20181231003150.8031-1-ischis2@cox.net","subject":"[PATCH 3/3] t0006-date.sh: add `human` date format tests.","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2018-12-31T00:31:50Z","receivedAt":"2018-12-31T00:32:26Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"The `human` date format varies based on two inputs: the date in the\nreference time which is constant and the local computers date which\nvaries.  Using hardcoded test expected output dates would require\nholding the local machines date and time constant which is not\ndesireable.\n\nAlternatively, letting the local date vary, which is the normal\nsituation, implies that the tests would be checking for formating\nchanges based on on a ref date relative to the local computers time.\n\nWhen using `human` several fields are suppressed depending on the time\ndifference between the reference date and the local computer date. In\ncases where the difference is less than a year, the year field is\nsupppressed. If the time is less than a day; the month and year is\nsuppressed.\n\nTest using a regular expression to verify that fields that are\nexpected to be suppressed are not displayed.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n t/t0006-date.sh | 24 ++++++++++++++++++++++++\n t/t4202-log.sh  | 24 ++++++++++++++++++++++++\n t/t7007-show.sh | 25 +++++++++++++++++++++++++\n 3 files changed, 73 insertions(+)\n\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex ffb2975e48..f208a80867 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -40,6 +40,16 @@ check_show () {\n \t'\n }\n \n+check_human_date () {\n+\ttime=$1\n+\texpect=$2\n+\ttest_expect_success \"check date ($format:$time)\" '\n+\t\techo \"$time -> $expect\" >expect &&\n+\t\tTZ=${zone:-$TZ} test-tool date show:\"$format\" \"$time\" >actual &&\n+\t\tgrep \"$expect\" actual \n+\t'\n+}\n+\n # arbitrary but sensible time for examples\n TIME='1466000000 +0200'\n check_show iso8601 \"$TIME\" '2016-06-15 16:13:20 +0200'\n@@ -52,6 +62,20 @@ check_show unix \"$TIME\" '1466000000'\n check_show iso-local \"$TIME\" '2016-06-15 14:13:20 +0000'\n check_show raw-local \"$TIME\" '1466000000 +0000'\n check_show unix-local \"$TIME\" '1466000000'\n+check_show human \"$TIME\" 'Jun 15 2016'\n+\n+# Subtract some known constant time and look for expected field format\n+TODAY_REGEX='5 hours ago'\n+THIS_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [012][0-9]:[0-6][0-9]'\n+MORE_THAN_A_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [0-9][0-9][0-9][0-9]'\n+check_human_date \"$(($(date +%s)-18000)) +0200\" $TODAY_REGEX # 5 hours ago\n+check_human_date \"$(($(date +%s)-432000)) +0200\" $THIS_YEAR_REGEX  # 5 days ago\n+check_human_date \"$(($(date +%s)-1728000)) +0200\" $THIS_YEAR_REGEX # 3 weeks ago\n+check_human_date \"$(($(date +%s)-13000000)) +0200\" $THIS_YEAR_REGEX # 5 months ago\n+check_human_date \"$(($(date +%s)-31449600)) +0200\" $THIS_YEAR_REGEX # 12 months ago\n+check_human_date \"$(($(date +%s)-37500000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 1 year, 2 months ago\n+check_human_date \"$(($(date +%s)-55188000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 1 year, 9 months ago\n+check_human_date \"$(($(date +%s)-630000000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 20 years ago\n \n check_show 'format:%z' \"$TIME\" '+0200'\n check_show 'format-local:%z' \"$TIME\" '+0000'\ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex 819c24d10e..d7f3b73650 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -1707,4 +1707,28 @@ test_expect_success '--exclude-promisor-objects does not BUG-crash' '\n \ttest_must_fail git log --exclude-promisor-objects source-a\n '\n \n+check_human_date() {\n+\tcommit_date=$1\n+\texpect=$2\n+\ttest_expect_success \"$commit_date\" \"\n+\t\techo $expect $commit_date >dates && \n+\t\tgit add dates &&\n+\t\tgit commit -m 'Expect String' --date=\\\"$commit_date\\\" dates &&\n+\t\tgit log -1 --date=human | grep \\\"^Date:\\\" >actual &&\n+\t\tgrep \\\"$expect\\\" actual\n+\"\n+}\n+\n+TODAY_REGEX='[A-Z][a-z][a-z] [012][0-9]:[0-6][0-9] .0200'\n+THIS_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [012][0-9]:[0-6][0-9]'\n+MORE_THAN_A_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [0-9][0-9][0-9][0-9]'\n+check_human_date \"$(($(date +%s)-18000)) +0200\" $TODAY_REGEX # 5 hours ago\n+check_human_date \"$(($(date +%s)-432000)) +0200\" $THIS_YEAR_REGEX  # 5 days ago\n+check_human_date \"$(($(date +%s)-1728000)) +0200\" $THIS_YEAR_REGEX # 3 weeks ago\n+check_human_date \"$(($(date +%s)-13000000)) +0200\" $THIS_YEAR_REGEX # 5 months ago\n+check_human_date \"$(($(date +%s)-31449600)) +0200\" $THIS_YEAR_REGEX # 12 months ago\n+check_human_date \"$(($(date +%s)-37500000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 1 year, 2 months ago\n+check_human_date \"$(($(date +%s)-55188000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 1 year, 9 months ago\n+check_human_date \"$(($(date +%s)-630000000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 20 years ago\n+\n test_done\ndiff --git a/t/t7007-show.sh b/t/t7007-show.sh\nindex 42d3db6246..0a0334a8b5 100755\n--- a/t/t7007-show.sh\n+++ b/t/t7007-show.sh\n@@ -128,4 +128,29 @@ test_expect_success 'show --graph is forbidden' '\n   test_must_fail git show --graph HEAD\n '\n \n+check_human_date() {\n+\tcommit_date=$1\n+\texpect=$2\n+\ttest_expect_success \"$commit_date\" \"\n+\t\techo $expect $commit_date >dates && \n+\t\tgit add dates &&\n+\t\tgit commit -m 'Expect String' --date=\\\"$commit_date\\\" dates &&\n+\t\tgit show --date=human | grep \\\"^Date:\\\" >actual &&\n+\t\tgrep \\\"$expect\\\" actual\n+\"\n+}\n+\n+TODAY_REGEX='[A-Z][a-z][a-z] [012][0-9]:[0-6][0-9] .0200'\n+THIS_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [012][0-9]:[0-6][0-9]'\n+MORE_THAN_A_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [0-9][0-9][0-9][0-9]'\n+check_human_date \"$(($(date +%s)-18000)) +0200\" $TODAY_REGEX # 5 hours ago\n+check_human_date \"$(($(date +%s)-432000)) +0200\" $THIS_YEAR_REGEX  # 5 days ago\n+check_human_date \"$(($(date +%s)-1728000)) +0200\" $THIS_YEAR_REGEX # 3 weeks ago\n+check_human_date \"$(($(date +%s)-13000000)) +0200\" $THIS_YEAR_REGEX # 5 months ago\n+check_human_date \"$(($(date +%s)-31449600)) +0200\" $THIS_YEAR_REGEX # 12 months ago\n+check_human_date \"$(($(date +%s)-37500000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 1 year, 2 months ago\n+check_human_date \"$(($(date +%s)-55188000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 1 year, 9 months ago\n+check_human_date \"$(($(date +%s)-630000000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 20 years ago\n+\n+\n test_done\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"366002","messageId":"20181231003150.8031-2-ischis2@cox.net","threadId":"50135","inReplyTo":"20181231003150.8031-1-ischis2@cox.net","subject":"[PATCH 1/3] Add 'human' date format","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2018-12-31T00:31:48Z","receivedAt":"2018-12-31T00:32:26Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"From: Linus Torvalds <torvalds@linux-foundation.org>\n\nThis adds --date=human, which skips the timezone if it matches the\ncurrent time-zone, and doesn't print the whole date if that matches (ie\nskip printing year for dates that are \"this year\", but also skip the\nwhole date itself if it's in the last few days and we can just say what\nweekday it was).\n\nFor really recent dates (same day), use the relative date stamp, while\nfor old dates (year doesn't match), don't bother with time and timezone.\n\nAlso add 'auto' date mode, which defaults to human if we're using the\npager.  So you can do\n\n\tgit config --add log.date auto\n\nand your \"git log\" commands will show the human-legible format unless\nyou're scripting things.\n\nNote that this time format still shows the timezone for recent enough\nevents (but not so recent that they show up as relative dates).  You can\ncombine it with the \"-local\" suffix to never show timezones for an even\nmore simplified view.\n\nSigned-off-by: Linus Torvalds <torvalds@linux-foundation.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n builtin/blame.c |   4 ++\n cache.h         |   1 +\n date.c          | 130 ++++++++++++++++++++++++++++++++++++++++--------\n 3 files changed, 115 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 6d798f9939..f684e31d82 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -925,6 +925,10 @@ int cmd_blame(int argc, const char **argv, const char *prefix)\n \t\t */\n \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n \t\tbreak;\n+\tcase DATE_HUMAN:\n+\t\t/* If the year is shown, no time is shown */\n+\t\tblame_date_width = sizeof(\"Thu Oct 19 16:00\");\n+\t\tbreak;\n \tcase DATE_NORMAL:\n \t\tblame_date_width = sizeof(\"Thu Oct 19 16:00:04 2006 -0700\");\n \t\tbreak;\ndiff --git a/cache.h b/cache.h\nindex ca36b44ee0..c4396ebaa6 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1439,6 +1439,7 @@ extern struct object *peel_to_type(const char *name, int namelen,\n \n enum date_mode_type {\n \tDATE_NORMAL = 0,\n+\tDATE_HUMAN,\n \tDATE_RELATIVE,\n \tDATE_SHORT,\n \tDATE_ISO8601,\ndiff --git a/date.c b/date.c\nindex 9bc15df6f9..a8d50eb206 100644\n--- a/date.c\n+++ b/date.c\n@@ -77,22 +77,16 @@ static struct tm *time_to_tm_local(timestamp_t time)\n }\n \n /*\n- * What value of \"tz\" was in effect back then at \"time\" in the\n- * local timezone?\n+ * Fill in the localtime 'struct tm' for the supplied time,\n+ * and return the local tz.\n  */\n-static int local_tzoffset(timestamp_t time)\n+static int local_time_tzoffset(time_t t, struct tm *tm)\n {\n-\ttime_t t, t_local;\n-\tstruct tm tm;\n+\ttime_t t_local;\n \tint offset, eastwest;\n \n-\tif (date_overflows(time))\n-\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n-\n-\tt = (time_t)time;\n-\tlocaltime_r(&t, &tm);\n-\tt_local = tm_to_time_t(&tm);\n-\n+\tlocaltime_r(&t, tm);\n+\tt_local = tm_to_time_t(tm);\n \tif (t_local == -1)\n \t\treturn 0; /* error; just use +0000 */\n \tif (t_local < t) {\n@@ -107,6 +101,20 @@ static int local_tzoffset(timestamp_t time)\n \treturn offset * eastwest;\n }\n \n+/*\n+ * What value of \"tz\" was in effect back then at \"time\" in the\n+ * local timezone?\n+ */\n+static int local_tzoffset(timestamp_t time)\n+{\n+\tstruct tm tm;\n+\n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\n+\treturn local_time_tzoffset((time_t)time, &tm);\n+}\n+\n void show_date_relative(timestamp_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n@@ -191,9 +199,80 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \treturn &mode;\n }\n \n+static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm, int tz, struct tm *human_tm, int human_tz, int local)\n+{\n+\tstruct {\n+\t\tunsigned int\tyear:1,\n+\t\t\t\tdate:1,\n+\t\t\t\twday:1,\n+\t\t\t\ttime:1,\n+\t\t\t\tseconds:1,\n+\t\t\t\ttz:1;\n+\t} hide = { 0 };\n+\n+\thide.tz = local || tz == human_tz;\n+\thide.year = tm->tm_year == human_tm->tm_year;\n+\tif (hide.year) {\n+\t\tif (tm->tm_mon == human_tm->tm_mon) {\n+\t\t\tif (tm->tm_mday > human_tm->tm_mday) {\n+\t\t\t\t/* Future date: think timezones */\n+\t\t\t} else if (tm->tm_mday == human_tm->tm_mday) {\n+\t\t\t\thide.date = hide.wday = 1;\n+\t\t\t} else if (tm->tm_mday + 5 > human_tm->tm_mday) {\n+\t\t\t\t/* Leave just weekday if it was a few days ago */\n+\t\t\t\thide.date = 1;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/* Show \"today\" times as just relative times */\n+\tif (hide.wday) {\n+\t\tstruct timeval now;\n+\t\tgettimeofday(&now, NULL);\n+\t\tshow_date_relative(time, tz, &now, buf);\n+\t\treturn;\n+\t}\n+\n+\t/*\n+\t * Always hide seconds for human-readable.\n+\t * Hide timezone if showing date.\n+\t * Hide weekday and time if showing year.\n+\t *\n+\t * The logic here is two-fold:\n+\t *  (a) only show details when recent enough to matter\n+\t *  (b) keep the maximum length \"similar\", and in check\n+\t */\n+\tif (human_tm->tm_year) {\n+\t\thide.seconds = 1;\n+\t\thide.tz |= !hide.date;\n+\t\thide.wday = hide.time = !hide.year;\n+\t}\n+\n+\tif (!hide.wday)\n+\t\tstrbuf_addf(buf, \"%.3s \", weekday_names[tm->tm_wday]);\n+\tif (!hide.date)\n+\t\tstrbuf_addf(buf, \"%.3s %d \", month_names[tm->tm_mon], tm->tm_mday);\n+\n+\t/* Do we want AM/PM depending on locale? */\n+\tif (!hide.time) {\n+\t\tstrbuf_addf(buf, \"%02d:%02d\", tm->tm_hour, tm->tm_min);\n+\t\tif (!hide.seconds)\n+\t\t\tstrbuf_addf(buf, \":%02d\", tm->tm_sec);\n+\t} else\n+\t\tstrbuf_rtrim(buf);\n+\n+\tif (!hide.year)\n+\t\tstrbuf_addf(buf, \" %d\", tm->tm_year + 1900);\n+\n+\tif (!hide.tz)\n+\t\tstrbuf_addf(buf, \" %+05d\", tz);\n+}\n+\n const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n {\n \tstruct tm *tm;\n+\tstruct tm human_tm = { 0 };\n+\tint human_tz = -1;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n \n \tif (mode->type == DATE_UNIX) {\n@@ -202,6 +281,15 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \t\treturn timebuf.buf;\n \t}\n \n+\tif (mode->type == DATE_HUMAN) {\n+\t\tstruct timeval now;\n+\n+\t\tgettimeofday(&now, NULL);\n+\n+\t\t/* Fill in the data for \"current time\" in human_tz and human_tm */\n+\t\thuman_tz = local_time_tzoffset(now.tv_sec, &human_tm);\n+\t}\n+\n \tif (mode->local)\n \t\ttz = local_tzoffset(time);\n \n@@ -258,14 +346,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \t\tstrbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,\n \t\t\t\t!mode->local);\n \telse\n-\t\tstrbuf_addf(&timebuf, \"%.3s %.3s %d %02d:%02d:%02d %d%c%+05d\",\n-\t\t\t\tweekday_names[tm->tm_wday],\n-\t\t\t\tmonth_names[tm->tm_mon],\n-\t\t\t\ttm->tm_mday,\n-\t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n-\t\t\t\ttm->tm_year + 1900,\n-\t\t\t\tmode->local ? 0 : ' ',\n-\t\t\t\ttz);\n+\t\tshow_date_normal(&timebuf, time, tm, tz, &human_tm, human_tz, mode->local);\n \treturn timebuf.buf;\n }\n \n@@ -802,6 +883,11 @@ int parse_date(const char *date, struct strbuf *result)\n \treturn 0;\n }\n \n+static int auto_date_style(void)\n+{\n+\treturn (isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;\n+}\n+\n static enum date_mode_type parse_date_type(const char *format, const char **end)\n {\n \tif (skip_prefix(format, \"relative\", end))\n@@ -819,6 +905,10 @@ static enum date_mode_type parse_date_type(const char *format, const char **end)\n \t\treturn DATE_SHORT;\n \tif (skip_prefix(format, \"default\", end))\n \t\treturn DATE_NORMAL;\n+\tif (skip_prefix(format, \"human\", end))\n+\t\treturn DATE_HUMAN;\n+\tif (skip_prefix(format, \"auto\", end))\n+\t\treturn auto_date_style();\n \tif (skip_prefix(format, \"raw\", end))\n \t\treturn DATE_RAW;\n \tif (skip_prefix(format, \"unix\", end))\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"366048","messageId":"xmqqva37j595.fsf@gitster-ct.c.googlers.com","threadId":"50135","inReplyTo":"20181231003150.8031-4-ischis2@cox.net","subject":"Re: [PATCH 3/3] t0006-date.sh: add `human` date format tests.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-02T18:15:02Z","receivedAt":"2019-01-02T18:15:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Stephen P. Smith\" <ischis2@cox.net> writes:\n\n> +# Subtract some known constant time and look for expected field format\n> +TODAY_REGEX='5 hours ago'\n> +THIS_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [012][0-9]:[0-6][0-9]'\n> +MORE_THAN_A_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [0-9][0-9][0-9][0-9]'\n> +check_human_date \"$(($(date +%s)-18000)) +0200\" $TODAY_REGEX # 5 hours ago\n> +check_human_date \"$(($(date +%s)-432000)) +0200\" $THIS_YEAR_REGEX  # 5 days ago\n\n'date +%s' is used everywhere in this patch but has never been used\nin our test suite before.  It is not portable.\n\nWe perhaps can use \"test-tool date timestamp\", like so\n\n\tcheck_human_date $(test-tool date timestamp \"18000 seconds ago\") ...\n\nor moving the part that munges 18000 into the above form inside\ncheck_human_date helper function, e.g.\n\n\tcheck_human_date () {\n\t\tcommit_date=$(test-tool date timestamp \"$1 seconds ago\")\n\t\tcommit_date=\"$commit_date +0200\"\n                expect=$2\n\t\t...\n\t}\n\nwhich would let us write\n\n\tcheck_human_date 432000\" $THIS_YEAR_REGEX  # 5 days ago\n\n> +check_human_date() {\n> +\tcommit_date=$1\n> +\texpect=$2\n> +\ttest_expect_success \"$commit_date\" \"\n> +\t\techo $expect $commit_date >dates && \n> +\t\tgit add dates &&\n> +\t\tgit commit -m 'Expect String' --date=\\\"$commit_date\\\" dates &&\n> +\t\tgit log -1 --date=human | grep \\\"^Date:\\\" >actual &&\n> +\t\tgrep \\\"$expect\\\" actual\n> +\"\n\nAs the body of the test_expect_success helper is eval'ed, variables\n$commit_date and $expect should be visible to it, without turning\nthem into values before executing test_expect_success function,\ni.e.\n\n\ttest_expect_success \"$commit_date\" '\n\t\techo \"$expect $commit_date\" >dates &&\n\t\t...\n\t\tgit commit -m \"Expect String\" --date=\"$commit_date\" dates &&\n\t\tgit show -s --date=human | grep '^Date:\" >actual &&\n\t\tgrep \"$expect\" actual\n\t'\n\nwhich would reduce the need for unreadable backslashes.\n\nInstead of duplicating, perhaps move this to a more common place?\nWould it make sense to make it \"check_date_format ()\" helper by\npassing another argument to parameterize --date=human part\n\n> +check_human_date() {\n> +\tcommit_date=$1\n> +\texpect=$2\n> +\ttest_expect_success \"$commit_date\" \"\n> +\t\techo $expect $commit_date >dates && \n> +\t\tgit add dates &&\n> +\t\tgit commit -m 'Expect String' --date=\\\"$commit_date\\\" dates &&\n> +\t\tgit show --date=human | grep \\\"^Date:\\\" >actual &&\n\nUsing \"show\" here is much better than \"log -1\" above; using \"show\n-s\" would be even better.\n\n> +\t\tgrep \\\"$expect\\\" actual\n> +\"\n> +}\n> +\n> +TODAY_REGEX='[A-Z][a-z][a-z] [012][0-9]:[0-6][0-9] .0200'\n> +THIS_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [012][0-9]:[0-6][0-9]'\n> +MORE_THAN_A_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [0-9][0-9][0-9][0-9]'\n> +check_human_date \"$(($(date +%s)-18000)) +0200\" $TODAY_REGEX # 5 hours ago\n> +check_human_date \"$(($(date +%s)-432000)) +0200\" $THIS_YEAR_REGEX  # 5 days ago\n> +check_human_date \"$(($(date +%s)-1728000)) +0200\" $THIS_YEAR_REGEX # 3 weeks ago\n> +check_human_date \"$(($(date +%s)-13000000)) +0200\" $THIS_YEAR_REGEX # 5 months ago\n> +check_human_date \"$(($(date +%s)-31449600)) +0200\" $THIS_YEAR_REGEX # 12 months ago\n> +check_human_date \"$(($(date +%s)-37500000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 1 year, 2 months ago\n> +check_human_date \"$(($(date +%s)-55188000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 1 year, 9 months ago\n> +check_human_date \"$(($(date +%s)-630000000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 20 years ago\n> +\n> +\n>  test_done\n"},{"id":"366061","messageId":"2832897.SWEsZI4Xea@thunderbird","threadId":"50135","inReplyTo":"xmqqva37j595.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 3/3] t0006-date.sh: add `human` date format tests.","fromName":"Stephen & Linda Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-03T02:36:16Z","receivedAt":"2019-01-03T02:36:19Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"On Wednesday, January 2, 2019 11:15:02 AM MST Junio C Hamano wrote:\n> 'date +%s' is used everywhere in this patch but has never been used\n> in our test suite before.  It is not portable.\nSo I don't make this mistake again, Is there a reference somewhere for that is \nand is not portable?\n\n> \n> We perhaps can use \"test-tool date timestamp\", like so\n> \n> \tcheck_human_date $(test-tool date timestamp \"18000 seconds ago\") ...\n> \n> or moving the part that munges 18000 into the above form inside\n> check_human_date helper function, e.g.\n> \n> \tcheck_human_date () {\n> \t\tcommit_date=$(test-tool date timestamp \"$1 seconds ago\")\n> \t\tcommit_date=\"$commit_date +0200\"\n>                 expect=$2\n> \t\t...\n> \t}\n> \n> which would let us write\n> \n> \tcheck_human_date 432000\" $THIS_YEAR_REGEX  # 5 days ago\nThanks\n\n>\n> > +check_human_date() {\n> > +\tcommit_date=$1\n> > +\texpect=$2\n> > +\ttest_expect_success \"$commit_date\" \"\n> > +\t\techo $expect $commit_date >dates &&\n> > +\t\tgit add dates &&\n> > +\t\tgit commit -m 'Expect String' --date=\\\"$commit_date\\\" dates &&\n> > +\t\tgit log -1 --date=human | grep \\\"^Date:\\\" >actual &&\n> > +\t\tgrep \\\"$expect\\\" actual\n> > +\"\n> \n> As the body of the test_expect_success helper is eval'ed, variables\n> $commit_date and $expect should be visible to it, without turning\n> them into values before executing test_expect_success function,\n> i.e.\n> \n> \ttest_expect_success \"$commit_date\" '\n> \t\techo \"$expect $commit_date\" >dates &&\n> \t\t...\n> \t\tgit commit -m \"Expect String\" --date=\"$commit_date\" dates &&\n> \t\tgit show -s --date=human | grep '^Date:\" >actual &&\n> \t\tgrep \"$expect\" actual\n> \t'\n> \n> which would reduce the need for unreadable backslashes.\nI was worried about embedded spaces that might not be parsed correctly by the \ncalled function.  I will update\n\n> \n> Instead of duplicating, perhaps move this to a more common place?\n> Would it make sense to make it \"check_date_format ()\" helper by\n> passing another argument to parameterize --date=human part\nI had considered that, but then noted that for the other formats specific \nstrings were being used.  The use of specific strings was possible since the \nother formats were always guarenteed to have the same string literal due to a \nsinge unvarying input.\n\nI don't mind parameterize the format and it would make the solution more \ngeneral.\n\n\n> > \"Stephen P. Smith\" <ischis2@cox.net> writes:\n> > +# Subtract some known constant time and look for expected field format\n> > +TODAY_REGEX='5 hours ago'\n> > +THIS_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]*\n> > [012][0-9]:[0-6][0-9]' +MORE_THAN_A_YEAR_REGEX='[A-Z][a-z][a-z]\n> > [A-Z][a-z][a-z] [0-9]* [0-9][0-9][0-9][0-9]' +check_human_date \"$(($(date\n> > +%s)-18000)) +0200\" $TODAY_REGEX # 5 hours ago +check_human_date\n> > \"$(($(date +%s)-432000)) +0200\" $THIS_YEAR_REGEX  # 5 days ago\n> > +check_human_date() {\n> > +\tcommit_date=$1\n> > +\texpect=$2\n> > +\ttest_expect_success \"$commit_date\" \"\n> > +\t\techo $expect $commit_date >dates &&\n> > +\t\tgit add dates &&\n> > +\t\tgit commit -m 'Expect String' --date=\\\"$commit_date\\\" dates &&\n> > +\t\tgit show --date=human | grep \\\"^Date:\\\" >actual &&\n> \n> Using \"show\" here is much better than \"log -1\" above; using \"show\n> -s\" would be even better.\n\nI was attempting to test both git log and git show.  For get log the `-1` was \nto only get the latest commit.\n\nAre you suggesting that t4202-log.sh not be updated and that only and  t7007-\nshow.sh and t0006-date.sh updated?  \n\nSide note:  I found when updating that all three scripts that log and show \nreturned the same formats, but date returned a different string if the delta \ndate was less than 24hours\n\nI just noted that the patch 3/3 should be re-titled since the tests are \ncurrently for three commands.\n\nHope you are better.\nsps\n\n\n\n"},{"id":"366070","messageId":"xmqqk1jmi6nn.fsf@gitster-ct.c.googlers.com","threadId":"50135","inReplyTo":"2832897.SWEsZI4Xea@thunderbird","subject":"Re: [PATCH 3/3] t0006-date.sh: add `human` date format tests.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-03T06:42:20Z","receivedAt":"2019-01-03T06:42:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stephen & Linda Smith <ischis2@cox.net> writes:\n\n> On Wednesday, January 2, 2019 11:15:02 AM MST Junio C Hamano wrote:\n>> 'date +%s' is used everywhere in this patch but has never been used\n>> in our test suite before.  It is not portable.\n> So I don't make this mistake again, Is there a reference somewhere for that is \n> and is not portable?\n\nI usually go to http://pubs.opengroup.org/onlinepubs/9699919799/\n\nEven though we do not say \"We'll use anything that is in POSIX.1; it\nis your problem if your platform does not support it\", we tend to\nsay \"It's not even in POSIX, so let's see if we can avoid it\".\n\n>> Using \"show\" here is much better than \"log -1\" above; using \"show\n>> -s\" would be even better.\n>\n> I was attempting to test both git log and git show.  For get log the `-1` was \n> to only get the latest commit.\n>\n> Are you suggesting that t4202-log.sh not be updated and that only and  t7007-\n> show.sh and t0006-date.sh updated?  \n\nI am saying that using \"log -1\" and \"show\" in different tests _only_\nfor the value of \"Date:\" field does not buy us much.  And by unifying,\nI was hoping that the single helper can be placed in a common file\nthat is dot-sourced by these three scripts more easily.\n\nThanks.\n"},{"id":"366075","messageId":"20190103073735.GB24925@sigill.intra.peff.net","threadId":"50135","inReplyTo":"20181231003150.8031-2-ischis2@cox.net","subject":"Re: [PATCH 1/3] Add 'human' date format","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-01-03T07:37:35Z","receivedAt":"2019-01-03T07:37:39Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Dec 30, 2018 at 05:31:48PM -0700, Stephen P. Smith wrote:\n\n> Also add 'auto' date mode, which defaults to human if we're using the\n> pager.  So you can do\n> \n> \tgit config --add log.date auto\n> \n> and your \"git log\" commands will show the human-legible format unless\n> you're scripting things.\n\nI like the idea of \"human\", and I like the idea of \"auto\", but it seems\nto me that these are really two orthogonal things. E.g., might some\npeople not want to do something like:\n\n  git config log.date auto:relative\n\n?\n\nI don't personally care about using this myself, but we already had to\ndeal with retrofitting \"local\" as a modifier. I'd prefer to avoid making\nthe same mistake again.\n\n(I'd actually argue that \"log.date\" should basically _always_ have the\n\"auto\" behavior, since it tends to get treated as plumbing anyway, and I\nsuspect that anybody who sets log.date now would see subtle breakage\nfrom scripts. But maybe it's too late at this point?).\n\n> diff --git a/builtin/blame.c b/builtin/blame.c\n> index 6d798f9939..f684e31d82 100644\n> --- a/builtin/blame.c\n> +++ b/builtin/blame.c\n> @@ -925,6 +925,10 @@ int cmd_blame(int argc, const char **argv, const char *prefix)\n>  \t\t */\n>  \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n>  \t\tbreak;\n> +\tcase DATE_HUMAN:\n> +\t\t/* If the year is shown, no time is shown */\n> +\t\tblame_date_width = sizeof(\"Thu Oct 19 16:00\");\n> +\t\tbreak;\n\nOK, and we expect the year to be less than 5 characters. I briefly\nwondered what would happen at Y100K (or somebody maliciously using a\nbogus year), but it is not a buffer overflow. It is simply a mis-aligned\nblame line (and actually, the same goes for the existing entries, which\nuse a 4-digit year).\n\n-Peff\n"},{"id":"366077","messageId":"20190103074421.GC24925@sigill.intra.peff.net","threadId":"50135","inReplyTo":"20181231003150.8031-4-ischis2@cox.net","subject":"Re: [PATCH 3/3] t0006-date.sh: add `human` date format tests.","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-01-03T07:44:22Z","receivedAt":"2019-01-03T07:44:25Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Dec 30, 2018 at 05:31:50PM -0700, Stephen P. Smith wrote:\n\n> The `human` date format varies based on two inputs: the date in the\n> reference time which is constant and the local computers date which\n> varies.  Using hardcoded test expected output dates would require\n> holding the local machines date and time constant which is not\n> desireable.\n> \n> Alternatively, letting the local date vary, which is the normal\n> situation, implies that the tests would be checking for formating\n> changes based on on a ref date relative to the local computers time.\n\nWe already have $TEST_DATE_NOW, which \"test-tool date\" will respect for\nvarious commands to pretend that it's currently a particular time. I\nthink you'd need to add a sub-command similar to \"relative\" (which\ndirectly calls show_date_relative()) which calls into the \"human\" code.\n\nNote that there _isn't_ a way to have actual non-test git programs read\nthe current time from an environment variable (as opposed to actually\ncalling gettimeofday()).\n\n-Peff\n"},{"id":"366085","messageId":"3321253.lROl3XOJ1W@thunderbird","threadId":"50135","inReplyTo":"20190103074421.GC24925@sigill.intra.peff.net","subject":"Re: [PATCH 3/3] t0006-date.sh: add `human` date format tests.","fromName":"Stephen & Linda Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-03T13:12:02Z","receivedAt":"2019-01-03T13:12:06Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"On Thursday, January 3, 2019 12:44:22 AM MST Jeff King wrote:\n> We already have $TEST_DATE_NOW, which \"test-tool date\" will respect for\n> various commands to pretend that it's currently a particular time. I\n> think you'd need to add a sub-command similar to \"relative\" (which\n> directly calls show_date_relative()) which calls into the \"human\" code.\n\nI'll investigate.  Looks like this comment is related other comments.\n\n> Note that there _isn't_ a way to have actual non-test git programs read\n> the current time from an environment variable (as opposed to actually\n> calling gettimeofday()).\nAgreed\n\n> \n> -Peff\n\n\n\n\n"},{"id":"366086","messageId":"2637944.PqRbksyA0G@thunderbird","threadId":"50135","inReplyTo":"20190103073735.GB24925@sigill.intra.peff.net","subject":"Re: [PATCH 1/3] Add 'human' date format","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-03T13:19:56Z","receivedAt":"2019-01-03T13:19:59Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"On Thursday, January 3, 2019 12:37:35 AM MST Jeff King wrote:\n> I like the idea of \"human\", and I like the idea of \"auto\", but it seems\n> to me that these are really two orthogonal things. E.g., might some\n> people not want to do something like:\n> \n>   git config log.date auto:relative\nI didn't see anything in the code which would prohibit setting something like \nthat.  \n\n> \n> I don't personally care about using this myself, but we already had to\n> deal with retrofitting \"local\" as a modifier. I'd prefer to avoid making\n> the same mistake again.\nSince I wasn't involved could you summarize the you are referring to?\n\n> \n> (I'd actually argue that \"log.date\" should basically _always_ have the\n> \"auto\" behavior, since it tends to get treated as plumbing anyway, and I\n> suspect that anybody who sets log.date now would see subtle breakage\n> from scripts. But maybe it's too late at this point?).\nIf auto isn't added to the \"log.date\" file, then the date behaviour is not \nchanged from is currently in the code base.   Therefore, there shouldn't be \nany breakage.\n> \n> > diff --git a/builtin/blame.c b/builtin/blame.c\n> > index 6d798f9939..f684e31d82 100644\n> > --- a/builtin/blame.c\n> > +++ b/builtin/blame.c\n> > @@ -925,6 +925,10 @@ int cmd_blame(int argc, const char **argv, const char\n> > *prefix)> \n> >  \t\t */\n> >  \t\t\n> >  \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /*\n> >  \t\tadd the null */ break;\n> > \n> > +\tcase DATE_HUMAN:\n> > +\t\t/* If the year is shown, no time is shown */\n> > +\t\tblame_date_width = sizeof(\"Thu Oct 19 16:00\");\n> > +\t\tbreak;\n> \n> OK, and we expect the year to be less than 5 characters. I briefly\n> wondered what would happen at Y100K (or somebody maliciously using a\n> bogus year), but it is not a buffer overflow. It is simply a mis-aligned\n> blame line (and actually, the same goes for the existing entries, which\n> use a 4-digit year).\n> \n> -Peff\n\n\n\n\n"},{"id":"366087","messageId":"7749329.coFLYGqBuQ@thunderbird","threadId":"50135","inReplyTo":"xmqqk1jmi6nn.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 3/3] t0006-date.sh: add `human` date format tests.","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-03T13:20:50Z","receivedAt":"2019-01-03T13:20:53Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"On Wednesday, January 2, 2019 11:42:20 PM MST Junio C Hamano wrote:\n> > Are you suggesting that t4202-log.sh not be updated and that only and \n> > t7007- show.sh and t0006-date.sh updated?\n> \n> I am saying that using \"log -1\" and \"show\" in different tests _only_\n> for the value of \"Date:\" field does not buy us much.  And by unifying,\n> I was hoping that the single helper can be placed in a common file\n> that is dot-sourced by these three scripts more easily.\n\nThanks for the clarification.\n\n\n\n"},{"id":"366110","messageId":"a5412274-028f-3662-e4f5-dbbcad4d9a40@iee.org","threadId":"50135","inReplyTo":"xmqqva37j595.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 3/3] t0006-date.sh: add `human` date format tests.","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2019-01-03T21:14:04Z","receivedAt":"2019-01-03T21:22:15Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"On 02/01/2019 18:15, Junio C Hamano wrote:\n> We perhaps can use \"test-tool date timestamp\", like so\n>\n> \tcheck_human_date $(test-tool date timestamp \"18000 seconds ago\") ...\n>\n> or moving the part that munges 18000 into the above form inside\n> check_human_date helper function, e.g.\n>\n> \tcheck_human_date () {\n> \t\tcommit_date=$(test-tool date timestamp \"$1 seconds ago\")\n> \t\tcommit_date=\"$commit_date +0200\"\n>                  expect=$2\n> \t\t...\n> \t}\n>\n> which would let us write\n>\n> \tcheck_human_date 432000\" $THIS_YEAR_REGEX  # 5 days ago\n\n\nJust a quick bikeshed: if used, would this have a year end 5 day \nroll-over error potential, or will it always use the single date?\n\n(I appreciate it is just suggestion code, not tested)\n\n-- \n\nPhilip\n\n"},{"id":"366114","messageId":"xmqq1s5th0u4.fsf@gitster-ct.c.googlers.com","threadId":"50135","inReplyTo":"a5412274-028f-3662-e4f5-dbbcad4d9a40@iee.org","subject":"Re: [PATCH 3/3] t0006-date.sh: add `human` date format tests.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-03T21:45:39Z","receivedAt":"2019-01-03T21:45:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Philip Oakley <philipoakley@iee.org> writes:\n\n> On 02/01/2019 18:15, Junio C Hamano wrote:\n>> We perhaps can use \"test-tool date timestamp\", like so\n>>\n>> \tcheck_human_date $(test-tool date timestamp \"18000 seconds ago\") ...\n>>\n>> or moving the part that munges 18000 into the above form inside\n>> check_human_date helper function, e.g.\n>>\n>> \tcheck_human_date () {\n>> \t\tcommit_date=$(test-tool date timestamp \"$1 seconds ago\")\n>> \t\tcommit_date=\"$commit_date +0200\"\n>>                  expect=$2\n>> \t\t...\n>> \t}\n>>\n>> which would let us write\n>>\n>> \tcheck_human_date 432000 \"$THIS_YEAR_REGEX\" # 5 days ago\n>\n>\n> Just a quick bikeshed: if used, would this have a year end 5 day\n> roll-over error potential, or will it always use the single date?\n\nHmph, interesting point.  Indeed, date.c::show_date_normal() decides\nto hide the year portion if the timestamp and the current time share\nthe same year, so on Thu Jan 3rd, an attempt to show a commit made\non Mon Dec 31st of the same week would end up showing the year, so\nyes, I agree with you that the above would break.\n\n+TODAY_REGEX='5 hours ago'\n+THIS_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [012][0-9]:[0-6][0-9]'\n+MORE_THAN_A_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [0-9][0-9][0-9][0-9]'\n\n>\n> (I appreciate it is just suggestion code, not tested)\n"},{"id":"366123","messageId":"2344590.WcCB8NM0fh@thunderbird","threadId":"50135","inReplyTo":"xmqq1s5th0u4.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 3/3] t0006-date.sh: add `human` date format tests.","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-03T23:57:25Z","receivedAt":"2019-01-03T23:57:34Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"On Thursday, January 3, 2019 2:45:39 PM MST Junio C Hamano wrote:\n> Philip Oakley <philipoakley@iee.org> writes:\n> >> \n> >> \tcheck_human_date 432000 \"$THIS_YEAR_REGEX\" # 5 days ago\n> > \n> > Just a quick bikeshed: if used, would this have a year end 5 day\n> > roll-over error potential, or will it always use the single date?\n> \n> Hmph, interesting point.  Indeed, date.c::show_date_normal() decides\n> to hide the year portion if the timestamp and the current time share\n> the same year, so on Thu Jan 3rd, an attempt to show a commit made\n> on Mon Dec 31st of the same week would end up showing the year, so\n> yes, I agree with you that the above would break.\n> \n\nThanks Philip.\n\nI wrote the test just before the new year so didn't see the rollover.   I \nhaven't run the test this year.\nsps\n\n\n\n\n\n\n"},{"id":"366132","messageId":"20190104075034.GA26014@sigill.intra.peff.net","threadId":"50135","inReplyTo":"2637944.PqRbksyA0G@thunderbird","subject":"Re: [PATCH 1/3] Add 'human' date format","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-01-04T07:50:35Z","receivedAt":"2019-01-04T07:50:38Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 03, 2019 at 06:19:56AM -0700, Stephen P. Smith wrote:\n\n> On Thursday, January 3, 2019 12:37:35 AM MST Jeff King wrote:\n> > I like the idea of \"human\", and I like the idea of \"auto\", but it seems\n> > to me that these are really two orthogonal things. E.g., might some\n> > people not want to do something like:\n> > \n> >   git config log.date auto:relative\n> I didn't see anything in the code which would prohibit setting something like \n> that.\n\nYeah, I don't think supporting that is too hard. I was thinking\nsomething like this:\n\ndiff --git a/date.c b/date.c\nindex 4486c028ac..f731803872 100644\n--- a/date.c\n+++ b/date.c\n@@ -883,11 +883,6 @@ int parse_date(const char *date, struct strbuf *result)\n \treturn 0;\n }\n \n-static int auto_date_style(void)\n-{\n-\treturn (isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;\n-}\n-\n static enum date_mode_type parse_date_type(const char *format, const char **end)\n {\n \tif (skip_prefix(format, \"relative\", end))\n@@ -907,8 +902,6 @@ static enum date_mode_type parse_date_type(const char *format, const char **end)\n \t\treturn DATE_NORMAL;\n \tif (skip_prefix(format, \"human\", end))\n \t\treturn DATE_HUMAN;\n-\tif (skip_prefix(format, \"auto\", end))\n-\t\treturn auto_date_style();\n \tif (skip_prefix(format, \"raw\", end))\n \t\treturn DATE_RAW;\n \tif (skip_prefix(format, \"unix\", end))\n@@ -923,6 +916,14 @@ void parse_date_format(const char *format, struct date_mode *mode)\n {\n \tconst char *p;\n \n+\t/* \"auto:foo\" is \"if tty/pager, then foo, otherwise normal\" */\n+\tif (skip_prefix(format, \"auto:\", &p)) {\n+\t\tif (isatty(1) || pager_in_use())\n+\t\t\tformat = p;\n+\t\telse\n+\t\t\tformat = \"default\";\n+\t}\n+\n \t/* historical alias */\n \tif (!strcmp(format, \"local\"))\n \t\tformat = \"default-local\";\n\nThat removes \"auto\" completely. We could still support it as an alias\nfor \"auto:human\" with something like:\n\n  if (!strcmp(format, \"auto\"))\n\tformat = \"auto:human\";\n\nbut IMHO it is a simpler interface to just have the user be explicit\n(this is meant to be set once in config, after all).\n\n> > I don't personally care about using this myself, but we already had to\n> > deal with retrofitting \"local\" as a modifier. I'd prefer to avoid making\n> > the same mistake again.\n> Since I wasn't involved could you summarize the you are referring to?\n\nThe format \"local\" was a variant of \"default\" that would use the local\ntimezone instead of the author's. But there was no way to format, say,\niso8601 in the local timezone. So we had to invent a new syntax that was\ncompatible (\"iso8601-local\"), and keep \"local\" around forever for\nbackwards compatibility. Not the end of the world, but we can avoid it\nin this case with a little preparation.\n\n> > (I'd actually argue that \"log.date\" should basically _always_ have the\n> > \"auto\" behavior, since it tends to get treated as plumbing anyway, and I\n> > suspect that anybody who sets log.date now would see subtle breakage\n> > from scripts. But maybe it's too late at this point?).\n> If auto isn't added to the \"log.date\" file, then the date behaviour is not \n> changed from is currently in the code base.   Therefore, there shouldn't be \n> any breakage.\n\nRight, this isn't a problem with your patches. I mean that the existing\n\"log.date\" is arguably mis-designed, and we ought to have had something\nlike \"auto\" from day one (or even made it the default for log.date).\n\n-Peff\n"},{"id":"366147","messageId":"4462659.Bys67ThUBR@thunderbird","threadId":"50135","inReplyTo":"20190104075034.GA26014@sigill.intra.peff.net","subject":"Re: [PATCH 1/3] Add 'human' date format","fromName":"Stephen P Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-04T13:03:18Z","receivedAt":"2019-01-04T13:03:22Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"On Friday, January 4, 2019 12:50:35 AM MST Jeff King wrote:\n> On Thu, Jan 03, 2019 at 06:19:56AM -0700, Stephen P. Smith wrote:\n> > \n> > I didn't see anything in the code which would prohibit setting something\n> > like that.\n> \n> Yeah, I don't think supporting that is too hard. I was thinking\n> something like this:\n\nI take it that if I update Linus's patch, I still keep Junio's and Linus' \nsign-off line for the purpose of the chain of custody?  Of should I use a \nsecond patch?\n\nJust trying to follow the rules.\nsps\n\n\n"},{"id":"366202","messageId":"20190106061935.GA4207@sigill.intra.peff.net","threadId":"50135","inReplyTo":"4462659.Bys67ThUBR@thunderbird","subject":"Re: [PATCH 1/3] Add 'human' date format","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-01-06T06:19:36Z","receivedAt":"2019-01-06T06:27:44Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 04, 2019 at 06:03:18AM -0700, Stephen P Smith wrote:\n\n> On Friday, January 4, 2019 12:50:35 AM MST Jeff King wrote:\n> > On Thu, Jan 03, 2019 at 06:19:56AM -0700, Stephen P. Smith wrote:\n> > > \n> > > I didn't see anything in the code which would prohibit setting something\n> > > like that.\n> > \n> > Yeah, I don't think supporting that is too hard. I was thinking\n> > something like this:\n> \n> I take it that if I update Linus's patch, I still keep Junio's and Linus' \n> sign-off line for the purpose of the chain of custody?  Of should I use a \n> second patch?\n\nI think the most interesting question is the actual authorship (i.e.,\nthe \"From:\" field).  I think people are generally OK with having their\npatches polished a bit to fix obvious bugs or short-comings. But at some\npoint if you make too many changes they or may not want to have the\nresult attributed to them. ;)\n\nFor the particular change I suggested, it's borderline to me on whether\nit hits that case, so I'd probably err on the side of caution. And I'd\neither expect Linus to say \"yeah, that sounds like a good direction\", or\nI'd do it as a separate patch. And if a separate patch, I'd probably\ntease Linus's patch out into two separate ones: one to add \"human\", and\none to implement \"auto\". And then drop the \"auto\" one in favor of your\nnew patch (with you as the author).\n\nAnd I think that makes the signoff questions go away for this instance\n(keep the signoffs for Linus's, and just signoff the new patch\nyourself). But here's some general pontificating in that direction:\n\n    Normally you can just drop Junio's signoff. The chain of custody is\n    usually \"author, then maintainer\" and he'll re-add his maintainer\n    signoff when he picks up your patch. In this case of this patch it's\n    \"author, then polisher, then maintainer\", but Junio is still at the\n    end.\n\n    Now one can argue that Junio picked up Linus's patch, which you then\n    picked up from Junio's repository and fed back to Junio. But you\n    could just as well have picked Linus's patch up from the mailing\n    list and then polished it. So I don't know that having Junio twice\n    in the chain is really that interesting.\n\n    Generally, yes, I'd keep Linus's signoff in a situation like this.\n    He is asserting that the original work done meets the DCO\n    requirements. You polishing the patch does not change that (of\n    course you could introduce a bunch of new code that doesn't meet the\n    DCO and sign it off anyway, but that's why there's ordering in the\n    chain of custody. Somebody investigating would probably walk\n    backwards up the chain).\n\n-Peff\n"},{"id":"366369","messageId":"a8a586d9-dad7-606f-948c-06725ac3e062@kdbg.org","threadId":"50135","inReplyTo":"20181231003150.8031-4-ischis2@cox.net","subject":"Re: [PATCH 3/3] t0006-date.sh: add `human` date format tests.","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2019-01-08T21:27:22Z","receivedAt":"2019-01-08T21:27:29Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 31.12.18 um 01:31 schrieb Stephen P. Smith:\n> +check_human_date () {\n> +\ttime=$1\n> +\texpect=$2\n> +\ttest_expect_success \"check date ($format:$time)\" '\n> +\t\techo \"$time -> $expect\" >expect &&\n> +\t\tTZ=${zone:-$TZ} test-tool date show:\"$format\" \"$time\" >actual &&\n> +\t\tgrep \"$expect\" actual\n> +\t'\n> +}\n> +\n>   # arbitrary but sensible time for examples\n>   TIME='1466000000 +0200'\n>   check_show iso8601 \"$TIME\" '2016-06-15 16:13:20 +0200'\n> @@ -52,6 +62,20 @@ check_show unix \"$TIME\" '1466000000'\n>   check_show iso-local \"$TIME\" '2016-06-15 14:13:20 +0000'\n>   check_show raw-local \"$TIME\" '1466000000 +0000'\n>   check_show unix-local \"$TIME\" '1466000000'\n> +check_show human \"$TIME\" 'Jun 15 2016'\n> +\n> +# Subtract some known constant time and look for expected field format\n> +TODAY_REGEX='5 hours ago'\n> +THIS_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [012][0-9]:[0-6][0-9]'\n> +MORE_THAN_A_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [0-9][0-9][0-9][0-9]'\n> +check_human_date \"$(($(date +%s)-18000)) +0200\" $TODAY_REGEX # 5 hours ago\n> +check_human_date \"$(($(date +%s)-432000)) +0200\" $THIS_YEAR_REGEX  # 5 days ago\n> +check_human_date \"$(($(date +%s)-1728000)) +0200\" $THIS_YEAR_REGEX # 3 weeks ago\n> +check_human_date \"$(($(date +%s)-13000000)) +0200\" $THIS_YEAR_REGEX # 5 months ago\n> +check_human_date \"$(($(date +%s)-31449600)) +0200\" $THIS_YEAR_REGEX # 12 months ago\n> +check_human_date \"$(($(date +%s)-37500000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 1 year, 2 months ago\n> +check_human_date \"$(($(date +%s)-55188000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 1 year, 9 months ago\n> +check_human_date \"$(($(date +%s)-630000000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 20 years ago\n>   \n>   check_show 'format:%z' \"$TIME\" '+0200'\n>   check_show 'format-local:%z' \"$TIME\" '+0000'\n> diff --git a/t/t4202-log.sh b/t/t4202-log.sh\n> index 819c24d10e..d7f3b73650 100755\n> --- a/t/t4202-log.sh\n> +++ b/t/t4202-log.sh\n> @@ -1707,4 +1707,28 @@ test_expect_success '--exclude-promisor-objects does not BUG-crash' '\n>   \ttest_must_fail git log --exclude-promisor-objects source-a\n>   '\n>   \n> +check_human_date() {\n> +\tcommit_date=$1\n> +\texpect=$2\n> +\ttest_expect_success \"$commit_date\" \"\n> +\t\techo $expect $commit_date >dates &&\n> +\t\tgit add dates &&\n> +\t\tgit commit -m 'Expect String' --date=\\\"$commit_date\\\" dates &&\n> +\t\tgit log -1 --date=human | grep \\\"^Date:\\\" >actual &&\n> +\t\tgrep \\\"$expect\\\" actual\n> +\"\n> +}\n> +\n> +TODAY_REGEX='[A-Z][a-z][a-z] [012][0-9]:[0-6][0-9] .0200'\n> +THIS_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [012][0-9]:[0-6][0-9]'\n> +MORE_THAN_A_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [0-9][0-9][0-9][0-9]'\n> +check_human_date \"$(($(date +%s)-18000)) +0200\" $TODAY_REGEX # 5 hours ago\n> +check_human_date \"$(($(date +%s)-432000)) +0200\" $THIS_YEAR_REGEX  # 5 days ago\n> +check_human_date \"$(($(date +%s)-1728000)) +0200\" $THIS_YEAR_REGEX # 3 weeks ago\n> +check_human_date \"$(($(date +%s)-13000000)) +0200\" $THIS_YEAR_REGEX # 5 months ago\n> +check_human_date \"$(($(date +%s)-31449600)) +0200\" $THIS_YEAR_REGEX # 12 months ago\n> +check_human_date \"$(($(date +%s)-37500000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 1 year, 2 months ago\n> +check_human_date \"$(($(date +%s)-55188000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 1 year, 9 months ago\n> +check_human_date \"$(($(date +%s)-630000000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 20 years ago\n> +\n>   test_done\n> diff --git a/t/t7007-show.sh b/t/t7007-show.sh\n> index 42d3db6246..0a0334a8b5 100755\n> --- a/t/t7007-show.sh\n> +++ b/t/t7007-show.sh\n> @@ -128,4 +128,29 @@ test_expect_success 'show --graph is forbidden' '\n>     test_must_fail git show --graph HEAD\n>   '\n>   \n> +check_human_date() {\n> +\tcommit_date=$1\n> +\texpect=$2\n> +\ttest_expect_success \"$commit_date\" \"\n> +\t\techo $expect $commit_date >dates &&\n> +\t\tgit add dates &&\n> +\t\tgit commit -m 'Expect String' --date=\\\"$commit_date\\\" dates &&\n> +\t\tgit show --date=human | grep \\\"^Date:\\\" >actual &&\n> +\t\tgrep \\\"$expect\\\" actual\n> +\"\n> +}\n> +\n> +TODAY_REGEX='[A-Z][a-z][a-z] [012][0-9]:[0-6][0-9] .0200'\n> +THIS_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [012][0-9]:[0-6][0-9]'\n> +MORE_THAN_A_YEAR_REGEX='[A-Z][a-z][a-z] [A-Z][a-z][a-z] [0-9]* [0-9][0-9][0-9][0-9]'\n> +check_human_date \"$(($(date +%s)-18000)) +0200\" $TODAY_REGEX # 5 hours ago\n> +check_human_date \"$(($(date +%s)-432000)) +0200\" $THIS_YEAR_REGEX  # 5 days ago\n> +check_human_date \"$(($(date +%s)-1728000)) +0200\" $THIS_YEAR_REGEX # 3 weeks ago\n> +check_human_date \"$(($(date +%s)-13000000)) +0200\" $THIS_YEAR_REGEX # 5 months ago\n> +check_human_date \"$(($(date +%s)-31449600)) +0200\" $THIS_YEAR_REGEX # 12 months ago\n> +check_human_date \"$(($(date +%s)-37500000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 1 year, 2 months ago\n> +check_human_date \"$(($(date +%s)-55188000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 1 year, 9 months ago\n> +check_human_date \"$(($(date +%s)-630000000)) +0200\" $MORE_THAN_A_YEAR_REGEX # 20 years ago\n\nThe $...REGEX expansions must be put in double-quotes to protect them \nfrom field splitting. But then the tests do not pass anymore (I tested \nonly t4202). Please revisit this change.\n\n-- Hannes\n"},{"id":"366391","messageId":"6530822.TNJIEUz5BA@thunderbird","threadId":"50135","inReplyTo":"a8a586d9-dad7-606f-948c-06725ac3e062@kdbg.org","subject":"Re: [PATCH 3/3] t0006-date.sh: add `human` date format tests.","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-09T00:44:00Z","receivedAt":"2019-01-09T00:44:03Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"On Tuesday, January 8, 2019 2:27:22 PM MST Johannes Sixt wrote:\n> Am 31.12.18 um 01:31 schrieb Stephen P. Smith:\n> > +\n> > +TODAY_REGEX='[A-Z][a-z][a-z] [012][0-9]:[0-6][0-9] .0200'\n<snip>\n> The $...REGEX expansions must be put in double-quotes to protect them\n> from field splitting. But then the tests do not pass anymore (I tested\n> only t4202). Please revisit this change.\n> \n> -- Hannes\n\nI will later figure out why you are seeing the fields splitting but I am not.   \nIn the mean time I will change the quoting.\n\nI started working on test updates based on prior comments this past weekend.\n\nsps\n\n\n\n\n"},{"id":"366399","messageId":"42e521e3-8a12-17c9-cb7f-bfba226ca126@kdbg.org","threadId":"50135","inReplyTo":"6530822.TNJIEUz5BA@thunderbird","subject":"Re: [PATCH 3/3] t0006-date.sh: add `human` date format tests.","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2019-01-09T06:58:29Z","receivedAt":"2019-01-09T06:58:37Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 09.01.19 um 01:44 schrieb Stephen P. Smith:\n> On Tuesday, January 8, 2019 2:27:22 PM MST Johannes Sixt wrote:\n>> Am 31.12.18 um 01:31 schrieb Stephen P. Smith:\n>>> +\n>>> +TODAY_REGEX='[A-Z][a-z][a-z] [012][0-9]:[0-6][0-9] .0200'\n> <snip>\n>> The $...REGEX expansions must be put in double-quotes to protect them\n>> from field splitting. But then the tests do not pass anymore (I tested\n>> only t4202). Please revisit this change.\n> \n> I will later figure out why you are seeing the fields splitting but I am not.\n> In the mean time I will change the quoting.\n\nIn this line\n\nTODAY_REGEX='[A-Z][a-z][a-z] [012][0-9]:[0-6][0-9] .0200'\n\nno field splitting occurs. The quoting is fine here. But notice that the \nvalue of $TODAY_REGEX contains blanks.\n\nIn this line\n\ncheck_human_date \"$(($(date +%s)-18000)) +0200\" $TODAY_REGEX\n\nthe value of $TODAY_REGEX is substituted and then the value is split \ninto fields at the blanks because the expansion is not quoted.\n\nAs a consequence, function check_human_date considers only the first \npart of $TODAY_REGEX, i.e. 'A-Z][a-z][a-z]' (which is parameter $2), but \nignores everything else (because it does not use $3 or $4).\n\n-- Hannes\n"},{"id":"366466","messageId":"2249216.RGRfnxe1O0@thunderbird","threadId":"50135","inReplyTo":"42e521e3-8a12-17c9-cb7f-bfba226ca126@kdbg.org","subject":"Re: [PATCH 3/3] t0006-date.sh: add `human` date format tests.","fromName":"Stephen & Linda Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-10T01:50:26Z","receivedAt":"2019-01-10T01:50:31Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"On Tuesday, January 8, 2019 11:58:29 PM MST Johannes Sixt wrote:\n> But notice that the value of $TODAY_REGEX contains blanks.\n> \n> In this line\n> \n> check_human_date \"$(($(date +%s)-18000)) +0200\" $TODAY_REGEX\n> \n> the value of $TODAY_REGEX is substituted and then the value is split\n> into fields at the blanks because the expansion is not quoted.\n> \n> As a consequence, function check_human_date considers only the first\n> part of $TODAY_REGEX, i.e. 'A-Z][a-z][a-z]' (which is parameter $2), but\n> ignores everything else (because it does not use $3 or $4).\n> \n> -- Hannes\n\nI hadn't understood your original comment, but now i understand.   Will fix.\n\n\n"},{"id":"367046","messageId":"20190118061805.19086-4-ischis2@cox.net","threadId":"50135","inReplyTo":"20190118061805.19086-1-ischis2@cox.net","subject":"[PATCH v2 3/5] Add 'human' date format documentation","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-18T06:18:03Z","receivedAt":"2019-01-18T06:18:10Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Display date and time information in a format similar to how people\nwrite dates in other contexts. If the year isn't specified then, the\nreader infers the date is given is in the current year.\n\nBy not displaying the redundant information, the reader concentrates\non the information that is different. The patch reports relative dates\nbased on information inferred from the date on the machine running the\ngit command at the time the command is executed.\n\nWhile the format is more useful to humans by dropping inferred\ninformation, there is nothing that makes it actually human. If the\n'relative' date format wasn't already implemented then using\n'relative' would have been appropriate.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n Documentation/git-log.txt          | 4 ++++\n Documentation/rev-list-options.txt | 6 ++++++\n 2 files changed, 10 insertions(+)\n\ndiff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\nindex 90761f1694..1d2d932c76 100644\n--- a/Documentation/git-log.txt\n+++ b/Documentation/git-log.txt\n@@ -193,6 +193,10 @@ log.date::\n \t`--date` option.)  Defaults to \"default\", which means to write\n \tdates like `Sat May 8 19:35:34 2010 -0500`.\n \n+\tIf the format is set to \"auto:foo\", then if the pager is in\n+\tuse format \"foo\" will be the used for the date format, otherwise\n+\t\"default\" will be used.\n+\n log.follow::\n \tIf `true`, `git log` will act as if the `--follow` option was used when\n \ta single <path> is given.  This has the same limitations as `--follow`,\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex bab5f50b17..5d58f35d19 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -835,6 +835,12 @@ Note that the `-local` option does not affect the seconds-since-epoch\n value (which is always measured in UTC), but does switch the accompanying\n timezone value.\n +\n+`--date=human` shows the timezone if it matches the current time-zone,\n+and doesn't print the whole date if that matches (ie skip printing\n+year for dates that are \"this year\", but also skip the whole date\n+itself if it's in the last few days and we can just say what weekday\n+it was).\n++\n `--date=unix` shows the date as a Unix epoch timestamp (seconds since\n 1970).  As with `--raw`, this is always in UTC and therefore `-local`\n has no effect.\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367047","messageId":"20190118061805.19086-3-ischis2@cox.net","threadId":"50135","inReplyTo":"20190118061805.19086-1-ischis2@cox.net","subject":"[PATCH v2 2/5] Remove the proposed use of auto as secondary way to specify human","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-18T06:18:02Z","receivedAt":"2019-01-18T06:18:10Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"In addition to adding the 'human' format, the patch added the auto\nkeyword which could be used in the config file as an alternate way to\nspecify the human format.  Removing 'auto' cleans up the 'human'\nformat interface.\n\nInstead add 'auto:human' date mode which defaults to human if we're\nusing the pager.  So you can do\n\n\tgit config --add log.date auto:human\n\nand your \"git log\" commands will show the human-legible format unless\nyou're scripting things.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n date.c | 15 ++++++++-------\n 1 file changed, 8 insertions(+), 7 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex a8d50eb206..43c3a84e25 100644\n--- a/date.c\n+++ b/date.c\n@@ -883,11 +883,6 @@ int parse_date(const char *date, struct strbuf *result)\n \treturn 0;\n }\n \n-static int auto_date_style(void)\n-{\n-\treturn (isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;\n-}\n-\n static enum date_mode_type parse_date_type(const char *format, const char **end)\n {\n \tif (skip_prefix(format, \"relative\", end))\n@@ -907,8 +902,6 @@ static enum date_mode_type parse_date_type(const char *format, const char **end)\n \t\treturn DATE_NORMAL;\n \tif (skip_prefix(format, \"human\", end))\n \t\treturn DATE_HUMAN;\n-\tif (skip_prefix(format, \"auto\", end))\n-\t\treturn auto_date_style();\n \tif (skip_prefix(format, \"raw\", end))\n \t\treturn DATE_RAW;\n \tif (skip_prefix(format, \"unix\", end))\n@@ -923,6 +916,14 @@ void parse_date_format(const char *format, struct date_mode *mode)\n {\n \tconst char *p;\n \n+\t/* \"auto:foo\" is \"if tty/pager, then foo, otherwise normal\" */\n+\tif (skip_prefix(format, \"auto:\", &p)) {\n+\t\tif (isatty(1) || pager_in_use())\n+\t\t\tformat = p;\n+\t\telse\n+\t\t\tformat = \"default\";\n+\t}\n+\n \t/* historical alias */\n \tif (!strcmp(format, \"local\"))\n \t\tformat = \"default-local\";\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367048","messageId":"20190118061805.19086-6-ischis2@cox.net","threadId":"50135","inReplyTo":"20190118061805.19086-1-ischis2@cox.net","subject":"[PATCH v2 5/5] Add `human` date format tests.","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-18T06:18:05Z","receivedAt":"2019-01-18T06:18:11Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"When using `human` several fields are suppressed depending on the time\ndifference between the reference date and the local computer date. In\ncases where the difference is less than a year, the year field is\nsupppressed. If the time is less than a day; the month and year is\nsuppressed.\n\nUse TEST_DATE_NOW environment variable when using the test-tool to\nhold the expected output strings constant.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n t/t0006-date.sh | 20 ++++++++++++++++++++\n 1 file changed, 20 insertions(+)\n\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex ffb2975e48..c7c0786b24 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -128,4 +128,24 @@ check_approxidate '6AM, June 7, 2009' '2009-06-07 06:00:00'\n check_approxidate '2008-12-01' '2008-12-01 19:20:00'\n check_approxidate '2009-12-01' '2009-12-01 19:20:00'\n \n+check_date_format() {\n+\tformat=$1\n+\tt=$(($TEST_DATE_NOW - $2))\n+\texpect=$3\n+\ttest_expect_success \"human date $t\" \"\n+\techo $TEST_DATE_NOW >now &&\n+\ttest-tool date human $t >actual &&\n+\tgrep '$expect' actual\n+\"\n+}\n+\n+check_date_format human 18000 \"5 hours ago\" # 5 hours ago\n+check_date_format human 432000 \"Tue Aug 25 19:20\" # 5 days ago\n+check_date_format human 1728000 \"Mon Aug 10 19:20\" # 3 weeks ago\n+check_date_format human 13000000 \"Thu Apr 2 08:13\" # 5 months ago\n+check_date_format human 31449600 \"Aug 31 2008\" # 12 months ago\n+check_date_format human 37500000 \"Jun 22 2008\" # 1 year, 2 months ago\n+check_date_format human 55188000 \"Dec 1 2007\" # 1 year, 9 months ago\n+check_date_format human 630000000 \"Sep 13 1989\" # 20 years ago\n+\n test_done\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367049","messageId":"20190118061805.19086-5-ischis2@cox.net","threadId":"50135","inReplyTo":"20190118061805.19086-1-ischis2@cox.net","subject":"[PATCH v2 4/5] Add `human` format to test-tool","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-18T06:18:04Z","receivedAt":"2019-01-18T06:18:12Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Add the human format support to the test tool so that TEST_DATE_NOW\ncan be used to specify the current time.\n\nA static variable is used for passing the tool specified value to\nget_date.  The get_date helper function eliminates the need to\nrefactor up the show_date and show_date normal functions to pass the\ntime value.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n cache.h              |  2 ++\n date.c               | 26 ++++++++++++++++++++++++--\n t/helper/test-date.c | 15 +++++++++++++++\n 3 files changed, 41 insertions(+), 2 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 34c33e6a28..fe00ddf910 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1467,6 +1467,8 @@ struct date_mode *date_mode_from_type(enum date_mode_type type);\n const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);\n void show_date_relative(timestamp_t time, int tz, const struct timeval *now,\n \t\t\tstruct strbuf *timebuf);\n+void show_date_human(timestamp_t time, int tz, const struct timeval *now,\n+\t\t\tstruct strbuf *timebuf);\n int parse_date(const char *date, struct strbuf *out);\n int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);\n int parse_expiry_date(const char *date, timestamp_t *timestamp);\ndiff --git a/date.c b/date.c\nindex 43c3a84e25..24435b1e1d 100644\n--- a/date.c\n+++ b/date.c\n@@ -115,6 +115,28 @@ static int local_tzoffset(timestamp_t time)\n \treturn local_time_tzoffset((time_t)time, &tm);\n }\n \n+const struct timeval *test_time = 0;\n+void show_date_human(timestamp_t time, int tz,\n+\t\t\t       const struct timeval *now,\n+\t\t\t       struct strbuf *timebuf)\n+{\n+\ttest_time = (const struct timeval *) now;\n+\tstrbuf_addstr( timebuf, show_date(time, tz, DATE_MODE(HUMAN)));\n+\ttest_time = (const struct timeval *) 0;\n+}\n+\n+static void get_time(struct timeval *now)\n+{\n+\tif(test_time != 0)\n+\t\t/*\n+\t\t * If show_date was called via the test\n+\t\t *  interface use the test_tool time\n+\t\t */\n+\t\t*now = *test_time;\n+\telse\n+\t\tgettimeofday(now, NULL);\n+}\n+\n void show_date_relative(timestamp_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n@@ -228,7 +250,7 @@ static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm\n \t/* Show \"today\" times as just relative times */\n \tif (hide.wday) {\n \t\tstruct timeval now;\n-\t\tgettimeofday(&now, NULL);\n+\t\tget_time(&now);\n \t\tshow_date_relative(time, tz, &now, buf);\n \t\treturn;\n \t}\n@@ -284,7 +306,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \tif (mode->type == DATE_HUMAN) {\n \t\tstruct timeval now;\n \n-\t\tgettimeofday(&now, NULL);\n+\t\tget_time(&now);\n \n \t\t/* Fill in the data for \"current time\" in human_tz and human_tm */\n \t\thuman_tz = local_time_tzoffset(now.tv_sec, &human_tm);\ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex a0837371ab..22d42a2174 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -3,6 +3,7 @@\n \n static const char *usage_msg = \"\\n\"\n \"  test-tool date relative [time_t]...\\n\"\n+\"  test-tool date human [time_t]...\\n\"\n \"  test-tool date show:<format> [time_t]...\\n\"\n \"  test-tool date parse [date]...\\n\"\n \"  test-tool date approxidate [date]...\\n\"\n@@ -22,6 +23,18 @@ static void show_relative_dates(const char **argv, struct timeval *now)\n \tstrbuf_release(&buf);\n }\n \n+static void show_human_dates(const char **argv, struct timeval *now)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\n+\tfor (; *argv; argv++) {\n+\t\ttime_t t = atoi(*argv);\n+\t\tshow_date_human(t, 0, now, &buf);\n+\t\tprintf(\"%s -> %s\\n\", *argv, buf.buf);\n+\t}\n+\tstrbuf_release(&buf);\n+}\n+\n static void show_dates(const char **argv, const char *format)\n {\n \tstruct date_mode mode;\n@@ -100,6 +113,8 @@ int cmd__date(int argc, const char **argv)\n \t\tusage(usage_msg);\n \tif (!strcmp(*argv, \"relative\"))\n \t\tshow_relative_dates(argv+1, &now);\n+\telse if (!strcmp(*argv, \"human\"))\n+\t\tshow_human_dates(argv+1, &now);\n \telse if (skip_prefix(*argv, \"show:\", &x))\n \t\tshow_dates(argv+1, x);\n \telse if (!strcmp(*argv, \"parse\"))\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367050","messageId":"20190118061805.19086-2-ischis2@cox.net","threadId":"50135","inReplyTo":"20190118061805.19086-1-ischis2@cox.net","subject":"[PATCH v2 1/5] Add 'human' date format","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-18T06:18:01Z","receivedAt":"2019-01-18T06:18:15Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"From: Linus Torvalds <torvalds@linux-foundation.org>\n\nThis adds --date=human, which skips the timezone if it matches the\ncurrent time-zone, and doesn't print the whole date if that matches (ie\nskip printing year for dates that are \"this year\", but also skip the\nwhole date itself if it's in the last few days and we can just say what\nweekday it was).\n\nFor really recent dates (same day), use the relative date stamp, while\nfor old dates (year doesn't match), don't bother with time and timezone.\n\nAlso add 'auto' date mode, which defaults to human if we're using the\npager.  So you can do\n\n\tgit config --add log.date auto\n\nand your \"git log\" commands will show the human-legible format unless\nyou're scripting things.\n\nNote that this time format still shows the timezone for recent enough\nevents (but not so recent that they show up as relative dates).  You can\ncombine it with the \"-local\" suffix to never show timezones for an even\nmore simplified view.\n\nSigned-off-by: Linus Torvalds <torvalds@linux-foundation.org>\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n builtin/blame.c |   4 ++\n cache.h         |   1 +\n date.c          | 130 ++++++++++++++++++++++++++++++++++++++++--------\n 3 files changed, 115 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 6d798f9939..f684e31d82 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -925,6 +925,10 @@ int cmd_blame(int argc, const char **argv, const char *prefix)\n \t\t */\n \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n \t\tbreak;\n+\tcase DATE_HUMAN:\n+\t\t/* If the year is shown, no time is shown */\n+\t\tblame_date_width = sizeof(\"Thu Oct 19 16:00\");\n+\t\tbreak;\n \tcase DATE_NORMAL:\n \t\tblame_date_width = sizeof(\"Thu Oct 19 16:00:04 2006 -0700\");\n \t\tbreak;\ndiff --git a/cache.h b/cache.h\nindex 49713cc5a5..34c33e6a28 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1439,6 +1439,7 @@ extern struct object *peel_to_type(const char *name, int namelen,\n \n enum date_mode_type {\n \tDATE_NORMAL = 0,\n+\tDATE_HUMAN,\n \tDATE_RELATIVE,\n \tDATE_SHORT,\n \tDATE_ISO8601,\ndiff --git a/date.c b/date.c\nindex 9bc15df6f9..a8d50eb206 100644\n--- a/date.c\n+++ b/date.c\n@@ -77,22 +77,16 @@ static struct tm *time_to_tm_local(timestamp_t time)\n }\n \n /*\n- * What value of \"tz\" was in effect back then at \"time\" in the\n- * local timezone?\n+ * Fill in the localtime 'struct tm' for the supplied time,\n+ * and return the local tz.\n  */\n-static int local_tzoffset(timestamp_t time)\n+static int local_time_tzoffset(time_t t, struct tm *tm)\n {\n-\ttime_t t, t_local;\n-\tstruct tm tm;\n+\ttime_t t_local;\n \tint offset, eastwest;\n \n-\tif (date_overflows(time))\n-\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n-\n-\tt = (time_t)time;\n-\tlocaltime_r(&t, &tm);\n-\tt_local = tm_to_time_t(&tm);\n-\n+\tlocaltime_r(&t, tm);\n+\tt_local = tm_to_time_t(tm);\n \tif (t_local == -1)\n \t\treturn 0; /* error; just use +0000 */\n \tif (t_local < t) {\n@@ -107,6 +101,20 @@ static int local_tzoffset(timestamp_t time)\n \treturn offset * eastwest;\n }\n \n+/*\n+ * What value of \"tz\" was in effect back then at \"time\" in the\n+ * local timezone?\n+ */\n+static int local_tzoffset(timestamp_t time)\n+{\n+\tstruct tm tm;\n+\n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\n+\treturn local_time_tzoffset((time_t)time, &tm);\n+}\n+\n void show_date_relative(timestamp_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n@@ -191,9 +199,80 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \treturn &mode;\n }\n \n+static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm, int tz, struct tm *human_tm, int human_tz, int local)\n+{\n+\tstruct {\n+\t\tunsigned int\tyear:1,\n+\t\t\t\tdate:1,\n+\t\t\t\twday:1,\n+\t\t\t\ttime:1,\n+\t\t\t\tseconds:1,\n+\t\t\t\ttz:1;\n+\t} hide = { 0 };\n+\n+\thide.tz = local || tz == human_tz;\n+\thide.year = tm->tm_year == human_tm->tm_year;\n+\tif (hide.year) {\n+\t\tif (tm->tm_mon == human_tm->tm_mon) {\n+\t\t\tif (tm->tm_mday > human_tm->tm_mday) {\n+\t\t\t\t/* Future date: think timezones */\n+\t\t\t} else if (tm->tm_mday == human_tm->tm_mday) {\n+\t\t\t\thide.date = hide.wday = 1;\n+\t\t\t} else if (tm->tm_mday + 5 > human_tm->tm_mday) {\n+\t\t\t\t/* Leave just weekday if it was a few days ago */\n+\t\t\t\thide.date = 1;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/* Show \"today\" times as just relative times */\n+\tif (hide.wday) {\n+\t\tstruct timeval now;\n+\t\tgettimeofday(&now, NULL);\n+\t\tshow_date_relative(time, tz, &now, buf);\n+\t\treturn;\n+\t}\n+\n+\t/*\n+\t * Always hide seconds for human-readable.\n+\t * Hide timezone if showing date.\n+\t * Hide weekday and time if showing year.\n+\t *\n+\t * The logic here is two-fold:\n+\t *  (a) only show details when recent enough to matter\n+\t *  (b) keep the maximum length \"similar\", and in check\n+\t */\n+\tif (human_tm->tm_year) {\n+\t\thide.seconds = 1;\n+\t\thide.tz |= !hide.date;\n+\t\thide.wday = hide.time = !hide.year;\n+\t}\n+\n+\tif (!hide.wday)\n+\t\tstrbuf_addf(buf, \"%.3s \", weekday_names[tm->tm_wday]);\n+\tif (!hide.date)\n+\t\tstrbuf_addf(buf, \"%.3s %d \", month_names[tm->tm_mon], tm->tm_mday);\n+\n+\t/* Do we want AM/PM depending on locale? */\n+\tif (!hide.time) {\n+\t\tstrbuf_addf(buf, \"%02d:%02d\", tm->tm_hour, tm->tm_min);\n+\t\tif (!hide.seconds)\n+\t\t\tstrbuf_addf(buf, \":%02d\", tm->tm_sec);\n+\t} else\n+\t\tstrbuf_rtrim(buf);\n+\n+\tif (!hide.year)\n+\t\tstrbuf_addf(buf, \" %d\", tm->tm_year + 1900);\n+\n+\tif (!hide.tz)\n+\t\tstrbuf_addf(buf, \" %+05d\", tz);\n+}\n+\n const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n {\n \tstruct tm *tm;\n+\tstruct tm human_tm = { 0 };\n+\tint human_tz = -1;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n \n \tif (mode->type == DATE_UNIX) {\n@@ -202,6 +281,15 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \t\treturn timebuf.buf;\n \t}\n \n+\tif (mode->type == DATE_HUMAN) {\n+\t\tstruct timeval now;\n+\n+\t\tgettimeofday(&now, NULL);\n+\n+\t\t/* Fill in the data for \"current time\" in human_tz and human_tm */\n+\t\thuman_tz = local_time_tzoffset(now.tv_sec, &human_tm);\n+\t}\n+\n \tif (mode->local)\n \t\ttz = local_tzoffset(time);\n \n@@ -258,14 +346,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \t\tstrbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,\n \t\t\t\t!mode->local);\n \telse\n-\t\tstrbuf_addf(&timebuf, \"%.3s %.3s %d %02d:%02d:%02d %d%c%+05d\",\n-\t\t\t\tweekday_names[tm->tm_wday],\n-\t\t\t\tmonth_names[tm->tm_mon],\n-\t\t\t\ttm->tm_mday,\n-\t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n-\t\t\t\ttm->tm_year + 1900,\n-\t\t\t\tmode->local ? 0 : ' ',\n-\t\t\t\ttz);\n+\t\tshow_date_normal(&timebuf, time, tm, tz, &human_tm, human_tz, mode->local);\n \treturn timebuf.buf;\n }\n \n@@ -802,6 +883,11 @@ int parse_date(const char *date, struct strbuf *result)\n \treturn 0;\n }\n \n+static int auto_date_style(void)\n+{\n+\treturn (isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;\n+}\n+\n static enum date_mode_type parse_date_type(const char *format, const char **end)\n {\n \tif (skip_prefix(format, \"relative\", end))\n@@ -819,6 +905,10 @@ static enum date_mode_type parse_date_type(const char *format, const char **end)\n \t\treturn DATE_SHORT;\n \tif (skip_prefix(format, \"default\", end))\n \t\treturn DATE_NORMAL;\n+\tif (skip_prefix(format, \"human\", end))\n+\t\treturn DATE_HUMAN;\n+\tif (skip_prefix(format, \"auto\", end))\n+\t\treturn auto_date_style();\n \tif (skip_prefix(format, \"raw\", end))\n \t\treturn DATE_RAW;\n \tif (skip_prefix(format, \"unix\", end))\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367051","messageId":"20190118061805.19086-1-ischis2@cox.net","threadId":"50135","inReplyTo":"20181231003150.8031-1-ischis2@cox.net","subject":"[PATCH v2 0/5] Re-roll of 'human' date format patch set","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-18T06:18:00Z","receivedAt":"2019-01-18T06:18:16Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Reworked documentation and tests for the previously submitted patch set. \n\n\nLinus Torvalds (1):\n  Add 'human' date format\n\nStephen P. Smith (4):\n  Remove the proposed use of auto as secondary way to specify human\n  Add 'human' date format documentation\n  Add `human` format to test-tool\n  Add `human` date format tests.\n\n Documentation/git-log.txt          |   4 +\n Documentation/rev-list-options.txt |   6 ++\n builtin/blame.c                    |   4 +\n cache.h                            |   3 +\n date.c                             | 153 +++++++++++++++++++++++++----\n t/helper/test-date.c               |  15 +++\n t/t0006-date.sh                    |  20 ++++\n 7 files changed, 185 insertions(+), 20 deletions(-)\n\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367125","messageId":"xmqq5zullsph.fsf@gitster-ct.c.googlers.com","threadId":"50135","inReplyTo":"20190118061805.19086-3-ischis2@cox.net","subject":"Re: [PATCH v2 2/5] Remove the proposed use of auto as secondary way to specify human","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-18T18:35:22Z","receivedAt":"2019-01-18T18:35:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Stephen P. Smith\" <ischis2@cox.net> writes:\n\n> In addition to adding the 'human' format, the patch added the auto\n> keyword which could be used in the config file as an alternate way to\n> specify the human format.  Removing 'auto' cleans up the 'human'\n> format interface.\n>\n> Instead add 'auto:human' date mode which defaults to human if we're\n> using the pager.  So you can do\n>\n> \tgit config --add log.date auto:human\n>\n> and your \"git log\" commands will show the human-legible format unless\n> you're scripting things.\n\nI think doing two things in this step (i.e. reverting Linus's \"auto\"\nsupport from 1/5, and adding \"auto\" that is similar to color's auto)\nis OK, but then the title should list both.  It sounded like it was\nthis step is doing only the former.\n\n>\n> Signed-off-by: Stephen P. Smith <ischis2@cox.net>\n> ---\n>  date.c | 15 ++++++++-------\n>  1 file changed, 8 insertions(+), 7 deletions(-)\n>\n> diff --git a/date.c b/date.c\n> index a8d50eb206..43c3a84e25 100644\n> --- a/date.c\n> +++ b/date.c\n> @@ -883,11 +883,6 @@ int parse_date(const char *date, struct strbuf *result)\n>  \treturn 0;\n>  }\n>  \n> -static int auto_date_style(void)\n> -{\n> -\treturn (isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;\n> -}\n> -\n>  static enum date_mode_type parse_date_type(const char *format, const char **end)\n>  {\n>  \tif (skip_prefix(format, \"relative\", end))\n> @@ -907,8 +902,6 @@ static enum date_mode_type parse_date_type(const char *format, const char **end)\n>  \t\treturn DATE_NORMAL;\n>  \tif (skip_prefix(format, \"human\", end))\n>  \t\treturn DATE_HUMAN;\n> -\tif (skip_prefix(format, \"auto\", end))\n> -\t\treturn auto_date_style();\n>  \tif (skip_prefix(format, \"raw\", end))\n>  \t\treturn DATE_RAW;\n>  \tif (skip_prefix(format, \"unix\", end))\n> @@ -923,6 +916,14 @@ void parse_date_format(const char *format, struct date_mode *mode)\n>  {\n>  \tconst char *p;\n>  \n> +\t/* \"auto:foo\" is \"if tty/pager, then foo, otherwise normal\" */\n> +\tif (skip_prefix(format, \"auto:\", &p)) {\n> +\t\tif (isatty(1) || pager_in_use())\n> +\t\t\tformat = p;\n> +\t\telse\n> +\t\t\tformat = \"default\";\n> +\t}\n> +\n>  \t/* historical alias */\n>  \tif (!strcmp(format, \"local\"))\n>  \t\tformat = \"default-local\";\n"},{"id":"367127","messageId":"xmqq1s59ls5j.fsf@gitster-ct.c.googlers.com","threadId":"50135","inReplyTo":"20190118061805.19086-4-ischis2@cox.net","subject":"Re: [PATCH v2 3/5] Add 'human' date format documentation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-18T18:47:20Z","receivedAt":"2019-01-18T18:47:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Stephen P. Smith\" <ischis2@cox.net> writes:\n\n> diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\n> index 90761f1694..1d2d932c76 100644\n> --- a/Documentation/git-log.txt\n> +++ b/Documentation/git-log.txt\n> @@ -193,6 +193,10 @@ log.date::\n>  \t`--date` option.)  Defaults to \"default\", which means to write\n>  \tdates like `Sat May 8 19:35:34 2010 -0500`.\n>  \n> +\tIf the format is set to \"auto:foo\", then if the pager is in\n> +\tuse format \"foo\" will be the used for the date format, otherwise\n> +\t\"default\" will be used.\n> +\n\nThis text is good, but this would break ASCIIdoc formatting,\nwouldn't it?  Observe how \"notes.displayRef::\" section does\nthree-paragraph description and mimick it to make this two-paragraph\ndescription, perhaps.\n\n>  log.follow::\n>  \tIf `true`, `git log` will act as if the `--follow` option was used when\n>  \ta single <path> is given.  This has the same limitations as `--follow`,\n> diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\n> index bab5f50b17..5d58f35d19 100644\n> --- a/Documentation/rev-list-options.txt\n> +++ b/Documentation/rev-list-options.txt\n> @@ -835,6 +835,12 @@ Note that the `-local` option does not affect the seconds-since-epoch\n>  value (which is always measured in UTC), but does switch the accompanying\n>  timezone value.\n>  +\n> +`--date=human` shows the timezone if it matches the current time-zone,\n\nIs it clear in the context that \"it\" refers to \"the timestamp being\nshown\"?\n\nI think the behaviour is that timezone is shown only the timestamp\nbeing shown is from a different timezone (i.e. if it *does* *not*\nmatch), though.\n\n> +and doesn't print the whole date if that matches (ie skip printing\n> +year for dates that are \"this year\", but also skip the whole date\n> +itself if it's in the last few days and we can just say what weekday\n> +it was).\n> ++\n\n... and also omit hour/minute part for a timestamp that is old\nenough.\n\n>  `--date=unix` shows the date as a Unix epoch timestamp (seconds since\n>  1970).  As with `--raw`, this is always in UTC and therefore `-local`\n>  has no effect.\n"},{"id":"367131","messageId":"xmqqtvi5kctv.fsf@gitster-ct.c.googlers.com","threadId":"50135","inReplyTo":"20190118061805.19086-5-ischis2@cox.net","subject":"Re: [PATCH v2 4/5] Add `human` format to test-tool","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-18T19:03:40Z","receivedAt":"2019-01-18T19:03:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Stephen P. Smith\" <ischis2@cox.net> writes:\n\n> Add the human format support to the test tool so that TEST_DATE_NOW\n> can be used to specify the current time.\n>\n> A static variable is used for passing the tool specified value to\n> get_date.  The get_date helper function eliminates the need to\n> refactor up the show_date and show_date normal functions to pass the\n> time value.\n\nHmph.  An interesting approach, but the implementation is a bit too\nmessy.\n\n> diff --git a/date.c b/date.c\n> index 43c3a84e25..24435b1e1d 100644\n> --- a/date.c\n> +++ b/date.c\n> @@ -115,6 +115,28 @@ static int local_tzoffset(timestamp_t time)\n>  \treturn local_time_tzoffset((time_t)time, &tm);\n>  }\n>  \n> +const struct timeval *test_time = 0;\n\nShouldn't this be file-scope static?\n\nLet BSS take care of initializing a variable to 0/NULL; drop \" = 0\"\nat the end.\n\n> +void show_date_human(timestamp_t time, int tz,\n> +\t\t\t       const struct timeval *now,\n> +\t\t\t       struct strbuf *timebuf)\n> +{\n> +\ttest_time = (const struct timeval *) now;\n> +\tstrbuf_addstr( timebuf, show_date(time, tz, DATE_MODE(HUMAN)));\n\nStyle:\n\tstrbuf_addstr(timebuf, show_date(time, tz, DATE_MODE(HUMAN)));\n\n> +\ttest_time = (const struct timeval *) 0;\n> +}\n\nIt is a shame that you introduced a nicely reusable get_time()\nmechanism to let external callers of show_date() specify what time\nto format, instead of the returned timestamp of gettimeofday(),\nbut limited its usefulness to only testing \"human\" format output.\nIf somebody wants to extend \"test-tool date\" for other formats, they\nalso have to add a similar \"show_date_XXX\" hack for their format.\n\nHow about doing it slightly differently?  E.g.\n\n - Get rid of show_date_human().\n\n - Keep get_time(), but have it pay attention to GIT_TEST_TIMESTAMP\n   environment variable, and when it is set, use that as if it is\n   the returned value from gettimeofday().\n\n - If there are gettimeofday() calls in date.c this patch did not\n   touch (because they were not part of the \"human-format\"\n   codepath), adjust them to use get_time() instead.\n\n - Have \"test-tool date\" excersize show_date() directly. \n\n\n\n> +static void get_time(struct timeval *now)\n> +{\n> +\tif(test_time != 0)\n> +\t\t/*\n> +\t\t * If show_date was called via the test\n> +\t\t *  interface use the test_tool time\n> +\t\t */\n> +\t\t*now = *test_time;\n> +\telse\n> +\t\tgettimeofday(now, NULL);\n> +}\n> +\n>  void show_date_relative(timestamp_t time, int tz,\n>  \t\t\t       const struct timeval *now,\n>  \t\t\t       struct strbuf *timebuf)\n> @@ -228,7 +250,7 @@ static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm\n>  \t/* Show \"today\" times as just relative times */\n>  \tif (hide.wday) {\n>  \t\tstruct timeval now;\n> -\t\tgettimeofday(&now, NULL);\n> +\t\tget_time(&now);\n>  \t\tshow_date_relative(time, tz, &now, buf);\n>  \t\treturn;\n>  \t}\n> @@ -284,7 +306,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n>  \tif (mode->type == DATE_HUMAN) {\n>  \t\tstruct timeval now;\n>  \n> -\t\tgettimeofday(&now, NULL);\n> +\t\tget_time(&now);\n>  \n>  \t\t/* Fill in the data for \"current time\" in human_tz and human_tm */\n>  \t\thuman_tz = local_time_tzoffset(now.tv_sec, &human_tm);\n> diff --git a/t/helper/test-date.c b/t/helper/test-date.c\n> index a0837371ab..22d42a2174 100644\n> --- a/t/helper/test-date.c\n> +++ b/t/helper/test-date.c\n> @@ -3,6 +3,7 @@\n>  \n>  static const char *usage_msg = \"\\n\"\n>  \"  test-tool date relative [time_t]...\\n\"\n> +\"  test-tool date human [time_t]...\\n\"\n>  \"  test-tool date show:<format> [time_t]...\\n\"\n>  \"  test-tool date parse [date]...\\n\"\n>  \"  test-tool date approxidate [date]...\\n\"\n> @@ -22,6 +23,18 @@ static void show_relative_dates(const char **argv, struct timeval *now)\n>  \tstrbuf_release(&buf);\n>  }\n>  \n> +static void show_human_dates(const char **argv, struct timeval *now)\n> +{\n> +\tstruct strbuf buf = STRBUF_INIT;\n> +\n> +\tfor (; *argv; argv++) {\n> +\t\ttime_t t = atoi(*argv);\n> +\t\tshow_date_human(t, 0, now, &buf);\n> +\t\tprintf(\"%s -> %s\\n\", *argv, buf.buf);\n> +\t}\n> +\tstrbuf_release(&buf);\n> +}\n> +\n>  static void show_dates(const char **argv, const char *format)\n>  {\n>  \tstruct date_mode mode;\n> @@ -100,6 +113,8 @@ int cmd__date(int argc, const char **argv)\n>  \t\tusage(usage_msg);\n>  \tif (!strcmp(*argv, \"relative\"))\n>  \t\tshow_relative_dates(argv+1, &now);\n> +\telse if (!strcmp(*argv, \"human\"))\n> +\t\tshow_human_dates(argv+1, &now);\n>  \telse if (skip_prefix(*argv, \"show:\", &x))\n>  \t\tshow_dates(argv+1, x);\n>  \telse if (!strcmp(*argv, \"parse\"))\n"},{"id":"367134","messageId":"xmqqpnstkbvy.fsf@gitster-ct.c.googlers.com","threadId":"50135","inReplyTo":"20190118061805.19086-6-ischis2@cox.net","subject":"Re: [PATCH v2 5/5] Add `human` date format tests.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-18T19:24:01Z","receivedAt":"2019-01-18T19:24:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Stephen P. Smith\" <ischis2@cox.net> writes:\n\n> +check_date_format() {\n> +\tformat=$1\n> +\tt=$(($TEST_DATE_NOW - $2))\n> +\texpect=$3\n\nNotice that neither $format nor $1 is used in this test, which means\nthat \"check_date_format\" is not a generic \"I can take a format\nparameter to check the specified one\".  So perhaps\n\n\tcheck_date_format_human () {\n\nand then lose the first parameter?\n\n> +\ttest_expect_success \"human date $t\" \"\n> +\techo $TEST_DATE_NOW >now &&\n> +\ttest-tool date human $t >actual &&\n> +\tgrep '$expect' actual\n> +\"\n\nHopefully $3 does not have a single quote in it ;-)  \n\nBut the test block can see the shell variables just fine, so writing\nit like the following is more in line with how the test framework is\ndesigned to be used.\n\n\ttest_expect_success \"human date $t\" '\n\t\techo \"$TEST_DATE_NOW\" >now &&\n\t\ttest-tool date human \"$t\" >actual &&\n\t\tgrep \"$expect\" actual\n\t'\n\nHow is the file 'now' get used?  Nobody seems to read it around here.\nIs the last one supposed to be \"grep\"?  Or should we do\n\n\techo \"$expect\" >expect &&\n\ttest_cmp expect actual\n\ninstead?\n\n> +}\n> +\n> +check_date_format human 18000 \"5 hours ago\" # 5 hours ago\n> +check_date_format human 432000 \"Tue Aug 25 19:20\" # 5 days ago\n> +check_date_format human 1728000 \"Mon Aug 10 19:20\" # 3 weeks ago\n> +check_date_format human 13000000 \"Thu Apr 2 08:13\" # 5 months ago\n> +check_date_format human 31449600 \"Aug 31 2008\" # 12 months ago\n> +check_date_format human 37500000 \"Jun 22 2008\" # 1 year, 2 months ago\n> +check_date_format human 55188000 \"Dec 1 2007\" # 1 year, 9 months ago\n> +check_date_format human 630000000 \"Sep 13 1989\" # 20 years ago\n> +\n>  test_done\n"},{"id":"367170","messageId":"1639837.7qUrSqU32g@thunderbird","threadId":"50135","inReplyTo":"xmqq5zullsph.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 2/5] Remove the proposed use of auto as secondary way to specify human","fromName":"Stephen & Linda Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-19T03:44:34Z","receivedAt":"2019-01-19T03:44:38Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"On Friday, January 18, 2019 11:35:22 AM MST Junio C Hamano wrote:\n> \"Stephen P. Smith\" <ischis2@cox.net> writes:\n> I think doing two things in this step (i.e. reverting Linus's \"auto\"\n> support from 1/5, and adding \"auto\" that is similar to color's auto)\n> is OK, but then the title should list both.  It sounded like it was\n> this step is doing only the former.\n\nWill change as part of a re-roll.\n\n\n\n"},{"id":"367202","messageId":"20190121051646.20991-2-ischis2@cox.net","threadId":"50135","inReplyTo":"20190121051646.20991-1-ischis2@cox.net","subject":"[PATCH v3 1/5] Add 'human' date format","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-21T05:16:42Z","receivedAt":"2019-01-21T07:13:12Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"From: Linus Torvalds <torvalds@linux-foundation.org>\n\nThis adds --date=human, which skips the timezone if it matches the\ncurrent time-zone, and doesn't print the whole date if that matches (ie\nskip printing year for dates that are \"this year\", but also skip the\nwhole date itself if it's in the last few days and we can just say what\nweekday it was).\n\nFor really recent dates (same day), use the relative date stamp, while\nfor old dates (year doesn't match), don't bother with time and timezone.\n\nAlso add 'auto' date mode, which defaults to human if we're using the\npager.  So you can do\n\n\tgit config --add log.date auto\n\nand your \"git log\" commands will show the human-legible format unless\nyou're scripting things.\n\nNote that this time format still shows the timezone for recent enough\nevents (but not so recent that they show up as relative dates).  You can\ncombine it with the \"-local\" suffix to never show timezones for an even\nmore simplified view.\n\nSigned-off-by: Linus Torvalds <torvalds@linux-foundation.org>\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n builtin/blame.c |   4 ++\n cache.h         |   1 +\n date.c          | 130 ++++++++++++++++++++++++++++++++++++++++--------\n 3 files changed, 115 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 6d798f9939..f684e31d82 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -925,6 +925,10 @@ int cmd_blame(int argc, const char **argv, const char *prefix)\n \t\t */\n \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n \t\tbreak;\n+\tcase DATE_HUMAN:\n+\t\t/* If the year is shown, no time is shown */\n+\t\tblame_date_width = sizeof(\"Thu Oct 19 16:00\");\n+\t\tbreak;\n \tcase DATE_NORMAL:\n \t\tblame_date_width = sizeof(\"Thu Oct 19 16:00:04 2006 -0700\");\n \t\tbreak;\ndiff --git a/cache.h b/cache.h\nindex 49713cc5a5..34c33e6a28 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1439,6 +1439,7 @@ extern struct object *peel_to_type(const char *name, int namelen,\n \n enum date_mode_type {\n \tDATE_NORMAL = 0,\n+\tDATE_HUMAN,\n \tDATE_RELATIVE,\n \tDATE_SHORT,\n \tDATE_ISO8601,\ndiff --git a/date.c b/date.c\nindex 9bc15df6f9..a8d50eb206 100644\n--- a/date.c\n+++ b/date.c\n@@ -77,22 +77,16 @@ static struct tm *time_to_tm_local(timestamp_t time)\n }\n \n /*\n- * What value of \"tz\" was in effect back then at \"time\" in the\n- * local timezone?\n+ * Fill in the localtime 'struct tm' for the supplied time,\n+ * and return the local tz.\n  */\n-static int local_tzoffset(timestamp_t time)\n+static int local_time_tzoffset(time_t t, struct tm *tm)\n {\n-\ttime_t t, t_local;\n-\tstruct tm tm;\n+\ttime_t t_local;\n \tint offset, eastwest;\n \n-\tif (date_overflows(time))\n-\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n-\n-\tt = (time_t)time;\n-\tlocaltime_r(&t, &tm);\n-\tt_local = tm_to_time_t(&tm);\n-\n+\tlocaltime_r(&t, tm);\n+\tt_local = tm_to_time_t(tm);\n \tif (t_local == -1)\n \t\treturn 0; /* error; just use +0000 */\n \tif (t_local < t) {\n@@ -107,6 +101,20 @@ static int local_tzoffset(timestamp_t time)\n \treturn offset * eastwest;\n }\n \n+/*\n+ * What value of \"tz\" was in effect back then at \"time\" in the\n+ * local timezone?\n+ */\n+static int local_tzoffset(timestamp_t time)\n+{\n+\tstruct tm tm;\n+\n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\n+\treturn local_time_tzoffset((time_t)time, &tm);\n+}\n+\n void show_date_relative(timestamp_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n@@ -191,9 +199,80 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \treturn &mode;\n }\n \n+static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm, int tz, struct tm *human_tm, int human_tz, int local)\n+{\n+\tstruct {\n+\t\tunsigned int\tyear:1,\n+\t\t\t\tdate:1,\n+\t\t\t\twday:1,\n+\t\t\t\ttime:1,\n+\t\t\t\tseconds:1,\n+\t\t\t\ttz:1;\n+\t} hide = { 0 };\n+\n+\thide.tz = local || tz == human_tz;\n+\thide.year = tm->tm_year == human_tm->tm_year;\n+\tif (hide.year) {\n+\t\tif (tm->tm_mon == human_tm->tm_mon) {\n+\t\t\tif (tm->tm_mday > human_tm->tm_mday) {\n+\t\t\t\t/* Future date: think timezones */\n+\t\t\t} else if (tm->tm_mday == human_tm->tm_mday) {\n+\t\t\t\thide.date = hide.wday = 1;\n+\t\t\t} else if (tm->tm_mday + 5 > human_tm->tm_mday) {\n+\t\t\t\t/* Leave just weekday if it was a few days ago */\n+\t\t\t\thide.date = 1;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/* Show \"today\" times as just relative times */\n+\tif (hide.wday) {\n+\t\tstruct timeval now;\n+\t\tgettimeofday(&now, NULL);\n+\t\tshow_date_relative(time, tz, &now, buf);\n+\t\treturn;\n+\t}\n+\n+\t/*\n+\t * Always hide seconds for human-readable.\n+\t * Hide timezone if showing date.\n+\t * Hide weekday and time if showing year.\n+\t *\n+\t * The logic here is two-fold:\n+\t *  (a) only show details when recent enough to matter\n+\t *  (b) keep the maximum length \"similar\", and in check\n+\t */\n+\tif (human_tm->tm_year) {\n+\t\thide.seconds = 1;\n+\t\thide.tz |= !hide.date;\n+\t\thide.wday = hide.time = !hide.year;\n+\t}\n+\n+\tif (!hide.wday)\n+\t\tstrbuf_addf(buf, \"%.3s \", weekday_names[tm->tm_wday]);\n+\tif (!hide.date)\n+\t\tstrbuf_addf(buf, \"%.3s %d \", month_names[tm->tm_mon], tm->tm_mday);\n+\n+\t/* Do we want AM/PM depending on locale? */\n+\tif (!hide.time) {\n+\t\tstrbuf_addf(buf, \"%02d:%02d\", tm->tm_hour, tm->tm_min);\n+\t\tif (!hide.seconds)\n+\t\t\tstrbuf_addf(buf, \":%02d\", tm->tm_sec);\n+\t} else\n+\t\tstrbuf_rtrim(buf);\n+\n+\tif (!hide.year)\n+\t\tstrbuf_addf(buf, \" %d\", tm->tm_year + 1900);\n+\n+\tif (!hide.tz)\n+\t\tstrbuf_addf(buf, \" %+05d\", tz);\n+}\n+\n const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n {\n \tstruct tm *tm;\n+\tstruct tm human_tm = { 0 };\n+\tint human_tz = -1;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n \n \tif (mode->type == DATE_UNIX) {\n@@ -202,6 +281,15 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \t\treturn timebuf.buf;\n \t}\n \n+\tif (mode->type == DATE_HUMAN) {\n+\t\tstruct timeval now;\n+\n+\t\tgettimeofday(&now, NULL);\n+\n+\t\t/* Fill in the data for \"current time\" in human_tz and human_tm */\n+\t\thuman_tz = local_time_tzoffset(now.tv_sec, &human_tm);\n+\t}\n+\n \tif (mode->local)\n \t\ttz = local_tzoffset(time);\n \n@@ -258,14 +346,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \t\tstrbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,\n \t\t\t\t!mode->local);\n \telse\n-\t\tstrbuf_addf(&timebuf, \"%.3s %.3s %d %02d:%02d:%02d %d%c%+05d\",\n-\t\t\t\tweekday_names[tm->tm_wday],\n-\t\t\t\tmonth_names[tm->tm_mon],\n-\t\t\t\ttm->tm_mday,\n-\t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n-\t\t\t\ttm->tm_year + 1900,\n-\t\t\t\tmode->local ? 0 : ' ',\n-\t\t\t\ttz);\n+\t\tshow_date_normal(&timebuf, time, tm, tz, &human_tm, human_tz, mode->local);\n \treturn timebuf.buf;\n }\n \n@@ -802,6 +883,11 @@ int parse_date(const char *date, struct strbuf *result)\n \treturn 0;\n }\n \n+static int auto_date_style(void)\n+{\n+\treturn (isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;\n+}\n+\n static enum date_mode_type parse_date_type(const char *format, const char **end)\n {\n \tif (skip_prefix(format, \"relative\", end))\n@@ -819,6 +905,10 @@ static enum date_mode_type parse_date_type(const char *format, const char **end)\n \t\treturn DATE_SHORT;\n \tif (skip_prefix(format, \"default\", end))\n \t\treturn DATE_NORMAL;\n+\tif (skip_prefix(format, \"human\", end))\n+\t\treturn DATE_HUMAN;\n+\tif (skip_prefix(format, \"auto\", end))\n+\t\treturn auto_date_style();\n \tif (skip_prefix(format, \"raw\", end))\n \t\treturn DATE_RAW;\n \tif (skip_prefix(format, \"unix\", end))\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367203","messageId":"20190121051646.20991-6-ischis2@cox.net","threadId":"50135","inReplyTo":"20190121051646.20991-1-ischis2@cox.net","subject":"[PATCH v3 5/5] Add `human` date format tests.","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-21T05:16:46Z","receivedAt":"2019-01-21T07:13:12Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"When using `human` several fields are suppressed depending on the time\ndifference between the reference date and the local computer date. In\ncases where the difference is less than a year, the year field is\nsupppressed. If the time is less than a day; the month and year is\nsuppressed.\n\nUse TEST_DATE_NOW environment variable when using the test-tool to\nhold the expected output strings constant.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n t/t0006-date.sh | 18 ++++++++++++++++++\n 1 file changed, 18 insertions(+)\n\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex ffb2975e48..35f7b52dd7 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -128,4 +128,22 @@ check_approxidate '6AM, June 7, 2009' '2009-06-07 06:00:00'\n check_approxidate '2008-12-01' '2008-12-01 19:20:00'\n check_approxidate '2009-12-01' '2009-12-01 19:20:00'\n \n+check_date_format_human() {\n+\tt=$(($TEST_DATE_NOW - $1))\n+\techo \"$t -> $2\" >expect\n+\ttest_expect_success \"human date $t\" '\n+\ttest-tool date human $t >actual &&\n+\ttest_cmp expect actual\n+'\n+}\n+\n+check_date_format_human 18000 \"5 hours ago\" # 5 hours ago\n+check_date_format_human 432000 \"Tue Aug 25 19:20\" # 5 days ago\n+check_date_format_human 1728000 \"Mon Aug 10 19:20\" # 3 weeks ago\n+check_date_format_human 13000000 \"Thu Apr 2 08:13\" # 5 months ago\n+check_date_format_human 31449600 \"Aug 31 2008\" # 12 months ago\n+check_date_format_human 37500000 \"Jun 22 2008\" # 1 year, 2 months ago\n+check_date_format_human 55188000 \"Dec 1 2007\" # 1 year, 9 months ago\n+check_date_format_human 630000000 \"Sep 13 1989\" # 20 years ago\n+\n test_done\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367204","messageId":"20190121053112.4736-2-ischis2@cox.net","threadId":"50135","inReplyTo":"20190121053112.4736-1-ischis2@cox.net","subject":"[PATCH v3 1/5] Add 'human' date format","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-21T05:31:08Z","receivedAt":"2019-01-21T07:13:13Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"From: Linus Torvalds <torvalds@linux-foundation.org>\n\nThis adds --date=human, which skips the timezone if it matches the\ncurrent time-zone, and doesn't print the whole date if that matches (ie\nskip printing year for dates that are \"this year\", but also skip the\nwhole date itself if it's in the last few days and we can just say what\nweekday it was).\n\nFor really recent dates (same day), use the relative date stamp, while\nfor old dates (year doesn't match), don't bother with time and timezone.\n\nAlso add 'auto' date mode, which defaults to human if we're using the\npager.  So you can do\n\n\tgit config --add log.date auto\n\nand your \"git log\" commands will show the human-legible format unless\nyou're scripting things.\n\nNote that this time format still shows the timezone for recent enough\nevents (but not so recent that they show up as relative dates).  You can\ncombine it with the \"-local\" suffix to never show timezones for an even\nmore simplified view.\n\nSigned-off-by: Linus Torvalds <torvalds@linux-foundation.org>\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n builtin/blame.c |   4 ++\n cache.h         |   1 +\n date.c          | 130 ++++++++++++++++++++++++++++++++++++++++--------\n 3 files changed, 115 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 6d798f9939..f684e31d82 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -925,6 +925,10 @@ int cmd_blame(int argc, const char **argv, const char *prefix)\n \t\t */\n \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n \t\tbreak;\n+\tcase DATE_HUMAN:\n+\t\t/* If the year is shown, no time is shown */\n+\t\tblame_date_width = sizeof(\"Thu Oct 19 16:00\");\n+\t\tbreak;\n \tcase DATE_NORMAL:\n \t\tblame_date_width = sizeof(\"Thu Oct 19 16:00:04 2006 -0700\");\n \t\tbreak;\ndiff --git a/cache.h b/cache.h\nindex 49713cc5a5..34c33e6a28 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1439,6 +1439,7 @@ extern struct object *peel_to_type(const char *name, int namelen,\n \n enum date_mode_type {\n \tDATE_NORMAL = 0,\n+\tDATE_HUMAN,\n \tDATE_RELATIVE,\n \tDATE_SHORT,\n \tDATE_ISO8601,\ndiff --git a/date.c b/date.c\nindex 9bc15df6f9..a8d50eb206 100644\n--- a/date.c\n+++ b/date.c\n@@ -77,22 +77,16 @@ static struct tm *time_to_tm_local(timestamp_t time)\n }\n \n /*\n- * What value of \"tz\" was in effect back then at \"time\" in the\n- * local timezone?\n+ * Fill in the localtime 'struct tm' for the supplied time,\n+ * and return the local tz.\n  */\n-static int local_tzoffset(timestamp_t time)\n+static int local_time_tzoffset(time_t t, struct tm *tm)\n {\n-\ttime_t t, t_local;\n-\tstruct tm tm;\n+\ttime_t t_local;\n \tint offset, eastwest;\n \n-\tif (date_overflows(time))\n-\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n-\n-\tt = (time_t)time;\n-\tlocaltime_r(&t, &tm);\n-\tt_local = tm_to_time_t(&tm);\n-\n+\tlocaltime_r(&t, tm);\n+\tt_local = tm_to_time_t(tm);\n \tif (t_local == -1)\n \t\treturn 0; /* error; just use +0000 */\n \tif (t_local < t) {\n@@ -107,6 +101,20 @@ static int local_tzoffset(timestamp_t time)\n \treturn offset * eastwest;\n }\n \n+/*\n+ * What value of \"tz\" was in effect back then at \"time\" in the\n+ * local timezone?\n+ */\n+static int local_tzoffset(timestamp_t time)\n+{\n+\tstruct tm tm;\n+\n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\n+\treturn local_time_tzoffset((time_t)time, &tm);\n+}\n+\n void show_date_relative(timestamp_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n@@ -191,9 +199,80 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \treturn &mode;\n }\n \n+static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm, int tz, struct tm *human_tm, int human_tz, int local)\n+{\n+\tstruct {\n+\t\tunsigned int\tyear:1,\n+\t\t\t\tdate:1,\n+\t\t\t\twday:1,\n+\t\t\t\ttime:1,\n+\t\t\t\tseconds:1,\n+\t\t\t\ttz:1;\n+\t} hide = { 0 };\n+\n+\thide.tz = local || tz == human_tz;\n+\thide.year = tm->tm_year == human_tm->tm_year;\n+\tif (hide.year) {\n+\t\tif (tm->tm_mon == human_tm->tm_mon) {\n+\t\t\tif (tm->tm_mday > human_tm->tm_mday) {\n+\t\t\t\t/* Future date: think timezones */\n+\t\t\t} else if (tm->tm_mday == human_tm->tm_mday) {\n+\t\t\t\thide.date = hide.wday = 1;\n+\t\t\t} else if (tm->tm_mday + 5 > human_tm->tm_mday) {\n+\t\t\t\t/* Leave just weekday if it was a few days ago */\n+\t\t\t\thide.date = 1;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/* Show \"today\" times as just relative times */\n+\tif (hide.wday) {\n+\t\tstruct timeval now;\n+\t\tgettimeofday(&now, NULL);\n+\t\tshow_date_relative(time, tz, &now, buf);\n+\t\treturn;\n+\t}\n+\n+\t/*\n+\t * Always hide seconds for human-readable.\n+\t * Hide timezone if showing date.\n+\t * Hide weekday and time if showing year.\n+\t *\n+\t * The logic here is two-fold:\n+\t *  (a) only show details when recent enough to matter\n+\t *  (b) keep the maximum length \"similar\", and in check\n+\t */\n+\tif (human_tm->tm_year) {\n+\t\thide.seconds = 1;\n+\t\thide.tz |= !hide.date;\n+\t\thide.wday = hide.time = !hide.year;\n+\t}\n+\n+\tif (!hide.wday)\n+\t\tstrbuf_addf(buf, \"%.3s \", weekday_names[tm->tm_wday]);\n+\tif (!hide.date)\n+\t\tstrbuf_addf(buf, \"%.3s %d \", month_names[tm->tm_mon], tm->tm_mday);\n+\n+\t/* Do we want AM/PM depending on locale? */\n+\tif (!hide.time) {\n+\t\tstrbuf_addf(buf, \"%02d:%02d\", tm->tm_hour, tm->tm_min);\n+\t\tif (!hide.seconds)\n+\t\t\tstrbuf_addf(buf, \":%02d\", tm->tm_sec);\n+\t} else\n+\t\tstrbuf_rtrim(buf);\n+\n+\tif (!hide.year)\n+\t\tstrbuf_addf(buf, \" %d\", tm->tm_year + 1900);\n+\n+\tif (!hide.tz)\n+\t\tstrbuf_addf(buf, \" %+05d\", tz);\n+}\n+\n const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n {\n \tstruct tm *tm;\n+\tstruct tm human_tm = { 0 };\n+\tint human_tz = -1;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n \n \tif (mode->type == DATE_UNIX) {\n@@ -202,6 +281,15 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \t\treturn timebuf.buf;\n \t}\n \n+\tif (mode->type == DATE_HUMAN) {\n+\t\tstruct timeval now;\n+\n+\t\tgettimeofday(&now, NULL);\n+\n+\t\t/* Fill in the data for \"current time\" in human_tz and human_tm */\n+\t\thuman_tz = local_time_tzoffset(now.tv_sec, &human_tm);\n+\t}\n+\n \tif (mode->local)\n \t\ttz = local_tzoffset(time);\n \n@@ -258,14 +346,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \t\tstrbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,\n \t\t\t\t!mode->local);\n \telse\n-\t\tstrbuf_addf(&timebuf, \"%.3s %.3s %d %02d:%02d:%02d %d%c%+05d\",\n-\t\t\t\tweekday_names[tm->tm_wday],\n-\t\t\t\tmonth_names[tm->tm_mon],\n-\t\t\t\ttm->tm_mday,\n-\t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n-\t\t\t\ttm->tm_year + 1900,\n-\t\t\t\tmode->local ? 0 : ' ',\n-\t\t\t\ttz);\n+\t\tshow_date_normal(&timebuf, time, tm, tz, &human_tm, human_tz, mode->local);\n \treturn timebuf.buf;\n }\n \n@@ -802,6 +883,11 @@ int parse_date(const char *date, struct strbuf *result)\n \treturn 0;\n }\n \n+static int auto_date_style(void)\n+{\n+\treturn (isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;\n+}\n+\n static enum date_mode_type parse_date_type(const char *format, const char **end)\n {\n \tif (skip_prefix(format, \"relative\", end))\n@@ -819,6 +905,10 @@ static enum date_mode_type parse_date_type(const char *format, const char **end)\n \t\treturn DATE_SHORT;\n \tif (skip_prefix(format, \"default\", end))\n \t\treturn DATE_NORMAL;\n+\tif (skip_prefix(format, \"human\", end))\n+\t\treturn DATE_HUMAN;\n+\tif (skip_prefix(format, \"auto\", end))\n+\t\treturn auto_date_style();\n \tif (skip_prefix(format, \"raw\", end))\n \t\treturn DATE_RAW;\n \tif (skip_prefix(format, \"unix\", end))\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367205","messageId":"3086071.UFgDplIbgl@thunderbird","threadId":"50135","inReplyTo":"xmqqtvi5kctv.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 4/5] Add `human` format to test-tool","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-20T22:11:24Z","receivedAt":"2019-01-21T07:13:15Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"On Friday, January 18, 2019 12:03:40 PM MST Junio C Hamano wrote:\n> It is a shame that you introduced a nicely reusable get_time()\n> mechanism to let external callers of show_date() specify what time\n> to format, instead of the returned timestamp of gettimeofday(),\n> but limited its usefulness to only testing \"human\" format output.\n> If somebody wants to extend \"test-tool date\" for other formats, they\n> also have to add a similar \"show_date_XXX\" hack for their format.\n> \n> How about doing it slightly differently?  E.g.\n> \n>  - Get rid of show_date_human().\n> \n>  - Keep get_time(), but have it pay attention to GIT_TEST_TIMESTAMP\n>    environment variable, and when it is set, use that as if it is\n>    the returned value from gettimeofday().\n> \n>  - If there are gettimeofday() calls in date.c this patch did not\n>    touch (because they were not part of the \"human-format\"\n>    codepath), adjust them to use get_time() instead.\n> \n>  - Have \"test-tool date\" excersize show_date() directly.\n> \nI did follow the pattern set for relative (which is why I created \nshow_date_human() to mimic show_date_relative() ) as had been suggested.   I \nlike this pattern better.\n\nWhy don't I create a second patch set after I git this one to next for \nrelative to match your suggestion.  I don't like the idea of conflating two \ntopics.\n\nsps\n\n\n"},{"id":"367206","messageId":"20190121053112.4736-3-ischis2@cox.net","threadId":"50135","inReplyTo":"20190121053112.4736-1-ischis2@cox.net","subject":"[PATCH v3 2/5] Replace the proposed 'auto' mode with 'auto:'","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-21T05:31:09Z","receivedAt":"2019-01-21T07:13:15Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"In addition to adding the 'human' format, the patch added the auto\nkeyword which could be used in the config file as an alternate way to\nspecify the human format.  Removing 'auto' cleans up the 'human'\nformat interface.\n\nAdded the ability to specify mode 'foo' if the pager is being used by\nusing auto:foo syntax.  Therefore, 'auto:human' date mode defaults to\nhuman if we're using the pager.  So you can do\n\n\tgit config --add log.date auto:human\n\nand your \"git log\" commands will show the human-legible format unless\nyou're scripting things.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n date.c | 15 ++++++++-------\n 1 file changed, 8 insertions(+), 7 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex a8d50eb206..43c3a84e25 100644\n--- a/date.c\n+++ b/date.c\n@@ -883,11 +883,6 @@ int parse_date(const char *date, struct strbuf *result)\n \treturn 0;\n }\n \n-static int auto_date_style(void)\n-{\n-\treturn (isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;\n-}\n-\n static enum date_mode_type parse_date_type(const char *format, const char **end)\n {\n \tif (skip_prefix(format, \"relative\", end))\n@@ -907,8 +902,6 @@ static enum date_mode_type parse_date_type(const char *format, const char **end)\n \t\treturn DATE_NORMAL;\n \tif (skip_prefix(format, \"human\", end))\n \t\treturn DATE_HUMAN;\n-\tif (skip_prefix(format, \"auto\", end))\n-\t\treturn auto_date_style();\n \tif (skip_prefix(format, \"raw\", end))\n \t\treturn DATE_RAW;\n \tif (skip_prefix(format, \"unix\", end))\n@@ -923,6 +916,14 @@ void parse_date_format(const char *format, struct date_mode *mode)\n {\n \tconst char *p;\n \n+\t/* \"auto:foo\" is \"if tty/pager, then foo, otherwise normal\" */\n+\tif (skip_prefix(format, \"auto:\", &p)) {\n+\t\tif (isatty(1) || pager_in_use())\n+\t\t\tformat = p;\n+\t\telse\n+\t\t\tformat = \"default\";\n+\t}\n+\n \t/* historical alias */\n \tif (!strcmp(format, \"local\"))\n \t\tformat = \"default-local\";\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367207","messageId":"20190121053112.4736-6-ischis2@cox.net","threadId":"50135","inReplyTo":"20190121053112.4736-1-ischis2@cox.net","subject":"[PATCH v3 5/5] Add `human` date format tests.","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-21T05:31:12Z","receivedAt":"2019-01-21T07:13:17Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"When using `human` several fields are suppressed depending on the time\ndifference between the reference date and the local computer date. In\ncases where the difference is less than a year, the year field is\nsupppressed. If the time is less than a day; the month and year is\nsuppressed.\n\nUse TEST_DATE_NOW environment variable when using the test-tool to\nhold the expected output strings constant.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n t/t0006-date.sh | 18 ++++++++++++++++++\n 1 file changed, 18 insertions(+)\n\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex ffb2975e48..35f7b52dd7 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -128,4 +128,22 @@ check_approxidate '6AM, June 7, 2009' '2009-06-07 06:00:00'\n check_approxidate '2008-12-01' '2008-12-01 19:20:00'\n check_approxidate '2009-12-01' '2009-12-01 19:20:00'\n \n+check_date_format_human() {\n+\tt=$(($TEST_DATE_NOW - $1))\n+\techo \"$t -> $2\" >expect\n+\ttest_expect_success \"human date $t\" '\n+\ttest-tool date human $t >actual &&\n+\ttest_cmp expect actual\n+'\n+}\n+\n+check_date_format_human 18000 \"5 hours ago\" # 5 hours ago\n+check_date_format_human 432000 \"Tue Aug 25 19:20\" # 5 days ago\n+check_date_format_human 1728000 \"Mon Aug 10 19:20\" # 3 weeks ago\n+check_date_format_human 13000000 \"Thu Apr 2 08:13\" # 5 months ago\n+check_date_format_human 31449600 \"Aug 31 2008\" # 12 months ago\n+check_date_format_human 37500000 \"Jun 22 2008\" # 1 year, 2 months ago\n+check_date_format_human 55188000 \"Dec 1 2007\" # 1 year, 9 months ago\n+check_date_format_human 630000000 \"Sep 13 1989\" # 20 years ago\n+\n test_done\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367208","messageId":"20190121051646.20991-5-ischis2@cox.net","threadId":"50135","inReplyTo":"20190121051646.20991-1-ischis2@cox.net","subject":"[PATCH v3 4/5] Add `human` format to test-tool","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-21T05:16:45Z","receivedAt":"2019-01-21T07:13:19Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Add the human format support to the test tool so that TEST_DATE_NOW\ncan be used to specify the current time.\n\nThe get_time() helper function was created and and checks the\nTEST_DATE_NOW environment variable.  If TEST_DATE_NOW is set, then\nthat date is used instead of the date returned by by gettimeofday().\n\nAll calls to gettimeofday() were replaced by calls to get_time().\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n cache.h              |  2 ++\n date.c               | 21 +++++++++++++++++----\n t/helper/test-date.c | 11 +++++++++++\n 3 files changed, 30 insertions(+), 4 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 34c33e6a28..fe00ddf910 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1467,6 +1467,8 @@ struct date_mode *date_mode_from_type(enum date_mode_type type);\n const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);\n void show_date_relative(timestamp_t time, int tz, const struct timeval *now,\n \t\t\tstruct strbuf *timebuf);\n+void show_date_human(timestamp_t time, int tz, const struct timeval *now,\n+\t\t\tstruct strbuf *timebuf);\n int parse_date(const char *date, struct strbuf *out);\n int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);\n int parse_expiry_date(const char *date, timestamp_t *timestamp);\ndiff --git a/date.c b/date.c\nindex 43c3a84e25..5f9ea7d5d7 100644\n--- a/date.c\n+++ b/date.c\n@@ -115,6 +115,19 @@ static int local_tzoffset(timestamp_t time)\n \treturn local_time_tzoffset((time_t)time, &tm);\n }\n \n+static void get_time(struct timeval *now)\n+{\n+\tconst char *x;\n+\n+\tx = getenv(\"TEST_DATE_NOW\");\n+\tif (x) {\n+\t\tnow->tv_sec = atoi(x);\n+\t\tnow->tv_usec = 0;\n+\t}\n+\telse\n+\t\tgettimeofday(now, NULL);\n+}\n+\n void show_date_relative(timestamp_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n@@ -228,7 +241,7 @@ static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm\n \t/* Show \"today\" times as just relative times */\n \tif (hide.wday) {\n \t\tstruct timeval now;\n-\t\tgettimeofday(&now, NULL);\n+\t\tget_time(&now);\n \t\tshow_date_relative(time, tz, &now, buf);\n \t\treturn;\n \t}\n@@ -284,7 +297,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \tif (mode->type == DATE_HUMAN) {\n \t\tstruct timeval now;\n \n-\t\tgettimeofday(&now, NULL);\n+\t\tget_time(&now);\n \n \t\t/* Fill in the data for \"current time\" in human_tz and human_tm */\n \t\thuman_tz = local_time_tzoffset(now.tv_sec, &human_tm);\n@@ -303,7 +316,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \t\tstruct timeval now;\n \n \t\tstrbuf_reset(&timebuf);\n-\t\tgettimeofday(&now, NULL);\n+\t\tget_time(&now);\n \t\tshow_date_relative(time, tz, &now, &timebuf);\n \t\treturn timebuf.buf;\n \t}\n@@ -1296,7 +1309,7 @@ timestamp_t approxidate_careful(const char *date, int *error_ret)\n \t\treturn timestamp;\n \t}\n \n-\tgettimeofday(&tv, NULL);\n+\tget_time(&tv);\n \treturn approxidate_str(date, &tv, error_ret);\n }\n \ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex a0837371ab..811b116c7e 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -3,6 +3,7 @@\n \n static const char *usage_msg = \"\\n\"\n \"  test-tool date relative [time_t]...\\n\"\n+\"  test-tool date human [time_t]...\\n\"\n \"  test-tool date show:<format> [time_t]...\\n\"\n \"  test-tool date parse [date]...\\n\"\n \"  test-tool date approxidate [date]...\\n\"\n@@ -22,6 +23,14 @@ static void show_relative_dates(const char **argv, struct timeval *now)\n \tstrbuf_release(&buf);\n }\n \n+static void show_human_dates(const char **argv)\n+{\n+\tfor (; *argv; argv++) {\n+\t\ttime_t t = atoi(*argv);\n+\t\tprintf(\"%s -> %s\\n\", *argv, show_date(t, 0, DATE_MODE(HUMAN)));\n+\t}\n+}\n+\n static void show_dates(const char **argv, const char *format)\n {\n \tstruct date_mode mode;\n@@ -100,6 +109,8 @@ int cmd__date(int argc, const char **argv)\n \t\tusage(usage_msg);\n \tif (!strcmp(*argv, \"relative\"))\n \t\tshow_relative_dates(argv+1, &now);\n+\telse if (!strcmp(*argv, \"human\"))\n+\t\tshow_human_dates(argv+1);\n \telse if (skip_prefix(*argv, \"show:\", &x))\n \t\tshow_dates(argv+1, x);\n \telse if (!strcmp(*argv, \"parse\"))\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367209","messageId":"20190121051646.20991-1-ischis2@cox.net","threadId":"50135","inReplyTo":"20181231003150.8031-1-ischis2@cox.net","subject":"[PATCH v3 0/5] Re-roll of 'human' date format patch set","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-21T05:16:41Z","receivedAt":"2019-01-21T07:13:20Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Reworked documentation and tests for the previously submitted patch set. \n\nLinus Torvalds (1):\n  Add 'human' date format\n\nStephen P. Smith (4):\n  Replace the proposed 'auto' mode with 'auto:'\n  Add 'human' date format documentation\n  Add `human` format to test-tool\n  Add `human` date format tests.\n\n Documentation/git-log.txt          |   4 +\n Documentation/rev-list-options.txt |   7 ++\n builtin/blame.c                    |   4 +\n cache.h                            |   3 +\n date.c                             | 148 ++++++++++++++++++++++++-----\n t/helper/test-date.c               |  11 +++\n t/t0006-date.sh                    |  18 ++++\n 7 files changed, 173 insertions(+), 22 deletions(-)\n\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367210","messageId":"20190121051646.20991-4-ischis2@cox.net","threadId":"50135","inReplyTo":"20190121051646.20991-1-ischis2@cox.net","subject":"[PATCH v3 3/5] Add 'human' date format documentation","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-21T05:16:44Z","receivedAt":"2019-01-21T07:13:22Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Display date and time information in a format similar to how people\nwrite dates in other contexts. If the year isn't specified then, the\nreader infers the date is given is in the current year.\n\nBy not displaying the redundant information, the reader concentrates\non the information that is different. The patch reports relative dates\nbased on information inferred from the date on the machine running the\ngit command at the time the command is executed.\n\nWhile the format is more useful to humans by dropping inferred\ninformation, there is nothing that makes it actually human. If the\n'relative' date format wasn't already implemented then using\n'relative' would have been appropriate.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n Documentation/git-log.txt          | 4 ++++\n Documentation/rev-list-options.txt | 7 +++++++\n 2 files changed, 11 insertions(+)\n\ndiff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\nindex 90761f1694..b02e922dc3 100644\n--- a/Documentation/git-log.txt\n+++ b/Documentation/git-log.txt\n@@ -192,6 +192,10 @@ log.date::\n \tDefault format for human-readable dates.  (Compare the\n \t`--date` option.)  Defaults to \"default\", which means to write\n \tdates like `Sat May 8 19:35:34 2010 -0500`.\n++\n+If the format is set to \"auto:foo\" and the pager is in use, format\n+\"foo\" will be the used for the date format. Otherwise \"default\" will\n+be used.\n \n log.follow::\n \tIf `true`, `git log` will act as if the `--follow` option was used when\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 98b538bc77..867a063a1c 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -831,6 +831,13 @@ Note that the `-local` option does not affect the seconds-since-epoch\n value (which is always measured in UTC), but does switch the accompanying\n timezone value.\n +\n+`--date=human` shows the timezone if the timezone does not match the\n+current time-zone, and doesn't print the whole date if that matches\n+(ie skip printing year for dates that are \"this year\", but also skip\n+the whole date itself if it's in the last few days and we can just say\n+what weekday it was).  For older dates the hour and minute is also\n+omitted.\n++\n `--date=unix` shows the date as a Unix epoch timestamp (seconds since\n 1970).  As with `--raw`, this is always in UTC and therefore `-local`\n has no effect.\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367211","messageId":"20190121051646.20991-3-ischis2@cox.net","threadId":"50135","inReplyTo":"20190121051646.20991-1-ischis2@cox.net","subject":"[PATCH v3 2/5] Replace the proposed 'auto' mode with 'auto:'","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-21T05:16:43Z","receivedAt":"2019-01-21T07:13:24Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"In addition to adding the 'human' format, the patch added the auto\nkeyword which could be used in the config file as an alternate way to\nspecify the human format.  Removing 'auto' cleans up the 'human'\nformat interface.\n\nAdded the ability to specify mode 'foo' if the pager is being used by\nusing auto:foo syntax.  Therefore, 'auto:human' date mode defaults to\nhuman if we're using the pager.  So you can do\n\n\tgit config --add log.date auto:human\n\nand your \"git log\" commands will show the human-legible format unless\nyou're scripting things.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n date.c | 15 ++++++++-------\n 1 file changed, 8 insertions(+), 7 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex a8d50eb206..43c3a84e25 100644\n--- a/date.c\n+++ b/date.c\n@@ -883,11 +883,6 @@ int parse_date(const char *date, struct strbuf *result)\n \treturn 0;\n }\n \n-static int auto_date_style(void)\n-{\n-\treturn (isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;\n-}\n-\n static enum date_mode_type parse_date_type(const char *format, const char **end)\n {\n \tif (skip_prefix(format, \"relative\", end))\n@@ -907,8 +902,6 @@ static enum date_mode_type parse_date_type(const char *format, const char **end)\n \t\treturn DATE_NORMAL;\n \tif (skip_prefix(format, \"human\", end))\n \t\treturn DATE_HUMAN;\n-\tif (skip_prefix(format, \"auto\", end))\n-\t\treturn auto_date_style();\n \tif (skip_prefix(format, \"raw\", end))\n \t\treturn DATE_RAW;\n \tif (skip_prefix(format, \"unix\", end))\n@@ -923,6 +916,14 @@ void parse_date_format(const char *format, struct date_mode *mode)\n {\n \tconst char *p;\n \n+\t/* \"auto:foo\" is \"if tty/pager, then foo, otherwise normal\" */\n+\tif (skip_prefix(format, \"auto:\", &p)) {\n+\t\tif (isatty(1) || pager_in_use())\n+\t\t\tformat = p;\n+\t\telse\n+\t\t\tformat = \"default\";\n+\t}\n+\n \t/* historical alias */\n \tif (!strcmp(format, \"local\"))\n \t\tformat = \"default-local\";\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367212","messageId":"20190121053112.4736-4-ischis2@cox.net","threadId":"50135","inReplyTo":"20190121053112.4736-1-ischis2@cox.net","subject":"[PATCH v3 3/5] Add 'human' date format documentation","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-21T05:31:10Z","receivedAt":"2019-01-21T07:13:36Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Display date and time information in a format similar to how people\nwrite dates in other contexts. If the year isn't specified then, the\nreader infers the date is given is in the current year.\n\nBy not displaying the redundant information, the reader concentrates\non the information that is different. The patch reports relative dates\nbased on information inferred from the date on the machine running the\ngit command at the time the command is executed.\n\nWhile the format is more useful to humans by dropping inferred\ninformation, there is nothing that makes it actually human. If the\n'relative' date format wasn't already implemented then using\n'relative' would have been appropriate.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n Documentation/git-log.txt          | 4 ++++\n Documentation/rev-list-options.txt | 7 +++++++\n 2 files changed, 11 insertions(+)\n\ndiff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\nindex 90761f1694..b02e922dc3 100644\n--- a/Documentation/git-log.txt\n+++ b/Documentation/git-log.txt\n@@ -192,6 +192,10 @@ log.date::\n \tDefault format for human-readable dates.  (Compare the\n \t`--date` option.)  Defaults to \"default\", which means to write\n \tdates like `Sat May 8 19:35:34 2010 -0500`.\n++\n+If the format is set to \"auto:foo\" and the pager is in use, format\n+\"foo\" will be the used for the date format. Otherwise \"default\" will\n+be used.\n \n log.follow::\n \tIf `true`, `git log` will act as if the `--follow` option was used when\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 98b538bc77..867a063a1c 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -831,6 +831,13 @@ Note that the `-local` option does not affect the seconds-since-epoch\n value (which is always measured in UTC), but does switch the accompanying\n timezone value.\n +\n+`--date=human` shows the timezone if the timezone does not match the\n+current time-zone, and doesn't print the whole date if that matches\n+(ie skip printing year for dates that are \"this year\", but also skip\n+the whole date itself if it's in the last few days and we can just say\n+what weekday it was).  For older dates the hour and minute is also\n+omitted.\n++\n `--date=unix` shows the date as a Unix epoch timestamp (seconds since\n 1970).  As with `--raw`, this is always in UTC and therefore `-local`\n has no effect.\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367213","messageId":"20190121053112.4736-5-ischis2@cox.net","threadId":"50135","inReplyTo":"20190121053112.4736-1-ischis2@cox.net","subject":"[PATCH v3 4/5] Add `human` format to test-tool","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-21T05:31:11Z","receivedAt":"2019-01-21T07:13:51Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Add the human format support to the test tool so that TEST_DATE_NOW\ncan be used to specify the current time.\n\nThe get_time() helper function was created and and checks the\nTEST_DATE_NOW environment variable.  If TEST_DATE_NOW is set, then\nthat date is used instead of the date returned by by gettimeofday().\n\nAll calls to gettimeofday() were replaced by calls to get_time().\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n cache.h              |  2 ++\n date.c               | 21 +++++++++++++++++----\n t/helper/test-date.c | 11 +++++++++++\n 3 files changed, 30 insertions(+), 4 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 34c33e6a28..fe00ddf910 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1467,6 +1467,8 @@ struct date_mode *date_mode_from_type(enum date_mode_type type);\n const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);\n void show_date_relative(timestamp_t time, int tz, const struct timeval *now,\n \t\t\tstruct strbuf *timebuf);\n+void show_date_human(timestamp_t time, int tz, const struct timeval *now,\n+\t\t\tstruct strbuf *timebuf);\n int parse_date(const char *date, struct strbuf *out);\n int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);\n int parse_expiry_date(const char *date, timestamp_t *timestamp);\ndiff --git a/date.c b/date.c\nindex 43c3a84e25..5f9ea7d5d7 100644\n--- a/date.c\n+++ b/date.c\n@@ -115,6 +115,19 @@ static int local_tzoffset(timestamp_t time)\n \treturn local_time_tzoffset((time_t)time, &tm);\n }\n \n+static void get_time(struct timeval *now)\n+{\n+\tconst char *x;\n+\n+\tx = getenv(\"TEST_DATE_NOW\");\n+\tif (x) {\n+\t\tnow->tv_sec = atoi(x);\n+\t\tnow->tv_usec = 0;\n+\t}\n+\telse\n+\t\tgettimeofday(now, NULL);\n+}\n+\n void show_date_relative(timestamp_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n@@ -228,7 +241,7 @@ static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm\n \t/* Show \"today\" times as just relative times */\n \tif (hide.wday) {\n \t\tstruct timeval now;\n-\t\tgettimeofday(&now, NULL);\n+\t\tget_time(&now);\n \t\tshow_date_relative(time, tz, &now, buf);\n \t\treturn;\n \t}\n@@ -284,7 +297,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \tif (mode->type == DATE_HUMAN) {\n \t\tstruct timeval now;\n \n-\t\tgettimeofday(&now, NULL);\n+\t\tget_time(&now);\n \n \t\t/* Fill in the data for \"current time\" in human_tz and human_tm */\n \t\thuman_tz = local_time_tzoffset(now.tv_sec, &human_tm);\n@@ -303,7 +316,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \t\tstruct timeval now;\n \n \t\tstrbuf_reset(&timebuf);\n-\t\tgettimeofday(&now, NULL);\n+\t\tget_time(&now);\n \t\tshow_date_relative(time, tz, &now, &timebuf);\n \t\treturn timebuf.buf;\n \t}\n@@ -1296,7 +1309,7 @@ timestamp_t approxidate_careful(const char *date, int *error_ret)\n \t\treturn timestamp;\n \t}\n \n-\tgettimeofday(&tv, NULL);\n+\tget_time(&tv);\n \treturn approxidate_str(date, &tv, error_ret);\n }\n \ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex a0837371ab..811b116c7e 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -3,6 +3,7 @@\n \n static const char *usage_msg = \"\\n\"\n \"  test-tool date relative [time_t]...\\n\"\n+\"  test-tool date human [time_t]...\\n\"\n \"  test-tool date show:<format> [time_t]...\\n\"\n \"  test-tool date parse [date]...\\n\"\n \"  test-tool date approxidate [date]...\\n\"\n@@ -22,6 +23,14 @@ static void show_relative_dates(const char **argv, struct timeval *now)\n \tstrbuf_release(&buf);\n }\n \n+static void show_human_dates(const char **argv)\n+{\n+\tfor (; *argv; argv++) {\n+\t\ttime_t t = atoi(*argv);\n+\t\tprintf(\"%s -> %s\\n\", *argv, show_date(t, 0, DATE_MODE(HUMAN)));\n+\t}\n+}\n+\n static void show_dates(const char **argv, const char *format)\n {\n \tstruct date_mode mode;\n@@ -100,6 +109,8 @@ int cmd__date(int argc, const char **argv)\n \t\tusage(usage_msg);\n \tif (!strcmp(*argv, \"relative\"))\n \t\tshow_relative_dates(argv+1, &now);\n+\telse if (!strcmp(*argv, \"human\"))\n+\t\tshow_human_dates(argv+1);\n \telse if (skip_prefix(*argv, \"show:\", &x))\n \t\tshow_dates(argv+1, x);\n \telse if (!strcmp(*argv, \"parse\"))\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367214","messageId":"20190121053112.4736-1-ischis2@cox.net","threadId":"50135","inReplyTo":"20190118061805.19086-1-ischis2@cox.net","subject":"[PATCH v3 0/5] Re-roll of 'human' date format patch set","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-21T05:31:07Z","receivedAt":"2019-01-21T07:13:52Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Reworked documentation and tests for the previously submitted patch set. \n\nLinus Torvalds (1):\n  Add 'human' date format\n\nStephen P. Smith (4):\n  Replace the proposed 'auto' mode with 'auto:'\n  Add 'human' date format documentation\n  Add `human` format to test-tool\n  Add `human` date format tests.\n\n Documentation/git-log.txt          |   4 +\n Documentation/rev-list-options.txt |   7 ++\n builtin/blame.c                    |   4 +\n cache.h                            |   3 +\n date.c                             | 148 ++++++++++++++++++++++++-----\n t/helper/test-date.c               |  11 +++\n t/t0006-date.sh                    |  18 ++++\n 7 files changed, 173 insertions(+), 22 deletions(-)\n\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367237","messageId":"20190121150429.GR840@szeder.dev","threadId":"50135","inReplyTo":"20190121051646.20991-6-ischis2@cox.net","subject":"Re: [PATCH v3 5/5] Add `human` date format tests.","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-01-21T15:04:29Z","receivedAt":"2019-01-21T15:04:36Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Sun, Jan 20, 2019 at 10:16:46PM -0700, Stephen P. Smith wrote:\n> When using `human` several fields are suppressed depending on the time\n> difference between the reference date and the local computer date. In\n> cases where the difference is less than a year, the year field is\n> supppressed. If the time is less than a day; the month and year is\n> suppressed.\n> \n> Use TEST_DATE_NOW environment variable when using the test-tool to\n> hold the expected output strings constant.\n> \n> Signed-off-by: Stephen P. Smith <ischis2@cox.net>\n> ---\n>  t/t0006-date.sh | 18 ++++++++++++++++++\n>  1 file changed, 18 insertions(+)\n> \n> diff --git a/t/t0006-date.sh b/t/t0006-date.sh\n> index ffb2975e48..35f7b52dd7 100755\n> --- a/t/t0006-date.sh\n> +++ b/t/t0006-date.sh\n> @@ -128,4 +128,22 @@ check_approxidate '6AM, June 7, 2009' '2009-06-07 06:00:00'\n>  check_approxidate '2008-12-01' '2008-12-01 19:20:00'\n>  check_approxidate '2009-12-01' '2009-12-01 19:20:00'\n>  \n> +check_date_format_human() {\n> +\tt=$(($TEST_DATE_NOW - $1))\n> +\techo \"$t -> $2\" >expect\n> +\ttest_expect_success \"human date $t\" '\n> +\ttest-tool date human $t >actual &&\n> +\ttest_cmp expect actual\n\nNote that the relative time output is translated, see all the Q_()\ncalls in show_date_relative().  Consequently, these tests fail in\nGETTEXT_POISON builds.  Please use 'test_i18ncmp' instead.\n\nFurthermore, I think it would help readibility of this helper function\nif the commands in the 'test_expect_success' block were indented.\n\n> +'\n> +}\n> +\n> +check_date_format_human 18000 \"5 hours ago\" # 5 hours ago\n> +check_date_format_human 432000 \"Tue Aug 25 19:20\" # 5 days ago\n> +check_date_format_human 1728000 \"Mon Aug 10 19:20\" # 3 weeks ago\n> +check_date_format_human 13000000 \"Thu Apr 2 08:13\" # 5 months ago\n> +check_date_format_human 31449600 \"Aug 31 2008\" # 12 months ago\n> +check_date_format_human 37500000 \"Jun 22 2008\" # 1 year, 2 months ago\n> +check_date_format_human 55188000 \"Dec 1 2007\" # 1 year, 9 months ago\n> +check_date_format_human 630000000 \"Sep 13 1989\" # 20 years ago\n> +\n>  test_done\n> -- \n> 2.20.1.2.gb21ebb671b\n> \n"},{"id":"367281","messageId":"2997973.Dc0KG2NI2d@thunderbird","threadId":"50135","inReplyTo":"20190121150429.GR840@szeder.dev","subject":"Re: [PATCH v3 5/5] Add `human` date format tests.","fromName":"Stephen & Linda Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-22T00:53:44Z","receivedAt":"2019-01-22T00:53:48Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"On Monday, January 21, 2019 8:04:29 AM MST SZEDER Gábor wrote:\n> Note that the relative time output is translated, see all the Q_()\n> calls in show_date_relative().  Consequently, these tests fail in\n> GETTEXT_POISON builds.  Please use 'test_i18ncmp' instead.\n> \n> Furthermore, I think it would help readibility of this helper function\n> if the commands in the 'test_expect_success' block were indented.\n\nNo problem.   I will wait a day or two for any more comments\n\n\n\n"},{"id":"367336","messageId":"xmqqh8e0h7ff.fsf@gitster-ct.c.googlers.com","threadId":"50135","inReplyTo":"3086071.UFgDplIbgl@thunderbird","subject":"Re: [PATCH v2 4/5] Add `human` format to test-tool","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-22T18:29:56Z","receivedAt":"2019-01-22T18:30:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Stephen P. Smith\" <ischis2@cox.net> writes:\n\n> Why don't I create a second patch set after I git this one to next for \n> relative to match your suggestion.  I don't like the idea of conflating two \n> topics.\n\nI'd prefer two separate patches, too, and I'd prefer to see clean-up\nfirst and then a new feature.\n\nThanks.\n"},{"id":"367386","messageId":"xmqq5zuge2y7.fsf@gitster-ct.c.googlers.com","threadId":"50135","inReplyTo":"20190121053112.4736-5-ischis2@cox.net","subject":"Re: [PATCH v3 4/5] Add `human` format to test-tool","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-22T22:34:56Z","receivedAt":"2019-01-22T22:35:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Stephen P. Smith\" <ischis2@cox.net> writes:\n\n> Add the human format support to the test tool so that TEST_DATE_NOW\n> can be used to specify the current time.\n\nThis sounds sensible, but let's do s/TEST_DATE_NOW/GIT_&/ to make\nsure that we will not pick up somebody else's random environment\nvariable in production Git binary.  \n\nThe name of the original environment variable was OK as it was very\nmuch limited to t/helper/test-date.c, but a name that we'll pay\nattention to in production binary is a different matter.\n\n> All calls to gettimeofday() were replaced by calls to get_time().\n\nYup, good.\n\nThe next to go would be the getenv(TEST_DATE_NOW) at the beginning\nof cmd__date(), which probably would lead to simplification to\nfunctions it calls by losing &now parameter.  But that is a separate\nclean-up.\n\n\n"},{"id":"367923","messageId":"20190129035016.25981-5-ischis2@cox.net","threadId":"50135","inReplyTo":"20190129035016.25981-1-ischis2@cox.net","subject":"[PATCH v4 4/5] Add `human` format to test-tool","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-29T03:50:15Z","receivedAt":"2019-01-29T03:50:20Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Add the human format support to the test tool so that\nGIT_TEST_DATE_NOW can be used to specify the current time.\n\nThe get_time() helper function was created and and checks the\nGIT_TEST_DATE_NOW environment variable.  If GIT_TEST_DATE_NOW is set,\nthen that date is used instead of the date returned by by\ngettimeofday().\n\nAll calls to gettimeofday() were replaced by calls to get_time().\n\nRenamed occurances of TEST_DATE_NOW to GIT_TEST_DATE_NOW since the\nvariable is now used in the get binary and not just in the test-tool.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n cache.h              |  2 ++\n date.c               | 21 +++++++++++++++++----\n t/helper/test-date.c | 13 ++++++++++++-\n t/t0006-date.sh      |  4 ++--\n 4 files changed, 33 insertions(+), 7 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 34c33e6a28..fe00ddf910 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1467,6 +1467,8 @@ struct date_mode *date_mode_from_type(enum date_mode_type type);\n const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);\n void show_date_relative(timestamp_t time, int tz, const struct timeval *now,\n \t\t\tstruct strbuf *timebuf);\n+void show_date_human(timestamp_t time, int tz, const struct timeval *now,\n+\t\t\tstruct strbuf *timebuf);\n int parse_date(const char *date, struct strbuf *out);\n int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);\n int parse_expiry_date(const char *date, timestamp_t *timestamp);\ndiff --git a/date.c b/date.c\nindex 43c3a84e25..e997664c1a 100644\n--- a/date.c\n+++ b/date.c\n@@ -115,6 +115,19 @@ static int local_tzoffset(timestamp_t time)\n \treturn local_time_tzoffset((time_t)time, &tm);\n }\n \n+static void get_time(struct timeval *now)\n+{\n+\tconst char *x;\n+\n+\tx = getenv(\"GIT_TEST_DATE_NOW\");\n+\tif (x) {\n+\t\tnow->tv_sec = atoi(x);\n+\t\tnow->tv_usec = 0;\n+\t}\n+\telse\n+\t\tgettimeofday(now, NULL);\n+}\n+\n void show_date_relative(timestamp_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n@@ -228,7 +241,7 @@ static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm\n \t/* Show \"today\" times as just relative times */\n \tif (hide.wday) {\n \t\tstruct timeval now;\n-\t\tgettimeofday(&now, NULL);\n+\t\tget_time(&now);\n \t\tshow_date_relative(time, tz, &now, buf);\n \t\treturn;\n \t}\n@@ -284,7 +297,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \tif (mode->type == DATE_HUMAN) {\n \t\tstruct timeval now;\n \n-\t\tgettimeofday(&now, NULL);\n+\t\tget_time(&now);\n \n \t\t/* Fill in the data for \"current time\" in human_tz and human_tm */\n \t\thuman_tz = local_time_tzoffset(now.tv_sec, &human_tm);\n@@ -303,7 +316,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \t\tstruct timeval now;\n \n \t\tstrbuf_reset(&timebuf);\n-\t\tgettimeofday(&now, NULL);\n+\t\tget_time(&now);\n \t\tshow_date_relative(time, tz, &now, &timebuf);\n \t\treturn timebuf.buf;\n \t}\n@@ -1296,7 +1309,7 @@ timestamp_t approxidate_careful(const char *date, int *error_ret)\n \t\treturn timestamp;\n \t}\n \n-\tgettimeofday(&tv, NULL);\n+\tget_time(&tv);\n \treturn approxidate_str(date, &tv, error_ret);\n }\n \ndiff --git a/t/helper/test-date.c b/t/helper/test-date.c\nindex a0837371ab..9b2ac772ee 100644\n--- a/t/helper/test-date.c\n+++ b/t/helper/test-date.c\n@@ -3,6 +3,7 @@\n \n static const char *usage_msg = \"\\n\"\n \"  test-tool date relative [time_t]...\\n\"\n+\"  test-tool date human [time_t]...\\n\"\n \"  test-tool date show:<format> [time_t]...\\n\"\n \"  test-tool date parse [date]...\\n\"\n \"  test-tool date approxidate [date]...\\n\"\n@@ -22,6 +23,14 @@ static void show_relative_dates(const char **argv, struct timeval *now)\n \tstrbuf_release(&buf);\n }\n \n+static void show_human_dates(const char **argv)\n+{\n+\tfor (; *argv; argv++) {\n+\t\ttime_t t = atoi(*argv);\n+\t\tprintf(\"%s -> %s\\n\", *argv, show_date(t, 0, DATE_MODE(HUMAN)));\n+\t}\n+}\n+\n static void show_dates(const char **argv, const char *format)\n {\n \tstruct date_mode mode;\n@@ -87,7 +96,7 @@ int cmd__date(int argc, const char **argv)\n \tstruct timeval now;\n \tconst char *x;\n \n-\tx = getenv(\"TEST_DATE_NOW\");\n+\tx = getenv(\"GIT_TEST_DATE_NOW\");\n \tif (x) {\n \t\tnow.tv_sec = atoi(x);\n \t\tnow.tv_usec = 0;\n@@ -100,6 +109,8 @@ int cmd__date(int argc, const char **argv)\n \t\tusage(usage_msg);\n \tif (!strcmp(*argv, \"relative\"))\n \t\tshow_relative_dates(argv+1, &now);\n+\telse if (!strcmp(*argv, \"human\"))\n+\t\tshow_human_dates(argv+1);\n \telse if (skip_prefix(*argv, \"show:\", &x))\n \t\tshow_dates(argv+1, x);\n \telse if (!strcmp(*argv, \"parse\"))\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex ffb2975e48..90930c2aa7 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -4,10 +4,10 @@ test_description='test date parsing and printing'\n . ./test-lib.sh\n \n # arbitrary reference time: 2009-08-30 19:20:00\n-TEST_DATE_NOW=1251660000; export TEST_DATE_NOW\n+GIT_TEST_DATE_NOW=1251660000; export GIT_TEST_DATE_NOW\n \n check_relative() {\n-\tt=$(($TEST_DATE_NOW - $1))\n+\tt=$(($GIT_TEST_DATE_NOW - $1))\n \techo \"$t -> $2\" >expect\n \ttest_expect_${3:-success} \"relative date ($2)\" \"\n \ttest-tool date relative $t >actual &&\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367924","messageId":"20190129035016.25981-2-ischis2@cox.net","threadId":"50135","inReplyTo":"20190129035016.25981-1-ischis2@cox.net","subject":"[PATCH v4 1/5] Add 'human' date format","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-29T03:50:12Z","receivedAt":"2019-01-29T03:50:21Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"From: Linus Torvalds <torvalds@linux-foundation.org>\n\nThis adds --date=human, which skips the timezone if it matches the\ncurrent time-zone, and doesn't print the whole date if that matches (ie\nskip printing year for dates that are \"this year\", but also skip the\nwhole date itself if it's in the last few days and we can just say what\nweekday it was).\n\nFor really recent dates (same day), use the relative date stamp, while\nfor old dates (year doesn't match), don't bother with time and timezone.\n\nAlso add 'auto' date mode, which defaults to human if we're using the\npager.  So you can do\n\n\tgit config --add log.date auto\n\nand your \"git log\" commands will show the human-legible format unless\nyou're scripting things.\n\nNote that this time format still shows the timezone for recent enough\nevents (but not so recent that they show up as relative dates).  You can\ncombine it with the \"-local\" suffix to never show timezones for an even\nmore simplified view.\n\nSigned-off-by: Linus Torvalds <torvalds@linux-foundation.org>\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n builtin/blame.c |   4 ++\n cache.h         |   1 +\n date.c          | 130 ++++++++++++++++++++++++++++++++++++++++--------\n 3 files changed, 115 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 6d798f9939..f684e31d82 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -925,6 +925,10 @@ int cmd_blame(int argc, const char **argv, const char *prefix)\n \t\t */\n \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n \t\tbreak;\n+\tcase DATE_HUMAN:\n+\t\t/* If the year is shown, no time is shown */\n+\t\tblame_date_width = sizeof(\"Thu Oct 19 16:00\");\n+\t\tbreak;\n \tcase DATE_NORMAL:\n \t\tblame_date_width = sizeof(\"Thu Oct 19 16:00:04 2006 -0700\");\n \t\tbreak;\ndiff --git a/cache.h b/cache.h\nindex 49713cc5a5..34c33e6a28 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1439,6 +1439,7 @@ extern struct object *peel_to_type(const char *name, int namelen,\n \n enum date_mode_type {\n \tDATE_NORMAL = 0,\n+\tDATE_HUMAN,\n \tDATE_RELATIVE,\n \tDATE_SHORT,\n \tDATE_ISO8601,\ndiff --git a/date.c b/date.c\nindex 9bc15df6f9..a8d50eb206 100644\n--- a/date.c\n+++ b/date.c\n@@ -77,22 +77,16 @@ static struct tm *time_to_tm_local(timestamp_t time)\n }\n \n /*\n- * What value of \"tz\" was in effect back then at \"time\" in the\n- * local timezone?\n+ * Fill in the localtime 'struct tm' for the supplied time,\n+ * and return the local tz.\n  */\n-static int local_tzoffset(timestamp_t time)\n+static int local_time_tzoffset(time_t t, struct tm *tm)\n {\n-\ttime_t t, t_local;\n-\tstruct tm tm;\n+\ttime_t t_local;\n \tint offset, eastwest;\n \n-\tif (date_overflows(time))\n-\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n-\n-\tt = (time_t)time;\n-\tlocaltime_r(&t, &tm);\n-\tt_local = tm_to_time_t(&tm);\n-\n+\tlocaltime_r(&t, tm);\n+\tt_local = tm_to_time_t(tm);\n \tif (t_local == -1)\n \t\treturn 0; /* error; just use +0000 */\n \tif (t_local < t) {\n@@ -107,6 +101,20 @@ static int local_tzoffset(timestamp_t time)\n \treturn offset * eastwest;\n }\n \n+/*\n+ * What value of \"tz\" was in effect back then at \"time\" in the\n+ * local timezone?\n+ */\n+static int local_tzoffset(timestamp_t time)\n+{\n+\tstruct tm tm;\n+\n+\tif (date_overflows(time))\n+\t\tdie(\"Timestamp too large for this system: %\"PRItime, time);\n+\n+\treturn local_time_tzoffset((time_t)time, &tm);\n+}\n+\n void show_date_relative(timestamp_t time, int tz,\n \t\t\t       const struct timeval *now,\n \t\t\t       struct strbuf *timebuf)\n@@ -191,9 +199,80 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \treturn &mode;\n }\n \n+static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm, int tz, struct tm *human_tm, int human_tz, int local)\n+{\n+\tstruct {\n+\t\tunsigned int\tyear:1,\n+\t\t\t\tdate:1,\n+\t\t\t\twday:1,\n+\t\t\t\ttime:1,\n+\t\t\t\tseconds:1,\n+\t\t\t\ttz:1;\n+\t} hide = { 0 };\n+\n+\thide.tz = local || tz == human_tz;\n+\thide.year = tm->tm_year == human_tm->tm_year;\n+\tif (hide.year) {\n+\t\tif (tm->tm_mon == human_tm->tm_mon) {\n+\t\t\tif (tm->tm_mday > human_tm->tm_mday) {\n+\t\t\t\t/* Future date: think timezones */\n+\t\t\t} else if (tm->tm_mday == human_tm->tm_mday) {\n+\t\t\t\thide.date = hide.wday = 1;\n+\t\t\t} else if (tm->tm_mday + 5 > human_tm->tm_mday) {\n+\t\t\t\t/* Leave just weekday if it was a few days ago */\n+\t\t\t\thide.date = 1;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/* Show \"today\" times as just relative times */\n+\tif (hide.wday) {\n+\t\tstruct timeval now;\n+\t\tgettimeofday(&now, NULL);\n+\t\tshow_date_relative(time, tz, &now, buf);\n+\t\treturn;\n+\t}\n+\n+\t/*\n+\t * Always hide seconds for human-readable.\n+\t * Hide timezone if showing date.\n+\t * Hide weekday and time if showing year.\n+\t *\n+\t * The logic here is two-fold:\n+\t *  (a) only show details when recent enough to matter\n+\t *  (b) keep the maximum length \"similar\", and in check\n+\t */\n+\tif (human_tm->tm_year) {\n+\t\thide.seconds = 1;\n+\t\thide.tz |= !hide.date;\n+\t\thide.wday = hide.time = !hide.year;\n+\t}\n+\n+\tif (!hide.wday)\n+\t\tstrbuf_addf(buf, \"%.3s \", weekday_names[tm->tm_wday]);\n+\tif (!hide.date)\n+\t\tstrbuf_addf(buf, \"%.3s %d \", month_names[tm->tm_mon], tm->tm_mday);\n+\n+\t/* Do we want AM/PM depending on locale? */\n+\tif (!hide.time) {\n+\t\tstrbuf_addf(buf, \"%02d:%02d\", tm->tm_hour, tm->tm_min);\n+\t\tif (!hide.seconds)\n+\t\t\tstrbuf_addf(buf, \":%02d\", tm->tm_sec);\n+\t} else\n+\t\tstrbuf_rtrim(buf);\n+\n+\tif (!hide.year)\n+\t\tstrbuf_addf(buf, \" %d\", tm->tm_year + 1900);\n+\n+\tif (!hide.tz)\n+\t\tstrbuf_addf(buf, \" %+05d\", tz);\n+}\n+\n const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n {\n \tstruct tm *tm;\n+\tstruct tm human_tm = { 0 };\n+\tint human_tz = -1;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n \n \tif (mode->type == DATE_UNIX) {\n@@ -202,6 +281,15 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \t\treturn timebuf.buf;\n \t}\n \n+\tif (mode->type == DATE_HUMAN) {\n+\t\tstruct timeval now;\n+\n+\t\tgettimeofday(&now, NULL);\n+\n+\t\t/* Fill in the data for \"current time\" in human_tz and human_tm */\n+\t\thuman_tz = local_time_tzoffset(now.tv_sec, &human_tm);\n+\t}\n+\n \tif (mode->local)\n \t\ttz = local_tzoffset(time);\n \n@@ -258,14 +346,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)\n \t\tstrbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,\n \t\t\t\t!mode->local);\n \telse\n-\t\tstrbuf_addf(&timebuf, \"%.3s %.3s %d %02d:%02d:%02d %d%c%+05d\",\n-\t\t\t\tweekday_names[tm->tm_wday],\n-\t\t\t\tmonth_names[tm->tm_mon],\n-\t\t\t\ttm->tm_mday,\n-\t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n-\t\t\t\ttm->tm_year + 1900,\n-\t\t\t\tmode->local ? 0 : ' ',\n-\t\t\t\ttz);\n+\t\tshow_date_normal(&timebuf, time, tm, tz, &human_tm, human_tz, mode->local);\n \treturn timebuf.buf;\n }\n \n@@ -802,6 +883,11 @@ int parse_date(const char *date, struct strbuf *result)\n \treturn 0;\n }\n \n+static int auto_date_style(void)\n+{\n+\treturn (isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;\n+}\n+\n static enum date_mode_type parse_date_type(const char *format, const char **end)\n {\n \tif (skip_prefix(format, \"relative\", end))\n@@ -819,6 +905,10 @@ static enum date_mode_type parse_date_type(const char *format, const char **end)\n \t\treturn DATE_SHORT;\n \tif (skip_prefix(format, \"default\", end))\n \t\treturn DATE_NORMAL;\n+\tif (skip_prefix(format, \"human\", end))\n+\t\treturn DATE_HUMAN;\n+\tif (skip_prefix(format, \"auto\", end))\n+\t\treturn auto_date_style();\n \tif (skip_prefix(format, \"raw\", end))\n \t\treturn DATE_RAW;\n \tif (skip_prefix(format, \"unix\", end))\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367925","messageId":"20190129035016.25981-4-ischis2@cox.net","threadId":"50135","inReplyTo":"20190129035016.25981-1-ischis2@cox.net","subject":"[PATCH v4 3/5] Add 'human' date format documentation","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-29T03:50:14Z","receivedAt":"2019-01-29T03:50:23Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Display date and time information in a format similar to how people\nwrite dates in other contexts. If the year isn't specified then, the\nreader infers the date is given is in the current year.\n\nBy not displaying the redundant information, the reader concentrates\non the information that is different. The patch reports relative dates\nbased on information inferred from the date on the machine running the\ngit command at the time the command is executed.\n\nWhile the format is more useful to humans by dropping inferred\ninformation, there is nothing that makes it actually human. If the\n'relative' date format wasn't already implemented then using\n'relative' would have been appropriate.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n Documentation/git-log.txt          | 4 ++++\n Documentation/rev-list-options.txt | 7 +++++++\n 2 files changed, 11 insertions(+)\n\ndiff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\nindex 90761f1694..b02e922dc3 100644\n--- a/Documentation/git-log.txt\n+++ b/Documentation/git-log.txt\n@@ -192,6 +192,10 @@ log.date::\n \tDefault format for human-readable dates.  (Compare the\n \t`--date` option.)  Defaults to \"default\", which means to write\n \tdates like `Sat May 8 19:35:34 2010 -0500`.\n++\n+If the format is set to \"auto:foo\" and the pager is in use, format\n+\"foo\" will be the used for the date format. Otherwise \"default\" will\n+be used.\n \n log.follow::\n \tIf `true`, `git log` will act as if the `--follow` option was used when\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 98b538bc77..867a063a1c 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -831,6 +831,13 @@ Note that the `-local` option does not affect the seconds-since-epoch\n value (which is always measured in UTC), but does switch the accompanying\n timezone value.\n +\n+`--date=human` shows the timezone if the timezone does not match the\n+current time-zone, and doesn't print the whole date if that matches\n+(ie skip printing year for dates that are \"this year\", but also skip\n+the whole date itself if it's in the last few days and we can just say\n+what weekday it was).  For older dates the hour and minute is also\n+omitted.\n++\n `--date=unix` shows the date as a Unix epoch timestamp (seconds since\n 1970).  As with `--raw`, this is always in UTC and therefore `-local`\n has no effect.\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367926","messageId":"20190129035016.25981-1-ischis2@cox.net","threadId":"50135","inReplyTo":"20190121053112.4736-1-ischis2@cox.net","subject":"[PATCH v4 0/5] Re-roll of 'human' date format patch set","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-29T03:50:11Z","receivedAt":"2019-01-29T03:50:24Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Changed the binary and test to rename TEST_DATE_NOW environment\nvariable.  Changed the 'human' test to test_i18ncmp.\n\nUpdates for the relative date format will be done in a follow-on patch.\n\nRange-diff relative to v3:\n\n1:  ee75d9002d = 1:  ee75d9002d Add 'human' date format\n2:  722c3319cd = 2:  722c3319cd Replace the proposed 'auto' mode with 'auto:'\n3:  67cb73edb4 = 3:  67cb73edb4 Add 'human' date format documentation\n4:  1562e7c713 ! 4:  a3f6f820b2 Add `human` format to test-tool\n    @@ -2,15 +2,19 @@\n     \n         Add `human` format to test-tool\n     \n    -    Add the human format support to the test tool so that TEST_DATE_NOW\n    -    can be used to specify the current time.\n    +    Add the human format support to the test tool so that\n    +    GIT_TEST_DATE_NOW can be used to specify the current time.\n     \n         The get_time() helper function was created and and checks the\n    -    TEST_DATE_NOW environment variable.  If TEST_DATE_NOW is set, then\n    -    that date is used instead of the date returned by by gettimeofday().\n    +    GIT_TEST_DATE_NOW environment variable.  If GIT_TEST_DATE_NOW is set,\n    +    then that date is used instead of the date returned by by\n    +    gettimeofday().\n     \n         All calls to gettimeofday() were replaced by calls to get_time().\n     \n    +    Renamed occurances of TEST_DATE_NOW to GIT_TEST_DATE_NOW since the\n    +    variable is now used in the get binary and not just in the test-tool.\n    +\n      diff --git a/cache.h b/cache.h\n      --- a/cache.h\n      +++ b/cache.h\n    @@ -35,7 +39,7 @@\n     +{\n     +\tconst char *x;\n     +\n    -+\tx = getenv(\"TEST_DATE_NOW\");\n    ++\tx = getenv(\"GIT_TEST_DATE_NOW\");\n     +\tif (x) {\n     +\t\tnow->tv_sec = atoi(x);\n     +\t\tnow->tv_usec = 0;\n    @@ -110,6 +114,15 @@\n      static void show_dates(const char **argv, const char *format)\n      {\n      \tstruct date_mode mode;\n    +@@\n    + \tstruct timeval now;\n    + \tconst char *x;\n    + \n    +-\tx = getenv(\"TEST_DATE_NOW\");\n    ++\tx = getenv(\"GIT_TEST_DATE_NOW\");\n    + \tif (x) {\n    + \t\tnow.tv_sec = atoi(x);\n    + \t\tnow.tv_usec = 0;\n     @@\n      \t\tusage(usage_msg);\n      \tif (!strcmp(*argv, \"relative\"))\n    @@ -119,3 +132,20 @@\n      \telse if (skip_prefix(*argv, \"show:\", &x))\n      \t\tshow_dates(argv+1, x);\n      \telse if (!strcmp(*argv, \"parse\"))\n    +\n    + diff --git a/t/t0006-date.sh b/t/t0006-date.sh\n    + --- a/t/t0006-date.sh\n    + +++ b/t/t0006-date.sh\n    +@@\n    + . ./test-lib.sh\n    + \n    + # arbitrary reference time: 2009-08-30 19:20:00\n    +-TEST_DATE_NOW=1251660000; export TEST_DATE_NOW\n    ++GIT_TEST_DATE_NOW=1251660000; export GIT_TEST_DATE_NOW\n    + \n    + check_relative() {\n    +-\tt=$(($TEST_DATE_NOW - $1))\n    ++\tt=$(($GIT_TEST_DATE_NOW - $1))\n    + \techo \"$t -> $2\" >expect\n    + \ttest_expect_${3:-success} \"relative date ($2)\" \"\n    + \ttest-tool date relative $t >actual &&\n5:  5e6b5705fd ! 5:  87d3a81e8a Add `human` date format tests.\n    @@ -19,11 +19,11 @@\n      check_approxidate '2009-12-01' '2009-12-01 19:20:00'\n      \n     +check_date_format_human() {\n    -+\tt=$(($TEST_DATE_NOW - $1))\n    ++\tt=$(($GIT_TEST_DATE_NOW - $1))\n     +\techo \"$t -> $2\" >expect\n     +\ttest_expect_success \"human date $t\" '\n    -+\ttest-tool date human $t >actual &&\n    -+\ttest_cmp expect actual\n    ++\t\ttest-tool date human $t >actual &&\n    ++\t\ttest_i18ncmp expect actual\n     +'\n     +}\n     +\n\n\nLinus Torvalds (1):\n  Add 'human' date format\n\nStephen P. Smith (4):\n  Replace the proposed 'auto' mode with 'auto:'\n  Add 'human' date format documentation\n  Add `human` format to test-tool\n  Add `human` date format tests.\n\n Documentation/git-log.txt          |   4 +\n Documentation/rev-list-options.txt |   7 ++\n builtin/blame.c                    |   4 +\n cache.h                            |   3 +\n date.c                             | 148 ++++++++++++++++++++++++-----\n t/helper/test-date.c               |  13 ++-\n t/t0006-date.sh                    |  22 ++++-\n 7 files changed, 176 insertions(+), 25 deletions(-)\n\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367927","messageId":"20190129035016.25981-3-ischis2@cox.net","threadId":"50135","inReplyTo":"20190129035016.25981-1-ischis2@cox.net","subject":"[PATCH v4 2/5] Replace the proposed 'auto' mode with 'auto:'","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-29T03:50:13Z","receivedAt":"2019-01-29T03:50:26Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"In addition to adding the 'human' format, the patch added the auto\nkeyword which could be used in the config file as an alternate way to\nspecify the human format.  Removing 'auto' cleans up the 'human'\nformat interface.\n\nAdded the ability to specify mode 'foo' if the pager is being used by\nusing auto:foo syntax.  Therefore, 'auto:human' date mode defaults to\nhuman if we're using the pager.  So you can do\n\n\tgit config --add log.date auto:human\n\nand your \"git log\" commands will show the human-legible format unless\nyou're scripting things.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n date.c | 15 ++++++++-------\n 1 file changed, 8 insertions(+), 7 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex a8d50eb206..43c3a84e25 100644\n--- a/date.c\n+++ b/date.c\n@@ -883,11 +883,6 @@ int parse_date(const char *date, struct strbuf *result)\n \treturn 0;\n }\n \n-static int auto_date_style(void)\n-{\n-\treturn (isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;\n-}\n-\n static enum date_mode_type parse_date_type(const char *format, const char **end)\n {\n \tif (skip_prefix(format, \"relative\", end))\n@@ -907,8 +902,6 @@ static enum date_mode_type parse_date_type(const char *format, const char **end)\n \t\treturn DATE_NORMAL;\n \tif (skip_prefix(format, \"human\", end))\n \t\treturn DATE_HUMAN;\n-\tif (skip_prefix(format, \"auto\", end))\n-\t\treturn auto_date_style();\n \tif (skip_prefix(format, \"raw\", end))\n \t\treturn DATE_RAW;\n \tif (skip_prefix(format, \"unix\", end))\n@@ -923,6 +916,14 @@ void parse_date_format(const char *format, struct date_mode *mode)\n {\n \tconst char *p;\n \n+\t/* \"auto:foo\" is \"if tty/pager, then foo, otherwise normal\" */\n+\tif (skip_prefix(format, \"auto:\", &p)) {\n+\t\tif (isatty(1) || pager_in_use())\n+\t\t\tformat = p;\n+\t\telse\n+\t\t\tformat = \"default\";\n+\t}\n+\n \t/* historical alias */\n \tif (!strcmp(format, \"local\"))\n \t\tformat = \"default-local\";\n-- \n2.20.1.2.gb21ebb671b\n\n"},{"id":"367928","messageId":"20190129035016.25981-6-ischis2@cox.net","threadId":"50135","inReplyTo":"20190129035016.25981-1-ischis2@cox.net","subject":"[PATCH v4 5/5] Add `human` date format tests.","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2019-01-29T03:50:16Z","receivedAt":"2019-01-29T03:50:27Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"When using `human` several fields are suppressed depending on the time\ndifference between the reference date and the local computer date. In\ncases where the difference is less than a year, the year field is\nsupppressed. If the time is less than a day; the month and year is\nsuppressed.\n\nUse TEST_DATE_NOW environment variable when using the test-tool to\nhold the expected output strings constant.\n\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n t/t0006-date.sh | 18 ++++++++++++++++++\n 1 file changed, 18 insertions(+)\n\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex 90930c2aa7..d9fcc829a9 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -128,4 +128,22 @@ check_approxidate '6AM, June 7, 2009' '2009-06-07 06:00:00'\n check_approxidate '2008-12-01' '2008-12-01 19:20:00'\n check_approxidate '2009-12-01' '2009-12-01 19:20:00'\n \n+check_date_format_human() {\n+\tt=$(($GIT_TEST_DATE_NOW - $1))\n+\techo \"$t -> $2\" >expect\n+\ttest_expect_success \"human date $t\" '\n+\t\ttest-tool date human $t >actual &&\n+\t\ttest_i18ncmp expect actual\n+'\n+}\n+\n+check_date_format_human 18000 \"5 hours ago\" # 5 hours ago\n+check_date_format_human 432000 \"Tue Aug 25 19:20\" # 5 days ago\n+check_date_format_human 1728000 \"Mon Aug 10 19:20\" # 3 weeks ago\n+check_date_format_human 13000000 \"Thu Apr 2 08:13\" # 5 months ago\n+check_date_format_human 31449600 \"Aug 31 2008\" # 12 months ago\n+check_date_format_human 37500000 \"Jun 22 2008\" # 1 year, 2 months ago\n+check_date_format_human 55188000 \"Dec 1 2007\" # 1 year, 9 months ago\n+check_date_format_human 630000000 \"Sep 13 1989\" # 20 years ago\n+\n test_done\n-- \n2.20.1.2.gb21ebb671b\n\n"}]}