Skip to content

Commit d939af1

Browse files
committed
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
2 parents 980a3d3 + e4f031e commit d939af1

28 files changed

+172
-78
lines changed

Documentation/rev-list-options.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,11 @@ format, often found in email messages.
727727
+
728728
`--date=raw` shows the date in the internal raw Git format `%s %z` format.
729729
+
730+
`--date=format:...` feeds the format `...` to your system `strftime`.
731+
Use `--date=format:%c` to show the date in your system locale's
732+
preferred format. See the `strftime` manual for a complete list of
733+
format placeholders.
734+
+
730735
`--date=default` shows timestamps in the original time zone
731736
(either committer's or author's).
732737

archive.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ static void format_subst(const struct commit *commit,
3434
char *to_free = NULL;
3535
struct strbuf fmt = STRBUF_INIT;
3636
struct pretty_print_context ctx = {0};
37-
ctx.date_mode = DATE_NORMAL;
37+
ctx.date_mode.type = DATE_NORMAL;
3838
ctx.abbrev = DEFAULT_ABBREV;
3939

4040
if (src == buf->buf)

builtin/blame.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ static int xdl_opts;
5151
static int abbrev = -1;
5252
static int no_whole_file_rename;
5353

54-
static enum date_mode blame_date_mode = DATE_ISO8601;
54+
static struct date_mode blame_date_mode = { DATE_ISO8601 };
5555
static size_t blame_date_width;
5656

5757
static struct string_list mailmap;
@@ -1828,7 +1828,7 @@ static const char *format_time(unsigned long time, const char *tz_str,
18281828
size_t time_width;
18291829
int tz;
18301830
tz = atoi(tz_str);
1831-
time_str = show_date(time, tz, blame_date_mode);
1831+
time_str = show_date(time, tz, &blame_date_mode);
18321832
strbuf_addstr(&time_buf, time_str);
18331833
/*
18341834
* Add space paddings to time_buf to display a fixed width
@@ -2188,7 +2188,7 @@ static int git_blame_config(const char *var, const char *value, void *cb)
21882188
if (!strcmp(var, "blame.date")) {
21892189
if (!value)
21902190
return config_error_nonbool(var);
2191-
blame_date_mode = parse_date_format(value);
2191+
parse_date_format(value, &blame_date_mode);
21922192
return 0;
21932193
}
21942194

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

25712571
if (cmd_is_annotate) {
25722572
output_option |= OUTPUT_ANNOTATE_COMPAT;
2573-
blame_date_mode = DATE_ISO8601;
2573+
blame_date_mode.type = DATE_ISO8601;
25742574
} else {
25752575
blame_date_mode = revs.date_mode;
25762576
}
25772577

25782578
/* The maximum width used to show the dates */
2579-
switch (blame_date_mode) {
2579+
switch (blame_date_mode.type) {
25802580
case DATE_RFC2822:
25812581
blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700");
25822582
break;
@@ -2605,6 +2605,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
26052605
case DATE_NORMAL:
26062606
blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
26072607
break;
2608+
case DATE_STRFTIME:
2609+
blame_date_width = strlen(show_date(0, 0, &blame_date_mode)) + 1; /* add the null */
2610+
break;
26082611
}
26092612
blame_date_width -= 1; /* strip the null */
26102613

builtin/commit.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
856856
_("%s"
857857
"Date: %s"),
858858
ident_shown++ ? "" : "\n",
859-
show_ident_date(&ai, DATE_NORMAL));
859+
show_ident_date(&ai, DATE_MODE(NORMAL)));
860860

861861
if (!committer_ident_sufficiently_given())
862862
status_printf_ln(s, GIT_COLOR_NORMAL,
@@ -1046,7 +1046,7 @@ static const char *find_author_by_nickname(const char *name)
10461046
commit = get_revision(&revs);
10471047
if (commit) {
10481048
struct pretty_print_context ctx = {0};
1049-
ctx.date_mode = DATE_NORMAL;
1049+
ctx.date_mode.type = DATE_NORMAL;
10501050
strbuf_release(&buf);
10511051
format_commit_message(commit, "%aN <%aE>", &buf, &ctx);
10521052
clear_mailmap(&mailmap);

builtin/log.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ static void cmd_log_init_defaults(struct rev_info *rev)
116116
DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV);
117117

118118
if (default_date_mode)
119-
rev->date_mode = parse_date_format(default_date_mode);
119+
parse_date_format(default_date_mode, &rev->date_mode);
120120
rev->diffopt.touched_flags = 0;
121121
}
122122

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

957957
msg = body;
958958
pp.fmt = CMIT_FMT_EMAIL;
959-
pp.date_mode = DATE_RFC2822;
959+
pp.date_mode.type = DATE_RFC2822;
960960
pp_user_info(&pp, NULL, &sb, committer, encoding);
961961
pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte);
962962
pp_remainder(&pp, &msg, &sb, 0);

