Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge branch 'jk/date-mode-format'
Teach "git log" and friends a new "--date=format:..." option to
format timestamps using system's strftime(3).

* jk/date-mode-format:
  strbuf: make strbuf_addftime more robust
  introduce "format" date-mode
  convert "enum date_mode" into a struct
  show-branch: use DATE_RELATIVE instead of magic number
  • Loading branch information
Junio C Hamano committed Aug 3, 2015
2 parents 980a3d3 + e4f031e commit d939af1
Show file tree
Hide file tree
Showing 28 changed files with 172 additions and 78 deletions.
5 changes: 5 additions & 0 deletions Documentation/rev-list-options.txt
Expand Up @@ -727,6 +727,11 @@ format, often found in email messages.
+
`--date=raw` shows the date in the internal raw Git format `%s %z` format.
+
`--date=format:...` feeds the format `...` to your system `strftime`.
Use `--date=format:%c` to show the date in your system locale's
preferred format. See the `strftime` manual for a complete list of
format placeholders.
+
`--date=default` shows timestamps in the original time zone
(either committer's or author's).

Expand Down
2 changes: 1 addition & 1 deletion archive.c
Expand Up @@ -34,7 +34,7 @@ static void format_subst(const struct commit *commit,
char *to_free = NULL;
struct strbuf fmt = STRBUF_INIT;
struct pretty_print_context ctx = {0};
ctx.date_mode = DATE_NORMAL;
ctx.date_mode.type = DATE_NORMAL;
ctx.abbrev = DEFAULT_ABBREV;

if (src == buf->buf)
Expand Down
13 changes: 8 additions & 5 deletions builtin/blame.c
Expand Up @@ -51,7 +51,7 @@ static int xdl_opts;
static int abbrev = -1;
static int no_whole_file_rename;

static enum date_mode blame_date_mode = DATE_ISO8601;
static struct date_mode blame_date_mode = { DATE_ISO8601 };
static size_t blame_date_width;

static struct string_list mailmap;
Expand Down Expand Up @@ -1828,7 +1828,7 @@ static const char *format_time(unsigned long time, const char *tz_str,
size_t time_width;
int tz;
tz = atoi(tz_str);
time_str = show_date(time, tz, blame_date_mode);
time_str = show_date(time, tz, &blame_date_mode);
strbuf_addstr(&time_buf, time_str);
/*
* Add space paddings to time_buf to display a fixed width
Expand Down Expand Up @@ -2188,7 +2188,7 @@ static int git_blame_config(const char *var, const char *value, void *cb)
if (!strcmp(var, "blame.date")) {
if (!value)
return config_error_nonbool(var);
blame_date_mode = parse_date_format(value);
parse_date_format(value, &blame_date_mode);
return 0;
}

Expand Down Expand Up @@ -2570,13 +2570,13 @@ int cmd_blame(int argc, const char **argv, const char *prefix)

if (cmd_is_annotate) {
output_option |= OUTPUT_ANNOTATE_COMPAT;
blame_date_mode = DATE_ISO8601;
blame_date_mode.type = DATE_ISO8601;
} else {
blame_date_mode = revs.date_mode;
}

/* The maximum width used to show the dates */
switch (blame_date_mode) {
switch (blame_date_mode.type) {
case DATE_RFC2822:
blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700");
break;
Expand Down Expand Up @@ -2605,6 +2605,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
case DATE_NORMAL:
blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
break;
case DATE_STRFTIME:
blame_date_width = strlen(show_date(0, 0, &blame_date_mode)) + 1; /* add the null */
break;
}
blame_date_width -= 1; /* strip the null */

Expand Down
4 changes: 2 additions & 2 deletions builtin/commit.c
Expand Up @@ -856,7 +856,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
_("%s"
"Date: %s"),
ident_shown++ ? "" : "\n",
show_ident_date(&ai, DATE_NORMAL));
show_ident_date(&ai, DATE_MODE(NORMAL)));

if (!committer_ident_sufficiently_given())
status_printf_ln(s, GIT_COLOR_NORMAL,
Expand Down Expand Up @@ -1046,7 +1046,7 @@ static const char *find_author_by_nickname(const char *name)
commit = get_revision(&revs);
if (commit) {
struct pretty_print_context ctx = {0};
ctx.date_mode = DATE_NORMAL;
ctx.date_mode.type = DATE_NORMAL;
strbuf_release(&buf);
format_commit_message(commit, "%aN <%aE>", &buf, &ctx);
clear_mailmap(&mailmap);
Expand Down
4 changes: 2 additions & 2 deletions builtin/log.c
Expand Up @@ -116,7 +116,7 @@ static void cmd_log_init_defaults(struct rev_info *rev)
DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV);

if (default_date_mode)
rev->date_mode = parse_date_format(default_date_mode);
parse_date_format(default_date_mode, &rev->date_mode);
rev->diffopt.touched_flags = 0;
}

Expand Down Expand Up @@ -956,7 +956,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,

msg = body;
pp.fmt = CMIT_FMT_EMAIL;
pp.date_mode = DATE_RFC2822;
pp.date_mode.type = DATE_RFC2822;
pp_user_info(&pp, NULL, &sb, committer, encoding);
pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte);
pp_remainder(&pp, &msg, &sb, 0);
Expand Down
2 changes: 1 addition & 1 deletion builtin/shortlog.c
Expand Up @@ -138,7 +138,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
ctx.abbrev = log->abbrev;
ctx.subject = "";
ctx.after_subject = "";
ctx.date_mode = DATE_NORMAL;
ctx.date_mode.type = DATE_NORMAL;
ctx.output_encoding = get_log_output_encoding();
pretty_print_commit(&ctx, commit, &ufbuf);
buffer = ufbuf.buf;
Expand Down
3 changes: 2 additions & 1 deletion builtin/show-branch.c
Expand Up @@ -784,7 +784,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
else
msg++;
reflog_msg[i] = xstrfmt("(%s) %s",
show_date(timestamp, tz, 1),
show_date(timestamp, tz,
DATE_MODE(RELATIVE)),
msg);
free(logmsg);
sprintf(nth_desc, "%s@{%d}", *av, base+i);
Expand Down
37 changes: 25 additions & 12 deletions cache.h
Expand Up @@ -1049,18 +1049,30 @@ extern void *read_object_with_reference(const unsigned char *sha1,
extern struct object *peel_to_type(const char *name, int namelen,
struct object *o, enum object_type);

enum date_mode {
DATE_NORMAL = 0,
DATE_RELATIVE,
DATE_SHORT,
DATE_LOCAL,
DATE_ISO8601,
DATE_ISO8601_STRICT,
DATE_RFC2822,
DATE_RAW
struct date_mode {
enum date_mode_type {
DATE_NORMAL = 0,
DATE_RELATIVE,
DATE_SHORT,
DATE_LOCAL,
DATE_ISO8601,
DATE_ISO8601_STRICT,
DATE_RFC2822,
DATE_STRFTIME,
DATE_RAW
} type;
const char *strftime_fmt;
};

const char *show_date(unsigned long time, int timezone, enum date_mode mode);
/*
* Convenience helper for passing a constant type, like:
*
* show_date(t, tz, DATE_MODE(NORMAL));
*/
#define DATE_MODE(t) date_mode_from_type(DATE_##t)
struct date_mode *date_mode_from_type(enum date_mode_type type);

const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);
void show_date_relative(unsigned long time, int tz, const struct timeval *now,
struct strbuf *timebuf);
int parse_date(const char *date, struct strbuf *out);
Expand All @@ -1070,7 +1082,7 @@ void datestamp(struct strbuf *out);
#define approxidate(s) approxidate_careful((s), NULL)
unsigned long approxidate_careful(const char *, int *);
unsigned long approxidate_relative(const char *date, const struct timeval *now);
enum date_mode parse_date_format(const char *format);
void parse_date_format(const char *format, struct date_mode *mode);
int date_overflows(unsigned long date);

#define IDENT_STRICT 1
Expand Down Expand Up @@ -1107,7 +1119,8 @@ extern int split_ident_line(struct ident_split *, const char *, int);
* the ident_split. It will also sanity-check the values and produce
* a well-known sentinel date if they appear bogus.
*/
const char *show_ident_date(const struct ident_split *id, enum date_mode mode);
const char *show_ident_date(const struct ident_split *id,
const struct date_mode *mode);

/*
* Compare split idents for equality or strict ordering. Note that we
Expand Down
2 changes: 1 addition & 1 deletion commit.h
Expand Up @@ -145,7 +145,7 @@ struct pretty_print_context {
const char *subject;
const char *after_subject;
int preserve_subject;
enum date_mode date_mode;
struct date_mode date_mode;
unsigned date_mode_explicit:1;
int need_8bit_cte;
char *notes_message;
Expand Down
52 changes: 33 additions & 19 deletions date.c
Expand Up @@ -160,18 +160,27 @@ void show_date_relative(unsigned long time, int tz,
(diff + 183) / 365);
}

const char *show_date(unsigned long time, int tz, enum date_mode mode)
struct date_mode *date_mode_from_type(enum date_mode_type type)
{
static struct date_mode mode;
if (type == DATE_STRFTIME)
die("BUG: cannot create anonymous strftime date_mode struct");
mode.type = type;
return &mode;
}

const char *show_date(unsigned long time, int tz, const struct date_mode *mode)
{
struct tm *tm;
static struct strbuf timebuf = STRBUF_INIT;

if (mode == DATE_RAW) {
if (mode->type == DATE_RAW) {
strbuf_reset(&timebuf);
strbuf_addf(&timebuf, "%lu %+05d", time, tz);
return timebuf.buf;
}

if (mode == DATE_RELATIVE) {
if (mode->type == DATE_RELATIVE) {
struct timeval now;

strbuf_reset(&timebuf);
Expand All @@ -180,7 +189,7 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
return timebuf.buf;
}

if (mode == DATE_LOCAL)
if (mode->type == DATE_LOCAL)
tz = local_tzoffset(time);

tm = time_to_tm(time, tz);
Expand All @@ -190,17 +199,17 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
}

strbuf_reset(&timebuf);
if (mode == DATE_SHORT)
if (mode->type == DATE_SHORT)
strbuf_addf(&timebuf, "%04d-%02d-%02d", tm->tm_year + 1900,
tm->tm_mon + 1, tm->tm_mday);
else if (mode == DATE_ISO8601)
else if (mode->type == DATE_ISO8601)
strbuf_addf(&timebuf, "%04d-%02d-%02d %02d:%02d:%02d %+05d",
tm->tm_year + 1900,
tm->tm_mon + 1,
tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec,
tz);
else if (mode == DATE_ISO8601_STRICT) {
else if (mode->type == DATE_ISO8601_STRICT) {
char sign = (tz >= 0) ? '+' : '-';
tz = abs(tz);
strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
Expand All @@ -209,19 +218,21 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec,
sign, tz / 100, tz % 100);
} else if (mode == DATE_RFC2822)
} else if (mode->type == DATE_RFC2822)
strbuf_addf(&timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d",
weekday_names[tm->tm_wday], tm->tm_mday,
month_names[tm->tm_mon], tm->tm_year + 1900,
tm->tm_hour, tm->tm_min, tm->tm_sec, tz);
else if (mode->type == DATE_STRFTIME)
strbuf_addftime(&timebuf, mode->strftime_fmt, tm);
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 == DATE_LOCAL) ? 0 : ' ',
(mode->type == DATE_LOCAL) ? 0 : ' ',
tz);
return timebuf.buf;
}
Expand Down Expand Up @@ -759,28 +770,31 @@ int parse_date(const char *date, struct strbuf *result)
return 0;
}

enum date_mode parse_date_format(const char *format)
void parse_date_format(const char *format, struct date_mode *mode)
{
if (!strcmp(format, "relative"))
return DATE_RELATIVE;
mode->type = DATE_RELATIVE;
else if (!strcmp(format, "iso8601") ||
!strcmp(format, "iso"))
return DATE_ISO8601;
mode->type = DATE_ISO8601;
else if (!strcmp(format, "iso8601-strict") ||
!strcmp(format, "iso-strict"))
return DATE_ISO8601_STRICT;
mode->type = DATE_ISO8601_STRICT;
else if (!strcmp(format, "rfc2822") ||
!strcmp(format, "rfc"))
return DATE_RFC2822;
mode->type = DATE_RFC2822;
else if (!strcmp(format, "short"))
return DATE_SHORT;
mode->type = DATE_SHORT;
else if (!strcmp(format, "local"))
return DATE_LOCAL;
mode->type = DATE_LOCAL;
else if (!strcmp(format, "default"))
return DATE_NORMAL;
mode->type = DATE_NORMAL;
else if (!strcmp(format, "raw"))
return DATE_RAW;
else
mode->type = DATE_RAW;
else if (skip_prefix(format, "format:", &format)) {
mode->type = DATE_STRFTIME;
mode->strftime_fmt = xstrdup(format);
} else
die("unknown date format %s", format);
}

Expand Down
2 changes: 1 addition & 1 deletion fast-import.c
Expand Up @@ -423,7 +423,7 @@ static void write_crash_report(const char *err)
fprintf(rpt, "fast-import crash report:\n");
fprintf(rpt, " fast-import process: %"PRIuMAX"\n", (uintmax_t) getpid());
fprintf(rpt, " parent process : %"PRIuMAX"\n", (uintmax_t) getppid());
fprintf(rpt, " at %s\n", show_date(time(NULL), 0, DATE_LOCAL));
fprintf(rpt, " at %s\n", show_date(time(NULL), 0, DATE_MODE(LOCAL)));
fputc('\n', rpt);

fputs("fatal: ", rpt);
Expand Down
1 change: 1 addition & 0 deletions gettext.c
Expand Up @@ -162,6 +162,7 @@ void git_setup_gettext(void)
podir = GIT_LOCALE_PATH;
bindtextdomain("git", podir);
setlocale(LC_MESSAGES, "");
setlocale(LC_TIME, "");
init_gettext_charset("git");
textdomain("git");
}
Expand Down
2 changes: 1 addition & 1 deletion http-backend.c
Expand Up @@ -92,7 +92,7 @@ static void hdr_int(const char *name, uintmax_t value)

static void hdr_date(const char *name, unsigned long when)
{
const char *value = show_date(when, 0, DATE_RFC2822);
const char *value = show_date(when, 0, DATE_MODE(RFC2822));
hdr_str(name, value);
}

Expand Down
2 changes: 1 addition & 1 deletion log-tree.c
Expand Up @@ -640,7 +640,7 @@ void show_log(struct rev_info *opt)
*/
show_reflog_message(opt->reflog_info,
opt->commit_format == CMIT_FMT_ONELINE,
opt->date_mode,
&opt->date_mode,
opt->date_mode_explicit);
if (opt->commit_format == CMIT_FMT_ONELINE)
return;
Expand Down

0 comments on commit d939af1

Please sign in to comment.