git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 1/5] Add 'human' date format

From
SSStephen P. Smith <ischis2@cox.net>
Date
Jan 18, 2019, 06:18 UTC
Message-ID
<20190118061805.19086-2-ischis2@cox.net>
In-Reply-To
<20190118061805.19086-1-ischis2@cox.net>
From: Linus Torvalds <torvalds@linux-foundation.org>

This adds --date=human, which skips the timezone if it matches the current time-zone, and doesn't print the whole date if that matches (ie skip printing year for dates that are "this year", but also skip the whole date itself if it's in the last few days and we can just say what weekday it was).

For really recent dates (same day), use the relative date stamp, while for old dates (year doesn't match), don't bother with time and timezone.

Also add 'auto' date mode, which defaults to human if we're using the pager. So you can do

	git config --add log.date auto

and your "git log" commands will show the human-legible format unless you're scripting things.

Note that this time format still shows the timezone for recent enough events (but not so recent that they show up as relative dates). You can combine it with the "-local" suffix to never show timezones for an even more simplified view.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Stephen P. Smith <ischis2@cox.net>
---
 builtin/blame.c |   4 ++
 cache.h         |   1 +
 date.c          | 130 ++++++++++++++++++++++++++++++++++++++++--------
 3 files changed, 115 insertions(+), 20 deletions(-)
diff --git a/builtin/blame.c b/builtin/blame.c
index 6d798f9939..f684e31d82 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -925,6 +925,10 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 		 */
 		blame_date_width = utf8_strwidth(_("4 years, 11 months ago")) + 1; /* add the null */
 		break;
+	case DATE_HUMAN:
+		/* If the year is shown, no time is shown */
+		blame_date_width = sizeof("Thu Oct 19 16:00");
+		break;
 	case DATE_NORMAL:
 		blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
 		break;
diff --git a/cache.h b/cache.h
index 49713cc5a5..34c33e6a28 100644
--- a/cache.h
+++ b/cache.h
@@ -1439,6 +1439,7 @@ extern struct object *peel_to_type(const char *name, int namelen,
 
 enum date_mode_type {
 	DATE_NORMAL = 0,
+	DATE_HUMAN,
 	DATE_RELATIVE,
 	DATE_SHORT,
 	DATE_ISO8601,
diff --git a/date.c b/date.c
index 9bc15df6f9..a8d50eb206 100644
--- a/date.c
+++ b/date.c
@@ -77,22 +77,16 @@ static struct tm *time_to_tm_local(timestamp_t time)
 }
 
 /*
- * What value of "tz" was in effect back then at "time" in the
- * local timezone?
+ * Fill in the localtime 'struct tm' for the supplied time,
+ * and return the local tz.
  */
-static int local_tzoffset(timestamp_t time)
+static int local_time_tzoffset(time_t t, struct tm *tm)
 {
-	time_t t, t_local;
-	struct tm tm;
+	time_t t_local;
 	int offset, eastwest;
 
-	if (date_overflows(time))
-		die("Timestamp too large for this system: %"PRItime, time);
-
-	t = (time_t)time;
-	localtime_r(&t, &tm);
-	t_local = tm_to_time_t(&tm);
-
+	localtime_r(&t, tm);
+	t_local = tm_to_time_t(tm);
 	if (t_local == -1)
 		return 0; /* error; just use +0000 */
 	if (t_local < t) {
@@ -107,6 +101,20 @@ static int local_tzoffset(timestamp_t time)
 	return offset * eastwest;
 }
 
+/*
+ * What value of "tz" was in effect back then at "time" in the
+ * local timezone?
+ */
+static int local_tzoffset(timestamp_t time)
+{
+	struct tm tm;
+
+	if (date_overflows(time))
+		die("Timestamp too large for this system: %"PRItime, time);
+
+	return local_time_tzoffset((time_t)time, &tm);
+}
+
 void show_date_relative(timestamp_t time, int tz,
 			       const struct timeval *now,
 			       struct strbuf *timebuf)
@@ -191,9 +199,80 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)
 	return &mode;
 }
 
+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)
+{
+	struct {
+		unsigned int	year:1,
+				date:1,
+				wday:1,
+				time:1,
+				seconds:1,
+				tz:1;
+	} hide = { 0 };
+
+	hide.tz = local || tz == human_tz;
+	hide.year = tm->tm_year == human_tm->tm_year;
+	if (hide.year) {
+		if (tm->tm_mon == human_tm->tm_mon) {
+			if (tm->tm_mday > human_tm->tm_mday) {
+				/* Future date: think timezones */
+			} else if (tm->tm_mday == human_tm->tm_mday) {
+				hide.date = hide.wday = 1;
+			} else if (tm->tm_mday + 5 > human_tm->tm_mday) {
+				/* Leave just weekday if it was a few days ago */
+				hide.date = 1;
+			}
+		}
+	}
+
+	/* Show "today" times as just relative times */
+	if (hide.wday) {
+		struct timeval now;
+		gettimeofday(&now, NULL);
+		show_date_relative(time, tz, &now, buf);
+		return;
+	}
+
+	/*
+	 * Always hide seconds for human-readable.
+	 * Hide timezone if showing date.
+	 * Hide weekday and time if showing year.
+	 *
+	 * The logic here is two-fold:
+	 *  (a) only show details when recent enough to matter
+	 *  (b) keep the maximum length "similar", and in check
+	 */
+	if (human_tm->tm_year) {
+		hide.seconds = 1;
+		hide.tz |= !hide.date;
+		hide.wday = hide.time = !hide.year;
+	}
+
+	if (!hide.wday)
+		strbuf_addf(buf, "%.3s ", weekday_names[tm->tm_wday]);
+	if (!hide.date)
+		strbuf_addf(buf, "%.3s %d ", month_names[tm->tm_mon], tm->tm_mday);
+
+	/* Do we want AM/PM depending on locale? */
+	if (!hide.time) {
+		strbuf_addf(buf, "%02d:%02d", tm->tm_hour, tm->tm_min);
+		if (!hide.seconds)
+			strbuf_addf(buf, ":%02d", tm->tm_sec);
+	} else
+		strbuf_rtrim(buf);
+
+	if (!hide.year)
+		strbuf_addf(buf, " %d", tm->tm_year + 1900);
+
+	if (!hide.tz)
+		strbuf_addf(buf, " %+05d", tz);
+}
+
 const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
 {
 	struct tm *tm;
+	struct tm human_tm = { 0 };
+	int human_tz = -1;
 	static struct strbuf timebuf = STRBUF_INIT;
 
 	if (mode->type == DATE_UNIX) {
@@ -202,6 +281,15 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
 		return timebuf.buf;
 	}
 
+	if (mode->type == DATE_HUMAN) {
+		struct timeval now;
+
+		gettimeofday(&now, NULL);
+
+		/* Fill in the data for "current time" in human_tz and human_tm */
+		human_tz = local_time_tzoffset(now.tv_sec, &human_tm);
+	}
+
 	if (mode->local)
 		tz = local_tzoffset(time);
 
@@ -258,14 +346,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
 		strbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,
 				!mode->local);
 	else