builtin/shortlog.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
138138
ctx.abbrev = log->abbrev;
139139
ctx.subject = "";
140140
ctx.after_subject = "";
141-
ctx.date_mode = DATE_NORMAL;
141+
ctx.date_mode.type = DATE_NORMAL;
142142
ctx.output_encoding = get_log_output_encoding();
143143
pretty_print_commit(&ctx, commit, &ufbuf);
144144
buffer = ufbuf.buf;

builtin/show-branch.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
784784
else
785785
msg++;
786786
reflog_msg[i] = xstrfmt("(%s) %s",
787-
show_date(timestamp, tz, 1),
787+
show_date(timestamp, tz,
788+
DATE_MODE(RELATIVE)),
788789
msg);
789790
free(logmsg);
790791
sprintf(nth_desc, "%s@{%d}", *av, base+i);

cache.h

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,18 +1049,30 @@ extern void *read_object_with_reference(const unsigned char *sha1,
10491049
extern struct object *peel_to_type(const char *name, int namelen,
10501050
struct object *o, enum object_type);
10511051

1052-
enum date_mode {
1053-
DATE_NORMAL = 0,
1054-
DATE_RELATIVE,
1055-
DATE_SHORT,
1056-
DATE_LOCAL,
1057-
DATE_ISO8601,
1058-
DATE_ISO8601_STRICT,
1059-
DATE_RFC2822,
1060-
DATE_RAW
1052+
struct date_mode {
1053+
enum date_mode_type {
1054+
DATE_NORMAL = 0,
1055+
DATE_RELATIVE,
1056+
DATE_SHORT,
1057+
DATE_LOCAL,
1058+
DATE_ISO8601,
1059+
DATE_ISO8601_STRICT,
1060+
DATE_RFC2822,
1061+
DATE_STRFTIME,
1062+
DATE_RAW
1063+
} type;
1064+
const char *strftime_fmt;
10611065
};
10621066

1063-
const char *show_date(unsigned long time, int timezone, enum date_mode mode);
1067+
/*
1068+
* Convenience helper for passing a constant type, like:
1069+
*
1070+
* show_date(t, tz, DATE_MODE(NORMAL));
1071+
*/
1072+
#define DATE_MODE(t) date_mode_from_type(DATE_##t)
1073+
struct date_mode *date_mode_from_type(enum date_mode_type type);
1074+
1075+
const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);
10641076
void show_date_relative(unsigned long time, int tz, const struct timeval *now,
10651077
struct strbuf *timebuf);
10661078
int parse_date(const char *date, struct strbuf *out);
@@ -1070,7 +1082,7 @@ void datestamp(struct strbuf *out);
10701082
#define approxidate(s) approxidate_careful((s), NULL)
10711083
unsigned long approxidate_careful(const char *, int *);
10721084
unsigned long approxidate_relative(const char *date, const struct timeval *now);
1073-
enum date_mode parse_date_format(const char *format);
1085+
void parse_date_format(const char *format, struct date_mode *mode);
10741086
int date_overflows(unsigned long date);
10751087

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

11121125
/*
11131126
* Compare split idents for equality or strict ordering. Note that we

commit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ struct pretty_print_context {
145145
const char *subject;
146146
const char *after_subject;
147147
int preserve_subject;
148-
enum date_mode date_mode;
148+
struct date_mode date_mode;
149149
unsigned date_mode_explicit:1;
150150
int need_8bit_cte;
151151
char *notes_message;

date.c

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -160,18 +160,27 @@ void show_date_relative(unsigned long time, int tz,
160160
(diff + 183) / 365);
161161
}
162162

163-
const char *show_date(unsigned long time, int tz, enum date_mode mode)
163+
struct date_mode *date_mode_from_type(enum date_mode_type type)
164+
{
165+
static struct date_mode mode;
166+
if (type == DATE_STRFTIME)
167+
die("BUG: cannot create anonymous strftime date_mode struct");
168+
mode.type = type;
169+
return &mode;
170+
}
171+
172+
const char *show_date(unsigned long time, int tz, const struct date_mode *mode)
164173
{
165174
struct tm *tm;
166175
static struct strbuf timebuf = STRBUF_INIT;
167176

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

174-
if (mode == DATE_RELATIVE) {
183+
if (mode->type == DATE_RELATIVE) {
175184
struct timeval now;
176185

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

183-
if (mode == DATE_LOCAL)
192+
if (mode->type == DATE_LOCAL)
184193
tz = local_tzoffset(time);
185194

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

192201
strbuf_reset(&timebuf);
193-
if (mode == DATE_SHORT)
202+
if (mode->type == DATE_SHORT)
194203
strbuf_addf(&timebuf, "%04d-%02d-%02d", tm->tm_year + 1900,
195204
tm->tm_mon + 1, tm->tm_mday);
196-
else if (mode == DATE_ISO8601)
205+
else if (mode->type == DATE_ISO8601)
197206
strbuf_addf(&timebuf, "%04d-%02d-%02d %02d:%02d:%02d %+05d",
198207
tm->tm_year + 1900,
199208
tm->tm_mon + 1,
200209
tm->tm_mday,
201210
tm->tm_hour, tm->tm_min, tm->tm_sec,
202211
tz);
203-
else if (mode == DATE_ISO8601_STRICT) {
212+
else if (mode->type == DATE_ISO8601_STRICT) {
204213
char sign = (tz >= 0) ? '+' : '-';
205214
tz = abs(tz);
206215
strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
@@ -209,19 +218,21 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
209218
tm->tm_mday,
210219
tm->tm_hour, tm->tm_min, tm->tm_sec,
211220
sign, tz / 100, tz % 100);
212-
} else if (mode == DATE_RFC2822)
221+
} else if (mode->type == DATE_RFC2822)
213222
strbuf_addf(&timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d",
214223
weekday_names[tm->tm_wday], tm->tm_mday,
215224
month_names[tm->tm_mon], tm->tm_year + 1900,
216225
tm->tm_hour, tm->tm_min, tm->tm_sec, tz);
226+
else if (mode->type == DATE_STRFTIME)
227+
strbuf_addftime(&timebuf, mode->strftime_fmt, tm);
217228
else
218229
strbuf_addf(&timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d",
219230
weekday_names[tm->tm_wday],
220231
month_names[tm->tm_mon],
221232
tm->tm_mday,
222233
tm->tm_hour, tm->tm_min, tm->tm_sec,
223234
tm->tm_year + 1900,
224-
(mode == DATE_LOCAL) ? 0 : ' ',
235+
(mode->type == DATE_LOCAL) ? 0 : ' ',
225236
tz);
226237
return timebuf.buf;
227238
}
@@ -759,28 +770,31 @@ int parse_date(const char *date, struct strbuf *result)
759770
return 0;
760771
}
761772

762-
enum date_mode parse_date_format(const char *format)
773+
void parse_date_format(const char *format, struct date_mode *mode)
763774
{
764775
if (!strcmp(format, "relative"))
765-
return DATE_RELATIVE;
776+
mode->type = DATE_RELATIVE;
766777
else if (!strcmp(format, "iso8601") ||
767778
!strcmp(format, "iso"))
768-
return DATE_ISO8601;
779+
mode->type = DATE_ISO8601;
769780
else if (!strcmp(format, "iso8601-strict") ||
770781
!strcmp(format, "iso-strict"))
771-
return DATE_ISO8601_STRICT;
782+
mode->type = DATE_ISO8601_STRICT;
772783
else if (!strcmp(format, "rfc2822") ||
773784
!strcmp(format, "rfc"))
774-
return DATE_RFC2822;
785+
mode->type = DATE_RFC2822;
775786
else if (!strcmp(format, "short"))
776-
return DATE_SHORT;
787+
mode->type = DATE_SHORT;
777788
else if (!strcmp(format, "local"))
778-
return DATE_LOCAL;
789+
mode->type = DATE_LOCAL;
779790
else if (!strcmp(format, "default"))
780-
return DATE_NORMAL;
791+
mode->type = DATE_NORMAL;
781792
else if (!strcmp(format, "raw"))
782-
return DATE_RAW;
783-
else
793+
mode->type = DATE_RAW;
794+
else if (skip_prefix(format, "format:", &format)) {
795+
mode->type = DATE_STRFTIME;
796+
mode->strftime_fmt = xstrdup(format);
797+
} else
784798
die("unknown date format %s", format);
785799
}
786800

0 commit comments

Comments
 (0)