Merge branch 'lt/date-human'
authorJunio C Hamano <gitster@pobox.com>
Thu, 7 Feb 2019 06:05:24 +0000 (22:05 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 7 Feb 2019 06:05:24 +0000 (22:05 -0800)
A new date format "--date=human" that morphs its output depending
on how far the time is from the current time has been introduced.
"--date=auto" can be used to use this new format when the output is
going to the pager or to the terminal and otherwise the default
format.

* lt/date-human:
Add `human` date format tests.
Add `human` format to test-tool
Add 'human' date format documentation
Replace the proposed 'auto' mode with 'auto:'
Add 'human' date format

1  2 
Documentation/rev-list-options.txt
builtin/blame.c
cache.h
date.c
t/helper/test-date.c
t/t0006-date.sh
Simple merge
diff --cc builtin/blame.c
Simple merge
diff --cc cache.h
index 400bc0ab25cd5dd12a3b1a71aab0168259df6e19,34e54dee4da903c0943f27634dbf8a12b159fda7..ef9f3c4eaf2956c416b3b698ce965acb9c58ca98
+++ b/cache.h
@@@ -1461,20 -1425,19 +1461,21 @@@ extern void *read_object_with_reference
  extern struct object *peel_to_type(const char *name, int namelen,
                                   struct object *o, enum object_type);
  
 +enum date_mode_type {
 +      DATE_NORMAL = 0,
++      DATE_HUMAN,
 +      DATE_RELATIVE,
 +      DATE_SHORT,
 +      DATE_ISO8601,
 +      DATE_ISO8601_STRICT,
 +      DATE_RFC2822,
 +      DATE_STRFTIME,
 +      DATE_RAW,
 +      DATE_UNIX
 +};
 +
  struct date_mode {
 -      enum date_mode_type {
 -              DATE_NORMAL = 0,
 -              DATE_HUMAN,
 -              DATE_RELATIVE,
 -              DATE_SHORT,
 -              DATE_ISO8601,
 -              DATE_ISO8601_STRICT,
 -              DATE_RFC2822,
 -              DATE_STRFTIME,
 -              DATE_RAW,
 -              DATE_UNIX
 -      } type;
 +      enum date_mode_type type;
        const char *strftime_fmt;
        int local;
  };
  struct date_mode *date_mode_from_type(enum date_mode_type type);
  
  const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);
 -void show_date_relative(timestamp_t time, int tz, const struct timeval *now,
 +void show_date_relative(timestamp_t time, const struct timeval *now,
                        struct strbuf *timebuf);
+ void show_date_human(timestamp_t time, int tz, const struct timeval *now,
+                       struct strbuf *timebuf);
  int parse_date(const char *date, struct strbuf *out);
  int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);
  int parse_expiry_date(const char *date, timestamp_t *timestamp);
diff --cc date.c
index 61449f8b2e51507f148617120d455eefda19a406,7b9e8fa2ba5afe5bcdd51be3dfc3c56d5bf8dedf..9c5870e102951ed25f5def2103dab15bf8ed5c99
--- 1/date.c
--- 2/date.c
+++ b/date.c
@@@ -107,9 -101,36 +101,36 @@@ static int local_time_tzoffset(time_t t
        return offset * eastwest;
  }
  
 -void show_date_relative(timestamp_t time, int tz,
 -                             const struct timeval *now,
 -                             struct strbuf *timebuf)
+ /*
+  * 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);
+ }
+ static void get_time(struct timeval *now)
+ {
+       const char *x;
+       x = getenv("GIT_TEST_DATE_NOW");
+       if (x) {
+               now->tv_sec = atoi(x);
+               now->tv_usec = 0;
+       }
+       else
+               gettimeofday(now, NULL);
+ }
 +void show_date_relative(timestamp_t time,
 +                      const struct timeval *now,
 +                      struct strbuf *timebuf)
  {
        timestamp_t diff;
        if (now->tv_sec < time) {
@@@ -191,6 -212,75 +212,75 @@@ struct date_mode *date_mode_from_type(e
        return &mode;
  }
  
 -              show_date_relative(time, tz, &now, buf);
+ 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;
+               get_time(&now);
++              show_date_relative(time, &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 timeval now;
  
                strbuf_reset(&timebuf);
-               gettimeofday(&now, NULL);
+               get_time(&now);
 -              show_date_relative(time, tz, &now, &timebuf);
 +              show_date_relative(time, &now, &timebuf);
                return timebuf.buf;
        }
  
Simple merge
diff --cc t/t0006-date.sh
Simple merge