t6300: add tests for "-local" date formats
[gitweb.git] / date.c
diff --git a/date.c b/date.c
index 733d1b29b19fc7dda04d599eb6a311e809212775..7c9f76998ac7a00fb5f8781dd8e460f899edbfac 100644 (file)
--- a/date.c
+++ b/date.c
@@ -160,18 +160,31 @@ 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;
+       mode.local = 0;
+       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->local)
+               tz = local_tzoffset(time);
+
+       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,9 +193,6 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
                return timebuf.buf;
        }
 
-       if (mode == DATE_LOCAL)
-               tz = local_tzoffset(time);
-
        tm = time_to_tm(time, tz);
        if (!tm) {
                tm = time_to_tm(0, 0);
@@ -190,17 +200,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 +219,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 +233,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->local ? 0 : ' ',
                                tz);
        return timebuf.buf;
 }
@@ -759,28 +771,50 @@ int parse_date(const char *date, struct strbuf *result)
        return 0;
 }
 
-enum date_mode parse_date_format(const char *format)
+static enum date_mode_type parse_date_type(const char *format, const char **end)
 {
-       if (!strcmp(format, "relative"))
+       if (skip_prefix(format, "relative", end))
                return DATE_RELATIVE;
-       else if (!strcmp(format, "iso8601") ||
-                !strcmp(format, "iso"))
-               return DATE_ISO8601;
-       else if (!strcmp(format, "iso8601-strict") ||
-                !strcmp(format, "iso-strict"))
+       if (skip_prefix(format, "iso8601-strict", end) ||
+           skip_prefix(format, "iso-strict", end))
                return DATE_ISO8601_STRICT;
-       else if (!strcmp(format, "rfc2822") ||
-                !strcmp(format, "rfc"))
+       if (skip_prefix(format, "iso8601", end) ||
+           skip_prefix(format, "iso", end))
+               return DATE_ISO8601;
+       if (skip_prefix(format, "rfc2822", end) ||
+           skip_prefix(format, "rfc", end))
                return DATE_RFC2822;
-       else if (!strcmp(format, "short"))
+       if (skip_prefix(format, "short", end))
                return DATE_SHORT;
-       else if (!strcmp(format, "local"))
-               return DATE_LOCAL;
-       else if (!strcmp(format, "default"))
+       if (skip_prefix(format, "default", end))
                return DATE_NORMAL;
-       else if (!strcmp(format, "raw"))
+       if (skip_prefix(format, "raw", end))
                return DATE_RAW;
-       else
+       if (skip_prefix(format, "format", end))
+               return DATE_STRFTIME;
+
+       die("unknown date format %s", format);
+}
+
+void parse_date_format(const char *format, struct date_mode *mode)
+{
+       const char *p;
+
+       /* historical alias */
+       if (!strcmp(format, "local"))
+               format = "default-local";
+
+       mode->type = parse_date_type(format, &p);
+       mode->local = 0;
+
+       if (skip_prefix(p, "-local", &p))
+               mode->local = 1;
+
+       if (mode->type == DATE_STRFTIME) {
+               if (!skip_prefix(p, ":", &p))
+                       die("date format missing colon separator: %s", format);
+               mode->strftime_fmt = xstrdup(p);
+       } else if (*p)
                die("unknown date format %s", format);
 }