-		strbuf_addf(&timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d",
-				weekday_names[tm->tm_wday],
-				month_names[tm->tm_mon],
-				tm->tm_mday,
-				tm->tm_hour, tm->tm_min, tm->tm_sec,
-				tm->tm_year + 1900,
-				mode->local ? 0 : ' ',
-				tz);
+		show_date_normal(&timebuf, time, tm, tz, &human_tm, human_tz, mode->local);
 	return timebuf.buf;
 }
 
@@ -802,6 +883,11 @@ int parse_date(const char *date, struct strbuf *result)
 	return 0;
 }
 
+static int auto_date_style(void)
+{
+	return (isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;
+}
+
 static enum date_mode_type parse_date_type(const char *format, const char **end)
 {
 	if (skip_prefix(format, "relative", end))
@@ -819,6 +905,10 @@ static enum date_mode_type parse_date_type(const char *format, const char **end)
 		return DATE_SHORT;
 	if (skip_prefix(format, "default", end))
 		return DATE_NORMAL;
+	if (skip_prefix(format, "human", end))
+		return DATE_HUMAN;
+	if (skip_prefix(format, "auto", end))
+		return auto_date_style();
 	if (skip_prefix(format, "raw", end))
 		return DATE_RAW;
 	if (skip_prefix(format, "unix", end))
-- 
2.20.1.2.gb21ebb671b
Previous: Junio C HamanoNext: Stephen P. Smith
Message 35 of 56 in “Add 'human' date format”
  1. 0/3 Add 'human' date formatStephen P. Smith, Dec 31, 2018
  2. 2/3 Add 'human' date format documentationStephen P. Smith, Dec 31, 2018
  3. 3/3 t0006-date.sh: add `human` date format tests.Stephen P. Smith, Dec 31, 2018
  4. Junio C HamanoJan 2, 2019
  5. Stephen & Linda SmithJan 3, 2019
  6. Junio C HamanoJan 3, 2019
  7. Stephen P. SmithJan 3, 2019
  8. Philip OakleyJan 3, 2019
  9. Junio C HamanoJan 3, 2019
  10. Stephen P. SmithJan 3, 2019
  11. Jeff KingJan 3, 2019
  12. Stephen & Linda SmithJan 3, 2019
  13. Johannes SixtJan 8, 2019
  14. Stephen P. SmithJan 9, 2019
  15. Johannes SixtJan 9, 2019
  16. Stephen & Linda SmithJan 10, 2019
  17. 1/3 Add 'human' date formatStephen P. Smith, Dec 31, 2018
  18. Jeff KingJan 3, 2019
  19. Stephen P. SmithJan 3, 2019
  20. Jeff KingJan 4, 2019
  21. Stephen P SmithJan 4, 2019
  22. Jeff KingJan 6, 2019
  23. 0/5 Re-roll of 'human' date format patch setStephen P. Smith, Jan 18, 2019
  24. 3/5 Add 'human' date format documentationStephen P. Smith, Jan 18, 2019
  25. Junio C HamanoJan 18, 2019
  26. 2/5 Remove the proposed use of auto as secondary way to specify humanStephen P. Smith, Jan 18, 2019
  27. Junio C HamanoJan 18, 2019
  28. Stephen & Linda SmithJan 19, 2019
  29. 5/5 Add `human` date format tests.Stephen P. Smith, Jan 18, 2019
  30. Junio C HamanoJan 18, 2019
  31. 4/5 Add `human` format to test-toolStephen P. Smith, Jan 18, 2019
  32. Junio C HamanoJan 18, 2019
  33. Stephen P. SmithJan 20, 2019
  34. Junio C HamanoJan 22, 2019
  35. 1/5 Add 'human' date formatStephen P. Smith, Jan 18, 2019
  36. 0/5 Re-roll of 'human' date format patch setStephen P. Smith, Jan 21, 2019
  37. 1/5 Add 'human' date formatStephen P. Smith, Jan 21, 2019
  38. 2/5 Replace the proposed 'auto' mode with 'auto:'Stephen P. Smith, Jan 21, 2019
  39. 5/5 Add `human` date format tests.Stephen P. Smith, Jan 21, 2019
  40. 3/5 Add 'human' date format documentationStephen P. Smith, Jan 21, 2019
  41. 4/5 Add `human` format to test-toolStephen P. Smith, Jan 21, 2019
  42. Junio C HamanoJan 22, 2019
  43. 0/5 Re-roll of 'human' date format patch setStephen P. Smith, Jan 29, 2019
  44. 4/5 Add `human` format to test-toolStephen P. Smith, Jan 29, 2019
  45. 1/5 Add 'human' date formatStephen P. Smith, Jan 29, 2019
  46. 3/5 Add 'human' date format documentationStephen P. Smith, Jan 29, 2019
  47. 2/5 Replace the proposed 'auto' mode with 'auto:'Stephen P. Smith, Jan 29, 2019
  48. 5/5 Add `human` date format tests.Stephen P. Smith, Jan 29, 2019
  49. 0/5 Re-roll of 'human' date format patch setStephen P. Smith, Jan 21, 2019
  50. 1/5 Add 'human' date formatStephen P. Smith, Jan 21, 2019
  51. 5/5 Add `human` date format tests.Stephen P. Smith, Jan 21, 2019
  52. SZEDER GáborJan 21, 2019
  53. Stephen & Linda SmithJan 22, 2019
  54. 4/5 Add `human` format to test-toolStephen P. Smith, Jan 21, 2019
  55. 3/5 Add 'human' date format documentationStephen P. Smith, Jan 21, 2019
  56. 2/5 Replace the proposed 'auto' mode with 'auto:'Stephen P. Smith, Jan 21, 2019

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.