Skip to content

Commit e9854a7

Browse files
torvaldsgitster
authored andcommitted
date/time: do not get confused by fractional seconds
The date/time parsing code was confused if the input time HH:MM:SS is followed by fractional seconds. Since we do not record anything finer grained than seconds, we could just drop fractional part, but there is a twist. We have taught people that not just spaces but dot can be used as word separators when spelling things like: $ git log --since 2.days $ git show @{12:34:56.7.days.ago} and we shouldn't mistake "7" in the latter example as a fraction and discard it. The rules are: - valid days of month/mday are always single or double digits. - valid years are either two or four digits No, we don't support the year 600 _anyway_, since our encoding is based on the UNIX epoch, and the day we worry about the year 10,000 is far away and we can raise the limit to five digits when we get closer. - Other numbers (eg "600 days ago") can have any number of digits, but they cannot start with a zero. Again, the only exception is for two-digit numbers, since that is fairly common for dates ("Dec 01" is not unheard of) So that means that any milli- or micro-second would be thrown out just because the number of digits shows that it cannot be an interesting date. A milli- or micro-second can obviously be a perfectly fine number according to the rules above, as long as it doesn't start with a '0'. So if we have 12:34:56.123 then that '123' gets parsed as a number, and we remember it. But because it's bigger than 31, we'll never use it as such _unless_ there is something after it to trigger that use. So you can say "12:34:56.123.days.ago", and because of the "days", that 123 will actually be meaninful now. Signed-off-by: Linus Torvalds <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c14639f commit e9854a7

File tree

1 file changed

+20
-6
lines changed

1 file changed

+20
-6
lines changed

date.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,15 @@ static int match_multi_number(unsigned long num, char c, const char *date, char
402402
return end - date;
403403
}
404404

405+
/* Have we filled in any part of the time/date yet? */
406+
static inline int nodate(struct tm *tm)
407+
{
408+
return tm->tm_year < 0 &&
409+
tm->tm_mon < 0 &&
410+
tm->tm_mday < 0 &&
411+
!(tm->tm_hour | tm->tm_min | tm->tm_sec);
412+
}
413+
405414
/*
406415
* We've seen a digit. Time? Year? Date?
407416
*/
@@ -418,7 +427,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
418427
* more than 8 digits. This is because we don't want to rule out
419428
* numbers like 20070606 as a YYYYMMDD date.
420429
*/
421-
if (num >= 100000000) {
430+
if (num >= 100000000 && nodate(tm)) {
422431
time_t time = num;
423432
if (gmtime_r(&time, tm)) {
424433
*tm_gmt = 1;
@@ -462,6 +471,13 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
462471
return n;
463472
}
464473

474+
/*
475+
* Ignore lots of numerals. We took care of 4-digit years above.
476+
* Days or months must be one or two digits.
477+
*/
478+
if (n > 2)
479+
return n;
480+
465481
/*
466482
* NOTE! We will give precedence to day-of-month over month or
467483
* year numbers in the 1-12 range. So 05 is always "mday 5",
@@ -488,10 +504,6 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
488504

489505
if (num > 0 && num < 32) {
490506
tm->tm_mday = num;
491-
} else if (num > 1900) {
492-
tm->tm_year = num - 1900;
493-
} else if (num > 70) {
494-
tm->tm_year = num;
495507
} else if (num > 0 && num < 13) {
496508
tm->tm_mon = num-1;
497509
}
@@ -823,7 +835,9 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num)
823835
}
824836
}
825837

826-
*num = number;
838+
/* Accept zero-padding only for small numbers ("Dec 02", never "Dec 0002") */
839+
if (date[0] != '0' || end - date <= 2)
840+
*num = number;
827841
return end;
828842
}
829843

0 commit comments

Comments
 (0)