{"thread":{"id":"15040","subject":"[BUG] minor: wrong handling of GIT_AUTHOR_DATE","startedAt":"2008-08-16T20:53:25Z","lastAt":"2008-08-17T16:07:19Z","messageCount":10,"participants":["Hermann Gausterer","Linus Torvalds","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"87388","messageId":"20080816205325.GD10729@mrq1.org","threadId":"15040","inReplyTo":null,"subject":"[BUG] minor: wrong handling of GIT_AUTHOR_DATE","fromName":"Hermann Gausterer","fromEmail":"git-mailinglist@mrq1.org","sentAt":"2008-08-16T20:53:25Z","receivedAt":"2008-08-16T20:53:25Z","isPatch":false,"sender":{"key":"git-mailinglist@mrq1.org","avatar":null},"body":"hi\n\ni found a minor bug in the handling of the\nenvironment variable GIT_AUTHOR_DATE\n\ni used this variable to import an old project.\n\ni used \"stat\" to get the timestamp of a file\nand set the git history to this date with\nthis command:\n\nGIT_AUTHOR_DATE=`stat -c '%y' \"$FILE\"`\n\nold files (created with an older kernel)\nproduced this output.\n\n2008-05-28 14:21:35.000000000 +0200\n\nbut new files return nanosecond resolution\ntimestamps.\n\n2008-06-04 17:25:54.917476713 +0200\n\nof course this resolution is NOT needed\nfor git, but git DOES NOT ignore this time-\nstamps. it changes the date to something\ncompletly wrong :-/\n\nsteps to reproduce:\n\n$ git init\n$ touch test\n$ stat -c %y test\n2008-08-16 22:25:45.491701924 +0200\n$ export GIT_AUTHOR_DATE=`stat -c %y test`\n$ git add test\n$ git commit -a\n$ git log\ncommit 56f92b8f6efc7bdaa5abdf03a8c5dbf79dd1fdff\nAuthor: Hermann Gausterer <git-bugreport@mrq1.org>\nDate:   Thu Aug 1 01:52:04 1985 +0200\n\n    test\n$\n\nmfg hermann\n"},{"id":"87391","messageId":"alpine.LFD.1.10.0808161543160.3324@nehalem.linux-foundation.org","threadId":"15040","inReplyTo":"20080816205325.GD10729@mrq1.org","subject":"Re: [BUG] minor: wrong handling of GIT_AUTHOR_DATE","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-08-16T23:03:27Z","receivedAt":"2008-08-16T23:03:27Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sat, 16 Aug 2008, Hermann Gausterer wrote:\n> \n> i used \"stat\" to get the timestamp of a file\n> and set the git history to this date with\n> this command:\n> \n> GIT_AUTHOR_DATE=`stat -c '%y' \"$FILE\"`\n> \n> old files (created with an older kernel)\n> produced this output.\n> \n> 2008-05-28 14:21:35.000000000 +0200\n> \n> but new files return nanosecond resolution\n> timestamps.\n> \n> 2008-06-04 17:25:54.917476713 +0200\n> \n> of course this resolution is NOT needed\n> for git, but git DOES NOT ignore this time-\n> stamps. it changes the date to something\n> completly wrong :-/\n\nGit uses a fairly odd date parsing library, and it turns out that \n917476713 +0200 is actually a perfectly valid date in the git format, \nbecause one thing git allows is the \"seconds since epoch\" one. So doing\n\n\t[torvalds@nehalem git]$ ./test-date \"917476713 +0200\"\n\t917476713 +0200 -> 917476713 +0200 -> Wed Jan 27 14:38:33 1999\n\t917476713 +0200 -> Wed Jan 27 14:38:33 1999\n\nand it turns out that git will totally ignore any other format date when i \nsees this standard format (yes, that is literally the format that git uses \ninternally).\n\nSo because git date parsing doesn't even really understand fractional \nseconds, and thus doesn't parse it, it will take the fraction, and if it \nwas larger than 100000000, it will assume it's a seconds-since-epoch date.\n\nUnlucky.\n\nAnyway, something like this should fix it.\n\nJunio: we might also make the code that actually parses the \nseconds-per-epoch thing only trigger if we haven't already seen a date (ie \nit might check for \"tm->tm_year < 0\" etc before accepting that seconds \nformat).\n\n\t\tLinus\n\n---\nSubject: Ignore fractional seconds in date parsing\nFrom: Linus Torvalds <torvads@linux-foundation.org>\n\n.. otherwise a nanosecond resolution fractional second might be \ninterpreted as a seconds-since-epoch date format string and overwrite the \ndate we so carefully just parsed.\n\nSigned-off-by: Linus Torvalds <torvalds@linux-foundation.org>\nNoticed-by: Hermann Gausterer <git-mailinglist@mrq1.org>\n---\n date.c |    5 +++++\n 1 files changed, 5 insertions(+), 0 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex 35a5257..5e502da 100644\n--- a/date.c\n+++ b/date.c\n@@ -363,6 +363,11 @@ static int match_multi_number(unsigned long num, char c, const char *date, char\n \t\t\ttm->tm_hour = num;\n \t\t\ttm->tm_min = num2;\n \t\t\ttm->tm_sec = num3;\n+\n+\t\t\t/* Ignore any possible fractional seconds */\n+\t\t\tif (*end == '.')\n+\t\t\t\t(void) strtol(end+1, &end, 10);\n+\n \t\t\tbreak;\n \t\t}\n \t\treturn 0;\n"},{"id":"87392","messageId":"alpine.LFD.1.10.0808161613520.3324@nehalem.linux-foundation.org","threadId":"15040","inReplyTo":"alpine.LFD.1.10.0808161543160.3324@nehalem.linux-foundation.org","subject":"Re: [BUG] minor: wrong handling of GIT_AUTHOR_DATE","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-08-16T23:17:50Z","receivedAt":"2008-08-16T23:17:50Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sat, 16 Aug 2008, Linus Torvalds wrote:\n> \n> Junio: we might also make the code that actually parses the \n> seconds-per-epoch thing only trigger if we haven't already seen a date (ie \n> it might check for \"tm->tm_year < 0\" etc before accepting that seconds \n> format).\n\nHere's a slightly expanded version of the previous patch, which will \nignore those big integer if it has already seen any human-readable date \nformat (either any time except 0:00:00 or any normal date).\n\nIt includes the fractional second parsing code from the previous patch \ntoo, since that's an independent thing and makes sense regardless.\n\nJunio, your call. But this one gets the date right for strings that just \nrandomly have some big number in them, ie\n\n\t[torvalds@nehalem git]$ ./test-date \"17:25:54 917476713 2008-06-04 -0700\"\n\t17:25:54 917476713 2008-06-04 -0700 -> 1212625554 -0700 -> Wed Jun  4 17:25:54 2008\n\t17:25:54 917476713 2008-06-04 -0700 -> Wed Jun  4 17:25:54 2008\n\nbecause it will now see that \"nodate()\" is not true. I think it's a good \nidea to only accept the epoch format when there hasn't been any other time \nformat visible.\n\n\t\t\tLinus\n\n---\n date.c |   16 +++++++++++++++-\n 1 files changed, 15 insertions(+), 1 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex 35a5257..e11e78e 100644\n--- a/date.c\n+++ b/date.c\n@@ -363,6 +363,11 @@ static int match_multi_number(unsigned long num, char c, const char *date, char\n \t\t\ttm->tm_hour = num;\n \t\t\ttm->tm_min = num2;\n \t\t\ttm->tm_sec = num3;\n+\n+\t\t\t/* Ignore any possible fractional seconds */\n+\t\t\tif (*end == '.')\n+\t\t\t\t(void) strtol(end+1, &end, 10);\n+\n \t\t\tbreak;\n \t\t}\n \t\treturn 0;\n@@ -402,6 +407,15 @@ static int match_multi_number(unsigned long num, char c, const char *date, char\n \treturn end - date;\n }\n \n+/* Have we filled in any part of the time/date yet? */\n+static inline int nodate(struct tm *tm)\n+{\n+\treturn tm->tm_year < 0 &&\n+\t\ttm->tm_mon < 0 &&\n+\t\ttm->tm_mday < 0 &&\n+\t\t!(tm->tm_hour | tm->tm_min | tm->tm_sec);\n+}\n+\n /*\n  * We've seen a digit. Time? Year? Date?\n  */\n@@ -418,7 +432,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n \t * more than 8 digits. This is because we don't want to rule out\n \t * numbers like 20070606 as a YYYYMMDD date.\n \t */\n-\tif (num >= 100000000) {\n+\tif (num >= 100000000 && nodate(tm)) {\n \t\ttime_t time = num;\n \t\tif (gmtime_r(&time, tm)) {\n \t\t\t*tm_gmt = 1;\n"},{"id":"87396","messageId":"7vr68obbpd.fsf@gitster.siamese.dyndns.org","threadId":"15040","inReplyTo":"alpine.LFD.1.10.0808161613520.3324@nehalem.linux-foundation.org","subject":"Re: [BUG] minor: wrong handling of GIT_AUTHOR_DATE","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-08-17T02:46:22Z","receivedAt":"2008-08-17T02:46:22Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@linux-foundation.org> writes:\n\n> Junio, your call. But this one gets the date right for strings that just \n> randomly have some big number in them, ie\n>\n> \t[torvalds@nehalem git]$ ./test-date \"17:25:54 917476713 2008-06-04 -0700\"\n> \t17:25:54 917476713 2008-06-04 -0700 -> 1212625554 -0700 -> Wed Jun  4 17:25:54 2008\n> \t17:25:54 917476713 2008-06-04 -0700 -> Wed Jun  4 17:25:54 2008\n\nBeing able to parse this is a very low priority.\n\nYou've taught people here and on the kernel list that the \"date\" can use\nany non-digit-non-word as a word separator, and \"git log --since 2.days\"\nis something you often do.\n\nPeople who followed that advice would have gotten used to this already, e.g.\n\n   $ git reflog delete master@{07.04.2005.15:15:00.-0700}\n\nshould not be broken.\n\nI think your first hunk needs to distinguish between \"very-long-precision\nposint\" (in which case we ignore because it is likely to be nanoseconds\nfraction) and others.\n"},{"id":"87397","messageId":"7vk5egbaft.fsf@gitster.siamese.dyndns.org","threadId":"15040","inReplyTo":"7vr68obbpd.fsf@gitster.siamese.dyndns.org","subject":"Re: [BUG] minor: wrong handling of GIT_AUTHOR_DATE","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-08-17T03:13:42Z","receivedAt":"2008-08-17T03:13:42Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> You've taught people here and on the kernel list that the \"date\" can use\n> any non-digit-non-word as a word separator, and \"git log --since 2.days\"\n> is something you often do.\n>\n> People who followed that advice would have gotten used to this already, e.g.\n>\n>    $ git reflog delete master@{07.04.2005.15:15:00.-0700}\n>\n> should not be broken.\n>\n> I think your first hunk needs to distinguish between \"very-long-precision\n> posint\" (in which case we ignore because it is likely to be nanoseconds\n> fraction) and others.\n\nPerhaps like this.\n\n-- >8 --\nFrom: Linus Torvalds <torvalds@linux-foundation.org>\nDate: Sat, 16 Aug 2008 16:17:50 -0700\nSubject: [PATCH] date parsing: do not mistake fractional nanosecond that follow HH:MM:SS\n\nSome program output nanosecond fractional after the usual HH:MM:SS format.\nIf the fraction is large enough, it can be interpreted as the seconds\nsince epoch, and can overwrite the already parsed date/time.\n\nWe also make sure we use the seconds since epoch interpretation only when\nwe have not seen any other date/time data in the input yet.\n\nNote that we cannot unconditionally drop anything that follows '.'; people\nhave been taught that we allow '.' as a word separator and have got used\nto formats like \"--since 2.days\" and \"2008.08.16.01:23:45.-0700\" to work.\n\nNoticed-by: Hermann Gausterer\nSigned-off-by: Linus Torvalds <torvalds@linux-foundation.org>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n date.c |   16 +++++++++++++++-\n 1 files changed, 15 insertions(+), 1 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex 35a5257..b2c5a8b 100644\n--- a/date.c\n+++ b/date.c\n@@ -363,6 +363,11 @@ static int match_multi_number(unsigned long num, char c, const char *date, char\n \t\t\ttm->tm_hour = num;\n \t\t\ttm->tm_min = num2;\n \t\t\ttm->tm_sec = num3;\n+\t\t\tif (*end == '.') {\n+\t\t\t\tnum = strspn(end+1, \"0123456789\");\n+\t\t\t\tif (9 <= num)\n+\t\t\t\t\tend += num + 1;\n+\t\t\t}\n \t\t\tbreak;\n \t\t}\n \t\treturn 0;\n@@ -402,6 +407,15 @@ static int match_multi_number(unsigned long num, char c, const char *date, char\n \treturn end - date;\n }\n \n+/* Have we filled in any part of the time/date yet? */\n+static inline int nodate(struct tm *tm)\n+{\n+\treturn tm->tm_year < 0 &&\n+\t\ttm->tm_mon < 0 &&\n+\t\ttm->tm_mday < 0 &&\n+\t\t!(tm->tm_hour | tm->tm_min | tm->tm_sec);\n+}\n+\n /*\n  * We've seen a digit. Time? Year? Date?\n  */\n@@ -418,7 +432,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n \t * more than 8 digits. This is because we don't want to rule out\n \t * numbers like 20070606 as a YYYYMMDD date.\n \t */\n-\tif (num >= 100000000) {\n+\tif (num >= 100000000 && nodate(tm)) {\n \t\ttime_t time = num;\n \t\tif (gmtime_r(&time, tm)) {\n \t\t\t*tm_gmt = 1;\n-- \n1.6.0.rc3.17.gc14c8\n"},{"id":"87399","messageId":"alpine.LFD.1.10.0808162040160.3324@nehalem.linux-foundation.org","threadId":"15040","inReplyTo":"7vr68obbpd.fsf@gitster.siamese.dyndns.org","subject":"Re: [BUG] minor: wrong handling of GIT_AUTHOR_DATE","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-08-17T03:50:45Z","receivedAt":"2008-08-17T03:50:45Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sat, 16 Aug 2008, Junio C Hamano wrote:\n> \n> People who followed that advice would have gotten used to this already, e.g.\n> \n>    $ git reflog delete master@{07.04.2005.15:15:00.-0700}\n> \n> should not be broken.\n\nHmm. Fair enough. In that case, just the \"nodate()\" approach is probably \nfine on its own. HOWEVER:\n\n> I think your first hunk needs to distinguish between \"very-long-precision\n> posint\" (in which case we ignore because it is likely to be nanoseconds\n> fraction) and others.\n\nWell, that ignores nanosecond resolution seconds, but not microseconds, \nfor example. Now, microseconds normally don't matter (because they won't \ntrigger the 'seconds-since-epoch' case), but they _can_ trigger some other \ncases.\n\nFor example, let's assume that we have microseconds in the date specifier. \nThen try this one:\n\n\t./test-date \"12:12:12.000001\"\n\nNotice what happens? Oops.\n\nWith my patch, you get\n\n\t12:12:12.0000001 -> Sat Aug 16 12:12:12 2008\n\nand with your, you get\n\n\t12:12:12.000001 -> Fri Aug  1 12:12:12 2008\n\nand yeah, it's odd, but I can explain it.\n\nBut you are definitely right about the case of doing\n\n\t\"15:15:00.-0700\"\n\nand yes, my patch was crap too. \n\n\t\t\tLinus\n"},{"id":"87403","messageId":"alpine.LFD.1.10.0808162054050.3324@nehalem.linux-foundation.org","threadId":"15040","inReplyTo":"7vk5egbaft.fsf@gitster.siamese.dyndns.org","subject":"Re: [BUG] minor: wrong handling of GIT_AUTHOR_DATE","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-08-17T04:25:40Z","receivedAt":"2008-08-17T04:25:40Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sat, 16 Aug 2008, Junio C Hamano wrote:\n> \n> Perhaps like this.\n\nSo see in the previous email why I don't think \"ignore nanoseconds\" is \nreally any better than \"igore all fractions\".\n\nThat said:\n\n> @@ -363,6 +363,11 @@ static int match_multi_number(unsigned long num, char c, const char *date, char\n>  \t\t\ttm->tm_hour = num;\n>  \t\t\ttm->tm_min = num2;\n>  \t\t\ttm->tm_sec = num3;\n> +\t\t\tif (*end == '.') {\n> +\t\t\t\tnum = strspn(end+1, \"0123456789\");\n> +\t\t\t\tif (9 <= num)\n> +\t\t\t\t\tend += num + 1;\n\nApart from the \"compare with 9\", your patch is _much_ better than mine. \nUsing \"strtoul()\" was a horrible horrible thing to do, since it will match \nnot just '+' and '-' but also spaces etc.\n\nSo my patch was definitely crap, and yours is better, but I don't much \nlike that expectations of 9+ digits. After all, if we only worry about 9+ \ndigits of a big number, then the \"nodate()\" logic already takes care of \nmuch of it.\n\nSo here's a much better version, I think.\n\nThe rules are:\n\n - valid days of month/mday are always single or double digits.\n\n - valid years are either two or four digits\n\n   No, we don't support the year 600 _anyway_, since our encoding is based \n   on the UNIX epoch, and the day we worry about the year 10,000 is far \n   away and we can raise the limit to five digits when we get closer.\n\n - Other numbers (eg \"600 days ago\") can have any number of digits, but \n   they cannot start with a zero. Again, the only exception is for \n   two-digit numbers, since that is fairly common for dates (\"Dec 01\" is \n   not unheard of)\n\nSo that means that any milli- or micro-second would be thrown out just \nbecause the number of digits shows that it cannot be an interesting date.\n\nThat would make the patch look something like this...\n\n[ Those four deleted lines I removed just because the cases had already \n  been handled, eg the \">1900\" case was already handled when we checked \n  for a four-digit year, and the >70 case was handled when we checked for \n  exactly two digits ]\n\nHmm?\n\n\t\tLinus\n\n---\n date.c |   26 ++++++++++++++++++++------\n 1 files changed, 20 insertions(+), 6 deletions(-)\n\ndiff --git a/date.c b/date.c\nindex 35a5257..950b88f 100644\n--- a/date.c\n+++ b/date.c\n@@ -402,6 +402,15 @@ static int match_multi_number(unsigned long num, char c, const char *date, char\n \treturn end - date;\n }\n \n+/* Have we filled in any part of the time/date yet? */\n+static inline int nodate(struct tm *tm)\n+{\n+\treturn tm->tm_year < 0 &&\n+\t\ttm->tm_mon < 0 &&\n+\t\ttm->tm_mday < 0 &&\n+\t\t!(tm->tm_hour | tm->tm_min | tm->tm_sec);\n+}\n+\n /*\n  * We've seen a digit. Time? Year? Date?\n  */\n@@ -418,7 +427,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n \t * more than 8 digits. This is because we don't want to rule out\n \t * numbers like 20070606 as a YYYYMMDD date.\n \t */\n-\tif (num >= 100000000) {\n+\tif (num >= 100000000 && nodate(tm)) {\n \t\ttime_t time = num;\n \t\tif (gmtime_r(&time, tm)) {\n \t\t\t*tm_gmt = 1;\n@@ -463,6 +472,13 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n \t}\n \n \t/*\n+\t * Ignore lots of numerals. We took care of 4-digit years above.\n+\t * Days or months must be one or two digits.\n+\t */\n+\tif (n > 2)\n+\t\treturn n;\n+\n+\t/*\n \t * NOTE! We will give precedence to day-of-month over month or\n \t * year numbers in the 1-12 range. So 05 is always \"mday 5\",\n \t * unless we already have a mday..\n@@ -488,10 +504,6 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n \n \tif (num > 0 && num < 32) {\n \t\ttm->tm_mday = num;\n-\t} else if (num > 1900) {\n-\t\ttm->tm_year = num - 1900;\n-\t} else if (num > 70) {\n-\t\ttm->tm_year = num;\n \t} else if (num > 0 && num < 13) {\n \t\ttm->tm_mon = num-1;\n \t}\n@@ -823,7 +835,9 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num)\n \t\t}\n \t}\n \n-\t*num = number;\n+\t/* Accept zero-padding only for small numbers (\"Dec 02\", never \"Dec 0002\") */\n+\tif (date[0] != '0' || end - date <= 2)\n+\t\t*num = number;\n \treturn end;\n }\n \n"},{"id":"87404","messageId":"alpine.LFD.1.10.0808162128400.3324@nehalem.linux-foundation.org","threadId":"15040","inReplyTo":"alpine.LFD.1.10.0808162054050.3324@nehalem.linux-foundation.org","subject":"Re: [BUG] minor: wrong handling of GIT_AUTHOR_DATE","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-08-17T04:37:05Z","receivedAt":"2008-08-17T04:37:05Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sat, 16 Aug 2008, Linus Torvalds wrote:\n> \n> The rules are:\n> \n>  - valid days of month/mday are always single or double digits.\n> \n>  - valid years are either two or four digits\n> \n>    No, we don't support the year 600 _anyway_, since our encoding is based \n>    on the UNIX epoch, and the day we worry about the year 10,000 is far \n>    away and we can raise the limit to five digits when we get closer.\n> \n>  - Other numbers (eg \"600 days ago\") can have any number of digits, but \n>    they cannot start with a zero. Again, the only exception is for \n>    two-digit numbers, since that is fairly common for dates (\"Dec 01\" is \n>    not unheard of)\n> \n> So that means that any milli- or micro-second would be thrown out just \n> because the number of digits shows that it cannot be an interesting date.\n\nI should explain that nonsensical statement a bit.\n\nA milli- or micro-second can obviously be a perfectly fine number \naccording to the rules above, as long as it doesn't start with a '0'. So \nif we have\n\n\t12:34:56.123\n\nthen that '123' gets parsed as a number, and we remember it. But because \nit's bigger than 31, we'll never use it as such _unless_ there is \nsomething after it to trigger that use.\n\nSo you can say \"12:34:56.123.days.ago\", and because of the \"days\", that \n123 will actually be meaninful now.\n\nBut the problem with \"12.34.56.001\" was that we used to remember the \"001\" \nas a number, and because we could see no other use for it we then assumed \nthat it meant the day of the month.\n\nOf course, we *should* do that only if we have seen a month-name too, but \nwe don't currently track that, so.. Adding that as a further sanity test \nwould be good, but it would require us to have some extra \"flags\" field. \nMaybe we should have a\n\n\t#define SEEN_MONTH\t1\n\t#define SEEN_YEAR\t2\n\t#define SEEN_DAY\t4\n\t#define SEEN_TIME\t8\n\t...\n\n\tstruct extended_tm {\n\t\tunsigned long seen;\n\t\tunsigned long number;\n\t\tstruct tm tm;\n\t}\n\nand pass *that* around instead of passing \"struct tm *\" and \"unsigned long \n*num\" around. That would be good. Then we could do\n\n\tif (tm->number && tm->number < 32 &&\n\t    (tm->seen & SEEN_MONTH) && !(tm->seen & SEEN_DAY))\n\t\ttm->tm.tm_mday = tm->number;\n\nthere instead, which would protect us from other numbers just being seen \nas days instead.\n\nAnybody? I'm not going to bother.\n\n\t\t\tLinus\n"},{"id":"87410","messageId":"7vljyw9pok.fsf@gitster.siamese.dyndns.org","threadId":"15040","inReplyTo":"alpine.LFD.1.10.0808162054050.3324@nehalem.linux-foundation.org","subject":"Re: [BUG] minor: wrong handling of GIT_AUTHOR_DATE","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-08-17T05:27:23Z","receivedAt":"2008-08-17T05:27:23Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@linux-foundation.org> writes:\n\n> [ Those four deleted lines I removed just because the cases had already \n>   been handled, eg the \">1900\" case was already handled when we checked \n>   for a four-digit year, and the >70 case was handled when we checked for \n>   exactly two digits ]\n>\n> Hmm?\n\n> @@ -488,10 +504,6 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt\n>  \n>  \tif (num > 0 && num < 32) {\n>  \t\ttm->tm_mday = num;\n> -\t} else if (num > 1900) {\n> -\t\ttm->tm_year = num - 1900;\n> -\t} else if (num > 70) {\n> -\t\ttm->tm_year = num;\n>  \t} else if (num > 0 && num < 13) {\n>  \t\ttm->tm_mon = num-1;\n>  \t}\n\nThe comment above this part says we always favor mday over mon, but I\nwonder why this sequence is not like:\n\n\tif (tm->tm_mday is not set && num > 0 && num < 32)\n\t\ttm->tm_mday = num;\n\telse if (tm->tm_mon is not set && num > 0 && num < 13)\n\t\ttm->tm_mon = num - 1;\n\nIs this because we do not initialize tm fields to \"unknown\" in the\nbeginning?  I admit I haven't bothered to look at this part of the code\nfor a looong time.\n"},{"id":"87446","messageId":"alpine.LFD.1.10.0808170905540.3324@nehalem.linux-foundation.org","threadId":"15040","inReplyTo":"7vljyw9pok.fsf@gitster.siamese.dyndns.org","subject":"Re: [BUG] minor: wrong handling of GIT_AUTHOR_DATE","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-08-17T16:07:19Z","receivedAt":"2008-08-17T16:07:19Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sat, 16 Aug 2008, Junio C Hamano wrote:\n> \n> Is this because we do not initialize tm fields to \"unknown\" in the\n> beginning?  I admit I haven't bothered to look at this part of the code\n> for a looong time.\n\nIndeed. The _exact_ date handling initializes the date to -1 (and the \ntime to 0), but the approxidate thing defaults to \"now\" and then modifies \nthat. \n\nWhich is why we'd need to have a separate flags field for \"I have \ninitialized this field\".\n\n\t\tLinus\n"}]}