Skip to content

Commit e1a2972

Browse files
committed
Merge branch 'lt/date-human' into pu
* lt/date-human: Add 'human' date format
2 parents 402ba25 + 74e8221 commit e1a2972

File tree

3 files changed

+115
-20
lines changed

3 files changed

+115
-20
lines changed

builtin/blame.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,10 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
919919
*/
920920
blame_date_width = utf8_strwidth(_("4 years, 11 months ago")) + 1; /* add the null */
921921
break;
922+
case DATE_HUMAN:
923+
/* If the year is shown, no time is shown */
924+
blame_date_width = sizeof("Thu Oct 19 16:00");
925+
break;
922926
case DATE_NORMAL:
923927
blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
924928
break;

cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,6 +1424,7 @@ extern struct object *peel_to_type(const char *name, int namelen,
14241424
struct date_mode {
14251425
enum date_mode_type {
14261426
DATE_NORMAL = 0,
1427+
DATE_HUMAN,
14271428
DATE_RELATIVE,
14281429
DATE_SHORT,
14291430
DATE_ISO8601,

date.c

Lines changed: 110 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,16 @@ static struct tm *time_to_tm_local(timestamp_t time)
7777
}
7878

7979
/*
80-
* What value of "tz" was in effect back then at "time" in the
81-
* local timezone?
80+
* Fill in the localtime 'struct tm' for the supplied time,
81+
* and return the local tz.
8282
*/
83-
static int local_tzoffset(timestamp_t time)
83+
static int local_time_tzoffset(time_t t, struct tm *tm)
8484
{
85-
time_t t, t_local;
86-
struct tm tm;
85+
time_t t_local;
8786
int offset, eastwest;
8887

89-
if (date_overflows(time))
90-
die("Timestamp too large for this system: %"PRItime, time);
91-
92-
t = (time_t)time;
93-
localtime_r(&t, &tm);
94-
t_local = tm_to_time_t(&tm);
95-
88+
localtime_r(&t, tm);
89+
t_local = tm_to_time_t(tm);
9690
if (t_local == -1)
9791
return 0; /* error; just use +0000 */
9892
if (t_local < t) {
@@ -107,6 +101,20 @@ static int local_tzoffset(timestamp_t time)
107101
return offset * eastwest;
108102
}
109103

104+
/*
105+
* What value of "tz" was in effect back then at "time" in the
106+
* local timezone?
107+
*/
108+
static int local_tzoffset(timestamp_t time)
109+
{
110+
struct tm tm;
111+
112+
if (date_overflows(time))
113+
die("Timestamp too large for this system: %"PRItime, time);
114+
115+
return local_time_tzoffset((time_t)time, &tm);
116+
}
117+
110118
void show_date_relative(timestamp_t time, int tz,
111119
const struct timeval *now,
112120
struct strbuf *timebuf)
@@ -191,9 +199,80 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)
191199
return &mode;
192200
}
193201

202+
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)
203+
{
204+
struct {
205+
unsigned int year:1,
206+
date:1,
207+
wday:1,
208+
time:1,
209+
seconds:1,
210+
tz:1;
211+
} hide = { 0 };
212+
213+
hide.tz = local || tz == human_tz;
214+
hide.year = tm->tm_year == human_tm->tm_year;
215+
if (hide.year) {
216+
if (tm->tm_mon == human_tm->tm_mon) {
217+
if (tm->tm_mday > human_tm->tm_mday) {
218+
/* Future date: think timezones */
219+
} else if (tm->tm_mday == human_tm->tm_mday) {
220+
hide.date = hide.wday = 1;
221+
} else if (tm->tm_mday + 5 > human_tm->tm_mday) {
222+
/* Leave just weekday if it was a few days ago */
223+
hide.date = 1;
224+
}
225+
}
226+
}
227+
228+
/* Show "today" times as just relative times */
229+
if (hide.wday) {
230+
struct timeval now;
231+
gettimeofday(&now, NULL);
232+
show_date_relative(time, tz, &now, buf);
233+
return;
234+
}
235+
236+
/*
237+
* Always hide seconds for human-readable.
238+
* Hide timezone if showing date.
239+
* Hide weekday and time if showing year.
240+
*
241+
* The logic here is two-fold:
242+
* (a) only show details when recent enough to matter
243+
* (b) keep the maximum length "similar", and in check
244+
*/
245+
if (human_tm->tm_year) {
246+
hide.seconds = 1;
247+
hide.tz |= !hide.date;
248+
hide.wday = hide.time = !hide.year;
249+
}
250+
251+
if (!hide.wday)
252+
strbuf_addf(buf, "%.3s ", weekday_names[tm->tm_wday]);
253+
if (!hide.date)
254+
strbuf_addf(buf, "%.3s %d ", month_names[tm->tm_mon], tm->tm_mday);
255+
256+
/* Do we want AM/PM depending on locale? */
257+
if (!hide.time) {
258+
strbuf_addf(buf, "%02d:%02d", tm->tm_hour, tm->tm_min);
259+
if (!hide.seconds)
260+
strbuf_addf(buf, ":%02d", tm->tm_sec);
261+
} else
262+
strbuf_rtrim(buf);
263+
264+
if (!hide.year)
265+
strbuf_addf(buf, " %d", tm->tm_year + 1900);
266+
267+
if (!hide.tz)
268+
strbuf_addf(buf, " %+05d", tz);
269+
}
270+
194271
const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
195272
{
196273
struct tm *tm;
274+
struct tm human_tm = { 0 };
275+
int human_tz = -1;
197276
static struct strbuf timebuf = STRBUF_INIT;
198277

199278
if (mode->type == DATE_UNIX) {
@@ -202,6 +281,15 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
202281
return timebuf.buf;
203282
}
204283

284+
if (mode->type == DATE_HUMAN) {
285+
struct timeval now;
286+
287+
gettimeofday(&now, NULL);
288+
289+
/* Fill in the data for "current time" in human_tz and human_tm */
290+
human_tz = local_time_tzoffset(now.tv_sec, &human_tm);
291+
}
292+
205293
if (mode->local)
206294
tz = local_tzoffset(time);
207295

@@ -258,14 +346,7 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
258346
strbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,
259347
!mode->local);
260348
else
261-
strbuf_addf(&timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d",
262-
weekday_names[tm->tm_wday],
263-
month_names[tm->tm_mon],
264-
tm->tm_mday,
265-
tm->tm_hour, tm->tm_min, tm->tm_sec,
266-
tm->tm_year + 1900,
267-
mode->local ? 0 : ' ',
268-
tz);
349+
show_date_normal(&timebuf, time, tm, tz, &human_tm, human_tz, mode->local);
269350
return timebuf.buf;
270351
}
271352

@@ -802,6 +883,11 @@ int parse_date(const char *date, struct strbuf *result)
802883
return 0;
803884
}
804885

886+
static int auto_date_style(void)
887+
{
888+
return (isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;
889+
}
890+
805891
static enum date_mode_type parse_date_type(const char *format, const char **end)
806892
{
807893
if (skip_prefix(format, "relative", end))
@@ -819,6 +905,10 @@ static enum date_mode_type parse_date_type(const char *format, const char **end)
819905
return DATE_SHORT;
820906
if (skip_prefix(format, "default", end))
821907
return DATE_NORMAL;
908+
if (skip_prefix(format, "human", end))
909+
return DATE_HUMAN;
910+
if (skip_prefix(format, "auto", end))
911+
return auto_date_style();
822912
if (skip_prefix(format, "raw", end))
823913
return DATE_RAW;
824914
if (skip_prefix(format, "unix", end))

0 commit comments

Comments
 (0)