{"thread":{"id":"40221","subject":"[RFC/PATCH] date: allow any format to display local time","startedAt":"2015-08-30T13:54:50Z","lastAt":"2015-09-08T07:53:43Z","messageCount":59,"participants":["John Keeping","Junio C Hamano","Jeff King","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"268933","messageId":"d3b9f8f6524e45c9fc7a3e104669572c8c4ddd8a.1440942688.git.john@keeping.me.uk","threadId":"40221","inReplyTo":null,"subject":"[RFC/PATCH] date: allow any format to display local time","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-08-30T13:54:50Z","receivedAt":"2015-08-30T13:54:50Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"Make DATE_LOCAL a bit flag that may be combined with the other formats.\nIn order to keep date_mode_type as a true enumeration the possible\ncombinations are included explicitly (except \"relative local time\" which\nis nonsensical).\n\nSigned-off-by: John Keeping <john@keeping.me.uk>\n---\nI primarily want this to make life easier in CGit (so that we can reuse\nlibgit.a for formatting dates in the originator's timezone), but I think\nit makes sense to expose these options to the user in general.\n\n builtin/blame.c |  3 +--\n cache.h         |  9 +++++++--\n date.c          | 31 ++++++++++++++++++++++++-------\n 3 files changed, 32 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 4db01c1..dff6934 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2575,7 +2575,7 @@ parse_done:\n \t}\n \n \t/* The maximum width used to show the dates */\n-\tswitch (blame_date_mode.type) {\n+\tswitch (blame_date_mode.type & ~DATE_LOCAL) {\n \tcase DATE_RFC2822:\n \t\tblame_date_width = sizeof(\"Thu, 19 Oct 2006 16:00:04 -0700\");\n \t\tbreak;\n@@ -2600,7 +2600,6 @@ parse_done:\n \t\t   fewer display columns. */\n \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n \t\tbreak;\n-\tcase DATE_LOCAL:\n \tcase DATE_NORMAL:\n \t\tblame_date_width = sizeof(\"Thu Oct 19 16:00:04 2006 -0700\");\n \t\tbreak;\ndiff --git a/cache.h b/cache.h\nindex 4e25271..cda5c51 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1091,12 +1091,17 @@ struct date_mode {\n \t\tDATE_NORMAL = 0,\n \t\tDATE_RELATIVE,\n \t\tDATE_SHORT,\n-\t\tDATE_LOCAL,\n \t\tDATE_ISO8601,\n \t\tDATE_ISO8601_STRICT,\n \t\tDATE_RFC2822,\n \t\tDATE_STRFTIME,\n-\t\tDATE_RAW\n+\t\tDATE_RAW,\n+\t\tDATE_LOCAL = 0x80,\n+\t\tDATE_SHORT_LOCAL = (DATE_SHORT | DATE_LOCAL),\n+\t\tDATE_ISO8601_LOCAL = (DATE_ISO8601 | DATE_LOCAL),\n+\t\tDATE_ISO8601_STRICT_LOCAL = (DATE_ISO8601_STRICT | DATE_LOCAL),\n+\t\tDATE_RFC2822_LOCAL = (DATE_RFC2822 | DATE_LOCAL),\n+\t\tDATE_STRFTIME_LOCAL = (DATE_STRFTIME | DATE_LOCAL),\n \t} type;\n \tconst char *strftime_fmt;\n };\ndiff --git a/date.c b/date.c\nindex 8f91569..e0e0f3b 100644\n--- a/date.c\n+++ b/date.c\n@@ -163,7 +163,7 @@ void show_date_relative(unsigned long time, int tz,\n struct date_mode *date_mode_from_type(enum date_mode_type type)\n {\n \tstatic struct date_mode mode;\n-\tif (type == DATE_STRFTIME)\n+\tif (type == DATE_STRFTIME || type == DATE_STRFTIME_LOCAL)\n \t\tdie(\"BUG: cannot create anonymous strftime date_mode struct\");\n \tmode.type = type;\n \treturn &mode;\n@@ -173,6 +173,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n {\n \tstruct tm *tm;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n+\tenum date_mode_type type = mode->type;\n \n \tif (mode->type == DATE_RAW) {\n \t\tstrbuf_reset(&timebuf);\n@@ -189,8 +190,10 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \t\treturn timebuf.buf;\n \t}\n \n-\tif (mode->type == DATE_LOCAL)\n+\tif (type & DATE_LOCAL) {\n \t\ttz = local_tzoffset(time);\n+\t\ttype &= ~DATE_LOCAL;\n+\t}\n \n \ttm = time_to_tm(time, tz);\n \tif (!tm) {\n@@ -199,17 +202,17 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \t}\n \n \tstrbuf_reset(&timebuf);\n-\tif (mode->type == DATE_SHORT)\n+\tif (type == DATE_SHORT)\n \t\tstrbuf_addf(&timebuf, \"%04d-%02d-%02d\", tm->tm_year + 1900,\n \t\t\t\ttm->tm_mon + 1, tm->tm_mday);\n-\telse if (mode->type == DATE_ISO8601)\n+\telse if (type == DATE_ISO8601)\n \t\tstrbuf_addf(&timebuf, \"%04d-%02d-%02d %02d:%02d:%02d %+05d\",\n \t\t\t\ttm->tm_year + 1900,\n \t\t\t\ttm->tm_mon + 1,\n \t\t\t\ttm->tm_mday,\n \t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n \t\t\t\ttz);\n-\telse if (mode->type == DATE_ISO8601_STRICT) {\n+\telse if (type == DATE_ISO8601_STRICT) {\n \t\tchar sign = (tz >= 0) ? '+' : '-';\n \t\ttz = abs(tz);\n \t\tstrbuf_addf(&timebuf, \"%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d\",\n@@ -218,12 +221,12 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \t\t\t\ttm->tm_mday,\n \t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n \t\t\t\tsign, tz / 100, tz % 100);\n-\t} else if (mode->type == DATE_RFC2822)\n+\t} else if (type == DATE_RFC2822)\n \t\tstrbuf_addf(&timebuf, \"%.3s, %d %.3s %d %02d:%02d:%02d %+05d\",\n \t\t\tweekday_names[tm->tm_wday], tm->tm_mday,\n \t\t\tmonth_names[tm->tm_mon], tm->tm_year + 1900,\n \t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec, tz);\n-\telse if (mode->type == DATE_STRFTIME)\n+\telse if (type == DATE_STRFTIME)\n \t\tstrbuf_addftime(&timebuf, mode->strftime_fmt, tm);\n \telse\n \t\tstrbuf_addf(&timebuf, \"%.3s %.3s %d %02d:%02d:%02d %d%c%+05d\",\n@@ -777,14 +780,25 @@ void parse_date_format(const char *format, struct date_mode *mode)\n \telse if (!strcmp(format, \"iso8601\") ||\n \t\t !strcmp(format, \"iso\"))\n \t\tmode->type = DATE_ISO8601;\n+\telse if (!strcmp(format, \"iso8601-local\") ||\n+\t\t !strcmp(format, \"iso-local\"))\n+\t\tmode->type = DATE_ISO8601_LOCAL;\n \telse if (!strcmp(format, \"iso8601-strict\") ||\n \t\t !strcmp(format, \"iso-strict\"))\n \t\tmode->type = DATE_ISO8601_STRICT;\n+\telse if (!strcmp(format, \"iso8601-strict-local\") ||\n+\t\t !strcmp(format, \"iso-strict-local\"))\n+\t\tmode->type = DATE_ISO8601_STRICT_LOCAL;\n \telse if (!strcmp(format, \"rfc2822\") ||\n \t\t !strcmp(format, \"rfc\"))\n \t\tmode->type = DATE_RFC2822;\n+\telse if (!strcmp(format, \"rfc2822-local\") ||\n+\t\t !strcmp(format, \"rfc-local\"))\n+\t\tmode->type = DATE_RFC2822_LOCAL;\n \telse if (!strcmp(format, \"short\"))\n \t\tmode->type = DATE_SHORT;\n+\telse if (!strcmp(format, \"short-local\"))\n+\t\tmode->type = DATE_SHORT_LOCAL;\n \telse if (!strcmp(format, \"local\"))\n \t\tmode->type = DATE_LOCAL;\n \telse if (!strcmp(format, \"default\"))\n@@ -794,6 +808,9 @@ void parse_date_format(const char *format, struct date_mode *mode)\n \telse if (skip_prefix(format, \"format:\", &format)) {\n \t\tmode->type = DATE_STRFTIME;\n \t\tmode->strftime_fmt = xstrdup(format);\n+\t} else if (skip_prefix(format, \"format-local:\", &format)) {\n+\t\tmode->type = DATE_STRFTIME_LOCAL;\n+\t\tmode->strftime_fmt = xstrdup(format);\n \t} else\n \t\tdie(\"unknown date format %s\", format);\n }\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269006","messageId":"xmqqtwrfweo7.fsf@gitster.mtv.corp.google.com","threadId":"40221","inReplyTo":"d3b9f8f6524e45c9fc7a3e104669572c8c4ddd8a.1440942688.git.john@keeping.me.uk","subject":"Re: [RFC/PATCH] date: allow any format to display local time","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-08-31T17:28:24Z","receivedAt":"2015-08-31T17:28:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"John Keeping <john@keeping.me.uk> writes:\n\n> Make DATE_LOCAL a bit flag that may be combined with the other formats.\n> In order to keep date_mode_type as a true enumeration the possible\n> combinations are included explicitly (except \"relative local time\" which\n> is nonsensical).\n>\n> Signed-off-by: John Keeping <john@keeping.me.uk>\n> ---\n\nThis needs to be CC'ed to the author of a5481a6c (convert \"enum\ndate_mode\" into a struct, 2015-06-25), which I just did.\n\nI am unhappy with the change to blame.c, and that is not because I\ndo not want \"blame\" to be touched.\n\nThe fact that this change has to touch it indicates that it is easy\nfor other new callers of date formatting code to forget masking\nDATE_LOCAL bit like this patch does when they want to change their\nbehaviour based on the settings of date-mode.  And it would be hard\nto catch such a subtle breakage during future reviews.\n\n> diff --git a/builtin/blame.c b/builtin/blame.c\n> index 4db01c1..dff6934 100644\n> --- a/builtin/blame.c\n> +++ b/builtin/blame.c\n> @@ -2575,7 +2575,7 @@ parse_done:\n>  \t}\n>  \n>  \t/* The maximum width used to show the dates */\n> -\tswitch (blame_date_mode.type) {\n> +\tswitch (blame_date_mode.type & ~DATE_LOCAL) {\n>  \tcase DATE_RFC2822:\n>  \t\tblame_date_width = sizeof(\"Thu, 19 Oct 2006 16:00:04 -0700\");\n>  \t\tbreak;\n> @@ -2600,7 +2600,6 @@ parse_done:\n>  \t\t   fewer display columns. */\n>  \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n>  \t\tbreak;\n> -\tcase DATE_LOCAL:\n>  \tcase DATE_NORMAL:\n>  \t\tblame_date_width = sizeof(\"Thu Oct 19 16:00:04 2006 -0700\");\n>  \t\tbreak;\n\n> diff --git a/cache.h b/cache.h\n> index 4e25271..cda5c51 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -1091,12 +1091,17 @@ struct date_mode {\n>  \t\tDATE_NORMAL = 0,\n>  \t\tDATE_RELATIVE,\n>  \t\tDATE_SHORT,\n> -\t\tDATE_LOCAL,\n>  \t\tDATE_ISO8601,\n>  \t\tDATE_ISO8601_STRICT,\n>  \t\tDATE_RFC2822,\n>  \t\tDATE_STRFTIME,\n> -\t\tDATE_RAW\n> +\t\tDATE_RAW,\n> +\t\tDATE_LOCAL = 0x80,\n> +\t\tDATE_SHORT_LOCAL = (DATE_SHORT | DATE_LOCAL),\n> +\t\tDATE_ISO8601_LOCAL = (DATE_ISO8601 | DATE_LOCAL),\n> +\t\tDATE_ISO8601_STRICT_LOCAL = (DATE_ISO8601_STRICT | DATE_LOCAL),\n> +\t\tDATE_RFC2822_LOCAL = (DATE_RFC2822 | DATE_LOCAL),\n> +\t\tDATE_STRFTIME_LOCAL = (DATE_STRFTIME | DATE_LOCAL),\n>  \t} type;\n>  \tconst char *strftime_fmt;\n>  };\n\nI agree that among \"enum date_mode_type\", DATE_LOCAL is an oddball.\nIt should be able to act as an orthogonal and independent flag with\nat least some, like NORMAL, SHORT, etc.  Specifying DATE_LOCAL with\nsome others at the same time, however, would not make much sense,\nwould it?  What does it even mean to say time as relative under\nDATE_LOCAL bit?\n\nBut this point is minor.  A bigger design issue is in show_date()\nbelow.\n\n> diff --git a/date.c b/date.c\n> index 8f91569..e0e0f3b 100644\n> --- a/date.c\n> +++ b/date.c\n> @@ -163,7 +163,7 @@ void show_date_relative(unsigned long time, int tz,\n>  struct date_mode *date_mode_from_type(enum date_mode_type type)\n>  {\n>  \tstatic struct date_mode mode;\n> -\tif (type == DATE_STRFTIME)\n> +\tif (type == DATE_STRFTIME || type == DATE_STRFTIME_LOCAL)\n>  \t\tdie(\"BUG: cannot create anonymous strftime date_mode struct\");\n>  \tmode.type = type;\n>  \treturn &mode;\n> @@ -173,6 +173,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n>  {\n>  \tstruct tm *tm;\n>  \tstatic struct strbuf timebuf = STRBUF_INIT;\n> +\tenum date_mode_type type = mode->type;\n>  \n>  \tif (mode->type == DATE_RAW) {\n>  \t\tstrbuf_reset(&timebuf);\n> @@ -189,8 +190,10 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n>  \t\treturn timebuf.buf;\n>  \t}\n>  \n> -\tif (mode->type == DATE_LOCAL)\n> +\tif (type & DATE_LOCAL) {\n>  \t\ttz = local_tzoffset(time);\n> +\t\ttype &= ~DATE_LOCAL;\n> +\t}\n>  \n>  \ttm = time_to_tm(time, tz);\n>  \tif (!tm) {\n> @@ -199,17 +202,17 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n>  \t}\n>  \n>  \tstrbuf_reset(&timebuf);\n> -\tif (mode->type == DATE_SHORT)\n> +\tif (type == DATE_SHORT)\n>  \t\tstrbuf_addf(&timebuf, \"%04d-%02d-%02d\", tm->tm_year + 1900,\n>  \t\t\t\ttm->tm_mon + 1, tm->tm_mday);\n> -\telse if (mode->type == DATE_ISO8601)\n> +\telse if (type == DATE_ISO8601)\n>  \t\tstrbuf_addf(&timebuf, \"%04d-%02d-%02d %02d:%02d:%02d %+05d\",\n>  \t\t\t\ttm->tm_year + 1900,\n>  \t\t\t\ttm->tm_mon + 1,\n>  \t\t\t\ttm->tm_mday,\n>  \t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n>  \t\t\t\ttz);\n> -\telse if (mode->type == DATE_ISO8601_STRICT) {\n> +\telse if (type == DATE_ISO8601_STRICT) {\n>  \t\tchar sign = (tz >= 0) ? '+' : '-';\n>  \t\ttz = abs(tz);\n>  \t\tstrbuf_addf(&timebuf, \"%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d\",\n> @@ -218,12 +221,12 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n>  \t\t\t\ttm->tm_mday,\n>  \t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n>  \t\t\t\tsign, tz / 100, tz % 100);\n> -\t} else if (mode->type == DATE_RFC2822)\n> +\t} else if (type == DATE_RFC2822)\n>  \t\tstrbuf_addf(&timebuf, \"%.3s, %d %.3s %d %02d:%02d:%02d %+05d\",\n>  \t\t\tweekday_names[tm->tm_wday], tm->tm_mday,\n>  \t\t\tmonth_names[tm->tm_mon], tm->tm_year + 1900,\n>  \t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec, tz);\n> -\telse if (mode->type == DATE_STRFTIME)\n> +\telse if (type == DATE_STRFTIME)\n>  \t\tstrbuf_addftime(&timebuf, mode->strftime_fmt, tm);\n>  \telse\n>  \t\tstrbuf_addf(&timebuf, \"%.3s %.3s %d %02d:%02d:%02d %d%c%+05d\",\n\nWhat cannot be seen in the post-context of this hunk is that we\ndeliberately drop the timezone information when tweaking the\n\"normal\" format to \"local\".  This is done only in the final else\nclause in show_date() because the code knows that LOCAL is not an\nindependent bit.\n\nI think the original motivation is that there is no need to show the\ntimezone information when the user knows the time is shown in the\nlocal timezone---after all, the --date=local option was given by her\nin the first place.  This kind of tweaking should be made consistent\nwith other variants, now the other variants are interacting with\nthis LOCAL bit.  If we were to go forward with this patch, I think\nwe probably should remove this special casing of \"showing normal\ndate in localzone, drop the zone information\", as we cannot sanely\ndrop the TZ offset from the output of some of the formats and stay\nvalid (e.g RFC2822).\n\n> @@ -777,14 +780,25 @@ void parse_date_format(const char *format, struct date_mode *mode)\n>  \telse if (!strcmp(format, \"iso8601\") ||\n>  \t\t !strcmp(format, \"iso\"))\n>  \t\tmode->type = DATE_ISO8601;\n> +\telse if (!strcmp(format, \"iso8601-local\") ||\n> +\t\t !strcmp(format, \"iso-local\"))\n> +\t\tmode->type = DATE_ISO8601_LOCAL;\n>  \telse if (!strcmp(format, \"iso8601-strict\") ||\n>  \t\t !strcmp(format, \"iso-strict\"))\n>  \t\tmode->type = DATE_ISO8601_STRICT;\n> +\telse if (!strcmp(format, \"iso8601-strict-local\") ||\n> +\t\t !strcmp(format, \"iso-strict-local\"))\n> +\t\tmode->type = DATE_ISO8601_STRICT_LOCAL;\n>  \telse if (!strcmp(format, \"rfc2822\") ||\n>  \t\t !strcmp(format, \"rfc\"))\n>  \t\tmode->type = DATE_RFC2822;\n> +\telse if (!strcmp(format, \"rfc2822-local\") ||\n> +\t\t !strcmp(format, \"rfc-local\"))\n> +\t\tmode->type = DATE_RFC2822_LOCAL;\n>  \telse if (!strcmp(format, \"short\"))\n>  \t\tmode->type = DATE_SHORT;\n> +\telse if (!strcmp(format, \"short-local\"))\n> +\t\tmode->type = DATE_SHORT_LOCAL;\n>  \telse if (!strcmp(format, \"local\"))\n>  \t\tmode->type = DATE_LOCAL;\n>  \telse if (!strcmp(format, \"default\"))\n> @@ -794,6 +808,9 @@ void parse_date_format(const char *format, struct date_mode *mode)\n>  \telse if (skip_prefix(format, \"format:\", &format)) {\n>  \t\tmode->type = DATE_STRFTIME;\n>  \t\tmode->strftime_fmt = xstrdup(format);\n> +\t} else if (skip_prefix(format, \"format-local:\", &format)) {\n> +\t\tmode->type = DATE_STRFTIME_LOCAL;\n> +\t\tmode->strftime_fmt = xstrdup(format);\n>  \t} else\n>  \t\tdie(\"unknown date format %s\", format);\n>  }\n"},{"id":"269020","messageId":"20150831185018.GA20555@sigill.intra.peff.net","threadId":"40221","inReplyTo":"xmqqtwrfweo7.fsf@gitster.mtv.corp.google.com","subject":"Re: [RFC/PATCH] date: allow any format to display local time","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-08-31T18:50:18Z","receivedAt":"2015-08-31T18:50:18Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Aug 31, 2015 at 10:28:24AM -0700, Junio C Hamano wrote:\n\n> This needs to be CC'ed to the author of a5481a6c (convert \"enum\n> date_mode\" into a struct, 2015-06-25), which I just did.\n\nThanks. I'm definitely interested.\n\n> I am unhappy with the change to blame.c, and that is not because I\n> do not want \"blame\" to be touched.\n> \n> The fact that this change has to touch it indicates that it is easy\n> for other new callers of date formatting code to forget masking\n> DATE_LOCAL bit like this patch does when they want to change their\n> behaviour based on the settings of date-mode.  And it would be hard\n> to catch such a subtle breakage during future reviews.\n\nYeah, my first instinct on seeing the bitfield was that it would\nprobably be much simpler to keep the enum pure, and add a bit to the\nstruct. A patch in that direction is below. I think the result is that\nthe using code is much cleaner, and the complexity of converting\n\"foo-local\" into the enum/bitfield combination is contained in\nparse_date_format. So for callers like blame:\n\n> >  \t/* The maximum width used to show the dates */\n> > -\tswitch (blame_date_mode.type) {\n> > +\tswitch (blame_date_mode.type & ~DATE_LOCAL) {\n> >  \tcase DATE_RFC2822:\n> >  \t\tblame_date_width = sizeof(\"Thu, 19 Oct 2006 16:00:04 -0700\");\n> >  \t\tbreak;\n\nWe can get rid of this hunk, which is good.\n\n> > @@ -2600,7 +2600,6 @@ parse_done:\n> >  \t\t   fewer display columns. */\n> >  \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n> >  \t\tbreak;\n> > -\tcase DATE_LOCAL:\n> >  \tcase DATE_NORMAL:\n> >  \t\tblame_date_width = sizeof(\"Thu Oct 19 16:00:04 2006 -0700\");\n> >  \t\tbreak;\n\nThis hunk stays, because there is no more DATE_LOCAL. We could keep it\nfor historical compatibility, but the compiler will let us know if new\ncallers arrive.\n\nThere is one call-site in fast-import which uses DATE_MODE(LOCAL). In my\npatch I convert it use a real \"struct date_mode\", as it is not much more\ncode, and is arguably more clear.\n\n> I agree that among \"enum date_mode_type\", DATE_LOCAL is an oddball.\n> It should be able to act as an orthogonal and independent flag with\n> at least some, like NORMAL, SHORT, etc.  Specifying DATE_LOCAL with\n> some others at the same time, however, would not make much sense,\n> would it?  What does it even mean to say time as relative under\n> DATE_LOCAL bit?\n\nI think the \"relative local\" thing is not _too_ bad, as John's patch\nenforces it at the user-level (it does not parse \"relative-local\" at\nall, and mine similarly complains).\n\n> >  \telse\n> >  \t\tstrbuf_addf(&timebuf, \"%.3s %.3s %d %02d:%02d:%02d %d%c%+05d\",\n> \n> What cannot be seen in the post-context of this hunk is that we\n> deliberately drop the timezone information when tweaking the\n> \"normal\" format to \"local\".  This is done only in the final else\n> clause in show_date() because the code knows that LOCAL is not an\n> independent bit.\n\nI didn't address this in my patch (except to convert the check of\nDATE_LOCAL to mode->local). I agree that we should handle it in other\nformats, too, but I think it must be format-dependent. Certainly \"rfc\"\nand \"iso\" must always show the timezone. I'd argue that \"raw\" probably\nshould, as well. That leaves only \"short\" and \"relative\", which do not\ndisplay the time zone in the first place. So all of the formats are\ncovered, I think.\n\n> I think the original motivation is that there is no need to show the\n> timezone information when the user knows the time is shown in the\n> local timezone---after all, the --date=local option was given by her\n> in the first place.  This kind of tweaking should be made consistent\n> with other variants, now the other variants are interacting with\n> this LOCAL bit.  If we were to go forward with this patch, I think\n> we probably should remove this special casing of \"showing normal\n> date in localzone, drop the zone information\", as we cannot sanely\n> drop the TZ offset from the output of some of the formats and stay\n> valid (e.g RFC2822).\n\nI think I'd rather remain inconsistent between the formats (which, after\nall, do not need to show exactly the same information), then have people\ncomplain that \"--date=local\" is regressed and now shows a timezone.\n\n> > @@ -777,14 +780,25 @@ void parse_date_format(const char *format, struct date_mode *mode)\n> >  \telse if (!strcmp(format, \"iso8601\") ||\n> >  \t\t !strcmp(format, \"iso\"))\n> >  \t\tmode->type = DATE_ISO8601;\n> > +\telse if (!strcmp(format, \"iso8601-local\") ||\n> > +\t\t !strcmp(format, \"iso-local\"))\n> > +\t\tmode->type = DATE_ISO8601_LOCAL;\n\nI found the manual \"-local\" handling here to be a little, well...manual.\nSo in the patch below I've revamped the parsing to look left-to-right\nfor each component: type, local modifier, strftime format.\n\nIt ends up being about the same amount of code, but has two advantages:\n\n  1. It's more flexible if we want to make more modifiers later. In\n     fact, it would be trivial to implement the current \"-strict\" as a\n     separate flag if we chose. I don't think there is much point in\n     doing so, but we could do something like \"default-local-strict\"\n     for showing the local time _with_ the timezone.\n\n  2. We can provide more specific error messages (like \"relative does\n     not make sense with -local\", rather than \"unknown date format:\n     relative-local\").\n\nBut that is somewhat orthogonal to the enum thing. We could leave the\nparsing as John has it, and just set mode->local as appropriate in each\nconditional block.\n\n---\n builtin/blame.c |  1 -\n cache.h         |  2 +-\n date.c          | 77 ++++++++++++++++++++++++++++++++++++++-------------------\n fast-import.c   |  6 ++++-\n 4 files changed, 57 insertions(+), 29 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 4db01c1..6fd1a63 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2600,7 +2600,6 @@ parse_done:\n \t\t   fewer display columns. */\n \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n \t\tbreak;\n-\tcase DATE_LOCAL:\n \tcase DATE_NORMAL:\n \t\tblame_date_width = sizeof(\"Thu Oct 19 16:00:04 2006 -0700\");\n \t\tbreak;\ndiff --git a/cache.h b/cache.h\nindex 4e25271..9a91b1d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1091,7 +1091,6 @@ struct date_mode {\n \t\tDATE_NORMAL = 0,\n \t\tDATE_RELATIVE,\n \t\tDATE_SHORT,\n-\t\tDATE_LOCAL,\n \t\tDATE_ISO8601,\n \t\tDATE_ISO8601_STRICT,\n \t\tDATE_RFC2822,\n@@ -1099,6 +1098,7 @@ struct date_mode {\n \t\tDATE_RAW\n \t} type;\n \tconst char *strftime_fmt;\n+\tint local;\n };\n \n /*\ndiff --git a/date.c b/date.c\nindex 8f91569..aa57cad 100644\n--- a/date.c\n+++ b/date.c\n@@ -166,6 +166,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \tif (type == DATE_STRFTIME)\n \t\tdie(\"BUG: cannot create anonymous strftime date_mode struct\");\n \tmode.type = type;\n+\tmode.local = 0;\n \treturn &mode;\n }\n \n@@ -189,7 +190,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \t\treturn timebuf.buf;\n \t}\n \n-\tif (mode->type == DATE_LOCAL)\n+\tif (mode->local)\n \t\ttz = local_tzoffset(time);\n \n \ttm = time_to_tm(time, tz);\n@@ -232,7 +233,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \t\t\t\ttm->tm_mday,\n \t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n \t\t\t\ttm->tm_year + 1900,\n-\t\t\t\t(mode->type == DATE_LOCAL) ? 0 : ' ',\n+\t\t\t\tmode->local ? 0 : ' ',\n \t\t\t\ttz);\n \treturn timebuf.buf;\n }\n@@ -770,32 +771,56 @@ int parse_date(const char *date, struct strbuf *result)\n \treturn 0;\n }\n \n+static enum date_mode_type parse_date_type(const char *format, const char **end)\n+{\n+\tif (skip_prefix(format, \"relative\", end))\n+\t\treturn DATE_RELATIVE;\n+\tif (skip_prefix(format, \"iso8601-strict\", end) ||\n+\t    skip_prefix(format, \"iso-strict\", end))\n+\t\treturn DATE_ISO8601_STRICT;\n+\tif (skip_prefix(format, \"iso8601\", end) ||\n+\t    skip_prefix(format, \"iso\", end))\n+\t\treturn DATE_ISO8601;\n+\tif (skip_prefix(format, \"rfc2822\", end) ||\n+\t    skip_prefix(format, \"rfc\", end))\n+\t\treturn DATE_RFC2822;\n+\tif (skip_prefix(format, \"short\", end))\n+\t\treturn DATE_SHORT;\n+\tif (skip_prefix(format, \"default\", end))\n+\t\treturn DATE_NORMAL;\n+\tif (skip_prefix(format, \"raw\", end))\n+\t\treturn DATE_RAW;\n+\tif (skip_prefix(format, \"format\", end))\n+\t\treturn DATE_STRFTIME;\n+\n+\tdie(\"unknown date format %s\", format);\n+}\n+\n void parse_date_format(const char *format, struct date_mode *mode)\n {\n-\tif (!strcmp(format, \"relative\"))\n-\t\tmode->type = DATE_RELATIVE;\n-\telse if (!strcmp(format, \"iso8601\") ||\n-\t\t !strcmp(format, \"iso\"))\n-\t\tmode->type = DATE_ISO8601;\n-\telse if (!strcmp(format, \"iso8601-strict\") ||\n-\t\t !strcmp(format, \"iso-strict\"))\n-\t\tmode->type = DATE_ISO8601_STRICT;\n-\telse if (!strcmp(format, \"rfc2822\") ||\n-\t\t !strcmp(format, \"rfc\"))\n-\t\tmode->type = DATE_RFC2822;\n-\telse if (!strcmp(format, \"short\"))\n-\t\tmode->type = DATE_SHORT;\n-\telse if (!strcmp(format, \"local\"))\n-\t\tmode->type = DATE_LOCAL;\n-\telse if (!strcmp(format, \"default\"))\n-\t\tmode->type = DATE_NORMAL;\n-\telse if (!strcmp(format, \"raw\"))\n-\t\tmode->type = DATE_RAW;\n-\telse if (skip_prefix(format, \"format:\", &format)) {\n-\t\tmode->type = DATE_STRFTIME;\n-\t\tmode->strftime_fmt = xstrdup(format);\n-\t} else\n-\t\tdie(\"unknown date format %s\", format);\n+\tconst char *p;\n+\n+\t/* historical alias */\n+\tif (!strcmp(format, \"local\"))\n+\t\tformat = \"default-local\";\n+\n+\tmode->type = parse_date_type(format, &p);\n+\tmode->local = 0;\n+\n+\tif (skip_prefix(p, \"-local\", &p)) {\n+\t\tif (mode->type == DATE_RELATIVE)\n+\t\t\tdie(\"relative-local date format is nonsensical\");\n+\t\tmode->local = 1;\n+\t}\n+\n+\tif (mode->type == DATE_STRFTIME) {\n+\t\tif (!skip_prefix(p, \":\", &p))\n+\t\t\tdie(\"date format missing colon separator: %s\", format);\n+\t\tmode->strftime_fmt = xstrdup(p);\n+\t}\n+\n+\tif (*p)\n+\t\tdie(\"unknown date-mode modifier: %s\", p);\n }\n \n void datestamp(struct strbuf *out)\ndiff --git a/fast-import.c b/fast-import.c\nindex 6c7c3c9..b19a1b5 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -412,6 +412,10 @@ static void write_crash_report(const char *err)\n \tstruct branch *b;\n \tunsigned long lu;\n \tstruct recent_command *rc;\n+\tstruct date_mode dm;\n+\n+\tdm.type = DATE_NORMAL;\n+\tdm.local = 1;\n \n \tif (!rpt) {\n \t\terror(\"can't write crash report %s: %s\", loc, strerror(errno));\n@@ -424,7 +428,7 @@ static void write_crash_report(const char *err)\n \tfprintf(rpt, \"fast-import crash report:\\n\");\n \tfprintf(rpt, \"    fast-import process: %\"PRIuMAX\"\\n\", (uintmax_t) getpid());\n \tfprintf(rpt, \"    parent process     : %\"PRIuMAX\"\\n\", (uintmax_t) getppid());\n-\tfprintf(rpt, \"    at %s\\n\", show_date(time(NULL), 0, DATE_MODE(LOCAL)));\n+\tfprintf(rpt, \"    at %s\\n\", show_date(time(NULL), 0, &dm));\n \tfputc('\\n', rpt);\n \n \tfputs(\"fatal: \", rpt);\n-- \n2.5.1.739.g7891f6b\n"},{"id":"269025","messageId":"20150831185657.GC20555@sigill.intra.peff.net","threadId":"40221","inReplyTo":"20150831185018.GA20555@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] date: allow any format to display local time","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-08-31T18:56:57Z","receivedAt":"2015-08-31T18:56:57Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Aug 31, 2015 at 02:50:18PM -0400, Jeff King wrote:\n\n> diff --git a/fast-import.c b/fast-import.c\n> index 6c7c3c9..b19a1b5 100644\n> --- a/fast-import.c\n> +++ b/fast-import.c\n> @@ -412,6 +412,10 @@ static void write_crash_report(const char *err)\n>  \tstruct branch *b;\n>  \tunsigned long lu;\n>  \tstruct recent_command *rc;\n> +\tstruct date_mode dm;\n> +\n> +\tdm.type = DATE_NORMAL;\n> +\tdm.local = 1;\n>  \n>  \tif (!rpt) {\n>  \t\terror(\"can't write crash report %s: %s\", loc, strerror(errno));\n> @@ -424,7 +428,7 @@ static void write_crash_report(const char *err)\n>  \tfprintf(rpt, \"fast-import crash report:\\n\");\n>  \tfprintf(rpt, \"    fast-import process: %\"PRIuMAX\"\\n\", (uintmax_t) getpid());\n>  \tfprintf(rpt, \"    parent process     : %\"PRIuMAX\"\\n\", (uintmax_t) getppid());\n> -\tfprintf(rpt, \"    at %s\\n\", show_date(time(NULL), 0, DATE_MODE(LOCAL)));\n> +\tfprintf(rpt, \"    at %s\\n\", show_date(time(NULL), 0, &dm));\n>  \tfputc('\\n', rpt);\n>  \n>  \tfputs(\"fatal: \", rpt);\n\nI also considered just switching this hunk to another format. I doubt\nthat anybody cares what format the fast-import crash-report timestamp is\nin. And in fact LOCAL is kind of a bad choice. Using the user's timezone\nis fine, but _omitting_ the timezone in a crash report seems like a\nrecipe for confusion. Probably iso8601-local would be saner.\n\n-Peff\n"},{"id":"269040","messageId":"xmqqlhcrut74.fsf@gitster.mtv.corp.google.com","threadId":"40221","inReplyTo":"20150831185018.GA20555@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] date: allow any format to display local time","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-08-31T19:57:35Z","receivedAt":"2015-08-31T19:57:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Yeah, my first instinct on seeing the bitfield was that it would\n> probably be much simpler to keep the enum pure, and add a bit to the\n> struct. A patch in that direction is below. ...\n\nI found it a much cleaner approach from my cursory look.  John, what\ndo you think?\n"},{"id":"269041","messageId":"20150831200016.GC30659@serenity.lan","threadId":"40221","inReplyTo":"20150831185018.GA20555@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] date: allow any format to display local time","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-08-31T20:00:16Z","receivedAt":"2015-08-31T20:00:16Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"On Mon, Aug 31, 2015 at 02:50:18PM -0400, Jeff King wrote:\n> On Mon, Aug 31, 2015 at 10:28:24AM -0700, Junio C Hamano wrote:\n> > I am unhappy with the change to blame.c, and that is not because I\n> > do not want \"blame\" to be touched.\n> > \n> > The fact that this change has to touch it indicates that it is easy\n> > for other new callers of date formatting code to forget masking\n> > DATE_LOCAL bit like this patch does when they want to change their\n> > behaviour based on the settings of date-mode.  And it would be hard\n> > to catch such a subtle breakage during future reviews.\n> \n> Yeah, my first instinct on seeing the bitfield was that it would\n> probably be much simpler to keep the enum pure, and add a bit to the\n> struct. A patch in that direction is below. I think the result is that\n> the using code is much cleaner, and the complexity of converting\n> \"foo-local\" into the enum/bitfield combination is contained in\n> parse_date_format.\n\nYes, the result below is much cleaner than my version.\n\n> > I agree that among \"enum date_mode_type\", DATE_LOCAL is an oddball.\n> > It should be able to act as an orthogonal and independent flag with\n> > at least some, like NORMAL, SHORT, etc.  Specifying DATE_LOCAL with\n> > some others at the same time, however, would not make much sense,\n> > would it?  What does it even mean to say time as relative under\n> > DATE_LOCAL bit?\n> \n> I think the \"relative local\" thing is not _too_ bad, as John's patch\n> enforces it at the user-level (it does not parse \"relative-local\" at\n> all, and mine similarly complains).\n> \n> > >  \telse\n> > >  \t\tstrbuf_addf(&timebuf, \"%.3s %.3s %d %02d:%02d:%02d %d%c%+05d\",\n> > \n> > What cannot be seen in the post-context of this hunk is that we\n> > deliberately drop the timezone information when tweaking the\n> > \"normal\" format to \"local\".  This is done only in the final else\n> > clause in show_date() because the code knows that LOCAL is not an\n> > independent bit.\n> \n> I didn't address this in my patch (except to convert the check of\n> DATE_LOCAL to mode->local). I agree that we should handle it in other\n> formats, too, but I think it must be format-dependent. Certainly \"rfc\"\n> and \"iso\" must always show the timezone. I'd argue that \"raw\" probably\n> should, as well. That leaves only \"short\" and \"relative\", which do not\n> display the time zone in the first place. So all of the formats are\n> covered, I think.\n> \n> > I think the original motivation is that there is no need to show the\n> > timezone information when the user knows the time is shown in the\n> > local timezone---after all, the --date=local option was given by her\n> > in the first place.  This kind of tweaking should be made consistent\n> > with other variants, now the other variants are interacting with\n> > this LOCAL bit.  If we were to go forward with this patch, I think\n> > we probably should remove this special casing of \"showing normal\n> > date in localzone, drop the zone information\", as we cannot sanely\n> > drop the TZ offset from the output of some of the formats and stay\n> > valid (e.g RFC2822).\n> \n> I think I'd rather remain inconsistent between the formats (which, after\n> all, do not need to show exactly the same information), then have people\n> complain that \"--date=local\" is regressed and now shows a timezone.\n> \n> > > @@ -777,14 +780,25 @@ void parse_date_format(const char *format, struct date_mode *mode)\n> > >  \telse if (!strcmp(format, \"iso8601\") ||\n> > >  \t\t !strcmp(format, \"iso\"))\n> > >  \t\tmode->type = DATE_ISO8601;\n> > > +\telse if (!strcmp(format, \"iso8601-local\") ||\n> > > +\t\t !strcmp(format, \"iso-local\"))\n> > > +\t\tmode->type = DATE_ISO8601_LOCAL;\n> \n> I found the manual \"-local\" handling here to be a little, well...manual.\n> So in the patch below I've revamped the parsing to look left-to-right\n> for each component: type, local modifier, strftime format.\n> \n> It ends up being about the same amount of code, but has two advantages:\n> \n>   1. It's more flexible if we want to make more modifiers later. In\n>      fact, it would be trivial to implement the current \"-strict\" as a\n>      separate flag if we chose. I don't think there is much point in\n>      doing so, but we could do something like \"default-local-strict\"\n>      for showing the local time _with_ the timezone.\n> \n>   2. We can provide more specific error messages (like \"relative does\n>      not make sense with -local\", rather than \"unknown date format:\n>      relative-local\").\n> \n> But that is somewhat orthogonal to the enum thing. We could leave the\n> parsing as John has it, and just set mode->local as appropriate in each\n> conditional block.\n\nI like that the parsing indicates that the format and \"local-ness\" are\northogonal in this version.\n\nAre you willing to resend this as a proper patch?\n\nI'm happy to build documentation & tests on top, although there don't\nseem to be any tests for date formats outside t6300-for-each-ref.sh at\nthe moment (and the \"format\" mode is neither tested nor documented for\ngit-for-each-ref although it does work)..\n\n> ---\n>  builtin/blame.c |  1 -\n>  cache.h         |  2 +-\n>  date.c          | 77 ++++++++++++++++++++++++++++++++++++++-------------------\n>  fast-import.c   |  6 ++++-\n>  4 files changed, 57 insertions(+), 29 deletions(-)\n> \n> diff --git a/builtin/blame.c b/builtin/blame.c\n> index 4db01c1..6fd1a63 100644\n> --- a/builtin/blame.c\n> +++ b/builtin/blame.c\n> @@ -2600,7 +2600,6 @@ parse_done:\n>  \t\t   fewer display columns. */\n>  \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n>  \t\tbreak;\n> -\tcase DATE_LOCAL:\n>  \tcase DATE_NORMAL:\n>  \t\tblame_date_width = sizeof(\"Thu Oct 19 16:00:04 2006 -0700\");\n>  \t\tbreak;\n> diff --git a/cache.h b/cache.h\n> index 4e25271..9a91b1d 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -1091,7 +1091,6 @@ struct date_mode {\n>  \t\tDATE_NORMAL = 0,\n>  \t\tDATE_RELATIVE,\n>  \t\tDATE_SHORT,\n> -\t\tDATE_LOCAL,\n>  \t\tDATE_ISO8601,\n>  \t\tDATE_ISO8601_STRICT,\n>  \t\tDATE_RFC2822,\n> @@ -1099,6 +1098,7 @@ struct date_mode {\n>  \t\tDATE_RAW\n>  \t} type;\n>  \tconst char *strftime_fmt;\n> +\tint local;\n>  };\n>  \n>  /*\n> diff --git a/date.c b/date.c\n> index 8f91569..aa57cad 100644\n> --- a/date.c\n> +++ b/date.c\n> @@ -166,6 +166,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n>  \tif (type == DATE_STRFTIME)\n>  \t\tdie(\"BUG: cannot create anonymous strftime date_mode struct\");\n>  \tmode.type = type;\n> +\tmode.local = 0;\n>  \treturn &mode;\n>  }\n>  \n> @@ -189,7 +190,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n>  \t\treturn timebuf.buf;\n>  \t}\n>  \n> -\tif (mode->type == DATE_LOCAL)\n> +\tif (mode->local)\n>  \t\ttz = local_tzoffset(time);\n>  \n>  \ttm = time_to_tm(time, tz);\n> @@ -232,7 +233,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n>  \t\t\t\ttm->tm_mday,\n>  \t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n>  \t\t\t\ttm->tm_year + 1900,\n> -\t\t\t\t(mode->type == DATE_LOCAL) ? 0 : ' ',\n> +\t\t\t\tmode->local ? 0 : ' ',\n>  \t\t\t\ttz);\n>  \treturn timebuf.buf;\n>  }\n> @@ -770,32 +771,56 @@ int parse_date(const char *date, struct strbuf *result)\n>  \treturn 0;\n>  }\n>  \n> +static enum date_mode_type parse_date_type(const char *format, const char **end)\n> +{\n> +\tif (skip_prefix(format, \"relative\", end))\n> +\t\treturn DATE_RELATIVE;\n> +\tif (skip_prefix(format, \"iso8601-strict\", end) ||\n> +\t    skip_prefix(format, \"iso-strict\", end))\n> +\t\treturn DATE_ISO8601_STRICT;\n> +\tif (skip_prefix(format, \"iso8601\", end) ||\n> +\t    skip_prefix(format, \"iso\", end))\n> +\t\treturn DATE_ISO8601;\n> +\tif (skip_prefix(format, \"rfc2822\", end) ||\n> +\t    skip_prefix(format, \"rfc\", end))\n> +\t\treturn DATE_RFC2822;\n> +\tif (skip_prefix(format, \"short\", end))\n> +\t\treturn DATE_SHORT;\n> +\tif (skip_prefix(format, \"default\", end))\n> +\t\treturn DATE_NORMAL;\n> +\tif (skip_prefix(format, \"raw\", end))\n> +\t\treturn DATE_RAW;\n> +\tif (skip_prefix(format, \"format\", end))\n> +\t\treturn DATE_STRFTIME;\n> +\n> +\tdie(\"unknown date format %s\", format);\n> +}\n> +\n>  void parse_date_format(const char *format, struct date_mode *mode)\n>  {\n> -\tif (!strcmp(format, \"relative\"))\n> -\t\tmode->type = DATE_RELATIVE;\n> -\telse if (!strcmp(format, \"iso8601\") ||\n> -\t\t !strcmp(format, \"iso\"))\n> -\t\tmode->type = DATE_ISO8601;\n> -\telse if (!strcmp(format, \"iso8601-strict\") ||\n> -\t\t !strcmp(format, \"iso-strict\"))\n> -\t\tmode->type = DATE_ISO8601_STRICT;\n> -\telse if (!strcmp(format, \"rfc2822\") ||\n> -\t\t !strcmp(format, \"rfc\"))\n> -\t\tmode->type = DATE_RFC2822;\n> -\telse if (!strcmp(format, \"short\"))\n> -\t\tmode->type = DATE_SHORT;\n> -\telse if (!strcmp(format, \"local\"))\n> -\t\tmode->type = DATE_LOCAL;\n> -\telse if (!strcmp(format, \"default\"))\n> -\t\tmode->type = DATE_NORMAL;\n> -\telse if (!strcmp(format, \"raw\"))\n> -\t\tmode->type = DATE_RAW;\n> -\telse if (skip_prefix(format, \"format:\", &format)) {\n> -\t\tmode->type = DATE_STRFTIME;\n> -\t\tmode->strftime_fmt = xstrdup(format);\n> -\t} else\n> -\t\tdie(\"unknown date format %s\", format);\n> +\tconst char *p;\n> +\n> +\t/* historical alias */\n> +\tif (!strcmp(format, \"local\"))\n> +\t\tformat = \"default-local\";\n> +\n> +\tmode->type = parse_date_type(format, &p);\n> +\tmode->local = 0;\n> +\n> +\tif (skip_prefix(p, \"-local\", &p)) {\n> +\t\tif (mode->type == DATE_RELATIVE)\n> +\t\t\tdie(\"relative-local date format is nonsensical\");\n> +\t\tmode->local = 1;\n> +\t}\n> +\n> +\tif (mode->type == DATE_STRFTIME) {\n> +\t\tif (!skip_prefix(p, \":\", &p))\n> +\t\t\tdie(\"date format missing colon separator: %s\", format);\n> +\t\tmode->strftime_fmt = xstrdup(p);\n> +\t}\n> +\n> +\tif (*p)\n> +\t\tdie(\"unknown date-mode modifier: %s\", p);\n>  }\n>  \n>  void datestamp(struct strbuf *out)\n> diff --git a/fast-import.c b/fast-import.c\n> index 6c7c3c9..b19a1b5 100644\n> --- a/fast-import.c\n> +++ b/fast-import.c\n> @@ -412,6 +412,10 @@ static void write_crash_report(const char *err)\n>  \tstruct branch *b;\n>  \tunsigned long lu;\n>  \tstruct recent_command *rc;\n> +\tstruct date_mode dm;\n> +\n> +\tdm.type = DATE_NORMAL;\n> +\tdm.local = 1;\n>  \n>  \tif (!rpt) {\n>  \t\terror(\"can't write crash report %s: %s\", loc, strerror(errno));\n> @@ -424,7 +428,7 @@ static void write_crash_report(const char *err)\n>  \tfprintf(rpt, \"fast-import crash report:\\n\");\n>  \tfprintf(rpt, \"    fast-import process: %\"PRIuMAX\"\\n\", (uintmax_t) getpid());\n>  \tfprintf(rpt, \"    parent process     : %\"PRIuMAX\"\\n\", (uintmax_t) getppid());\n> -\tfprintf(rpt, \"    at %s\\n\", show_date(time(NULL), 0, DATE_MODE(LOCAL)));\n> +\tfprintf(rpt, \"    at %s\\n\", show_date(time(NULL), 0, &dm));\n>  \tfputc('\\n', rpt);\n>  \n>  \tfputs(\"fatal: \", rpt);\n> -- \n> 2.5.1.739.g7891f6b\n"},{"id":"269050","messageId":"20150831204444.GA4385@sigill.intra.peff.net","threadId":"40221","inReplyTo":"20150831200016.GC30659@serenity.lan","subject":"Re: [RFC/PATCH] date: allow any format to display local time","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-08-31T20:44:45Z","receivedAt":"2015-08-31T20:44:45Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Aug 31, 2015 at 09:00:16PM +0100, John Keeping wrote:\n\n> Are you willing to resend this as a proper patch?\n\nYup.\n\n  [1/2]: fast-import: switch crash-report date to iso8601\n  [2/2]: date: make \"local\" orthogonal to date format\n\n> I'm happy to build documentation & tests on top, although there don't\n> seem to be any tests for date formats outside t6300-for-each-ref.sh at\n> the moment\n\nI've added documentation, but not tests. Tests on top would be very much\nappreciated.\n\n> (and the \"format\" mode is neither tested nor documented for\n> git-for-each-ref although it does work)..\n\nI think it is the opposite for testing: we test only for-each-ref.  I\nremember when I did the original patch finding that there were no\nexisting tests for log --date, and I was too lazy to add them. It would\nbe nice to add some now.\n\nI agree that the documentation for for-each-ref is not up to date. I\nthink it should do a better job of just pointing to the existing\ndate-format (and then we do not have to keep documenting new features in\ntwo places).\n\nWe could also push the content into a new file and include it from both\nplaces. But I'd be much more in favor of actually pulling the date\ndiscussion into a separate \"gitdates(7)\" manpage and just referencing it\nfrom both places.  Even though it creates more work for a user following\nthe reference (in manpages, at least, which are not hyperlinked), I\nthink there is a cognitive benefit to the user in realizing that the\nsame concept can be applied in both places.\n\n-Peff\n"},{"id":"269051","messageId":"20150831204716.GA10338@sigill.intra.peff.net","threadId":"40221","inReplyTo":"20150831204444.GA4385@sigill.intra.peff.net","subject":"[PATCH 1/2] fast-import: switch crash-report date to iso8601","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-08-31T20:47:16Z","receivedAt":"2015-08-31T20:47:16Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"When fast-import emits a crash report, it does so in the\nuser's local timezone. But because we omit the timezone\ncompletely for DATE_LOCAL, a reader of the report does not\nimmediately know which time zone was used. Let's switch this\nto ISO8601 instead, which includes the time zone.\n\nThis does mean we will show the time in UTC, but that's not\na big deal. A crash report like this will either be looked\nat immediately (in which case nobody even looks at the\ntimestamp), or it will be passed along to a developer to\ndebug, in which case the original timezone is less likely to\nbe of interest.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nAfter patch 2/2, we could make this iso8601-local. But frankly, I have a\nhard time believing anybody really cares about this format.\n\n fast-import.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 6c7c3c9..adcbfc6 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -424,7 +424,7 @@ static void write_crash_report(const char *err)\n \tfprintf(rpt, \"fast-import crash report:\\n\");\n \tfprintf(rpt, \"    fast-import process: %\"PRIuMAX\"\\n\", (uintmax_t) getpid());\n \tfprintf(rpt, \"    parent process     : %\"PRIuMAX\"\\n\", (uintmax_t) getppid());\n-\tfprintf(rpt, \"    at %s\\n\", show_date(time(NULL), 0, DATE_MODE(LOCAL)));\n+\tfprintf(rpt, \"    at %s\\n\", show_date(time(NULL), 0, DATE_MODE(ISO8601)));\n \tfputc('\\n', rpt);\n \n \tfputs(\"fatal: \", rpt);\n-- \n2.5.1.739.g7891f6b\n"},{"id":"269052","messageId":"20150831204831.GB10338@sigill.intra.peff.net","threadId":"40221","inReplyTo":"20150831204444.GA4385@sigill.intra.peff.net","subject":"[PATCH 2/2] date: make \"local\" orthogonal to date format","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-08-31T20:48:32Z","receivedAt":"2015-08-31T20:48:32Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Most of our \"--date\" modes are about the format of the date:\nwhich items we show and in what order. But \"--date=local\" is\na bit of an oddball. It means \"show the date in the normal\nformat, but using the local timezone\". The timezone we use\nis orthogonal to the actual format, and there is no reason\nwe could not have \"localized iso8601\", etc.\n\nThis patch adds a \"local\" boolean field to \"struct\ndate_mode\", and drops the DATE_LOCAL element from the\ndate_mode_type enum (it's now just DATE_NORMAL plus\nlocal=1). The new feature is accessible to users by adding\n\"-local\" to any date mode (e.g., \"iso-local\"), and we retain\n\"local\" as an alias for \"default-local\" for backwards\ncompatibility.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nI wonder if anybody would be confused and try \"iso-local-strict\", which\ndoes not work with this code. If we bumped \"-strict\" to become a\nmodifier (like \"-local\"), we could easily make the order\ninterchangeable.\n\n Documentation/rev-list-options.txt | 21 ++++++++---\n builtin/blame.c                    |  1 -\n cache.h                            |  2 +-\n date.c                             | 77 +++++++++++++++++++++++++-------------\n 4 files changed, 67 insertions(+), 34 deletions(-)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex a9b808f..35dc44b 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -702,12 +702,16 @@ include::pretty-options.txt[]\n --date=(relative|local|default|iso|iso-strict|rfc|short|raw)::\n \tOnly takes effect for dates shown in human-readable format, such\n \tas when using `--pretty`. `log.date` config variable sets a default\n-\tvalue for the log command's `--date` option.\n+\tvalue for the log command's `--date` option. By default, dates\n+\tare shown in the original time zone (either committer's or\n+\tauthor's). If `-local` is appended to the format (e.g.,\n+\t`iso-local`), the user's local time zone is used instead.\n +\n `--date=relative` shows dates relative to the current time,\n-e.g. ``2 hours ago''.\n+e.g. ``2 hours ago''. The `-local` option cannot be used with\n+`--relative`.\n +\n-`--date=local` shows timestamps in user's local time zone.\n+`--date=local` is an alias for `--date=default-local`.\n +\n `--date=iso` (or `--date=iso8601`) shows timestamps in a ISO 8601-like format.\n The differences to the strict ISO 8601 format are:\n@@ -730,10 +734,15 @@ format, often found in email messages.\n `--date=format:...` feeds the format `...` to your system `strftime`.\n Use `--date=format:%c` to show the date in your system locale's\n preferred format.  See the `strftime` manual for a complete list of\n-format placeholders.\n+format placeholders. When using `-local`, the correct syntax is\n+`--date=format-local:...`.\n +\n-`--date=default` shows timestamps in the original time zone\n-(either committer's or author's).\n+`--date=default` is the default format, and is similar to\n+`--date=rfc2822`, with a few exceptions:\n+\n+\t- there is no comma after the day-of-week\n+\n+\t- the time zone is omitted when the local time zone is used\n \n ifdef::git-rev-list[]\n --header::\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 4db01c1..6fd1a63 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2600,7 +2600,6 @@ parse_done:\n \t\t   fewer display columns. */\n \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n \t\tbreak;\n-\tcase DATE_LOCAL:\n \tcase DATE_NORMAL:\n \t\tblame_date_width = sizeof(\"Thu Oct 19 16:00:04 2006 -0700\");\n \t\tbreak;\ndiff --git a/cache.h b/cache.h\nindex 4e25271..9a91b1d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1091,7 +1091,6 @@ struct date_mode {\n \t\tDATE_NORMAL = 0,\n \t\tDATE_RELATIVE,\n \t\tDATE_SHORT,\n-\t\tDATE_LOCAL,\n \t\tDATE_ISO8601,\n \t\tDATE_ISO8601_STRICT,\n \t\tDATE_RFC2822,\n@@ -1099,6 +1098,7 @@ struct date_mode {\n \t\tDATE_RAW\n \t} type;\n \tconst char *strftime_fmt;\n+\tint local;\n };\n \n /*\ndiff --git a/date.c b/date.c\nindex 8f91569..aa57cad 100644\n--- a/date.c\n+++ b/date.c\n@@ -166,6 +166,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \tif (type == DATE_STRFTIME)\n \t\tdie(\"BUG: cannot create anonymous strftime date_mode struct\");\n \tmode.type = type;\n+\tmode.local = 0;\n \treturn &mode;\n }\n \n@@ -189,7 +190,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \t\treturn timebuf.buf;\n \t}\n \n-\tif (mode->type == DATE_LOCAL)\n+\tif (mode->local)\n \t\ttz = local_tzoffset(time);\n \n \ttm = time_to_tm(time, tz);\n@@ -232,7 +233,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \t\t\t\ttm->tm_mday,\n \t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n \t\t\t\ttm->tm_year + 1900,\n-\t\t\t\t(mode->type == DATE_LOCAL) ? 0 : ' ',\n+\t\t\t\tmode->local ? 0 : ' ',\n \t\t\t\ttz);\n \treturn timebuf.buf;\n }\n@@ -770,32 +771,56 @@ int parse_date(const char *date, struct strbuf *result)\n \treturn 0;\n }\n \n+static enum date_mode_type parse_date_type(const char *format, const char **end)\n+{\n+\tif (skip_prefix(format, \"relative\", end))\n+\t\treturn DATE_RELATIVE;\n+\tif (skip_prefix(format, \"iso8601-strict\", end) ||\n+\t    skip_prefix(format, \"iso-strict\", end))\n+\t\treturn DATE_ISO8601_STRICT;\n+\tif (skip_prefix(format, \"iso8601\", end) ||\n+\t    skip_prefix(format, \"iso\", end))\n+\t\treturn DATE_ISO8601;\n+\tif (skip_prefix(format, \"rfc2822\", end) ||\n+\t    skip_prefix(format, \"rfc\", end))\n+\t\treturn DATE_RFC2822;\n+\tif (skip_prefix(format, \"short\", end))\n+\t\treturn DATE_SHORT;\n+\tif (skip_prefix(format, \"default\", end))\n+\t\treturn DATE_NORMAL;\n+\tif (skip_prefix(format, \"raw\", end))\n+\t\treturn DATE_RAW;\n+\tif (skip_prefix(format, \"format\", end))\n+\t\treturn DATE_STRFTIME;\n+\n+\tdie(\"unknown date format %s\", format);\n+}\n+\n void parse_date_format(const char *format, struct date_mode *mode)\n {\n-\tif (!strcmp(format, \"relative\"))\n-\t\tmode->type = DATE_RELATIVE;\n-\telse if (!strcmp(format, \"iso8601\") ||\n-\t\t !strcmp(format, \"iso\"))\n-\t\tmode->type = DATE_ISO8601;\n-\telse if (!strcmp(format, \"iso8601-strict\") ||\n-\t\t !strcmp(format, \"iso-strict\"))\n-\t\tmode->type = DATE_ISO8601_STRICT;\n-\telse if (!strcmp(format, \"rfc2822\") ||\n-\t\t !strcmp(format, \"rfc\"))\n-\t\tmode->type = DATE_RFC2822;\n-\telse if (!strcmp(format, \"short\"))\n-\t\tmode->type = DATE_SHORT;\n-\telse if (!strcmp(format, \"local\"))\n-\t\tmode->type = DATE_LOCAL;\n-\telse if (!strcmp(format, \"default\"))\n-\t\tmode->type = DATE_NORMAL;\n-\telse if (!strcmp(format, \"raw\"))\n-\t\tmode->type = DATE_RAW;\n-\telse if (skip_prefix(format, \"format:\", &format)) {\n-\t\tmode->type = DATE_STRFTIME;\n-\t\tmode->strftime_fmt = xstrdup(format);\n-\t} else\n-\t\tdie(\"unknown date format %s\", format);\n+\tconst char *p;\n+\n+\t/* historical alias */\n+\tif (!strcmp(format, \"local\"))\n+\t\tformat = \"default-local\";\n+\n+\tmode->type = parse_date_type(format, &p);\n+\tmode->local = 0;\n+\n+\tif (skip_prefix(p, \"-local\", &p)) {\n+\t\tif (mode->type == DATE_RELATIVE)\n+\t\t\tdie(\"relative-local date format is nonsensical\");\n+\t\tmode->local = 1;\n+\t}\n+\n+\tif (mode->type == DATE_STRFTIME) {\n+\t\tif (!skip_prefix(p, \":\", &p))\n+\t\t\tdie(\"date format missing colon separator: %s\", format);\n+\t\tmode->strftime_fmt = xstrdup(p);\n+\t}\n+\n+\tif (*p)\n+\t\tdie(\"unknown date-mode modifier: %s\", p);\n }\n \n void datestamp(struct strbuf *out)\n-- \n2.5.1.739.g7891f6b\n"},{"id":"269056","messageId":"20150831212754.GD30659@serenity.lan","threadId":"40221","inReplyTo":"20150831204831.GB10338@sigill.intra.peff.net","subject":"Re: [PATCH 2/2] date: make \"local\" orthogonal to date format","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-08-31T21:27:54Z","receivedAt":"2015-08-31T21:27:54Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"On Mon, Aug 31, 2015 at 04:48:32PM -0400, Jeff King wrote:\n> Most of our \"--date\" modes are about the format of the date:\n> which items we show and in what order. But \"--date=local\" is\n> a bit of an oddball. It means \"show the date in the normal\n> format, but using the local timezone\". The timezone we use\n> is orthogonal to the actual format, and there is no reason\n> we could not have \"localized iso8601\", etc.\n> \n> This patch adds a \"local\" boolean field to \"struct\n> date_mode\", and drops the DATE_LOCAL element from the\n> date_mode_type enum (it's now just DATE_NORMAL plus\n> local=1). The new feature is accessible to users by adding\n> \"-local\" to any date mode (e.g., \"iso-local\"), and we retain\n> \"local\" as an alias for \"default-local\" for backwards\n> compatibility.\n> \n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n\nThis fails t6300 with:\n\nfatal: unknown date-mode modifier: my date is %Y-%m-%d\nnot ok 83 - Check format of strftime date fields\n#\n#               echo \"my date is 2006-07-03\" >expected &&\n#               git for-each-ref \\\n#                 --format=\"%(authordate:format:my date is %Y-%m-%d)\" \\\n#                 refs/heads >actual &&\n#               test_cmp expected actual\n#\n\nThe following squash-in fixes it:\n\ndiff --git a/date.c b/date.c\nindex aa57cad..3aa8002 100644\n--- a/date.c\n+++ b/date.c\n@@ -817,9 +817,7 @@ void parse_date_format(const char *format, struct date_mode *mode)\n \t\tif (!skip_prefix(p, \":\", &p))\n \t\t\tdie(\"date format missing colon separator: %s\", format);\n \t\tmode->strftime_fmt = xstrdup(p);\n-\t}\n-\n-\tif (*p)\n+\t} else if (*p)\n \t\tdie(\"unknown date-mode modifier: %s\", p);\n }\n \n\n> I wonder if anybody would be confused and try \"iso-local-strict\", which\n> does not work with this code. If we bumped \"-strict\" to become a\n> modifier (like \"-local\"), we could easily make the order\n> interchangeable.\n> \n>  Documentation/rev-list-options.txt | 21 ++++++++---\n>  builtin/blame.c                    |  1 -\n>  cache.h                            |  2 +-\n>  date.c                             | 77 +++++++++++++++++++++++++-------------\n>  4 files changed, 67 insertions(+), 34 deletions(-)\n> \n> diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\n> index a9b808f..35dc44b 100644\n> --- a/Documentation/rev-list-options.txt\n> +++ b/Documentation/rev-list-options.txt\n> @@ -702,12 +702,16 @@ include::pretty-options.txt[]\n>  --date=(relative|local|default|iso|iso-strict|rfc|short|raw)::\n>  \tOnly takes effect for dates shown in human-readable format, such\n>  \tas when using `--pretty`. `log.date` config variable sets a default\n> -\tvalue for the log command's `--date` option.\n> +\tvalue for the log command's `--date` option. By default, dates\n> +\tare shown in the original time zone (either committer's or\n> +\tauthor's). If `-local` is appended to the format (e.g.,\n> +\t`iso-local`), the user's local time zone is used instead.\n>  +\n>  `--date=relative` shows dates relative to the current time,\n> -e.g. ``2 hours ago''.\n> +e.g. ``2 hours ago''. The `-local` option cannot be used with\n> +`--relative`.\n>  +\n> -`--date=local` shows timestamps in user's local time zone.\n> +`--date=local` is an alias for `--date=default-local`.\n>  +\n>  `--date=iso` (or `--date=iso8601`) shows timestamps in a ISO 8601-like format.\n>  The differences to the strict ISO 8601 format are:\n> @@ -730,10 +734,15 @@ format, often found in email messages.\n>  `--date=format:...` feeds the format `...` to your system `strftime`.\n>  Use `--date=format:%c` to show the date in your system locale's\n>  preferred format.  See the `strftime` manual for a complete list of\n> -format placeholders.\n> +format placeholders. When using `-local`, the correct syntax is\n> +`--date=format-local:...`.\n>  +\n> -`--date=default` shows timestamps in the original time zone\n> -(either committer's or author's).\n> +`--date=default` is the default format, and is similar to\n> +`--date=rfc2822`, with a few exceptions:\n> +\n> +\t- there is no comma after the day-of-week\n> +\n> +\t- the time zone is omitted when the local time zone is used\n>  \n>  ifdef::git-rev-list[]\n>  --header::\n> diff --git a/builtin/blame.c b/builtin/blame.c\n> index 4db01c1..6fd1a63 100644\n> --- a/builtin/blame.c\n> +++ b/builtin/blame.c\n> @@ -2600,7 +2600,6 @@ parse_done:\n>  \t\t   fewer display columns. */\n>  \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n>  \t\tbreak;\n> -\tcase DATE_LOCAL:\n>  \tcase DATE_NORMAL:\n>  \t\tblame_date_width = sizeof(\"Thu Oct 19 16:00:04 2006 -0700\");\n>  \t\tbreak;\n> diff --git a/cache.h b/cache.h\n> index 4e25271..9a91b1d 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -1091,7 +1091,6 @@ struct date_mode {\n>  \t\tDATE_NORMAL = 0,\n>  \t\tDATE_RELATIVE,\n>  \t\tDATE_SHORT,\n> -\t\tDATE_LOCAL,\n>  \t\tDATE_ISO8601,\n>  \t\tDATE_ISO8601_STRICT,\n>  \t\tDATE_RFC2822,\n> @@ -1099,6 +1098,7 @@ struct date_mode {\n>  \t\tDATE_RAW\n>  \t} type;\n>  \tconst char *strftime_fmt;\n> +\tint local;\n>  };\n>  \n>  /*\n> diff --git a/date.c b/date.c\n> index 8f91569..aa57cad 100644\n> --- a/date.c\n> +++ b/date.c\n> @@ -166,6 +166,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n>  \tif (type == DATE_STRFTIME)\n>  \t\tdie(\"BUG: cannot create anonymous strftime date_mode struct\");\n>  \tmode.type = type;\n> +\tmode.local = 0;\n>  \treturn &mode;\n>  }\n>  \n> @@ -189,7 +190,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n>  \t\treturn timebuf.buf;\n>  \t}\n>  \n> -\tif (mode->type == DATE_LOCAL)\n> +\tif (mode->local)\n>  \t\ttz = local_tzoffset(time);\n>  \n>  \ttm = time_to_tm(time, tz);\n> @@ -232,7 +233,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n>  \t\t\t\ttm->tm_mday,\n>  \t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n>  \t\t\t\ttm->tm_year + 1900,\n> -\t\t\t\t(mode->type == DATE_LOCAL) ? 0 : ' ',\n> +\t\t\t\tmode->local ? 0 : ' ',\n>  \t\t\t\ttz);\n>  \treturn timebuf.buf;\n>  }\n> @@ -770,32 +771,56 @@ int parse_date(const char *date, struct strbuf *result)\n>  \treturn 0;\n>  }\n>  \n> +static enum date_mode_type parse_date_type(const char *format, const char **end)\n> +{\n> +\tif (skip_prefix(format, \"relative\", end))\n> +\t\treturn DATE_RELATIVE;\n> +\tif (skip_prefix(format, \"iso8601-strict\", end) ||\n> +\t    skip_prefix(format, \"iso-strict\", end))\n> +\t\treturn DATE_ISO8601_STRICT;\n> +\tif (skip_prefix(format, \"iso8601\", end) ||\n> +\t    skip_prefix(format, \"iso\", end))\n> +\t\treturn DATE_ISO8601;\n> +\tif (skip_prefix(format, \"rfc2822\", end) ||\n> +\t    skip_prefix(format, \"rfc\", end))\n> +\t\treturn DATE_RFC2822;\n> +\tif (skip_prefix(format, \"short\", end))\n> +\t\treturn DATE_SHORT;\n> +\tif (skip_prefix(format, \"default\", end))\n> +\t\treturn DATE_NORMAL;\n> +\tif (skip_prefix(format, \"raw\", end))\n> +\t\treturn DATE_RAW;\n> +\tif (skip_prefix(format, \"format\", end))\n> +\t\treturn DATE_STRFTIME;\n> +\n> +\tdie(\"unknown date format %s\", format);\n> +}\n> +\n>  void parse_date_format(const char *format, struct date_mode *mode)\n>  {\n> -\tif (!strcmp(format, \"relative\"))\n> -\t\tmode->type = DATE_RELATIVE;\n> -\telse if (!strcmp(format, \"iso8601\") ||\n> -\t\t !strcmp(format, \"iso\"))\n> -\t\tmode->type = DATE_ISO8601;\n> -\telse if (!strcmp(format, \"iso8601-strict\") ||\n> -\t\t !strcmp(format, \"iso-strict\"))\n> -\t\tmode->type = DATE_ISO8601_STRICT;\n> -\telse if (!strcmp(format, \"rfc2822\") ||\n> -\t\t !strcmp(format, \"rfc\"))\n> -\t\tmode->type = DATE_RFC2822;\n> -\telse if (!strcmp(format, \"short\"))\n> -\t\tmode->type = DATE_SHORT;\n> -\telse if (!strcmp(format, \"local\"))\n> -\t\tmode->type = DATE_LOCAL;\n> -\telse if (!strcmp(format, \"default\"))\n> -\t\tmode->type = DATE_NORMAL;\n> -\telse if (!strcmp(format, \"raw\"))\n> -\t\tmode->type = DATE_RAW;\n> -\telse if (skip_prefix(format, \"format:\", &format)) {\n> -\t\tmode->type = DATE_STRFTIME;\n> -\t\tmode->strftime_fmt = xstrdup(format);\n> -\t} else\n> -\t\tdie(\"unknown date format %s\", format);\n> +\tconst char *p;\n> +\n> +\t/* historical alias */\n> +\tif (!strcmp(format, \"local\"))\n> +\t\tformat = \"default-local\";\n> +\n> +\tmode->type = parse_date_type(format, &p);\n> +\tmode->local = 0;\n> +\n> +\tif (skip_prefix(p, \"-local\", &p)) {\n> +\t\tif (mode->type == DATE_RELATIVE)\n> +\t\t\tdie(\"relative-local date format is nonsensical\");\n> +\t\tmode->local = 1;\n> +\t}\n> +\n> +\tif (mode->type == DATE_STRFTIME) {\n> +\t\tif (!skip_prefix(p, \":\", &p))\n> +\t\t\tdie(\"date format missing colon separator: %s\", format);\n> +\t\tmode->strftime_fmt = xstrdup(p);\n> +\t}\n> +\n> +\tif (*p)\n> +\t\tdie(\"unknown date-mode modifier: %s\", p);\n>  }\n>  \n>  void datestamp(struct strbuf *out)\n> -- \n> 2.5.1.739.g7891f6b\n"},{"id":"269057","messageId":"20150831213336.GA11720@sigill.intra.peff.net","threadId":"40221","inReplyTo":"20150831212754.GD30659@serenity.lan","subject":"Re: [PATCH 2/2] date: make \"local\" orthogonal to date format","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-08-31T21:33:37Z","receivedAt":"2015-08-31T21:33:37Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Aug 31, 2015 at 10:27:54PM +0100, John Keeping wrote:\n\n> This fails t6300 with:\n> \n> fatal: unknown date-mode modifier: my date is %Y-%m-%d\n> not ok 83 - Check format of strftime date fields\n> #\n> #               echo \"my date is 2006-07-03\" >expected &&\n> #               git for-each-ref \\\n> #                 --format=\"%(authordate:format:my date is %Y-%m-%d)\" \\\n> #                 refs/heads >actual &&\n> #               test_cmp expected actual\n> #\n\nWhoops. I obviously did not actually run the test suite. I think when\nwriting the commit message, my brain said \"we are not changing anything,\nso no need to run the tests\", forgetting that I did not run them the\nfirst time when posting an untested \"eh, how about this\" patch.\n\n> The following squash-in fixes it:\n> \n> diff --git a/date.c b/date.c\n> index aa57cad..3aa8002 100644\n> --- a/date.c\n> +++ b/date.c\n> @@ -817,9 +817,7 @@ void parse_date_format(const char *format, struct date_mode *mode)\n>  \t\tif (!skip_prefix(p, \":\", &p))\n>  \t\t\tdie(\"date format missing colon separator: %s\", format);\n>  \t\tmode->strftime_fmt = xstrdup(p);\n> -\t}\n> -\n> -\tif (*p)\n> +\t} else if (*p)\n>  \t\tdie(\"unknown date-mode modifier: %s\", p);\n\nYeah, that works. We could also advance \"p\" in the DATE_STRFTIME\nconditional, but I think your solution is less ugly.\n\nThanks for debugging my mess.\n\n-Peff\n"},{"id":"269061","messageId":"20150831220508.GA31973@sigill.intra.peff.net","threadId":"40221","inReplyTo":"20150831213336.GA11720@sigill.intra.peff.net","subject":"Re: [PATCH 2/2] date: make \"local\" orthogonal to date format","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-08-31T22:05:09Z","receivedAt":"2015-08-31T22:05:09Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Aug 31, 2015 at 05:33:37PM -0400, Jeff King wrote:\n\n> > diff --git a/date.c b/date.c\n> > index aa57cad..3aa8002 100644\n> > --- a/date.c\n> > +++ b/date.c\n> > @@ -817,9 +817,7 @@ void parse_date_format(const char *format, struct date_mode *mode)\n> >  \t\tif (!skip_prefix(p, \":\", &p))\n> >  \t\t\tdie(\"date format missing colon separator: %s\", format);\n> >  \t\tmode->strftime_fmt = xstrdup(p);\n> > -\t}\n> > -\n> > -\tif (*p)\n> > +\t} else if (*p)\n> >  \t\tdie(\"unknown date-mode modifier: %s\", p);\n> \n> Yeah, that works. We could also advance \"p\" in the DATE_STRFTIME\n> conditional, but I think your solution is less ugly.\n> \n> Thanks for debugging my mess.\n\nBy the way, I was imagining you would pick these up and add to them with\nmore tests and documentation. If that's the case, please feel free to\nsquash that in and keep my signoff. If not, then I can post a re-roll\nafter waiting for other comments.\n\n-Peff\n"},{"id":"269085","messageId":"20150901083731.GE30659@serenity.lan","threadId":"40221","inReplyTo":"20150831220508.GA31973@sigill.intra.peff.net","subject":"Re: [PATCH 2/2] date: make \"local\" orthogonal to date format","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-01T08:37:31Z","receivedAt":"2015-09-01T08:37:31Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"On Mon, Aug 31, 2015 at 06:05:09PM -0400, Jeff King wrote:\n> On Mon, Aug 31, 2015 at 05:33:37PM -0400, Jeff King wrote:\n> \n> > > diff --git a/date.c b/date.c\n> > > index aa57cad..3aa8002 100644\n> > > --- a/date.c\n> > > +++ b/date.c\n> > > @@ -817,9 +817,7 @@ void parse_date_format(const char *format, struct date_mode *mode)\n> > >  \t\tif (!skip_prefix(p, \":\", &p))\n> > >  \t\t\tdie(\"date format missing colon separator: %s\", format);\n> > >  \t\tmode->strftime_fmt = xstrdup(p);\n> > > -\t}\n> > > -\n> > > -\tif (*p)\n> > > +\t} else if (*p)\n> > >  \t\tdie(\"unknown date-mode modifier: %s\", p);\n> > \n> > Yeah, that works. We could also advance \"p\" in the DATE_STRFTIME\n> > conditional, but I think your solution is less ugly.\n> > \n> > Thanks for debugging my mess.\n> \n> By the way, I was imagining you would pick these up and add to them with\n> more tests and documentation. If that's the case, please feel free to\n> squash that in and keep my signoff. If not, then I can post a re-roll\n> after waiting for other comments.\n\nOK, I'll send them with some additions to t6300 built on top, although\nit may take a couple of days.\n\nThe other documentation improvements feel like an independent topic that\nisn't necessary for this series to graduate; I'd prefer not to block\nthis waiting for those changes.\n"},{"id":"269155","messageId":"cover.1441144343.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"20150901083731.GE30659@serenity.lan","subject":"[PATCH v2 0/6] Make \"local\" orthogonal to date format","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-01T21:55:38Z","receivedAt":"2015-09-01T21:55:38Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"Jeff's first patch is unmodified but I've squashed the fixed currently\non \"pu\" into the second.  I also realised while adding the tests that\n\"raw-local\" is meaningless so I've modified the code to reject it in the\nsame way as \"relative-local\".\n\nJeff King (2):\n  fast-import: switch crash-report date to iso8601\n  date: make \"local\" orthogonal to date format\n\nJohn Keeping (4):\n  t6300: introduce test_date() helper\n  t6300: make UTC and local dates different\n  t6300: add test for \"raw\" date format\n  t6300: add tests for \"-local\" date formats\n\n Documentation/rev-list-options.txt |  21 ++++--\n builtin/blame.c                    |   1 -\n cache.h                            |   2 +-\n date.c                             |  77 +++++++++++++-------\n fast-import.c                      |   2 +-\n t/t6300-for-each-ref.sh            | 139 +++++++++++++++++++------------------\n 6 files changed, 140 insertions(+), 102 deletions(-)\n\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269156","messageId":"4977dd98027fa3b456d23e8300ec87dd54ee421e.1441144343.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441144343.git.john@keeping.me.uk","subject":"[PATCH v2 1/6] fast-import: switch crash-report date to iso8601","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-01T21:55:39Z","receivedAt":"2015-09-01T21:55:39Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nWhen fast-import emits a crash report, it does so in the\nuser's local timezone. But because we omit the timezone\ncompletely for DATE_LOCAL, a reader of the report does not\nimmediately know which time zone was used. Let's switch this\nto ISO8601 instead, which includes the time zone.\n\nThis does mean we will show the time in UTC, but that's not\na big deal. A crash report like this will either be looked\nat immediately (in which case nobody even looks at the\ntimestamp), or it will be passed along to a developer to\ndebug, in which case the original timezone is less likely to\nbe of interest.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: John Keeping <john@keeping.me.uk>\n---\n fast-import.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 6c7c3c9..adcbfc6 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -424,7 +424,7 @@ static void write_crash_report(const char *err)\n \tfprintf(rpt, \"fast-import crash report:\\n\");\n \tfprintf(rpt, \"    fast-import process: %\"PRIuMAX\"\\n\", (uintmax_t) getpid());\n \tfprintf(rpt, \"    parent process     : %\"PRIuMAX\"\\n\", (uintmax_t) getppid());\n-\tfprintf(rpt, \"    at %s\\n\", show_date(time(NULL), 0, DATE_MODE(LOCAL)));\n+\tfprintf(rpt, \"    at %s\\n\", show_date(time(NULL), 0, DATE_MODE(ISO8601)));\n \tfputc('\\n', rpt);\n \n \tfputs(\"fatal: \", rpt);\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269157","messageId":"35b1313d4eb084ddc2bd70510d56e11a1d84e993.1441144343.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441144343.git.john@keeping.me.uk","subject":"[PATCH v2 2/6] date: make \"local\" orthogonal to date format","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-01T21:55:40Z","receivedAt":"2015-09-01T21:55:40Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nMost of our \"--date\" modes are about the format of the date:\nwhich items we show and in what order. But \"--date=local\" is\na bit of an oddball. It means \"show the date in the normal\nformat, but using the local timezone\". The timezone we use\nis orthogonal to the actual format, and there is no reason\nwe could not have \"localized iso8601\", etc.\n\nThis patch adds a \"local\" boolean field to \"struct\ndate_mode\", and drops the DATE_LOCAL element from the\ndate_mode_type enum (it's now just DATE_NORMAL plus\nlocal=1). The new feature is accessible to users by adding\n\"-local\" to any date mode (e.g., \"iso-local\"), and we retain\n\"local\" as an alias for \"default-local\" for backwards\ncompatibility.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: John Keeping <john@keeping.me.uk>\n---\nThis is Jeff's original patch with my fixup for DATE_STRFTIME squashed\nin and a new change to reject \"raw-local\" (in both Documentation/ and\ndate.c).\n\n Documentation/rev-list-options.txt | 21 ++++++++---\n builtin/blame.c                    |  1 -\n cache.h                            |  2 +-\n date.c                             | 77 +++++++++++++++++++++++++-------------\n 4 files changed, 67 insertions(+), 34 deletions(-)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex a9b808f..5d28133 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -702,12 +702,16 @@ include::pretty-options.txt[]\n --date=(relative|local|default|iso|iso-strict|rfc|short|raw)::\n \tOnly takes effect for dates shown in human-readable format, such\n \tas when using `--pretty`. `log.date` config variable sets a default\n-\tvalue for the log command's `--date` option.\n+\tvalue for the log command's `--date` option. By default, dates\n+\tare shown in the original time zone (either committer's or\n+\tauthor's). If `-local` is appended to the format (e.g.,\n+\t`iso-local`), the user's local time zone is used instead.\n +\n `--date=relative` shows dates relative to the current time,\n-e.g. ``2 hours ago''.\n+e.g. ``2 hours ago''. The `-local` option cannot be used with\n+`--raw` or `--relative`.\n +\n-`--date=local` shows timestamps in user's local time zone.\n+`--date=local` is an alias for `--date=default-local`.\n +\n `--date=iso` (or `--date=iso8601`) shows timestamps in a ISO 8601-like format.\n The differences to the strict ISO 8601 format are:\n@@ -730,10 +734,15 @@ format, often found in email messages.\n `--date=format:...` feeds the format `...` to your system `strftime`.\n Use `--date=format:%c` to show the date in your system locale's\n preferred format.  See the `strftime` manual for a complete list of\n-format placeholders.\n+format placeholders. When using `-local`, the correct syntax is\n+`--date=format-local:...`.\n +\n-`--date=default` shows timestamps in the original time zone\n-(either committer's or author's).\n+`--date=default` is the default format, and is similar to\n+`--date=rfc2822`, with a few exceptions:\n+\n+\t- there is no comma after the day-of-week\n+\n+\t- the time zone is omitted when the local time zone is used\n \n ifdef::git-rev-list[]\n --header::\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 4db01c1..6fd1a63 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2600,7 +2600,6 @@ parse_done:\n \t\t   fewer display columns. */\n \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n \t\tbreak;\n-\tcase DATE_LOCAL:\n \tcase DATE_NORMAL:\n \t\tblame_date_width = sizeof(\"Thu Oct 19 16:00:04 2006 -0700\");\n \t\tbreak;\ndiff --git a/cache.h b/cache.h\nindex 4e25271..9a91b1d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1091,7 +1091,6 @@ struct date_mode {\n \t\tDATE_NORMAL = 0,\n \t\tDATE_RELATIVE,\n \t\tDATE_SHORT,\n-\t\tDATE_LOCAL,\n \t\tDATE_ISO8601,\n \t\tDATE_ISO8601_STRICT,\n \t\tDATE_RFC2822,\n@@ -1099,6 +1098,7 @@ struct date_mode {\n \t\tDATE_RAW\n \t} type;\n \tconst char *strftime_fmt;\n+\tint local;\n };\n \n /*\ndiff --git a/date.c b/date.c\nindex 8f91569..f048416 100644\n--- a/date.c\n+++ b/date.c\n@@ -166,6 +166,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \tif (type == DATE_STRFTIME)\n \t\tdie(\"BUG: cannot create anonymous strftime date_mode struct\");\n \tmode.type = type;\n+\tmode.local = 0;\n \treturn &mode;\n }\n \n@@ -189,7 +190,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \t\treturn timebuf.buf;\n \t}\n \n-\tif (mode->type == DATE_LOCAL)\n+\tif (mode->local)\n \t\ttz = local_tzoffset(time);\n \n \ttm = time_to_tm(time, tz);\n@@ -232,7 +233,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \t\t\t\ttm->tm_mday,\n \t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n \t\t\t\ttm->tm_year + 1900,\n-\t\t\t\t(mode->type == DATE_LOCAL) ? 0 : ' ',\n+\t\t\t\tmode->local ? 0 : ' ',\n \t\t\t\ttz);\n \treturn timebuf.buf;\n }\n@@ -770,32 +771,56 @@ int parse_date(const char *date, struct strbuf *result)\n \treturn 0;\n }\n \n+static enum date_mode_type parse_date_type(const char *format, const char **end)\n+{\n+\tif (skip_prefix(format, \"relative\", end))\n+\t\treturn DATE_RELATIVE;\n+\tif (skip_prefix(format, \"iso8601-strict\", end) ||\n+\t    skip_prefix(format, \"iso-strict\", end))\n+\t\treturn DATE_ISO8601_STRICT;\n+\tif (skip_prefix(format, \"iso8601\", end) ||\n+\t    skip_prefix(format, \"iso\", end))\n+\t\treturn DATE_ISO8601;\n+\tif (skip_prefix(format, \"rfc2822\", end) ||\n+\t    skip_prefix(format, \"rfc\", end))\n+\t\treturn DATE_RFC2822;\n+\tif (skip_prefix(format, \"short\", end))\n+\t\treturn DATE_SHORT;\n+\tif (skip_prefix(format, \"default\", end))\n+\t\treturn DATE_NORMAL;\n+\tif (skip_prefix(format, \"raw\", end))\n+\t\treturn DATE_RAW;\n+\tif (skip_prefix(format, \"format\", end))\n+\t\treturn DATE_STRFTIME;\n+\n+\tdie(\"unknown date format %s\", format);\n+}\n+\n void parse_date_format(const char *format, struct date_mode *mode)\n {\n-\tif (!strcmp(format, \"relative\"))\n-\t\tmode->type = DATE_RELATIVE;\n-\telse if (!strcmp(format, \"iso8601\") ||\n-\t\t !strcmp(format, \"iso\"))\n-\t\tmode->type = DATE_ISO8601;\n-\telse if (!strcmp(format, \"iso8601-strict\") ||\n-\t\t !strcmp(format, \"iso-strict\"))\n-\t\tmode->type = DATE_ISO8601_STRICT;\n-\telse if (!strcmp(format, \"rfc2822\") ||\n-\t\t !strcmp(format, \"rfc\"))\n-\t\tmode->type = DATE_RFC2822;\n-\telse if (!strcmp(format, \"short\"))\n-\t\tmode->type = DATE_SHORT;\n-\telse if (!strcmp(format, \"local\"))\n-\t\tmode->type = DATE_LOCAL;\n-\telse if (!strcmp(format, \"default\"))\n-\t\tmode->type = DATE_NORMAL;\n-\telse if (!strcmp(format, \"raw\"))\n-\t\tmode->type = DATE_RAW;\n-\telse if (skip_prefix(format, \"format:\", &format)) {\n-\t\tmode->type = DATE_STRFTIME;\n-\t\tmode->strftime_fmt = xstrdup(format);\n-\t} else\n-\t\tdie(\"unknown date format %s\", format);\n+\tconst char *p;\n+\n+\t/* historical alias */\n+\tif (!strcmp(format, \"local\"))\n+\t\tformat = \"default-local\";\n+\n+\tmode->type = parse_date_type(format, &p);\n+\tmode->local = 0;\n+\n+\tif (skip_prefix(p, \"-local\", &p)) {\n+\t\tif (mode->type == DATE_RELATIVE)\n+\t\t\tdie(\"relative-local date format is nonsensical\");\n+\t\tif (mode->type == DATE_RAW)\n+\t\t\tdie(\"raw-local date format is nonsensical\");\n+\t\tmode->local = 1;\n+\t}\n+\n+\tif (mode->type == DATE_STRFTIME) {\n+\t\tif (!skip_prefix(p, \":\", &p))\n+\t\t\tdie(\"date format missing colon separator: %s\", format);\n+\t\tmode->strftime_fmt = xstrdup(p);\n+\t} else if (*p)\n+\t\tdie(\"unknown date-mode modifier: %s\", p);\n }\n \n void datestamp(struct strbuf *out)\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269158","messageId":"8e869f362971a44bb1f40ca5fed98b658efaa0dd.1441144343.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441144343.git.john@keeping.me.uk","subject":"[PATCH v2 3/6] t6300: introduce test_date() helper","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-01T21:55:41Z","receivedAt":"2015-09-01T21:55:41Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"This moves the setup of the \"expected\" file inside the test case.  The\nhelper function has the advantage that we can use SQ in the file content\nwithout needing to escape the quotes.\n\nSigned-off-by: John Keeping <john@keeping.me.uk>\n---\nI considered moving the test_expect_success into the helper, like with\ntest_atom earlier in the file, but it doesn't make the code much more\nconcise and we still need either to setup the output outside the test\ncase or to escape SQ inside SQ.\n\n t/t6300-for-each-ref.sh | 73 ++++++++++++++-----------------------------------\n 1 file changed, 21 insertions(+), 52 deletions(-)\n\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 7c9bec7..5fdb964 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -146,85 +146,54 @@ test_expect_success 'Check invalid format specifiers are errors' '\n \ttest_must_fail git for-each-ref --format=\"%(authordate:INVALID)\" refs/heads\n '\n \n-cat >expected <<\\EOF\n-'refs/heads/master' 'Mon Jul 3 17:18:43 2006 +0200' 'Mon Jul 3 17:18:44 2006 +0200'\n-'refs/tags/testtag' 'Mon Jul 3 17:18:45 2006 +0200'\n-EOF\n+test_date () {\n+\tf=$1\n+\tcommitter_date=$2 &&\n+\tauthor_date=$3 &&\n+\ttagger_date=$4 &&\n+\tcat >expected <<-EOF &&\n+\t'refs/heads/master' '$committer_date' '$author_date'\n+\t'refs/tags/testtag' '$tagger_date'\n+\tEOF\n+\t(\n+\t\tgit for-each-ref --shell --format=\"%(refname) %(committerdate${f:+:$f}) %(authordate${f:+:$f})\" refs/heads &&\n+\t\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate${f:+:$f})\" refs/tags\n+\t) >actual &&\n+\ttest_cmp expected actual\n+}\n \n test_expect_success 'Check unformatted date fields output' '\n-\t(git for-each-ref --shell --format=\"%(refname) %(committerdate) %(authordate)\" refs/heads &&\n-\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate)\" refs/tags) >actual &&\n-\ttest_cmp expected actual\n+\ttest_date \"\" \"Mon Jul 3 17:18:43 2006 +0200\" \"Mon Jul 3 17:18:44 2006 +0200\" \"Mon Jul 3 17:18:45 2006 +0200\"\n '\n \n test_expect_success 'Check format \"default\" formatted date fields output' '\n-\tf=default &&\n-\t(git for-each-ref --shell --format=\"%(refname) %(committerdate:$f) %(authordate:$f)\" refs/heads &&\n-\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate:$f)\" refs/tags) >actual &&\n-\ttest_cmp expected actual\n+\ttest_date default \"Mon Jul 3 17:18:43 2006 +0200\" \"Mon Jul 3 17:18:44 2006 +0200\" \"Mon Jul 3 17:18:45 2006 +0200\"\n '\n \n # Don't know how to do relative check because I can't know when this script\n # is going to be run and can't fake the current time to git, and hence can't\n # provide expected output.  Instead, I'll just make sure that \"relative\"\n # doesn't exit in error\n-#\n-#cat >expected <<\\EOF\n-#\n-#EOF\n-#\n test_expect_success 'Check format \"relative\" date fields output' '\n \tf=relative &&\n \t(git for-each-ref --shell --format=\"%(refname) %(committerdate:$f) %(authordate:$f)\" refs/heads &&\n \tgit for-each-ref --shell --format=\"%(refname) %(taggerdate:$f)\" refs/tags) >actual\n '\n \n-cat >expected <<\\EOF\n-'refs/heads/master' '2006-07-03' '2006-07-03'\n-'refs/tags/testtag' '2006-07-03'\n-EOF\n-\n test_expect_success 'Check format \"short\" date fields output' '\n-\tf=short &&\n-\t(git for-each-ref --shell --format=\"%(refname) %(committerdate:$f) %(authordate:$f)\" refs/heads &&\n-\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate:$f)\" refs/tags) >actual &&\n-\ttest_cmp expected actual\n+\ttest_date short 2006-07-03 2006-07-03 2006-07-03\n '\n \n-cat >expected <<\\EOF\n-'refs/heads/master' 'Mon Jul 3 15:18:43 2006' 'Mon Jul 3 15:18:44 2006'\n-'refs/tags/testtag' 'Mon Jul 3 15:18:45 2006'\n-EOF\n-\n test_expect_success 'Check format \"local\" date fields output' '\n-\tf=local &&\n-\t(git for-each-ref --shell --format=\"%(refname) %(committerdate:$f) %(authordate:$f)\" refs/heads &&\n-\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate:$f)\" refs/tags) >actual &&\n-\ttest_cmp expected actual\n+\ttest_date local \"Mon Jul 3 15:18:43 2006\" \"Mon Jul 3 15:18:44 2006\" \"Mon Jul 3 15:18:45 2006\"\n '\n \n-cat >expected <<\\EOF\n-'refs/heads/master' '2006-07-03 17:18:43 +0200' '2006-07-03 17:18:44 +0200'\n-'refs/tags/testtag' '2006-07-03 17:18:45 +0200'\n-EOF\n-\n test_expect_success 'Check format \"iso8601\" date fields output' '\n-\tf=iso8601 &&\n-\t(git for-each-ref --shell --format=\"%(refname) %(committerdate:$f) %(authordate:$f)\" refs/heads &&\n-\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate:$f)\" refs/tags) >actual &&\n-\ttest_cmp expected actual\n+\ttest_date iso8601 \"2006-07-03 17:18:43 +0200\" \"2006-07-03 17:18:44 +0200\" \"2006-07-03 17:18:45 +0200\"\n '\n \n-cat >expected <<\\EOF\n-'refs/heads/master' 'Mon, 3 Jul 2006 17:18:43 +0200' 'Mon, 3 Jul 2006 17:18:44 +0200'\n-'refs/tags/testtag' 'Mon, 3 Jul 2006 17:18:45 +0200'\n-EOF\n-\n test_expect_success 'Check format \"rfc2822\" date fields output' '\n-\tf=rfc2822 &&\n-\t(git for-each-ref --shell --format=\"%(refname) %(committerdate:$f) %(authordate:$f)\" refs/heads &&\n-\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate:$f)\" refs/tags) >actual &&\n-\ttest_cmp expected actual\n+\ttest_date rfc2822 \"Mon, 3 Jul 2006 17:18:43 +0200\" \"Mon, 3 Jul 2006 17:18:44 +0200\" \"Mon, 3 Jul 2006 17:18:45 +0200\"\n '\n \n test_expect_success 'Check format of strftime date fields' '\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269159","messageId":"ea99176ca84d865e22fa09afd38d2495e0837b67.1441144343.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441144343.git.john@keeping.me.uk","subject":"[PATCH v2 4/6] t6300: make UTC and local dates different","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-01T21:55:42Z","receivedAt":"2015-09-01T21:55:42Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"By setting the UTC time to 23:18:43 the date in +0200 is the following\nday, 2006-07-04.  This will ensure that the test for \"short-local\" to be\nadded in a following patch tests for different output from the \"short\"\nformat.\n\nSigned-off-by: John Keeping <john@keeping.me.uk>\n---\n t/t6300-for-each-ref.sh | 48 ++++++++++++++++++++++++------------------------\n 1 file changed, 24 insertions(+), 24 deletions(-)\n\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 5fdb964..9e0096f 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -8,8 +8,8 @@ test_description='for-each-ref test'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-gpg.sh\n \n-# Mon Jul 3 15:18:43 2006 +0000\n-datestamp=1151939923\n+# Mon Jul 3 23:18:43 2006 +0000\n+datestamp=1151968723\n setdate_and_increment () {\n     GIT_COMMITTER_DATE=\"$datestamp +0200\"\n     datestamp=$(expr \"$datestamp\" + 1)\n@@ -61,21 +61,21 @@ test_atom head object ''\n test_atom head type ''\n test_atom head '*objectname' ''\n test_atom head '*objecttype' ''\n-test_atom head author 'A U Thor <author@example.com> 1151939924 +0200'\n+test_atom head author 'A U Thor <author@example.com> 1151968724 +0200'\n test_atom head authorname 'A U Thor'\n test_atom head authoremail '<author@example.com>'\n-test_atom head authordate 'Mon Jul 3 17:18:44 2006 +0200'\n-test_atom head committer 'C O Mitter <committer@example.com> 1151939923 +0200'\n+test_atom head authordate 'Tue Jul 4 01:18:44 2006 +0200'\n+test_atom head committer 'C O Mitter <committer@example.com> 1151968723 +0200'\n test_atom head committername 'C O Mitter'\n test_atom head committeremail '<committer@example.com>'\n-test_atom head committerdate 'Mon Jul 3 17:18:43 2006 +0200'\n+test_atom head committerdate 'Tue Jul 4 01:18:43 2006 +0200'\n test_atom head tag ''\n test_atom head tagger ''\n test_atom head taggername ''\n test_atom head taggeremail ''\n test_atom head taggerdate ''\n-test_atom head creator 'C O Mitter <committer@example.com> 1151939923 +0200'\n-test_atom head creatordate 'Mon Jul 3 17:18:43 2006 +0200'\n+test_atom head creator 'C O Mitter <committer@example.com> 1151968723 +0200'\n+test_atom head creatordate 'Tue Jul 4 01:18:43 2006 +0200'\n test_atom head subject 'Initial'\n test_atom head contents:subject 'Initial'\n test_atom head body ''\n@@ -96,7 +96,7 @@ test_atom tag parent ''\n test_atom tag numparent ''\n test_atom tag object $(git rev-parse refs/tags/testtag^0)\n test_atom tag type 'commit'\n-test_atom tag '*objectname' '67a36f10722846e891fbada1ba48ed035de75581'\n+test_atom tag '*objectname' 'ea122842f48be4afb2d1fc6a4b96c05885ab7463'\n test_atom tag '*objecttype' 'commit'\n test_atom tag author ''\n test_atom tag authorname ''\n@@ -107,18 +107,18 @@ test_atom tag committername ''\n test_atom tag committeremail ''\n test_atom tag committerdate ''\n test_atom tag tag 'testtag'\n-test_atom tag tagger 'C O Mitter <committer@example.com> 1151939925 +0200'\n+test_atom tag tagger 'C O Mitter <committer@example.com> 1151968725 +0200'\n test_atom tag taggername 'C O Mitter'\n test_atom tag taggeremail '<committer@example.com>'\n-test_atom tag taggerdate 'Mon Jul 3 17:18:45 2006 +0200'\n-test_atom tag creator 'C O Mitter <committer@example.com> 1151939925 +0200'\n-test_atom tag creatordate 'Mon Jul 3 17:18:45 2006 +0200'\n-test_atom tag subject 'Tagging at 1151939927'\n-test_atom tag contents:subject 'Tagging at 1151939927'\n+test_atom tag taggerdate 'Tue Jul 4 01:18:45 2006 +0200'\n+test_atom tag creator 'C O Mitter <committer@example.com> 1151968725 +0200'\n+test_atom tag creatordate 'Tue Jul 4 01:18:45 2006 +0200'\n+test_atom tag subject 'Tagging at 1151968727'\n+test_atom tag contents:subject 'Tagging at 1151968727'\n test_atom tag body ''\n test_atom tag contents:body ''\n test_atom tag contents:signature ''\n-test_atom tag contents 'Tagging at 1151939927\n+test_atom tag contents 'Tagging at 1151968727\n '\n test_atom tag HEAD ' '\n \n@@ -163,11 +163,11 @@ test_date () {\n }\n \n test_expect_success 'Check unformatted date fields output' '\n-\ttest_date \"\" \"Mon Jul 3 17:18:43 2006 +0200\" \"Mon Jul 3 17:18:44 2006 +0200\" \"Mon Jul 3 17:18:45 2006 +0200\"\n+\ttest_date \"\" \"Tue Jul 4 01:18:43 2006 +0200\" \"Tue Jul 4 01:18:44 2006 +0200\" \"Tue Jul 4 01:18:45 2006 +0200\"\n '\n \n test_expect_success 'Check format \"default\" formatted date fields output' '\n-\ttest_date default \"Mon Jul 3 17:18:43 2006 +0200\" \"Mon Jul 3 17:18:44 2006 +0200\" \"Mon Jul 3 17:18:45 2006 +0200\"\n+\ttest_date default \"Tue Jul 4 01:18:43 2006 +0200\" \"Tue Jul 4 01:18:44 2006 +0200\" \"Tue Jul 4 01:18:45 2006 +0200\"\n '\n \n # Don't know how to do relative check because I can't know when this script\n@@ -181,23 +181,23 @@ test_expect_success 'Check format \"relative\" date fields output' '\n '\n \n test_expect_success 'Check format \"short\" date fields output' '\n-\ttest_date short 2006-07-03 2006-07-03 2006-07-03\n+\ttest_date short 2006-07-04 2006-07-04 2006-07-04\n '\n \n test_expect_success 'Check format \"local\" date fields output' '\n-\ttest_date local \"Mon Jul 3 15:18:43 2006\" \"Mon Jul 3 15:18:44 2006\" \"Mon Jul 3 15:18:45 2006\"\n+\ttest_date local \"Mon Jul 3 23:18:43 2006\" \"Mon Jul 3 23:18:44 2006\" \"Mon Jul 3 23:18:45 2006\"\n '\n \n test_expect_success 'Check format \"iso8601\" date fields output' '\n-\ttest_date iso8601 \"2006-07-03 17:18:43 +0200\" \"2006-07-03 17:18:44 +0200\" \"2006-07-03 17:18:45 +0200\"\n+\ttest_date iso8601 \"2006-07-04 01:18:43 +0200\" \"2006-07-04 01:18:44 +0200\" \"2006-07-04 01:18:45 +0200\"\n '\n \n test_expect_success 'Check format \"rfc2822\" date fields output' '\n-\ttest_date rfc2822 \"Mon, 3 Jul 2006 17:18:43 +0200\" \"Mon, 3 Jul 2006 17:18:44 +0200\" \"Mon, 3 Jul 2006 17:18:45 +0200\"\n+\ttest_date rfc2822 \"Tue, 4 Jul 2006 01:18:43 +0200\" \"Tue, 4 Jul 2006 01:18:44 +0200\" \"Tue, 4 Jul 2006 01:18:45 +0200\"\n '\n \n test_expect_success 'Check format of strftime date fields' '\n-\techo \"my date is 2006-07-03\" >expected &&\n+\techo \"my date is 2006-07-04\" >expected &&\n \tgit for-each-ref \\\n \t  --format=\"%(authordate:format:my date is %Y-%m-%d)\" \\\n \t  refs/heads >actual &&\n@@ -515,8 +515,8 @@ body contents\n $sig\"\n \n cat >expected <<EOF\n-$(git rev-parse refs/tags/master) <committer@example.com> refs/tags/master\n $(git rev-parse refs/tags/bogo) <committer@example.com> refs/tags/bogo\n+$(git rev-parse refs/tags/master) <committer@example.com> refs/tags/master\n EOF\n \n test_expect_success 'Verify sort with multiple keys' '\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269160","messageId":"2d0ac9bc81db744897f32de6ef1ebec69fdaae9f.1441144343.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441144343.git.john@keeping.me.uk","subject":"[PATCH v2 5/6] t6300: add test for \"raw\" date format","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-01T21:55:43Z","receivedAt":"2015-09-01T21:55:43Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"Signed-off-by: John Keeping <john@keeping.me.uk>\n---\n t/t6300-for-each-ref.sh | 4 ++++\n 1 file changed, 4 insertions(+)\n\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 9e0096f..2e76ca9 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -196,6 +196,10 @@ test_expect_success 'Check format \"rfc2822\" date fields output' '\n \ttest_date rfc2822 \"Tue, 4 Jul 2006 01:18:43 +0200\" \"Tue, 4 Jul 2006 01:18:44 +0200\" \"Tue, 4 Jul 2006 01:18:45 +0200\"\n '\n \n+test_expect_success 'Check format \"raw\" date fields output' '\n+\ttest_date raw \"1151968723 +0200\" \"1151968724 +0200\" \"1151968725 +0200\"\n+'\n+\n test_expect_success 'Check format of strftime date fields' '\n \techo \"my date is 2006-07-04\" >expected &&\n \tgit for-each-ref \\\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269161","messageId":"2663f49187d2e7617a21c6e22e93e56a879fff10.1441144343.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441144343.git.john@keeping.me.uk","subject":"[PATCH v2 6/6] t6300: add tests for \"-local\" date formats","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-01T21:55:44Z","receivedAt":"2015-09-01T21:55:44Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"Signed-off-by: John Keeping <john@keeping.me.uk>\n---\n t/t6300-for-each-ref.sh | 32 ++++++++++++++++++++++++++++++++\n 1 file changed, 32 insertions(+)\n\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 2e76ca9..c3aee70 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -170,6 +170,10 @@ test_expect_success 'Check format \"default\" formatted date fields output' '\n \ttest_date default \"Tue Jul 4 01:18:43 2006 +0200\" \"Tue Jul 4 01:18:44 2006 +0200\" \"Tue Jul 4 01:18:45 2006 +0200\"\n '\n \n+test_expect_success 'Check format \"default-local\" date fields output' '\n+\ttest_date default-local \"Mon Jul 3 23:18:43 2006\" \"Mon Jul 3 23:18:44 2006\" \"Mon Jul 3 23:18:45 2006\"\n+'\n+\n # Don't know how to do relative check because I can't know when this script\n # is going to be run and can't fake the current time to git, and hence can't\n # provide expected output.  Instead, I'll just make sure that \"relative\"\n@@ -180,10 +184,18 @@ test_expect_success 'Check format \"relative\" date fields output' '\n \tgit for-each-ref --shell --format=\"%(refname) %(taggerdate:$f)\" refs/tags) >actual\n '\n \n+test_expect_success 'Format \"relative-local\" is not allowed' '\n+\ttest_must_fail git for-each-ref --format=\"%(authordate:relative-local)\" refs/heads\n+'\n+\n test_expect_success 'Check format \"short\" date fields output' '\n \ttest_date short 2006-07-04 2006-07-04 2006-07-04\n '\n \n+test_expect_success 'Check format \"short-local\" date fields output' '\n+\ttest_date short-local 2006-07-03 2006-07-03 2006-07-03\n+'\n+\n test_expect_success 'Check format \"local\" date fields output' '\n \ttest_date local \"Mon Jul 3 23:18:43 2006\" \"Mon Jul 3 23:18:44 2006\" \"Mon Jul 3 23:18:45 2006\"\n '\n@@ -192,14 +204,26 @@ test_expect_success 'Check format \"iso8601\" date fields output' '\n \ttest_date iso8601 \"2006-07-04 01:18:43 +0200\" \"2006-07-04 01:18:44 +0200\" \"2006-07-04 01:18:45 +0200\"\n '\n \n+test_expect_success 'Check format \"iso8601-local\" date fields output' '\n+\ttest_date iso8601-local \"2006-07-03 23:18:43 +0000\" \"2006-07-03 23:18:44 +0000\" \"2006-07-03 23:18:45 +0000\"\n+'\n+\n test_expect_success 'Check format \"rfc2822\" date fields output' '\n \ttest_date rfc2822 \"Tue, 4 Jul 2006 01:18:43 +0200\" \"Tue, 4 Jul 2006 01:18:44 +0200\" \"Tue, 4 Jul 2006 01:18:45 +0200\"\n '\n \n+test_expect_success 'Check format \"rfc2822-local\" date fields output' '\n+\ttest_date rfc2822-local \"Mon, 3 Jul 2006 23:18:43 +0000\" \"Mon, 3 Jul 2006 23:18:44 +0000\" \"Mon, 3 Jul 2006 23:18:45 +0000\"\n+'\n+\n test_expect_success 'Check format \"raw\" date fields output' '\n \ttest_date raw \"1151968723 +0200\" \"1151968724 +0200\" \"1151968725 +0200\"\n '\n \n+test_expect_success 'Format \"raw-local\" is not allowed' '\n+\ttest_must_fail git for-each-ref --format=\"%(authordate:raw-local)\" refs/heads\n+'\n+\n test_expect_success 'Check format of strftime date fields' '\n \techo \"my date is 2006-07-04\" >expected &&\n \tgit for-each-ref \\\n@@ -208,6 +232,14 @@ test_expect_success 'Check format of strftime date fields' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'Check format of strftime-local date fields' '\n+\techo \"my date is 2006-07-03\" >expected &&\n+\tgit for-each-ref \\\n+\t  --format=\"%(authordate:format-local:my date is %Y-%m-%d)\" \\\n+\t  refs/heads >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_expect_success 'exercise strftime with odd fields' '\n \techo >expected &&\n \tgit for-each-ref --format=\"%(authordate:format:)\" refs/heads >actual &&\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269165","messageId":"xmqqwpw9pyy5.fsf@gitster.mtv.corp.google.com","threadId":"40221","inReplyTo":"35b1313d4eb084ddc2bd70510d56e11a1d84e993.1441144343.git.john@keeping.me.uk","subject":"Re: [PATCH v2 2/6] date: make \"local\" orthogonal to date format","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-01T22:16:50Z","receivedAt":"2015-09-01T22:16:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"John Keeping <john@keeping.me.uk> writes:\n\n> This is Jeff's original patch with my fixup for DATE_STRFTIME squashed\n> in and a new change to reject \"raw-local\" (in both Documentation/ and\n> date.c).\n\nEven in --date=raw, we do show the timezone offset, so I do not\nnecessarily agree that raw-local is nonsensical.  That's the only\ndifference between the one I queued yesterday and this one.\n"},{"id":"269167","messageId":"xmqqsi6xpyu0.fsf@gitster.mtv.corp.google.com","threadId":"40221","inReplyTo":"8e869f362971a44bb1f40ca5fed98b658efaa0dd.1441144343.git.john@keeping.me.uk","subject":"Re: [PATCH v2 3/6] t6300: introduce test_date() helper","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-01T22:19:19Z","receivedAt":"2015-09-01T22:19:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nicely done.\n"},{"id":"269170","messageId":"20150901222529.GC7862@sigill.intra.peff.net","threadId":"40221","inReplyTo":"xmqqwpw9pyy5.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 2/6] date: make \"local\" orthogonal to date format","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-09-01T22:25:29Z","receivedAt":"2015-09-01T22:25:29Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Sep 01, 2015 at 03:16:50PM -0700, Junio C Hamano wrote:\n\n> John Keeping <john@keeping.me.uk> writes:\n> \n> > This is Jeff's original patch with my fixup for DATE_STRFTIME squashed\n> > in and a new change to reject \"raw-local\" (in both Documentation/ and\n> > date.c).\n> \n> Even in --date=raw, we do show the timezone offset, so I do not\n> necessarily agree that raw-local is nonsensical.  That's the only\n> difference between the one I queued yesterday and this one.\n\nYeah, that's why I didn't change it in the original. But to be honest, I\ncannot imagine any case where that is _useful_, so I do not mind at all\nto declare it off-limits, even though it is not nonsensical (though it\nis a little strange to ask for \"raw\" data and then ask for it to be\nmunged).\n\nIOW, I do not mind either way, but the fact that we have to _add_ code\nto disallow it makes me slightly in favor of allowing it. :)\n\n-Peff\n"},{"id":"269171","messageId":"CAPig+cRyiuPhcQ4tm=cxEPk0zHa6=2Wh-nHdnPJLFTDaO9vVTQ@mail.gmail.com","threadId":"40221","inReplyTo":"8e869f362971a44bb1f40ca5fed98b658efaa0dd.1441144343.git.john@keeping.me.uk","subject":"Re: [PATCH v2 3/6] t6300: introduce test_date() helper","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-09-01T22:26:15Z","receivedAt":"2015-09-01T22:26:15Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, Sep 1, 2015 at 5:55 PM, John Keeping <john@keeping.me.uk> wrote:\n> This moves the setup of the \"expected\" file inside the test case.  The\n> helper function has the advantage that we can use SQ in the file content\n> without needing to escape the quotes.\n>\n> Signed-off-by: John Keeping <john@keeping.me.uk>\n> ---\n> diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\n> index 7c9bec7..5fdb964 100755\n> --- a/t/t6300-for-each-ref.sh\n> +++ b/t/t6300-for-each-ref.sh\n> @@ -146,85 +146,54 @@ test_expect_success 'Check invalid format specifiers are errors' '\n>         test_must_fail git for-each-ref --format=\"%(authordate:INVALID)\" refs/heads\n>  '\n>\n> -cat >expected <<\\EOF\n> -'refs/heads/master' 'Mon Jul 3 17:18:43 2006 +0200' 'Mon Jul 3 17:18:44 2006 +0200'\n> -'refs/tags/testtag' 'Mon Jul 3 17:18:45 2006 +0200'\n> -EOF\n> +test_date () {\n> +       f=$1\n\nf=$1 &&\n\n> +       committer_date=$2 &&\n> +       author_date=$3 &&\n> +       tagger_date=$4 &&\n> +       cat >expected <<-EOF &&\n> +       'refs/heads/master' '$committer_date' '$author_date'\n> +       'refs/tags/testtag' '$tagger_date'\n> +       EOF\n> +       (\n> +               git for-each-ref --shell --format=\"%(refname) %(committerdate${f:+:$f}) %(authordate${f:+:$f})\" refs/heads &&\n> +               git for-each-ref --shell --format=\"%(refname) %(taggerdate${f:+:$f})\" refs/tags\n> +       ) >actual &&\n> +       test_cmp expected actual\n> +}\n"},{"id":"269174","messageId":"20150901223157.GE7862@sigill.intra.peff.net","threadId":"40221","inReplyTo":"8e869f362971a44bb1f40ca5fed98b658efaa0dd.1441144343.git.john@keeping.me.uk","subject":"Re: [PATCH v2 3/6] t6300: introduce test_date() helper","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-09-01T22:31:58Z","receivedAt":"2015-09-01T22:31:58Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Sep 01, 2015 at 10:55:41PM +0100, John Keeping wrote:\n\n> I considered moving the test_expect_success into the helper, like with\n> test_atom earlier in the file, but it doesn't make the code much more\n> concise and we still need either to setup the output outside the test\n> case or to escape SQ inside SQ.\n\nMoving it inside also makes it harder to test_expect_failure. :)\n\n>  test_expect_success 'Check unformatted date fields output' '\n> -\t(git for-each-ref --shell --format=\"%(refname) %(committerdate) %(authordate)\" refs/heads &&\n> -\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate)\" refs/tags) >actual &&\n> -\ttest_cmp expected actual\n> +\ttest_date \"\" \"Mon Jul 3 17:18:43 2006 +0200\" \"Mon Jul 3 17:18:44 2006 +0200\" \"Mon Jul 3 17:18:45 2006 +0200\"\n\nI notice we end up with rather long lines for some of these. Would:\n\n  test_date \"\" <<-\\EOF\n  Mon Jul 3 17:18:43 2006 +0200\n  Mon Jul 3 17:18:44 2006 +0200\n  Mon Jul 3 17:18:45 2006 +0200\n  EOF\n\nbe more readable?\n\n-Peff\n"},{"id":"269175","messageId":"20150901223308.GI30659@serenity.lan","threadId":"40221","inReplyTo":"xmqqwpw9pyy5.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 2/6] date: make \"local\" orthogonal to date format","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-01T22:33:08Z","receivedAt":"2015-09-01T22:33:08Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"On Tue, Sep 01, 2015 at 03:16:50PM -0700, Junio C Hamano wrote:\n> John Keeping <john@keeping.me.uk> writes:\n> \n> > This is Jeff's original patch with my fixup for DATE_STRFTIME squashed\n> > in and a new change to reject \"raw-local\" (in both Documentation/ and\n> > date.c).\n> \n> Even in --date=raw, we do show the timezone offset, so I do not\n> necessarily agree that raw-local is nonsensical.  That's the only\n> difference between the one I queued yesterday and this one.\n\nI suspect it depends on the interpretation of \"raw\"; the code currently\ninterprets raw to mean \"exactly what exists in the commit/tag\", in which\ncase converting it to the local timezone is wrong.  But the\ndocumentation describes \"raw\" as \"the raw Git %s %z format\", and if we\ninterpret it to mean \"Git's internal date format\" then \"raw-local\" makes\nsense.\n\nThe alternative would be the patch below as a preparatory step.\n\n-- >8 --\ndiff --git a/date.c b/date.c\nindex f048416..345890f 100644\n--- a/date.c\n+++ b/date.c\n@@ -175,12 +175,6 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \tstruct tm *tm;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n \n-\tif (mode->type == DATE_RAW) {\n-\t\tstrbuf_reset(&timebuf);\n-\t\tstrbuf_addf(&timebuf, \"%lu %+05d\", time, tz);\n-\t\treturn timebuf.buf;\n-\t}\n-\n \tif (mode->type == DATE_RELATIVE) {\n \t\tstruct timeval now;\n \n@@ -193,6 +187,12 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \tif (mode->local)\n \t\ttz = local_tzoffset(time);\n \n+\tif (mode->type == DATE_RAW) {\n+\t\tstrbuf_reset(&timebuf);\n+\t\tstrbuf_addf(&timebuf, \"%lu %+05d\", time, tz);\n+\t\treturn timebuf.buf;\n+\t}\n+\n \ttm = time_to_tm(time, tz);\n \tif (!tm) {\n \t\ttm = time_to_tm(0, 0);\n"},{"id":"269177","messageId":"20150901223959.GG7862@sigill.intra.peff.net","threadId":"40221","inReplyTo":"20150901223308.GI30659@serenity.lan","subject":"Re: [PATCH v2 2/6] date: make \"local\" orthogonal to date format","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-09-01T22:39:59Z","receivedAt":"2015-09-01T22:39:59Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Sep 01, 2015 at 11:33:08PM +0100, John Keeping wrote:\n\n> > Even in --date=raw, we do show the timezone offset, so I do not\n> > necessarily agree that raw-local is nonsensical.  That's the only\n> > difference between the one I queued yesterday and this one.\n> \n> I suspect it depends on the interpretation of \"raw\"; the code currently\n> interprets raw to mean \"exactly what exists in the commit/tag\", in which\n> case converting it to the local timezone is wrong.  But the\n> documentation describes \"raw\" as \"the raw Git %s %z format\", and if we\n> interpret it to mean \"Git's internal date format\" then \"raw-local\" makes\n> sense.\n> \n> The alternative would be the patch below as a preparatory step.\n\nAh, right, I forgot that we need to refactor show_date() to actually do\nthe right thing.\n\nI think I'd be in favor of just disallowing \"raw-local\", then.\n\n-Peff\n"},{"id":"269178","messageId":"20150901224013.GJ30659@serenity.lan","threadId":"40221","inReplyTo":"20150901223157.GE7862@sigill.intra.peff.net","subject":"Re: [PATCH v2 3/6] t6300: introduce test_date() helper","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-01T22:40:13Z","receivedAt":"2015-09-01T22:40:13Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"On Tue, Sep 01, 2015 at 06:31:58PM -0400, Jeff King wrote:\n> On Tue, Sep 01, 2015 at 10:55:41PM +0100, John Keeping wrote:\n> \n> > I considered moving the test_expect_success into the helper, like with\n> > test_atom earlier in the file, but it doesn't make the code much more\n> > concise and we still need either to setup the output outside the test\n> > case or to escape SQ inside SQ.\n> \n> Moving it inside also makes it harder to test_expect_failure. :)\n> \n> >  test_expect_success 'Check unformatted date fields output' '\n> > -\t(git for-each-ref --shell --format=\"%(refname) %(committerdate) %(authordate)\" refs/heads &&\n> > -\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate)\" refs/tags) >actual &&\n> > -\ttest_cmp expected actual\n> > +\ttest_date \"\" \"Mon Jul 3 17:18:43 2006 +0200\" \"Mon Jul 3 17:18:44 2006 +0200\" \"Mon Jul 3 17:18:45 2006 +0200\"\n> \n> I notice we end up with rather long lines for some of these. Would:\n> \n>   test_date \"\" <<-\\EOF\n>   Mon Jul 3 17:18:43 2006 +0200\n>   Mon Jul 3 17:18:44 2006 +0200\n>   Mon Jul 3 17:18:45 2006 +0200\n>   EOF\n> \n> be more readable?\n\nWe could just do:\n\n\ttest_date \"\" \\\n\t\t\"Tue Jul 4 01:18:43 2006 +0200\" \\\n\t\t\"Tue Jul 4 01:18:44 2006 +0200\" \\\n\t\t\"Tue Jul 4 01:18:45 2006 +0200\"\n\nI'm not entirely sure why I didn't now that I look at it!\n"},{"id":"269180","messageId":"CAPc5daWEH2UtFHe_2+2SChgMd-TcYPsA0oJFZJjw539WRS6oSQ@mail.gmail.com","threadId":"40221","inReplyTo":"20150901223959.GG7862@sigill.intra.peff.net","subject":"Re: [PATCH v2 2/6] date: make \"local\" orthogonal to date format","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-01T22:41:20Z","receivedAt":"2015-09-01T22:41:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"OK by me. Thanks, I also forgot that need for preparatory code movement.\n\nOn Tue, Sep 1, 2015 at 3:39 PM, Jeff King <peff@peff.net> wrote:\n> On Tue, Sep 01, 2015 at 11:33:08PM +0100, John Keeping wrote:\n>\n>> > Even in --date=raw, we do show the timezone offset, so I do not\n>> > necessarily agree that raw-local is nonsensical.  That's the only\n>> > difference between the one I queued yesterday and this one.\n>>\n>> I suspect it depends on the interpretation of \"raw\"; the code currently\n>> interprets raw to mean \"exactly what exists in the commit/tag\", in which\n>> case converting it to the local timezone is wrong.  But the\n>> documentation describes \"raw\" as \"the raw Git %s %z format\", and if we\n>> interpret it to mean \"Git's internal date format\" then \"raw-local\" makes\n>> sense.\n>>\n>> The alternative would be the patch below as a preparatory step.\n>\n> Ah, right, I forgot that we need to refactor show_date() to actually do\n> the right thing.\n>\n> I think I'd be in favor of just disallowing \"raw-local\", then.\n>\n> -Peff\n"},{"id":"269179","messageId":"20150901224135.GH7862@sigill.intra.peff.net","threadId":"40221","inReplyTo":"20150901224013.GJ30659@serenity.lan","subject":"Re: [PATCH v2 3/6] t6300: introduce test_date() helper","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-09-01T22:41:35Z","receivedAt":"2015-09-01T22:41:35Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Sep 01, 2015 at 11:40:13PM +0100, John Keeping wrote:\n\n> > I notice we end up with rather long lines for some of these. Would:\n> > \n> >   test_date \"\" <<-\\EOF\n> >   Mon Jul 3 17:18:43 2006 +0200\n> >   Mon Jul 3 17:18:44 2006 +0200\n> >   Mon Jul 3 17:18:45 2006 +0200\n> >   EOF\n> > \n> > be more readable?\n> \n> We could just do:\n> \n> \ttest_date \"\" \\\n> \t\t\"Tue Jul 4 01:18:43 2006 +0200\" \\\n> \t\t\"Tue Jul 4 01:18:44 2006 +0200\" \\\n> \t\t\"Tue Jul 4 01:18:45 2006 +0200\"\n> \n> I'm not entirely sure why I didn't now that I look at it!\n\nYeah, that also looks good, and is probably less confusing that the\nhere-doc.\n\n-Peff\n"},{"id":"269181","messageId":"20150901224431.GA9353@sigill.intra.peff.net","threadId":"40221","inReplyTo":"cover.1441144343.git.john@keeping.me.uk","subject":"Re: [PATCH v2 0/6] Make \"local\" orthogonal to date format","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-09-01T22:44:31Z","receivedAt":"2015-09-01T22:44:31Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Sep 01, 2015 at 10:55:38PM +0100, John Keeping wrote:\n\n> Jeff's first patch is unmodified but I've squashed the fixed currently\n> on \"pu\" into the second.  I also realised while adding the tests that\n> \"raw-local\" is meaningless so I've modified the code to reject it in the\n> same way as \"relative-local\".\n> \n> Jeff King (2):\n>   fast-import: switch crash-report date to iso8601\n>   date: make \"local\" orthogonal to date format\n> \n> John Keeping (4):\n>   t6300: introduce test_date() helper\n>   t6300: make UTC and local dates different\n>   t6300: add test for \"raw\" date format\n>   t6300: add tests for \"-local\" date formats\n\nLooks like we've agreed on disallowing \"raw-local\"[1] for the 2nd patch.\nThe other 4 all look good to me, with the exception of the line-wrapping\non 3/6.  Thanks for taking care of this.\n\n-Peff\n\n[1] I do think the error message for \"relative-local is nonsense\" could\n    perhaps be more explanatory, but I couldn't come up with any better\n    wording. But if you have ideas, feel free to switch it.\n"},{"id":"269190","messageId":"20150902074826.GK30659@serenity.lan","threadId":"40221","inReplyTo":"20150901224431.GA9353@sigill.intra.peff.net","subject":"Re: [PATCH v2 0/6] Make \"local\" orthogonal to date format","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-02T07:48:26Z","receivedAt":"2015-09-02T07:48:26Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"On Tue, Sep 01, 2015 at 06:44:31PM -0400, Jeff King wrote:\n> [1] I do think the error message for \"relative-local is nonsense\" could\n>     perhaps be more explanatory, but I couldn't come up with any better\n>     wording. But if you have ideas, feel free to switch it.\n\nMy only suggestion would be to reuse the \"unknown date format: %s\"\nmessage and avoid having a special message in this case.\n"},{"id":"269191","messageId":"20150902080529.GA19248@sigill.intra.peff.net","threadId":"40221","inReplyTo":"20150902074826.GK30659@serenity.lan","subject":"Re: [PATCH v2 0/6] Make \"local\" orthogonal to date format","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-09-02T08:05:29Z","receivedAt":"2015-09-02T08:05:29Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Sep 02, 2015 at 08:48:26AM +0100, John Keeping wrote:\n\n> On Tue, Sep 01, 2015 at 06:44:31PM -0400, Jeff King wrote:\n> > [1] I do think the error message for \"relative-local is nonsense\" could\n> >     perhaps be more explanatory, but I couldn't come up with any better\n> >     wording. But if you have ideas, feel free to switch it.\n> \n> My only suggestion would be to reuse the \"unknown date format: %s\"\n> message and avoid having a special message in this case.\n\nHeh, that was what I was trying to avoid. I wanted to avoid \"I do not\nunderstand our request\" and have it more like \"I understand what you're\n_trying_ to do, but it doesn't make sense\".\n\nI guess \"relative dates do not depend on timezones, so -local is\nmeaningless\" would be the closest thing.\n\nI don't think it is that big a deal whichever way we go, though.\n\n-Peff\n"},{"id":"269208","messageId":"xmqq4mjcq2ac.fsf@gitster.mtv.corp.google.com","threadId":"40221","inReplyTo":"20150902080529.GA19248@sigill.intra.peff.net","subject":"Re: [PATCH v2 0/6] Make \"local\" orthogonal to date format","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-02T15:16:59Z","receivedAt":"2015-09-02T15:16:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Wed, Sep 02, 2015 at 08:48:26AM +0100, John Keeping wrote:\n>\n>> On Tue, Sep 01, 2015 at 06:44:31PM -0400, Jeff King wrote:\n>> > [1] I do think the error message for \"relative-local is nonsense\" could\n>> >     perhaps be more explanatory, but I couldn't come up with any better\n>> >     wording. But if you have ideas, feel free to switch it.\n>> \n>> My only suggestion would be to reuse the \"unknown date format: %s\"\n>> message and avoid having a special message in this case.\n>\n> Heh, that was what I was trying to avoid. I wanted to avoid \"I do not\n> understand our request\" and have it more like \"I understand what you're\n> _trying_ to do, but it doesn't make sense\".\n>\n> I guess \"relative dates do not depend on timezones, so -local is\n> meaningless\" would be the closest thing.\n>\n> I don't think it is that big a deal whichever way we go, though.\n\nI somehow thought that the discussion was about raw-local, not\nrelative-local, but anyway, I think it would make more sense to\nallow both of them.  If you define the meaning of \"-local\" as:\n\n    Pretend that the event in question was recorded with your\n    timezone, and show the timestamp using the specified format sans\n    -local suffix.\n\nthat explains what happens for all the other formats well, and it\nalso makes sense for what would happen to raw and even relative, I\nthink.\n"},{"id":"269222","messageId":"xmqq7fo8oh98.fsf@gitster.mtv.corp.google.com","threadId":"40221","inReplyTo":"35b1313d4eb084ddc2bd70510d56e11a1d84e993.1441144343.git.john@keeping.me.uk","subject":"Re: [PATCH v2 2/6] date: make \"local\" orthogonal to date format","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-02T17:36:35Z","receivedAt":"2015-09-02T17:36:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"John Keeping <john@keeping.me.uk> writes:\n\n> diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\n> index a9b808f..5d28133 100644\n> --- a/Documentation/rev-list-options.txt\n> +++ b/Documentation/rev-list-options.txt\n> @@ -702,12 +702,16 @@ include::pretty-options.txt[]\n>  --date=(relative|local|default|iso|iso-strict|rfc|short|raw)::\n>  \tOnly takes effect for dates shown in human-readable format, such\n>  \tas when using `--pretty`. `log.date` config variable sets a default\n> -\tvalue for the log command's `--date` option.\n> +\tvalue for the log command's `--date` option. By default, dates\n> +\tare shown in the original time zone (either committer's or\n> +\tauthor's). If `-local` is appended to the format (e.g.,\n> +\t`iso-local`), the user's local time zone is used instead.\n>  +\n>  `--date=relative` shows dates relative to the current time,\n> -e.g. ``2 hours ago''.\n> +e.g. ``2 hours ago''. The `-local` option cannot be used with\n> +`--raw` or `--relative`.\n>  +\n> -`--date=local` shows timestamps in user's local time zone.\n> +`--date=local` is an alias for `--date=default-local`.\n>  +\n\nThis can also affect for-each-ref's \"%(authordate:short)\" and\nfriends.  We have this rather unfortunately detailed description:\n\n    As a special case for the date-type fields, you may specify a format for\n    the date by adding one of `:default`, `:relative`, `:short`, `:local`,\n    `:iso8601`, `:rfc2822` or `:raw` to the end of the fieldname; e.g.\n    `%(taggerdate:relative)`.\n\nWe would probably want to make this more vague by replacing \"adding\none of...\" with \"adding ':' followed by date format name (see the\nvalues the --date option to linkgit::git-rev-list[1] takes)\" or\nsomething like that.\n"},{"id":"269223","messageId":"xmqq37ywoh0x.fsf@gitster.mtv.corp.google.com","threadId":"40221","inReplyTo":"20150831204831.GB10338@sigill.intra.peff.net","subject":"Re: [PATCH 2/2] date: make \"local\" orthogonal to date format","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-02T17:41:34Z","receivedAt":"2015-09-02T17:41:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> +\t/* historical alias */\n> +\tif (!strcmp(format, \"local\"))\n> +\t\tformat = \"default-local\";\n> +\n> +\tmode->type = parse_date_type(format, &p);\n> +\tmode->local = 0;\n> +\n> +\tif (skip_prefix(p, \"-local\", &p)) {\n> +\t\tif (mode->type == DATE_RELATIVE)\n> +\t\t\tdie(\"relative-local date format is nonsensical\");\n> +\t\tmode->local = 1;\n> +\t}\n\nI notice that we give something funny like this:\n\n    $ git show --date=short-locale\n    fatal: unknown date-mode modifier: e\n\nWhat is the intention here?  In other words, what kind of things can\nplausibly follow \"--date=short-local\" in enhanced versions of Git in\nthe future?  \"--date=short-local:some other magic\"?\n"},{"id":"269230","messageId":"20150902194946.GL30659@serenity.lan","threadId":"40221","inReplyTo":"xmqq4mjcq2ac.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 0/6] Make \"local\" orthogonal to date format","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-02T19:49:46Z","receivedAt":"2015-09-02T19:49:46Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"On Wed, Sep 02, 2015 at 08:16:59AM -0700, Junio C Hamano wrote:\n> Jeff King <peff@peff.net> writes:\n> \n> > On Wed, Sep 02, 2015 at 08:48:26AM +0100, John Keeping wrote:\n> >\n> >> On Tue, Sep 01, 2015 at 06:44:31PM -0400, Jeff King wrote:\n> >> > [1] I do think the error message for \"relative-local is nonsense\" could\n> >> >     perhaps be more explanatory, but I couldn't come up with any better\n> >> >     wording. But if you have ideas, feel free to switch it.\n> >> \n> >> My only suggestion would be to reuse the \"unknown date format: %s\"\n> >> message and avoid having a special message in this case.\n> >\n> > Heh, that was what I was trying to avoid. I wanted to avoid \"I do not\n> > understand our request\" and have it more like \"I understand what you're\n> > _trying_ to do, but it doesn't make sense\".\n> >\n> > I guess \"relative dates do not depend on timezones, so -local is\n> > meaningless\" would be the closest thing.\n> >\n> > I don't think it is that big a deal whichever way we go, though.\n> \n> I somehow thought that the discussion was about raw-local, not\n> relative-local, but anyway, I think it would make more sense to\n> allow both of them.  If you define the meaning of \"-local\" as:\n> \n>     Pretend that the event in question was recorded with your\n>     timezone, and show the timestamp using the specified format sans\n>     -local suffix.\n> \n> that explains what happens for all the other formats well, and it\n> also makes sense for what would happen to raw and even relative, I\n> think.\n\nThe discussion about \"raw-local\" was in a separate subthread, I think\nwe're just bikeshedding the particular error message here.\n\nOTOH, I don't think there's any disagreement about what \"relative-local\"\nand \"raw-local\" would output were they supported, just whether they are\nuseful.  There doesn't seem to be any harm in supporting them;\n\"relative-local\" will be identical to \"relative\" and \"raw-local\" will\nrequire preparatory code movement for the raw output.\n"},{"id":"269231","messageId":"xmqqk2s8mvig.fsf@gitster.mtv.corp.google.com","threadId":"40221","inReplyTo":"20150902194946.GL30659@serenity.lan","subject":"Re: [PATCH v2 0/6] Make \"local\" orthogonal to date format","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-02T20:11:35Z","receivedAt":"2015-09-02T20:11:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"John Keeping <john@keeping.me.uk> writes:\n\n> On Wed, Sep 02, 2015 at 08:16:59AM -0700, Junio C Hamano wrote:\n>> Jeff King <peff@peff.net> writes:\n>> \n>> > I guess \"relative dates do not depend on timezones, so -local is\n>> > meaningless\" would be the closest thing.\n>\n> The discussion about \"raw-local\" was in a separate subthread, I think\n> we're just bikeshedding the particular error message here.\n\nOK.\n\n> OTOH, I don't think there's any disagreement about what \"relative-local\"\n> and \"raw-local\" would output were they supported, just whether they are\n> useful.  There doesn't seem to be any harm in supporting them;\n> \"relative-local\" will be identical to \"relative\" and \"raw-local\" will\n> require preparatory code movement for the raw output.\n\nSure.\n\nBikeshedding further, while Peff's message \"-local is meaningless\"\nis a correct statement of the fact, I do not think it explains well\nwhy we chose to error out instead of giving the most natural result\n(i.e. exactly the same as 'relative').\n\nPerhaps stating \"relative-local is not supported\" without saying why\nwould be better.  \"Because it is meaningless, we refuse to support\nthe option.\" is a very strong statement that tells aspiring future\nGit hackers not to attempt to add a support for it, which is\nprobably a wrong message to send.\n"},{"id":"269232","messageId":"20150902202148.GM30659@serenity.lan","threadId":"40221","inReplyTo":"xmqqk2s8mvig.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 0/6] Make \"local\" orthogonal to date format","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-02T20:21:48Z","receivedAt":"2015-09-02T20:21:48Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"On Wed, Sep 02, 2015 at 01:11:35PM -0700, Junio C Hamano wrote:\n> John Keeping <john@keeping.me.uk> writes:\n> > OTOH, I don't think there's any disagreement about what \"relative-local\"\n> > and \"raw-local\" would output were they supported, just whether they are\n> > useful.  There doesn't seem to be any harm in supporting them;\n> > \"relative-local\" will be identical to \"relative\" and \"raw-local\" will\n> > require preparatory code movement for the raw output.\n> \n> Sure.\n> \n> Bikeshedding further, while Peff's message \"-local is meaningless\"\n> is a correct statement of the fact, I do not think it explains well\n> why we chose to error out instead of giving the most natural result\n> (i.e. exactly the same as 'relative').\n> \n> Perhaps stating \"relative-local is not supported\" without saying why\n> would be better.  \"Because it is meaningless, we refuse to support\n> the option.\" is a very strong statement that tells aspiring future\n> Git hackers not to attempt to add a support for it, which is\n> probably a wrong message to send.\n\nIn which case, should we just support it now?\n\nNormally I'd suggest banning controversial options on the basis that\nit's easier in the future to allow something that was previously banned\nthan change the meaning of an options, but in this case I can't see any\nother meaning for these options than that described above.\n"},{"id":"269233","messageId":"xmqqfv2wmup7.fsf@gitster.mtv.corp.google.com","threadId":"40221","inReplyTo":"20150902202148.GM30659@serenity.lan","subject":"Re: [PATCH v2 0/6] Make \"local\" orthogonal to date format","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-02T20:29:08Z","receivedAt":"2015-09-02T20:29:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"John Keeping <john@keeping.me.uk> writes:\n\n> In which case, should we just support it now?\n>\n> Normally I'd suggest banning controversial options on the basis that\n> it's easier in the future to allow something that was previously banned\n> than change the meaning of an options, but in this case I can't see any\n> other meaning for these options than that described above.\n\nMy usual stance is the same as yours, and I agree that there is no\nother sane and useful behaviour for \"relative-local\" to do the same\nas \"relative\".\n\nAs we'll go into pre-release feature freeze soonish, we have enough\ntime to add missing support to the code (the new feature won't have\nto make the upcoming 2.6 wait).\n\nThanks.\n"},{"id":"269237","messageId":"20150902212733.GA21612@sigill.intra.peff.net","threadId":"40221","inReplyTo":"xmqqfv2wmup7.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 0/6] Make \"local\" orthogonal to date format","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-09-02T21:27:34Z","receivedAt":"2015-09-02T21:27:34Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Sep 02, 2015 at 01:29:08PM -0700, Junio C Hamano wrote:\n\n> John Keeping <john@keeping.me.uk> writes:\n> \n> > In which case, should we just support it now?\n> >\n> > Normally I'd suggest banning controversial options on the basis that\n> > it's easier in the future to allow something that was previously banned\n> > than change the meaning of an options, but in this case I can't see any\n> > other meaning for these options than that described above.\n> \n> My usual stance is the same as yours, and I agree that there is no\n> other sane and useful behaviour for \"relative-local\" to do the same\n> as \"relative\".\n\nThat sounds fine to me. Then we don't have to worry about the error\nmessages. ;)\n\n-Peff\n"},{"id":"269238","messageId":"20150902213013.GB21612@sigill.intra.peff.net","threadId":"40221","inReplyTo":"xmqq37ywoh0x.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 2/2] date: make \"local\" orthogonal to date format","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-09-02T21:30:14Z","receivedAt":"2015-09-02T21:30:14Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Sep 02, 2015 at 10:41:34AM -0700, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > +\t/* historical alias */\n> > +\tif (!strcmp(format, \"local\"))\n> > +\t\tformat = \"default-local\";\n> > +\n> > +\tmode->type = parse_date_type(format, &p);\n> > +\tmode->local = 0;\n> > +\n> > +\tif (skip_prefix(p, \"-local\", &p)) {\n> > +\t\tif (mode->type == DATE_RELATIVE)\n> > +\t\t\tdie(\"relative-local date format is nonsensical\");\n> > +\t\tmode->local = 1;\n> > +\t}\n> \n> I notice that we give something funny like this:\n> \n>     $ git show --date=short-locale\n>     fatal: unknown date-mode modifier: e\n\nYeah, that's not ideal.\n\n> What is the intention here?  In other words, what kind of things can\n> plausibly follow \"--date=short-local\" in enhanced versions of Git in\n> the future?  \"--date=short-local:some other magic\"?\n\nI had assumed it would be \"short-local-othermagic\", since \":\" is already\nthe separator for \"format:\". But I admit I have no idea what other\nmodifiers would be interesting.\n\nI think the error message would be a lot nicer if we indicate that \"-\"\nis syntactically interesting, and say:\n\n  fatal: unknown date-mode modifier: locale\n\n-Peff\n"},{"id":"269244","messageId":"20150902220740.GN30659@serenity.lan","threadId":"40221","inReplyTo":"20150902213013.GB21612@sigill.intra.peff.net","subject":"Re: [PATCH 2/2] date: make \"local\" orthogonal to date format","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-02T22:07:40Z","receivedAt":"2015-09-02T22:07:40Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"On Wed, Sep 02, 2015 at 05:30:14PM -0400, Jeff King wrote:\n> On Wed, Sep 02, 2015 at 10:41:34AM -0700, Junio C Hamano wrote:\n> \n> > Jeff King <peff@peff.net> writes:\n> > \n> > > +\t/* historical alias */\n> > > +\tif (!strcmp(format, \"local\"))\n> > > +\t\tformat = \"default-local\";\n> > > +\n> > > +\tmode->type = parse_date_type(format, &p);\n> > > +\tmode->local = 0;\n> > > +\n> > > +\tif (skip_prefix(p, \"-local\", &p)) {\n> > > +\t\tif (mode->type == DATE_RELATIVE)\n> > > +\t\t\tdie(\"relative-local date format is nonsensical\");\n> > > +\t\tmode->local = 1;\n> > > +\t}\n> > \n> > I notice that we give something funny like this:\n> > \n> >     $ git show --date=short-locale\n> >     fatal: unknown date-mode modifier: e\n> \n> Yeah, that's not ideal.\n> \n> > What is the intention here?  In other words, what kind of things can\n> > plausibly follow \"--date=short-local\" in enhanced versions of Git in\n> > the future?  \"--date=short-local:some other magic\"?\n> \n> I had assumed it would be \"short-local-othermagic\", since \":\" is already\n> the separator for \"format:\". But I admit I have no idea what other\n> modifiers would be interesting.\n> \n> I think the error message would be a lot nicer if we indicate that \"-\"\n> is syntactically interesting, and say:\n> \n>   fatal: unknown date-mode modifier: locale\n\nI wonder if we'd be better just saying:\n\n\tfatal: unknown date format: short-locale\n\nI'm not sure users will consider \"local\" to be a modifier, there is\nsimply a list of formats that happens to include pairs of matching\n\"-local\" and \"not -local\" variants.\n\nThat has the benefit of keeping the code simple, otherwise we have to\nworry about \"shorter\" as well (in the patch as it stands that gives\n\"unknown date-mode modifier: er\").\n"},{"id":"269325","messageId":"xmqq613rmram.fsf@gitster.mtv.corp.google.com","threadId":"40221","inReplyTo":"20150902220740.GN30659@serenity.lan","subject":"Re: [PATCH 2/2] date: make \"local\" orthogonal to date format","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-03T15:54:57Z","receivedAt":"2015-09-03T15:54:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"John Keeping <john@keeping.me.uk> writes:\n\n> On Wed, Sep 02, 2015 at 05:30:14PM -0400, Jeff King wrote:\n>> I think the error message would be a lot nicer if we indicate that \"-\"\n>> is syntactically interesting, and say:\n>> \n>>   fatal: unknown date-mode modifier: locale\n>\n> I wonder if we'd be better just saying:\n>\n> \tfatal: unknown date format: short-locale\n>\n> I'm not sure users will consider \"local\" to be a modifier, there is\n> simply a list of formats that happens to include pairs of matching\n> \"-local\" and \"not -local\" variants.\n\nEither is acceptable and better than the 'e' output.  I think yours\nis better because it would equally work well for those who think in\nterms of \"modifier\" and those who think in terms of \"flat list of\npossibilities\".\n\nThanks.\n"},{"id":"269372","messageId":"cover.1441316394.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441144343.git.john@keeping.me.uk","subject":"[PATCH v3 00/11] Make \"local\" orthogonal to date format","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-03T21:48:50Z","receivedAt":"2015-09-03T21:48:50Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"Since version 2 there are four new preparatory patches which remove\nlists of date formats from documentation in favour of referring to the\ndetailed list in git-rev-list(1) or git-log(1) (both generated from\nDocumentation/rev-list-options.txt) depending on whether the page in\nquestion is plumbing/porcelain.\n\nI've also reordered the test cleanup patches earlier so that the test\nfor \"--date=raw\" is added before the new patch that moves \"local\"\nprocessing before the \"raw\" case.  The tests also now wrap long lines\nand a missing \"&&\" has been added.\n\nIn patch 7 (date: check for \"local\" before anything else), we no longer\nreject \"relative-local\" and \"raw-local\" now prints the user's local\ntimezone offset.  The error message for invalid formats that are\nprefixed with a valid format name is now the same as that if there is no\nvalid prefix.\n\nJeff King (2):\n  fast-import: switch crash-report date to iso8601\n  date: make \"local\" orthogonal to date format\n\nJohn Keeping (9):\n  Documentation/blame-options: don't list date formats\n  Documentation/config: don't list date formats\n  Documentation/git-for-each-ref: don't list date formats\n  Documentation/rev-list: don't list date formats\n  t6300: introduce test_date() helper\n  t6300: add test for \"raw\" date format\n  date: check for \"local\" before anything else\n  t6300: make UTC and local dates different\n  t6300: add tests for \"-local\" date formats\n\n Documentation/blame-options.txt    |   5 +-\n Documentation/config.txt           |   4 +-\n Documentation/git-for-each-ref.txt |   5 +-\n Documentation/git-rev-list.txt     |   2 +-\n Documentation/rev-list-options.txt |  23 ++++--\n builtin/blame.c                    |   1 -\n cache.h                            |   2 +-\n date.c                             |  74 ++++++++++-------\n fast-import.c                      |   2 +-\n t/t6300-for-each-ref.sh            | 162 ++++++++++++++++++++++---------------\n 10 files changed, 166 insertions(+), 114 deletions(-)\n\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269373","messageId":"d1b464560847135404dec0c7d125f5e84578c361.1441316394.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441316394.git.john@keeping.me.uk","subject":"[PATCH v3 01/11] Documentation/blame-options: don't list date formats","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-03T21:48:51Z","receivedAt":"2015-09-03T21:48:51Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"This list is already incomplete (missing \"raw\") and we're about to add\nnew formats.  Remove it and refer to the canonical documentation in\ngit-log(1).\n\nSigned-off-by: John Keeping <john@keeping.me.uk>\n---\n Documentation/blame-options.txt | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt\nindex a09969b..760eab7 100644\n--- a/Documentation/blame-options.txt\n+++ b/Documentation/blame-options.txt\n@@ -63,11 +63,10 @@ include::line-range-format.txt[]\n \t`-` to make the command read from the standard input).\n \n --date <format>::\n-\tThe value is one of the following alternatives:\n-\t{relative,local,default,iso,rfc,short}. If --date is not\n+\tSpecifies the format used to output dates. If --date is not\n \tprovided, the value of the blame.date config variable is\n \tused. If the blame.date config variable is also not set, the\n-\tiso format is used. For more information, See the discussion\n+\tiso format is used. For supported values, see the discussion\n \tof the --date option at linkgit:git-log[1].\n \n -M|<num>|::\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269374","messageId":"c3c43d509e5e8497499d4804e083739cbade6e84.1441316394.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441316394.git.john@keeping.me.uk","subject":"[PATCH v3 02/11] Documentation/config: don't list date formats","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-03T21:48:52Z","receivedAt":"2015-09-03T21:48:52Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"This list is already incomplete (missing \"raw\") and we're about to add\nnew formats.  Since this option sets a default for git-log's --date\noption, just refer to git-log(1).\n\nSigned-off-by: John Keeping <john@keeping.me.uk>\n---\n Documentation/config.txt | 4 +---\n 1 file changed, 1 insertion(+), 3 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex f5d15ff..49f9fa8 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1829,9 +1829,7 @@ log.abbrevCommit::\n log.date::\n \tSet the default date-time mode for the 'log' command.\n \tSetting a value for log.date is similar to using 'git log''s\n-\t`--date` option.  Possible values are `relative`, `local`,\n-\t`default`, `iso`, `rfc`, and `short`; see linkgit:git-log[1]\n-\tfor details.\n+\t`--date` option.  See linkgit:git-log[1] for details.\n \n log.decorate::\n \tPrint out the ref names of any commits that are shown by the log\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269375","messageId":"d246532e4fbcecdf7b826added2dd88f3afe8e09.1441316394.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441316394.git.john@keeping.me.uk","subject":"[PATCH v3 03/11] Documentation/git-for-each-ref: don't list date formats","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-03T21:48:53Z","receivedAt":"2015-09-03T21:48:53Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"We are about to add a new set of supported date formats and do not want\nto have to maintain the same list in several different bits of\ndocumentation.  Refer to git-rev-list(1) which contains the full list of\nsupported formats.\n\nSigned-off-by: John Keeping <john@keeping.me.uk>\n---\n Documentation/git-for-each-ref.txt | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 7f8d9a5..d062639 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -134,9 +134,8 @@ the object referred by the ref does not cause an error.  It\n returns an empty string instead.\n \n As a special case for the date-type fields, you may specify a format for\n-the date by adding one of `:default`, `:relative`, `:short`, `:local`,\n-`:iso8601`, `:rfc2822` or `:raw` to the end of the fieldname; e.g.\n-`%(taggerdate:relative)`.\n+the date by adding `:` followed by date format name (see the\n+values the `--date` option to linkgit::git-rev-list[1] takes).\n \n \n EXAMPLES\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269376","messageId":"cfc780ad4f30521a4f54eba2a96ced8e0bbfc519.1441316394.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441316394.git.john@keeping.me.uk","subject":"[PATCH v3 04/11] Documentation/rev-list: don't list date formats","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-03T21:48:54Z","receivedAt":"2015-09-03T21:48:54Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"We are about to add several new date formats which will make this list\ntoo long to display in a single line.\n\nSigned-off-by: John Keeping <john@keeping.me.uk>\n---\n Documentation/git-rev-list.txt     | 2 +-\n Documentation/rev-list-options.txt | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt\nindex 7b49c85..ef22f17 100644\n--- a/Documentation/git-rev-list.txt\n+++ b/Documentation/git-rev-list.txt\n@@ -45,7 +45,7 @@ SYNOPSIS\n \t     [ --regexp-ignore-case | -i ]\n \t     [ --extended-regexp | -E ]\n \t     [ --fixed-strings | -F ]\n-\t     [ --date=(local|relative|default|iso|iso-strict|rfc|short) ]\n+\t     [ --date=<format>]\n \t     [ [ --objects | --objects-edge | --objects-edge-aggressive ]\n \t       [ --unpacked ] ]\n \t     [ --pretty | --header ]\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex a9b808f..14c4cce 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -699,7 +699,7 @@ include::pretty-options.txt[]\n --relative-date::\n \tSynonym for `--date=relative`.\n \n---date=(relative|local|default|iso|iso-strict|rfc|short|raw)::\n+--date=<format>::\n \tOnly takes effect for dates shown in human-readable format, such\n \tas when using `--pretty`. `log.date` config variable sets a default\n \tvalue for the log command's `--date` option.\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269377","messageId":"9094670ba26fe6a63fa4264f3564e877513ba1ec.1441316394.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441316394.git.john@keeping.me.uk","subject":"[PATCH v3 05/11] fast-import: switch crash-report date to iso8601","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-03T21:48:55Z","receivedAt":"2015-09-03T21:48:55Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nWhen fast-import emits a crash report, it does so in the\nuser's local timezone. But because we omit the timezone\ncompletely for DATE_LOCAL, a reader of the report does not\nimmediately know which time zone was used. Let's switch this\nto ISO8601 instead, which includes the time zone.\n\nThis does mean we will show the time in UTC, but that's not\na big deal. A crash report like this will either be looked\nat immediately (in which case nobody even looks at the\ntimestamp), or it will be passed along to a developer to\ndebug, in which case the original timezone is less likely to\nbe of interest.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: John Keeping <john@keeping.me.uk>\n---\n fast-import.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/fast-import.c b/fast-import.c\nindex 6c7c3c9..adcbfc6 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -424,7 +424,7 @@ static void write_crash_report(const char *err)\n \tfprintf(rpt, \"fast-import crash report:\\n\");\n \tfprintf(rpt, \"    fast-import process: %\"PRIuMAX\"\\n\", (uintmax_t) getpid());\n \tfprintf(rpt, \"    parent process     : %\"PRIuMAX\"\\n\", (uintmax_t) getppid());\n-\tfprintf(rpt, \"    at %s\\n\", show_date(time(NULL), 0, DATE_MODE(LOCAL)));\n+\tfprintf(rpt, \"    at %s\\n\", show_date(time(NULL), 0, DATE_MODE(ISO8601)));\n \tfputc('\\n', rpt);\n \n \tfputs(\"fatal: \", rpt);\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269378","messageId":"e3c925c0d572ba68f4a0e30a8c88d78a3abf9a34.1441316394.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441316394.git.john@keeping.me.uk","subject":"[PATCH v3 06/11] t6300: introduce test_date() helper","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-03T21:48:56Z","receivedAt":"2015-09-03T21:48:56Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"This moves the setup of the \"expected\" file inside the test case.  The\nhelper function has the advantage that we can use SQ in the file content\nwithout needing to escape the quotes.\n\nSigned-off-by: John Keeping <john@keeping.me.uk>\n---\nChanges since v2:\n- add missing \"&&\" after \"f=$1\"\n- wrap long lines\n\n t/t6300-for-each-ref.sh | 92 +++++++++++++++++++++----------------------------\n 1 file changed, 40 insertions(+), 52 deletions(-)\n\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 7c9bec7..0bf709b 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -146,85 +146,73 @@ test_expect_success 'Check invalid format specifiers are errors' '\n \ttest_must_fail git for-each-ref --format=\"%(authordate:INVALID)\" refs/heads\n '\n \n-cat >expected <<\\EOF\n-'refs/heads/master' 'Mon Jul 3 17:18:43 2006 +0200' 'Mon Jul 3 17:18:44 2006 +0200'\n-'refs/tags/testtag' 'Mon Jul 3 17:18:45 2006 +0200'\n-EOF\n+test_date () {\n+\tf=$1 &&\n+\tcommitter_date=$2 &&\n+\tauthor_date=$3 &&\n+\ttagger_date=$4 &&\n+\tcat >expected <<-EOF &&\n+\t'refs/heads/master' '$committer_date' '$author_date'\n+\t'refs/tags/testtag' '$tagger_date'\n+\tEOF\n+\t(\n+\t\tgit for-each-ref --shell \\\n+\t\t\t--format=\"%(refname) %(committerdate${f:+:$f}) %(authordate${f:+:$f})\" \\\n+\t\t\trefs/heads &&\n+\t\tgit for-each-ref --shell \\\n+\t\t\t--format=\"%(refname) %(taggerdate${f:+:$f})\" \\\n+\t\t\trefs/tags\n+\t) >actual &&\n+\ttest_cmp expected actual\n+}\n \n test_expect_success 'Check unformatted date fields output' '\n-\t(git for-each-ref --shell --format=\"%(refname) %(committerdate) %(authordate)\" refs/heads &&\n-\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate)\" refs/tags) >actual &&\n-\ttest_cmp expected actual\n+\ttest_date \"\" \\\n+\t\t\"Mon Jul 3 17:18:43 2006 +0200\" \\\n+\t\t\"Mon Jul 3 17:18:44 2006 +0200\" \\\n+\t\t\"Mon Jul 3 17:18:45 2006 +0200\"\n '\n \n test_expect_success 'Check format \"default\" formatted date fields output' '\n-\tf=default &&\n-\t(git for-each-ref --shell --format=\"%(refname) %(committerdate:$f) %(authordate:$f)\" refs/heads &&\n-\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate:$f)\" refs/tags) >actual &&\n-\ttest_cmp expected actual\n+\ttest_date default \\\n+\t\t\"Mon Jul 3 17:18:43 2006 +0200\" \\\n+\t\t\"Mon Jul 3 17:18:44 2006 +0200\" \\\n+\t\t\"Mon Jul 3 17:18:45 2006 +0200\"\n '\n \n # Don't know how to do relative check because I can't know when this script\n # is going to be run and can't fake the current time to git, and hence can't\n # provide expected output.  Instead, I'll just make sure that \"relative\"\n # doesn't exit in error\n-#\n-#cat >expected <<\\EOF\n-#\n-#EOF\n-#\n test_expect_success 'Check format \"relative\" date fields output' '\n \tf=relative &&\n \t(git for-each-ref --shell --format=\"%(refname) %(committerdate:$f) %(authordate:$f)\" refs/heads &&\n \tgit for-each-ref --shell --format=\"%(refname) %(taggerdate:$f)\" refs/tags) >actual\n '\n \n-cat >expected <<\\EOF\n-'refs/heads/master' '2006-07-03' '2006-07-03'\n-'refs/tags/testtag' '2006-07-03'\n-EOF\n-\n test_expect_success 'Check format \"short\" date fields output' '\n-\tf=short &&\n-\t(git for-each-ref --shell --format=\"%(refname) %(committerdate:$f) %(authordate:$f)\" refs/heads &&\n-\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate:$f)\" refs/tags) >actual &&\n-\ttest_cmp expected actual\n+\ttest_date short 2006-07-03 2006-07-03 2006-07-03\n '\n \n-cat >expected <<\\EOF\n-'refs/heads/master' 'Mon Jul 3 15:18:43 2006' 'Mon Jul 3 15:18:44 2006'\n-'refs/tags/testtag' 'Mon Jul 3 15:18:45 2006'\n-EOF\n-\n test_expect_success 'Check format \"local\" date fields output' '\n-\tf=local &&\n-\t(git for-each-ref --shell --format=\"%(refname) %(committerdate:$f) %(authordate:$f)\" refs/heads &&\n-\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate:$f)\" refs/tags) >actual &&\n-\ttest_cmp expected actual\n+\ttest_date local \\\n+\t\t\"Mon Jul 3 15:18:43 2006\" \\\n+\t\t\"Mon Jul 3 15:18:44 2006\" \\\n+\t\t\"Mon Jul 3 15:18:45 2006\"\n '\n \n-cat >expected <<\\EOF\n-'refs/heads/master' '2006-07-03 17:18:43 +0200' '2006-07-03 17:18:44 +0200'\n-'refs/tags/testtag' '2006-07-03 17:18:45 +0200'\n-EOF\n-\n test_expect_success 'Check format \"iso8601\" date fields output' '\n-\tf=iso8601 &&\n-\t(git for-each-ref --shell --format=\"%(refname) %(committerdate:$f) %(authordate:$f)\" refs/heads &&\n-\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate:$f)\" refs/tags) >actual &&\n-\ttest_cmp expected actual\n+\ttest_date iso8601 \\\n+\t\t\"2006-07-03 17:18:43 +0200\" \\\n+\t\t\"2006-07-03 17:18:44 +0200\" \\\n+\t\t\"2006-07-03 17:18:45 +0200\"\n '\n \n-cat >expected <<\\EOF\n-'refs/heads/master' 'Mon, 3 Jul 2006 17:18:43 +0200' 'Mon, 3 Jul 2006 17:18:44 +0200'\n-'refs/tags/testtag' 'Mon, 3 Jul 2006 17:18:45 +0200'\n-EOF\n-\n test_expect_success 'Check format \"rfc2822\" date fields output' '\n-\tf=rfc2822 &&\n-\t(git for-each-ref --shell --format=\"%(refname) %(committerdate:$f) %(authordate:$f)\" refs/heads &&\n-\tgit for-each-ref --shell --format=\"%(refname) %(taggerdate:$f)\" refs/tags) >actual &&\n-\ttest_cmp expected actual\n+\ttest_date rfc2822 \\\n+\t\t\"Mon, 3 Jul 2006 17:18:43 +0200\" \\\n+\t\t\"Mon, 3 Jul 2006 17:18:44 +0200\" \\\n+\t\t\"Mon, 3 Jul 2006 17:18:45 +0200\"\n '\n \n test_expect_success 'Check format of strftime date fields' '\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269379","messageId":"c0c0a1c5eaa36388bba38b604e2fbcae30677b86.1441316394.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441316394.git.john@keeping.me.uk","subject":"[PATCH v3 07/11] t6300: add test for \"raw\" date format","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-03T21:48:57Z","receivedAt":"2015-09-03T21:48:57Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"Signed-off-by: John Keeping <john@keeping.me.uk>\n---\n t/t6300-for-each-ref.sh | 4 ++++\n 1 file changed, 4 insertions(+)\n\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 0bf709b..6afcff6 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -215,6 +215,10 @@ test_expect_success 'Check format \"rfc2822\" date fields output' '\n \t\t\"Mon, 3 Jul 2006 17:18:45 +0200\"\n '\n \n+test_expect_success 'Check format \"raw\" date fields output' '\n+\ttest_date raw \"1151939923 +0200\" \"1151939924 +0200\" \"1151939925 +0200\"\n+'\n+\n test_expect_success 'Check format of strftime date fields' '\n \techo \"my date is 2006-07-03\" >expected &&\n \tgit for-each-ref \\\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269380","messageId":"7b53c15203dadbf143239c787f43ea39b6bf28fa.1441316394.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441316394.git.john@keeping.me.uk","subject":"[PATCH v3 08/11] date: check for \"local\" before anything else","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-03T21:48:58Z","receivedAt":"2015-09-03T21:48:58Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"In a following commit we will make \"local\" orthogonal to the format.\nAlthough this will not apply to \"relative\", which does not use the\ntimezone, it applies to all other formats so move the timezone\nconversion to the start of the function.\n\nSigned-off-by: John Keeping <john@keeping.me.uk>\n---\n date.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex 8f91569..9f0a5dd 100644\n--- a/date.c\n+++ b/date.c\n@@ -174,6 +174,9 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \tstruct tm *tm;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n \n+\tif (mode->type == DATE_LOCAL)\n+\t\ttz = local_tzoffset(time);\n+\n \tif (mode->type == DATE_RAW) {\n \t\tstrbuf_reset(&timebuf);\n \t\tstrbuf_addf(&timebuf, \"%lu %+05d\", time, tz);\n@@ -189,9 +192,6 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \t\treturn timebuf.buf;\n \t}\n \n-\tif (mode->type == DATE_LOCAL)\n-\t\ttz = local_tzoffset(time);\n-\n \ttm = time_to_tm(time, tz);\n \tif (!tm) {\n \t\ttm = time_to_tm(0, 0);\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269381","messageId":"697ac08e0d5faddaaa09e280f7658c07be62f823.1441316394.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441316394.git.john@keeping.me.uk","subject":"[PATCH v3 09/11] date: make \"local\" orthogonal to date format","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-03T21:48:59Z","receivedAt":"2015-09-03T21:48:59Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nMost of our \"--date\" modes are about the format of the date:\nwhich items we show and in what order. But \"--date=local\" is\na bit of an oddball. It means \"show the date in the normal\nformat, but using the local timezone\". The timezone we use\nis orthogonal to the actual format, and there is no reason\nwe could not have \"localized iso8601\", etc.\n\nThis patch adds a \"local\" boolean field to \"struct\ndate_mode\", and drops the DATE_LOCAL element from the\ndate_mode_type enum (it's now just DATE_NORMAL plus\nlocal=1). The new feature is accessible to users by adding\n\"-local\" to any date mode (e.g., \"iso-local\"), and we retain\n\"local\" as an alias for \"default-local\" for backwards\ncompatibility.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: John Keeping <john@keeping.me.uk>\n---\nChanges since v2:\n- \"local\" check has moved above DATE_RAW processing as a result of an\n  earlier patch\n- \"relative-local\" and \"raw-local\" are now allowed\n- the error message if the format starts with a valid sequence but is\n  invalid as a whole is now consistent with the case where there is no\n  valid prefix\n\n Documentation/rev-list-options.txt | 21 ++++++++----\n builtin/blame.c                    |  1 -\n cache.h                            |  2 +-\n date.c                             | 70 ++++++++++++++++++++++++--------------\n 4 files changed, 61 insertions(+), 33 deletions(-)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 14c4cce..359587c 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -702,12 +702,16 @@ include::pretty-options.txt[]\n --date=<format>::\n \tOnly takes effect for dates shown in human-readable format, such\n \tas when using `--pretty`. `log.date` config variable sets a default\n-\tvalue for the log command's `--date` option.\n+\tvalue for the log command's `--date` option. By default, dates\n+\tare shown in the original time zone (either committer's or\n+\tauthor's). If `-local` is appended to the format (e.g.,\n+\t`iso-local`), the user's local time zone is used instead.\n +\n `--date=relative` shows dates relative to the current time,\n-e.g. ``2 hours ago''.\n+e.g. ``2 hours ago''. The `-local` option cannot be used with\n+`--raw` or `--relative`.\n +\n-`--date=local` shows timestamps in user's local time zone.\n+`--date=local` is an alias for `--date=default-local`.\n +\n `--date=iso` (or `--date=iso8601`) shows timestamps in a ISO 8601-like format.\n The differences to the strict ISO 8601 format are:\n@@ -730,10 +734,15 @@ format, often found in email messages.\n `--date=format:...` feeds the format `...` to your system `strftime`.\n Use `--date=format:%c` to show the date in your system locale's\n preferred format.  See the `strftime` manual for a complete list of\n-format placeholders.\n+format placeholders. When using `-local`, the correct syntax is\n+`--date=format-local:...`.\n +\n-`--date=default` shows timestamps in the original time zone\n-(either committer's or author's).\n+`--date=default` is the default format, and is similar to\n+`--date=rfc2822`, with a few exceptions:\n+\n+\t- there is no comma after the day-of-week\n+\n+\t- the time zone is omitted when the local time zone is used\n \n ifdef::git-rev-list[]\n --header::\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 4db01c1..6fd1a63 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2600,7 +2600,6 @@ parse_done:\n \t\t   fewer display columns. */\n \t\tblame_date_width = utf8_strwidth(_(\"4 years, 11 months ago\")) + 1; /* add the null */\n \t\tbreak;\n-\tcase DATE_LOCAL:\n \tcase DATE_NORMAL:\n \t\tblame_date_width = sizeof(\"Thu Oct 19 16:00:04 2006 -0700\");\n \t\tbreak;\ndiff --git a/cache.h b/cache.h\nindex 4e25271..9a91b1d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1091,7 +1091,6 @@ struct date_mode {\n \t\tDATE_NORMAL = 0,\n \t\tDATE_RELATIVE,\n \t\tDATE_SHORT,\n-\t\tDATE_LOCAL,\n \t\tDATE_ISO8601,\n \t\tDATE_ISO8601_STRICT,\n \t\tDATE_RFC2822,\n@@ -1099,6 +1098,7 @@ struct date_mode {\n \t\tDATE_RAW\n \t} type;\n \tconst char *strftime_fmt;\n+\tint local;\n };\n \n /*\ndiff --git a/date.c b/date.c\nindex 9f0a5dd..7c9f769 100644\n--- a/date.c\n+++ b/date.c\n@@ -166,6 +166,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)\n \tif (type == DATE_STRFTIME)\n \t\tdie(\"BUG: cannot create anonymous strftime date_mode struct\");\n \tmode.type = type;\n+\tmode.local = 0;\n \treturn &mode;\n }\n \n@@ -174,7 +175,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \tstruct tm *tm;\n \tstatic struct strbuf timebuf = STRBUF_INIT;\n \n-\tif (mode->type == DATE_LOCAL)\n+\tif (mode->local)\n \t\ttz = local_tzoffset(time);\n \n \tif (mode->type == DATE_RAW) {\n@@ -232,7 +233,7 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n \t\t\t\ttm->tm_mday,\n \t\t\t\ttm->tm_hour, tm->tm_min, tm->tm_sec,\n \t\t\t\ttm->tm_year + 1900,\n-\t\t\t\t(mode->type == DATE_LOCAL) ? 0 : ' ',\n+\t\t\t\tmode->local ? 0 : ' ',\n \t\t\t\ttz);\n \treturn timebuf.buf;\n }\n@@ -770,31 +771,50 @@ int parse_date(const char *date, struct strbuf *result)\n \treturn 0;\n }\n \n+static enum date_mode_type parse_date_type(const char *format, const char **end)\n+{\n+\tif (skip_prefix(format, \"relative\", end))\n+\t\treturn DATE_RELATIVE;\n+\tif (skip_prefix(format, \"iso8601-strict\", end) ||\n+\t    skip_prefix(format, \"iso-strict\", end))\n+\t\treturn DATE_ISO8601_STRICT;\n+\tif (skip_prefix(format, \"iso8601\", end) ||\n+\t    skip_prefix(format, \"iso\", end))\n+\t\treturn DATE_ISO8601;\n+\tif (skip_prefix(format, \"rfc2822\", end) ||\n+\t    skip_prefix(format, \"rfc\", end))\n+\t\treturn DATE_RFC2822;\n+\tif (skip_prefix(format, \"short\", end))\n+\t\treturn DATE_SHORT;\n+\tif (skip_prefix(format, \"default\", end))\n+\t\treturn DATE_NORMAL;\n+\tif (skip_prefix(format, \"raw\", end))\n+\t\treturn DATE_RAW;\n+\tif (skip_prefix(format, \"format\", end))\n+\t\treturn DATE_STRFTIME;\n+\n+\tdie(\"unknown date format %s\", format);\n+}\n+\n void parse_date_format(const char *format, struct date_mode *mode)\n {\n-\tif (!strcmp(format, \"relative\"))\n-\t\tmode->type = DATE_RELATIVE;\n-\telse if (!strcmp(format, \"iso8601\") ||\n-\t\t !strcmp(format, \"iso\"))\n-\t\tmode->type = DATE_ISO8601;\n-\telse if (!strcmp(format, \"iso8601-strict\") ||\n-\t\t !strcmp(format, \"iso-strict\"))\n-\t\tmode->type = DATE_ISO8601_STRICT;\n-\telse if (!strcmp(format, \"rfc2822\") ||\n-\t\t !strcmp(format, \"rfc\"))\n-\t\tmode->type = DATE_RFC2822;\n-\telse if (!strcmp(format, \"short\"))\n-\t\tmode->type = DATE_SHORT;\n-\telse if (!strcmp(format, \"local\"))\n-\t\tmode->type = DATE_LOCAL;\n-\telse if (!strcmp(format, \"default\"))\n-\t\tmode->type = DATE_NORMAL;\n-\telse if (!strcmp(format, \"raw\"))\n-\t\tmode->type = DATE_RAW;\n-\telse if (skip_prefix(format, \"format:\", &format)) {\n-\t\tmode->type = DATE_STRFTIME;\n-\t\tmode->strftime_fmt = xstrdup(format);\n-\t} else\n+\tconst char *p;\n+\n+\t/* historical alias */\n+\tif (!strcmp(format, \"local\"))\n+\t\tformat = \"default-local\";\n+\n+\tmode->type = parse_date_type(format, &p);\n+\tmode->local = 0;\n+\n+\tif (skip_prefix(p, \"-local\", &p))\n+\t\tmode->local = 1;\n+\n+\tif (mode->type == DATE_STRFTIME) {\n+\t\tif (!skip_prefix(p, \":\", &p))\n+\t\t\tdie(\"date format missing colon separator: %s\", format);\n+\t\tmode->strftime_fmt = xstrdup(p);\n+\t} else if (*p)\n \t\tdie(\"unknown date format %s\", format);\n }\n \n-- \n2.5.0.466.g9af26fa\n"},{"id":"269382","messageId":"26f3b006a7848343ccaaf3b9b9e105b24428547c.1441316394.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441316394.git.john@keeping.me.uk","subject":"[PATCH v3 10/11] t6300: make UTC and local dates different","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-03T21:49:00Z","receivedAt":"2015-09-03T21:49:00Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"By setting the UTC time to 23:18:43 the date in +0200 is the following\nday, 2006-07-04.  This will ensure that the test for \"short-local\" to be\nadded in the following patch tests for different output from the \"short\"\nformat.\n\nSigned-off-by: John Keeping <john@keeping.me.uk>\n---\n t/t6300-for-each-ref.sh | 70 ++++++++++++++++++++++++-------------------------\n 1 file changed, 35 insertions(+), 35 deletions(-)\n\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 6afcff6..899251e 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -8,8 +8,8 @@ test_description='for-each-ref test'\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-gpg.sh\n \n-# Mon Jul 3 15:18:43 2006 +0000\n-datestamp=1151939923\n+# Mon Jul 3 23:18:43 2006 +0000\n+datestamp=1151968723\n setdate_and_increment () {\n     GIT_COMMITTER_DATE=\"$datestamp +0200\"\n     datestamp=$(expr \"$datestamp\" + 1)\n@@ -61,21 +61,21 @@ test_atom head object ''\n test_atom head type ''\n test_atom head '*objectname' ''\n test_atom head '*objecttype' ''\n-test_atom head author 'A U Thor <author@example.com> 1151939924 +0200'\n+test_atom head author 'A U Thor <author@example.com> 1151968724 +0200'\n test_atom head authorname 'A U Thor'\n test_atom head authoremail '<author@example.com>'\n-test_atom head authordate 'Mon Jul 3 17:18:44 2006 +0200'\n-test_atom head committer 'C O Mitter <committer@example.com> 1151939923 +0200'\n+test_atom head authordate 'Tue Jul 4 01:18:44 2006 +0200'\n+test_atom head committer 'C O Mitter <committer@example.com> 1151968723 +0200'\n test_atom head committername 'C O Mitter'\n test_atom head committeremail '<committer@example.com>'\n-test_atom head committerdate 'Mon Jul 3 17:18:43 2006 +0200'\n+test_atom head committerdate 'Tue Jul 4 01:18:43 2006 +0200'\n test_atom head tag ''\n test_atom head tagger ''\n test_atom head taggername ''\n test_atom head taggeremail ''\n test_atom head taggerdate ''\n-test_atom head creator 'C O Mitter <committer@example.com> 1151939923 +0200'\n-test_atom head creatordate 'Mon Jul 3 17:18:43 2006 +0200'\n+test_atom head creator 'C O Mitter <committer@example.com> 1151968723 +0200'\n+test_atom head creatordate 'Tue Jul 4 01:18:43 2006 +0200'\n test_atom head subject 'Initial'\n test_atom head contents:subject 'Initial'\n test_atom head body ''\n@@ -96,7 +96,7 @@ test_atom tag parent ''\n test_atom tag numparent ''\n test_atom tag object $(git rev-parse refs/tags/testtag^0)\n test_atom tag type 'commit'\n-test_atom tag '*objectname' '67a36f10722846e891fbada1ba48ed035de75581'\n+test_atom tag '*objectname' 'ea122842f48be4afb2d1fc6a4b96c05885ab7463'\n test_atom tag '*objecttype' 'commit'\n test_atom tag author ''\n test_atom tag authorname ''\n@@ -107,18 +107,18 @@ test_atom tag committername ''\n test_atom tag committeremail ''\n test_atom tag committerdate ''\n test_atom tag tag 'testtag'\n-test_atom tag tagger 'C O Mitter <committer@example.com> 1151939925 +0200'\n+test_atom tag tagger 'C O Mitter <committer@example.com> 1151968725 +0200'\n test_atom tag taggername 'C O Mitter'\n test_atom tag taggeremail '<committer@example.com>'\n-test_atom tag taggerdate 'Mon Jul 3 17:18:45 2006 +0200'\n-test_atom tag creator 'C O Mitter <committer@example.com> 1151939925 +0200'\n-test_atom tag creatordate 'Mon Jul 3 17:18:45 2006 +0200'\n-test_atom tag subject 'Tagging at 1151939927'\n-test_atom tag contents:subject 'Tagging at 1151939927'\n+test_atom tag taggerdate 'Tue Jul 4 01:18:45 2006 +0200'\n+test_atom tag creator 'C O Mitter <committer@example.com> 1151968725 +0200'\n+test_atom tag creatordate 'Tue Jul 4 01:18:45 2006 +0200'\n+test_atom tag subject 'Tagging at 1151968727'\n+test_atom tag contents:subject 'Tagging at 1151968727'\n test_atom tag body ''\n test_atom tag contents:body ''\n test_atom tag contents:signature ''\n-test_atom tag contents 'Tagging at 1151939927\n+test_atom tag contents 'Tagging at 1151968727\n '\n test_atom tag HEAD ' '\n \n@@ -168,16 +168,16 @@ test_date () {\n \n test_expect_success 'Check unformatted date fields output' '\n \ttest_date \"\" \\\n-\t\t\"Mon Jul 3 17:18:43 2006 +0200\" \\\n-\t\t\"Mon Jul 3 17:18:44 2006 +0200\" \\\n-\t\t\"Mon Jul 3 17:18:45 2006 +0200\"\n+\t\t\"Tue Jul 4 01:18:43 2006 +0200\" \\\n+\t\t\"Tue Jul 4 01:18:44 2006 +0200\" \\\n+\t\t\"Tue Jul 4 01:18:45 2006 +0200\"\n '\n \n test_expect_success 'Check format \"default\" formatted date fields output' '\n \ttest_date default \\\n-\t\t\"Mon Jul 3 17:18:43 2006 +0200\" \\\n-\t\t\"Mon Jul 3 17:18:44 2006 +0200\" \\\n-\t\t\"Mon Jul 3 17:18:45 2006 +0200\"\n+\t\t\"Tue Jul 4 01:18:43 2006 +0200\" \\\n+\t\t\"Tue Jul 4 01:18:44 2006 +0200\" \\\n+\t\t\"Tue Jul 4 01:18:45 2006 +0200\"\n '\n \n # Don't know how to do relative check because I can't know when this script\n@@ -191,36 +191,36 @@ test_expect_success 'Check format \"relative\" date fields output' '\n '\n \n test_expect_success 'Check format \"short\" date fields output' '\n-\ttest_date short 2006-07-03 2006-07-03 2006-07-03\n+\ttest_date short 2006-07-04 2006-07-04 2006-07-04\n '\n \n test_expect_success 'Check format \"local\" date fields output' '\n \ttest_date local \\\n-\t\t\"Mon Jul 3 15:18:43 2006\" \\\n-\t\t\"Mon Jul 3 15:18:44 2006\" \\\n-\t\t\"Mon Jul 3 15:18:45 2006\"\n+\t\t\"Mon Jul 3 23:18:43 2006\" \\\n+\t\t\"Mon Jul 3 23:18:44 2006\" \\\n+\t\t\"Mon Jul 3 23:18:45 2006\"\n '\n \n test_expect_success 'Check format \"iso8601\" date fields output' '\n \ttest_date iso8601 \\\n-\t\t\"2006-07-03 17:18:43 +0200\" \\\n-\t\t\"2006-07-03 17:18:44 +0200\" \\\n-\t\t\"2006-07-03 17:18:45 +0200\"\n+\t\t\"2006-07-04 01:18:43 +0200\" \\\n+\t\t\"2006-07-04 01:18:44 +0200\" \\\n+\t\t\"2006-07-04 01:18:45 +0200\"\n '\n \n test_expect_success 'Check format \"rfc2822\" date fields output' '\n \ttest_date rfc2822 \\\n-\t\t\"Mon, 3 Jul 2006 17:18:43 +0200\" \\\n-\t\t\"Mon, 3 Jul 2006 17:18:44 +0200\" \\\n-\t\t\"Mon, 3 Jul 2006 17:18:45 +0200\"\n+\t\t\"Tue, 4 Jul 2006 01:18:43 +0200\" \\\n+\t\t\"Tue, 4 Jul 2006 01:18:44 +0200\" \\\n+\t\t\"Tue, 4 Jul 2006 01:18:45 +0200\"\n '\n \n test_expect_success 'Check format \"raw\" date fields output' '\n-\ttest_date raw \"1151939923 +0200\" \"1151939924 +0200\" \"1151939925 +0200\"\n+\ttest_date raw \"1151968723 +0200\" \"1151968724 +0200\" \"1151968725 +0200\"\n '\n \n test_expect_success 'Check format of strftime date fields' '\n-\techo \"my date is 2006-07-03\" >expected &&\n+\techo \"my date is 2006-07-04\" >expected &&\n \tgit for-each-ref \\\n \t  --format=\"%(authordate:format:my date is %Y-%m-%d)\" \\\n \t  refs/heads >actual &&\n@@ -538,8 +538,8 @@ body contents\n $sig\"\n \n cat >expected <<EOF\n-$(git rev-parse refs/tags/master) <committer@example.com> refs/tags/master\n $(git rev-parse refs/tags/bogo) <committer@example.com> refs/tags/bogo\n+$(git rev-parse refs/tags/master) <committer@example.com> refs/tags/master\n EOF\n \n test_expect_success 'Verify sort with multiple keys' '\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269383","messageId":"5559d4bca517cb1be881e2a2e6ff7aefbd0fee64.1441316394.git.john@keeping.me.uk","threadId":"40221","inReplyTo":"cover.1441316394.git.john@keeping.me.uk","subject":"[PATCH v3 11/11] t6300: add tests for \"-local\" date formats","fromName":"John Keeping","fromEmail":"john@keeping.me.uk","sentAt":"2015-09-03T21:49:01Z","receivedAt":"2015-09-03T21:49:01Z","isPatch":true,"sender":{"key":"john@keeping.me.uk","avatar":"https://avatars.githubusercontent.com/u/1702081?v=4"},"body":"Signed-off-by: John Keeping <john@keeping.me.uk>\n---\nChanges since v2:\n- \"relative-local\" and \"raw-local\" are now allowed\n\n t/t6300-for-each-ref.sh | 36 ++++++++++++++++++++++++++++++++++++\n 1 file changed, 36 insertions(+)\n\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex 899251e..03873b0 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -180,6 +180,10 @@ test_expect_success 'Check format \"default\" formatted date fields output' '\n \t\t\"Tue Jul 4 01:18:45 2006 +0200\"\n '\n \n+test_expect_success 'Check format \"default-local\" date fields output' '\n+\ttest_date default-local \"Mon Jul 3 23:18:43 2006\" \"Mon Jul 3 23:18:44 2006\" \"Mon Jul 3 23:18:45 2006\"\n+'\n+\n # Don't know how to do relative check because I can't know when this script\n # is going to be run and can't fake the current time to git, and hence can't\n # provide expected output.  Instead, I'll just make sure that \"relative\"\n@@ -190,10 +194,22 @@ test_expect_success 'Check format \"relative\" date fields output' '\n \tgit for-each-ref --shell --format=\"%(refname) %(taggerdate:$f)\" refs/tags) >actual\n '\n \n+# We just check that this is the same as \"relative\" for now.\n+test_expect_success 'Check format \"relative-local\" date fields output' '\n+\ttest_date relative-local \\\n+\t\t\"$(git for-each-ref --format=\"%(committerdate:relative)\" refs/heads)\" \\\n+\t\t\"$(git for-each-ref --format=\"%(authordate:relative)\" refs/heads)\" \\\n+\t\t\"$(git for-each-ref --format=\"%(taggerdate:relative)\" refs/tags)\"\n+'\n+\n test_expect_success 'Check format \"short\" date fields output' '\n \ttest_date short 2006-07-04 2006-07-04 2006-07-04\n '\n \n+test_expect_success 'Check format \"short-local\" date fields output' '\n+\ttest_date short-local 2006-07-03 2006-07-03 2006-07-03\n+'\n+\n test_expect_success 'Check format \"local\" date fields output' '\n \ttest_date local \\\n \t\t\"Mon Jul 3 23:18:43 2006\" \\\n@@ -208,6 +224,10 @@ test_expect_success 'Check format \"iso8601\" date fields output' '\n \t\t\"2006-07-04 01:18:45 +0200\"\n '\n \n+test_expect_success 'Check format \"iso8601-local\" date fields output' '\n+\ttest_date iso8601-local \"2006-07-03 23:18:43 +0000\" \"2006-07-03 23:18:44 +0000\" \"2006-07-03 23:18:45 +0000\"\n+'\n+\n test_expect_success 'Check format \"rfc2822\" date fields output' '\n \ttest_date rfc2822 \\\n \t\t\"Tue, 4 Jul 2006 01:18:43 +0200\" \\\n@@ -215,10 +235,18 @@ test_expect_success 'Check format \"rfc2822\" date fields output' '\n \t\t\"Tue, 4 Jul 2006 01:18:45 +0200\"\n '\n \n+test_expect_success 'Check format \"rfc2822-local\" date fields output' '\n+\ttest_date rfc2822-local \"Mon, 3 Jul 2006 23:18:43 +0000\" \"Mon, 3 Jul 2006 23:18:44 +0000\" \"Mon, 3 Jul 2006 23:18:45 +0000\"\n+'\n+\n test_expect_success 'Check format \"raw\" date fields output' '\n \ttest_date raw \"1151968723 +0200\" \"1151968724 +0200\" \"1151968725 +0200\"\n '\n \n+test_expect_success 'Check format \"raw-local\" date fields output' '\n+\ttest_date raw-local \"1151968723 +0000\" \"1151968724 +0000\" \"1151968725 +0000\"\n+'\n+\n test_expect_success 'Check format of strftime date fields' '\n \techo \"my date is 2006-07-04\" >expected &&\n \tgit for-each-ref \\\n@@ -227,6 +255,14 @@ test_expect_success 'Check format of strftime date fields' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'Check format of strftime-local date fields' '\n+\techo \"my date is 2006-07-03\" >expected &&\n+\tgit for-each-ref \\\n+\t  --format=\"%(authordate:format-local:my date is %Y-%m-%d)\" \\\n+\t  refs/heads >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_expect_success 'exercise strftime with odd fields' '\n \techo >expected &&\n \tgit for-each-ref --format=\"%(authordate:format:)\" refs/heads >actual &&\n-- \n2.5.0.466.g9af26fa\n"},{"id":"269387","messageId":"xmqqvbbrgmft.fsf@gitster.mtv.corp.google.com","threadId":"40221","inReplyTo":"cfc780ad4f30521a4f54eba2a96ced8e0bbfc519.1441316394.git.john@keeping.me.uk","subject":"Re: [PATCH v3 04/11] Documentation/rev-list: don't list date formats","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-03T22:36:22Z","receivedAt":"2015-09-03T22:36:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"John Keeping <john@keeping.me.uk> writes:\n\n> We are about to add several new date formats which will make this list\n> too long to display in a single line.\n>\n> Signed-off-by: John Keeping <john@keeping.me.uk>\n> ---\n>  Documentation/git-rev-list.txt     | 2 +-\n>  Documentation/rev-list-options.txt | 2 +-\n>  2 files changed, 2 insertions(+), 2 deletions(-)\n\nAfter seeing 1-3/11 this makes me wonder if we still have a list\nsomewhere in the documentation.  I'll read on first but I may have\nto come back to this later.\n\nThanks.\n\n>\n> diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt\n> index 7b49c85..ef22f17 100644\n> --- a/Documentation/git-rev-list.txt\n> +++ b/Documentation/git-rev-list.txt\n> @@ -45,7 +45,7 @@ SYNOPSIS\n>  \t     [ --regexp-ignore-case | -i ]\n>  \t     [ --extended-regexp | -E ]\n>  \t     [ --fixed-strings | -F ]\n> -\t     [ --date=(local|relative|default|iso|iso-strict|rfc|short) ]\n> +\t     [ --date=<format>]\n>  \t     [ [ --objects | --objects-edge | --objects-edge-aggressive ]\n>  \t       [ --unpacked ] ]\n>  \t     [ --pretty | --header ]\n> diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\n> index a9b808f..14c4cce 100644\n> --- a/Documentation/rev-list-options.txt\n> +++ b/Documentation/rev-list-options.txt\n> @@ -699,7 +699,7 @@ include::pretty-options.txt[]\n>  --relative-date::\n>  \tSynonym for `--date=relative`.\n>  \n> ---date=(relative|local|default|iso|iso-strict|rfc|short|raw)::\n> +--date=<format>::\n>  \tOnly takes effect for dates shown in human-readable format, such\n>  \tas when using `--pretty`. `log.date` config variable sets a default\n>  \tvalue for the log command's `--date` option.\n"},{"id":"269388","messageId":"xmqqr3mfgm0u.fsf@gitster.mtv.corp.google.com","threadId":"40221","inReplyTo":"7b53c15203dadbf143239c787f43ea39b6bf28fa.1441316394.git.john@keeping.me.uk","subject":"Re: [PATCH v3 08/11] date: check for \"local\" before anything else","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-09-03T22:45:21Z","receivedAt":"2015-09-03T22:45:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"John Keeping <john@keeping.me.uk> writes:\n\n> In a following commit we will make \"local\" orthogonal to the format.\n> Although this will not apply to \"relative\", which does not use the\n> timezone, it applies to all other formats so move the timezone\n> conversion to the start of the function.\n\n\"local\" is a request to show the timestamp in the output in our\nlocal timezone regardless of the format, so even though \"relative\"\nis not affected by the timezone (because \"relative\" does not show a\ntimestamp at all---it only shows the duration), this change\nconceptually makes sense.\n\nThanks.\n\n\n>\n> Signed-off-by: John Keeping <john@keeping.me.uk>\n> ---\n>  date.c | 6 +++---\n>  1 file changed, 3 insertions(+), 3 deletions(-)\n>\n> diff --git a/date.c b/date.c\n> index 8f91569..9f0a5dd 100644\n> --- a/date.c\n> +++ b/date.c\n> @@ -174,6 +174,9 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n>  \tstruct tm *tm;\n>  \tstatic struct strbuf timebuf = STRBUF_INIT;\n>  \n> +\tif (mode->type == DATE_LOCAL)\n> +\t\ttz = local_tzoffset(time);\n> +\n>  \tif (mode->type == DATE_RAW) {\n>  \t\tstrbuf_reset(&timebuf);\n>  \t\tstrbuf_addf(&timebuf, \"%lu %+05d\", time, tz);\n> @@ -189,9 +192,6 @@ const char *show_date(unsigned long time, int tz, const struct date_mode *mode)\n>  \t\treturn timebuf.buf;\n>  \t}\n>  \n> -\tif (mode->type == DATE_LOCAL)\n> -\t\ttz = local_tzoffset(time);\n> -\n>  \ttm = time_to_tm(time, tz);\n>  \tif (!tm) {\n>  \t\ttm = time_to_tm(0, 0);\n"},{"id":"269599","messageId":"20150908075343.GA2991@sigill.intra.peff.net","threadId":"40221","inReplyTo":"cover.1441316394.git.john@keeping.me.uk","subject":"Re: [PATCH v3 00/11] Make \"local\" orthogonal to date format","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2015-09-08T07:53:43Z","receivedAt":"2015-09-08T07:53:43Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 03, 2015 at 10:48:50PM +0100, John Keeping wrote:\n\n> Since version 2 there are four new preparatory patches which remove\n> lists of date formats from documentation in favour of referring to the\n> detailed list in git-rev-list(1) or git-log(1) (both generated from\n> Documentation/rev-list-options.txt) depending on whether the page in\n> question is plumbing/porcelain.\n\nThis version looks good to me. It turned out to be a bigger job than we\nexpected at first; thanks for seeing it through.\n\n> In patch 7 (date: check for \"local\" before anything else), we no longer\n> reject \"relative-local\" and \"raw-local\" now prints the user's local\n> timezone offset.  The error message for invalid formats that are\n> prefixed with a valid format name is now the same as that if there is no\n> valid prefix.\n\nThat sounds OK. We have enough information in our parsing state to say\n\"I understood the 'iso8601', but '-foobar' did not make any sense to\nme\". But it's doubtful that would ever come up in practice.\n\n-Peff\n"}]}