{"thread":{"id":"37447","subject":"[PATCH v3] pretty: add --date=iso-strict, a strict ISO-8601 date format","startedAt":"2014-08-29T20:55:50Z","lastAt":"2014-08-29T20:55:50Z","messageCount":1,"participants":["Beat Bolli"],"isPatch":true,"patchVersion":3,"patchTotal":null},"messages":[{"id":"248588","messageId":"1409345750-9608-1-git-send-email-bbolli@ewanet.ch","threadId":"37447","inReplyTo":null,"subject":"[PATCH v3] pretty: add --date=iso-strict, a strict ISO-8601 date format","fromName":"Beat Bolli","fromEmail":"bbolli@ewanet.ch","sentAt":"2014-08-29T20:55:50Z","receivedAt":"2014-08-29T20:55:50Z","isPatch":true,"sender":{"key":"bbolli@ewanet.ch","avatar":"https://avatars.githubusercontent.com/u/21444?v=4"},"body":"There has been concern that Git's \"ISO\" date format does not really\nconform to the ISO-8601 standard. Thus, it cannot be parsed by ISO-8601\ncompliant parsers, e.g. those of XML toolchains.\n\nThe --date=iso format Git uses deviates from ISO-8601 in these ways:\n  - a space instead of the \"T\" date/time delimiter\n  - a space between time and time zone\n  - no colon between hours and minutes of the time zone\n\nAdd a strict ISO-8601 date format for displaying committer and author\ndates. Use the '%aI' and '%cI' format specifiers (note the uppercase\n'I') and the '--date=iso-strict' or '--date=iso8601-strict' date format\nnames.\n\nSee http://thread.gmane.org/gmane.comp.version-control.git/255879 and\nhttp://thread.gmane.org/gmane.comp.version-control.git/52414/focus=52585\nfor discussion.\n\nSigned-off-by: Beat Bolli <bbolli@ewanet.ch>\n---\n\nv3:\n  - Improve the commit message\n  - Add the new format in builtin/blame.c\n\nv2:\n  - Improve the commit message\n  - Fix time zone display for negative values close to zero\n\n Documentation/git-rev-list.txt     |  2 +-\n Documentation/pretty-formats.txt   |  6 ++++--\n Documentation/rev-list-options.txt | 13 +++++++++++--\n builtin/blame.c                    |  3 +++\n cache.h                            |  1 +\n date.c                             | 14 +++++++++++++-\n pretty.c                           |  5 ++++-\n t/t4205-log-pretty-formats.sh      |  7 +++++++\n 8 files changed, 44 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt\nindex 7a1585d..fd7f8b5 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|rfc|short) ]\n+\t     [ \\--date=(local|relative|default|iso|iso-strict|rfc|short) ]\n \t     [ [\\--objects | \\--objects-edge] [ \\--unpacked ] ]\n \t     [ \\--pretty | \\--header ]\n \t     [ \\--bisect ]\ndiff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt\nindex 85d6353..50a2c30 100644\n--- a/Documentation/pretty-formats.txt\n+++ b/Documentation/pretty-formats.txt\n@@ -115,7 +115,8 @@ The placeholders are:\n - '%aD': author date, RFC2822 style\n - '%ar': author date, relative\n - '%at': author date, UNIX timestamp\n-- '%ai': author date, ISO 8601 format\n+- '%ai': author date, ISO 8601-like format\n+- '%aI': author date, strict ISO 8601 format\n - '%cn': committer name\n - '%cN': committer name (respecting .mailmap, see\n   linkgit:git-shortlog[1] or linkgit:git-blame[1])\n@@ -126,7 +127,8 @@ The placeholders are:\n - '%cD': committer date, RFC2822 style\n - '%cr': committer date, relative\n - '%ct': committer date, UNIX timestamp\n-- '%ci': committer date, ISO 8601 format\n+- '%ci': committer date, ISO 8601-like format\n+- '%cI': committer date, strict ISO 8601 format\n - '%d': ref names, like the --decorate option of linkgit:git-log[1]\n - '%e': encoding\n - '%s': subject\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex deb8cca..5d311b8 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -677,7 +677,7 @@ include::pretty-options.txt[]\n --relative-date::\n \tSynonym for `--date=relative`.\n \n---date=(relative|local|default|iso|rfc|short|raw)::\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@@ -687,7 +687,16 @@ e.g. ``2 hours ago''.\n +\n `--date=local` shows timestamps in user's local time zone.\n +\n-`--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format.\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+\n+\t- a space instead of the `T` date/time delimiter\n+\t- a space between time and time zone\n+\t- no colon between hours and minutes of the time zone\n+\n++\n+`--date=iso-strict` (or `--date=iso8601-strict`) shows timestamps in strict\n+ISO 8601 format.\n +\n `--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822\n format, often found in email messages.\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 17d30d0..4f974aa 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -2583,6 +2583,9 @@ parse_done:\n \tcase DATE_ISO8601:\n \t\tblame_date_width = sizeof(\"2006-10-19 16:00:04 -0700\");\n \t\tbreak;\n+\tcase DATE_ISO8601_STRICT:\n+\t\tblame_date_width = sizeof(\"2006-10-19T16:00:04-07:00\");\n+\t\tbreak;\n \tcase DATE_RAW:\n \t\tblame_date_width = sizeof(\"1161298804 -0700\");\n \t\tbreak;\ndiff --git a/cache.h b/cache.h\nindex fcb511d..fa92aaf 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1037,6 +1037,7 @@ enum date_mode {\n \tDATE_SHORT,\n \tDATE_LOCAL,\n \tDATE_ISO8601,\n+\tDATE_ISO8601_STRICT,\n \tDATE_RFC2822,\n \tDATE_RAW\n };\ndiff --git a/date.c b/date.c\nindex 782de95..5d73d9b 100644\n--- a/date.c\n+++ b/date.c\n@@ -200,7 +200,16 @@ const char *show_date(unsigned long time, int tz, enum 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\ttz);\n-\telse if (mode == DATE_RFC2822)\n+\telse if (mode == 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+\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\tsign, tz / 100, tz % 100);\n+\t} else if (mode == 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@@ -751,6 +760,9 @@ enum date_mode parse_date_format(const char *format)\n \telse if (!strcmp(format, \"iso8601\") ||\n \t\t !strcmp(format, \"iso\"))\n \t\treturn DATE_ISO8601;\n+\telse if (!strcmp(format, \"iso8601-strict\") ||\n+\t\t !strcmp(format, \"iso-strict\"))\n+\t\treturn DATE_ISO8601_STRICT;\n \telse if (!strcmp(format, \"rfc2822\") ||\n \t\t !strcmp(format, \"rfc\"))\n \t\treturn DATE_RFC2822;\ndiff --git a/pretty.c b/pretty.c\nindex 3a1da6f..7dd5601 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -731,9 +731,12 @@ static size_t format_person_part(struct strbuf *sb, char part,\n \tcase 'r':\t/* date, relative */\n \t\tstrbuf_addstr(sb, show_ident_date(&s, DATE_RELATIVE));\n \t\treturn placeholder_len;\n-\tcase 'i':\t/* date, ISO 8601 */\n+\tcase 'i':\t/* date, ISO 8601-like */\n \t\tstrbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601));\n \t\treturn placeholder_len;\n+\tcase 'I':\t/* date, ISO 8601 strict */\n+\t\tstrbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601_STRICT));\n+\t\treturn placeholder_len;\n \t}\n \n skip:\ndiff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh\nindex 349c531..aad7a80 100755\n--- a/t/t4205-log-pretty-formats.sh\n+++ b/t/t4205-log-pretty-formats.sh\n@@ -431,6 +431,13 @@ EOF\n \ttest_cmp expected actual\n '\n \n+# ISO strict date format\n+test_expect_success 'ISO and ISO-strict date formats display the same values' '\n+\tgit log --format=%ai%n%ci | sed -e \"s/ /T/; s/ //; s/..\\$/:&/\" >expected &&\n+\tgit log --format=%aI%n%cI >actual &&\n+\ttest_cmp expected actual\n+'\n+\n # get new digests (with no abbreviations)\n head1=$(git rev-parse --verify HEAD~0) &&\n head2=$(git rev-parse --verify HEAD~1) &&\n-- \n2.1.0\n"}]}