summaryrefslogtreecommitdiff
path: root/date.c
diff options
context:
space:
mode:
Diffstat (limited to 'date.c')
-rw-r--r--date.c66
1 files changed, 42 insertions, 24 deletions
diff --git a/date.c b/date.c
index 3eba2dfe88..8f9156909b 100644
--- a/date.c
+++ b/date.c
@@ -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);
@@ -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);
@@ -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",
@@ -209,11 +218,13 @@ 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],
@@ -221,7 +232,7 @@ 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,
tm->tm_year + 1900,
- (mode == DATE_LOCAL) ? 0 : ' ',
+ (mode->type == DATE_LOCAL) ? 0 : ' ',
tz);
return timebuf.buf;
}
@@ -704,10 +715,17 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)
date += match;
}
- /* mktime uses local timezone */
+ /* do not use mktime(), which uses local timezone, here */
*timestamp = tm_to_time_t(&tm);
+ if (*timestamp == -1)
+ return -1;
+
if (*offset == -1) {
- time_t temp_time = mktime(&tm);
+ time_t temp_time;
+
+ /* gmtime_r() in match_digit() may have clobbered it */
+ tm.tm_isdst = -1;
+ temp_time = mktime(&tm);
if ((time_t)*timestamp > temp_time) {
*offset = ((time_t)*timestamp - temp_time) / 60;
} else {
@@ -715,9 +733,6 @@ int parse_date_basic(const char *date, unsigned long *timestamp, int *offset)
}
}
- if (*timestamp == -1)
- return -1;
-
if (!tm_gmt)
*timestamp -= *offset * 60;
return 0; /* success */
@@ -755,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);
}