Merge branch 'rs/strbuf-addftime-zZ'
As there is no portable way to pass timezone information to strftime, some output format from "git log" and friends are impossible to produce. Teach our own strbuf_addftime to replace %z and %Z with caller-supplied values to help working around this. * rs/strbuf-addftime-zZ: date: use localtime() for "-local" time formats t0006: check --date=format zone offsets strbuf: let strbuf_addftime handle %z and %Z itself
This commit is contained in:
commit
9eafe86d58
@ -769,7 +769,8 @@ timezone value.
|
|||||||
1970). As with `--raw`, this is always in UTC and therefore `-local`
|
1970). As with `--raw`, this is always in UTC and therefore `-local`
|
||||||
has no effect.
|
has no effect.
|
||||||
+
|
+
|
||||||
`--date=format:...` feeds the format `...` to your system `strftime`.
|
`--date=format:...` feeds the format `...` to your system `strftime`,
|
||||||
|
except for %z and %Z, which are handled internally.
|
||||||
Use `--date=format:%c` to show the date in your system locale's
|
Use `--date=format:%c` to show the date in your system locale's
|
||||||
preferred format. See the `strftime` manual for a complete list of
|
preferred format. See the `strftime` manual for a complete list of
|
||||||
format placeholders. When using `-local`, the correct syntax is
|
format placeholders. When using `-local`, the correct syntax is
|
||||||
|
14
date.c
14
date.c
@ -70,6 +70,12 @@ static struct tm *time_to_tm(timestamp_t time, int tz)
|
|||||||
return gmtime(&t);
|
return gmtime(&t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct tm *time_to_tm_local(timestamp_t time)
|
||||||
|
{
|
||||||
|
time_t t = time;
|
||||||
|
return localtime(&t);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* What value of "tz" was in effect back then at "time" in the
|
* What value of "tz" was in effect back then at "time" in the
|
||||||
* local timezone?
|
* local timezone?
|
||||||
@ -214,7 +220,10 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
|
|||||||
return timebuf.buf;
|
return timebuf.buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
tm = time_to_tm(time, tz);
|
if (mode->local)
|
||||||
|
tm = time_to_tm_local(time);
|
||||||
|
else
|
||||||
|
tm = time_to_tm(time, tz);
|
||||||
if (!tm) {
|
if (!tm) {
|
||||||
tm = time_to_tm(0, 0);
|
tm = time_to_tm(0, 0);
|
||||||
tz = 0;
|
tz = 0;
|
||||||
@ -246,7 +255,8 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
|
|||||||
month_names[tm->tm_mon], tm->tm_year + 1900,
|
month_names[tm->tm_mon], tm->tm_year + 1900,
|
||||||
tm->tm_hour, tm->tm_min, tm->tm_sec, tz);
|
tm->tm_hour, tm->tm_min, tm->tm_sec, tz);
|
||||||
else if (mode->type == DATE_STRFTIME)
|
else if (mode->type == DATE_STRFTIME)
|
||||||
strbuf_addftime(&timebuf, mode->strftime_fmt, tm);
|
strbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,
|
||||||
|
mode->local ? NULL : "");
|
||||||
else
|
else
|
||||||
strbuf_addf(&timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d",
|
strbuf_addf(&timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d",
|
||||||
weekday_names[tm->tm_wday],
|
weekday_names[tm->tm_wday],
|
||||||
|
41
strbuf.c
41
strbuf.c
@ -785,14 +785,48 @@ char *xstrfmt(const char *fmt, ...)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm)
|
void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
|
||||||
|
int tz_offset, const char *tz_name)
|
||||||
{
|
{
|
||||||
|
struct strbuf munged_fmt = STRBUF_INIT;
|
||||||
size_t hint = 128;
|
size_t hint = 128;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
if (!*fmt)
|
if (!*fmt)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There is no portable way to pass timezone information to
|
||||||
|
* strftime, so we handle %z and %Z here.
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
const char *percent = strchrnul(fmt, '%');
|
||||||
|
strbuf_add(&munged_fmt, fmt, percent - fmt);
|
||||||
|
if (!*percent)
|
||||||
|
break;
|
||||||
|
fmt = percent + 1;
|
||||||
|
switch (*fmt) {
|
||||||
|
case '%':
|
||||||
|
strbuf_addstr(&munged_fmt, "%%");
|
||||||
|
fmt++;
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
strbuf_addf(&munged_fmt, "%+05d", tz_offset);
|
||||||
|
fmt++;
|
||||||
|
break;
|
||||||
|
case 'Z':
|
||||||
|
if (tz_name) {
|
||||||
|
strbuf_addstr(&munged_fmt, tz_name);
|
||||||
|
fmt++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
default:
|
||||||
|
strbuf_addch(&munged_fmt, '%');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt = munged_fmt.buf;
|
||||||
|
|
||||||
strbuf_grow(sb, hint);
|
strbuf_grow(sb, hint);
|
||||||
len = strftime(sb->buf + sb->len, sb->alloc - sb->len, fmt, tm);
|
len = strftime(sb->buf + sb->len, sb->alloc - sb->len, fmt, tm);
|
||||||
|
|
||||||
@ -804,17 +838,16 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm)
|
|||||||
* output contains at least one character, and then drop the extra
|
* output contains at least one character, and then drop the extra
|
||||||
* character before returning.
|
* character before returning.
|
||||||
*/
|
*/
|
||||||
struct strbuf munged_fmt = STRBUF_INIT;
|
strbuf_addch(&munged_fmt, ' ');
|
||||||
strbuf_addf(&munged_fmt, "%s ", fmt);
|
|
||||||
while (!len) {
|
while (!len) {
|
||||||
hint *= 2;
|
hint *= 2;
|
||||||
strbuf_grow(sb, hint);
|
strbuf_grow(sb, hint);
|
||||||
len = strftime(sb->buf + sb->len, sb->alloc - sb->len,
|
len = strftime(sb->buf + sb->len, sb->alloc - sb->len,
|
||||||
munged_fmt.buf, tm);
|
munged_fmt.buf, tm);
|
||||||
}
|
}
|
||||||
strbuf_release(&munged_fmt);
|
|
||||||
len--; /* drop munged space */
|
len--; /* drop munged space */
|
||||||
}
|
}
|
||||||
|
strbuf_release(&munged_fmt);
|
||||||
strbuf_setlen(sb, sb->len + len);
|
strbuf_setlen(sb, sb->len + len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
strbuf.h
8
strbuf.h
@ -340,8 +340,14 @@ extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the time specified by `tm`, as formatted by `strftime`.
|
* Add the time specified by `tm`, as formatted by `strftime`.
|
||||||
|
* `tz_name` is used to expand %Z internally unless it's NULL.
|
||||||
|
* `tz_offset` is in decimal hhmm format, e.g. -600 means six hours west
|
||||||
|
* of Greenwich, and it's used to expand %z internally. However, tokens
|
||||||
|
* with modifiers (e.g. %Ez) are passed to `strftime`.
|
||||||
*/
|
*/
|
||||||
extern void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm);
|
extern void strbuf_addftime(struct strbuf *sb, const char *fmt,
|
||||||
|
const struct tm *tm, int tz_offset,
|
||||||
|
const char *tz_name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a given size of data from a FILE* pointer to the buffer.
|
* Read a given size of data from a FILE* pointer to the buffer.
|
||||||
|
@ -31,9 +31,11 @@ check_show () {
|
|||||||
format=$1
|
format=$1
|
||||||
time=$2
|
time=$2
|
||||||
expect=$3
|
expect=$3
|
||||||
test_expect_success $4 "show date ($format:$time)" '
|
prereqs=$4
|
||||||
|
zone=$5
|
||||||
|
test_expect_success $prereqs "show date ($format:$time)" '
|
||||||
echo "$time -> $expect" >expect &&
|
echo "$time -> $expect" >expect &&
|
||||||
test-date show:$format "$time" >actual &&
|
TZ=${zone:-$TZ} test-date show:"$format" "$time" >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
}
|
}
|
||||||
@ -51,6 +53,16 @@ check_show iso-local "$TIME" '2016-06-15 14:13:20 +0000'
|
|||||||
check_show raw-local "$TIME" '1466000000 +0000'
|
check_show raw-local "$TIME" '1466000000 +0000'
|
||||||
check_show unix-local "$TIME" '1466000000'
|
check_show unix-local "$TIME" '1466000000'
|
||||||
|
|
||||||
|
check_show 'format:%z' "$TIME" '+0200'
|
||||||
|
check_show 'format-local:%z' "$TIME" '+0000'
|
||||||
|
check_show 'format:%Z' "$TIME" ''
|
||||||
|
check_show 'format-local:%Z' "$TIME" 'UTC'
|
||||||
|
check_show 'format:%%z' "$TIME" '%z'
|
||||||
|
check_show 'format-local:%%z' "$TIME" '%z'
|
||||||
|
|
||||||
|
check_show 'format:%Y-%m-%d %H:%M:%S' "$TIME" '2016-06-15 16:13:20'
|
||||||
|
check_show 'format-local:%Y-%m-%d %H:%M:%S' "$TIME" '2016-06-15 09:13:20' '' EST5
|
||||||
|
|
||||||
# arbitrary time absurdly far in the future
|
# arbitrary time absurdly far in the future
|
||||||
FUTURE="5758122296 -0400"
|
FUTURE="5758122296 -0400"
|
||||||
check_show iso "$FUTURE" "2152-06-19 18:24:56 -0400" TIME_IS_64BIT,TIME_T_IS_64BIT
|
check_show iso "$FUTURE" "2152-06-19 18:24:56 -0400" TIME_IS_64BIT,TIME_T_IS_64BIT
|
||||||
|
Loading…
Reference in New Issue
Block a user