@@ -197,33 +197,53 @@ static int match_alpha(const char *date, struct tm *tm, int *offset)
197197 return skip_alpha (date );
198198}
199199
200- static int is_date (int year , int month , int day , struct tm * tm )
200+ static int is_date (int year , int month , int day , struct tm * now_tm , time_t now , struct tm * tm )
201201{
202202 if (month > 0 && month < 13 && day > 0 && day < 32 ) {
203+ struct tm check = * tm ;
204+ struct tm * r = (now_tm ? & check : tm );
205+ time_t specified ;
206+
207+ r -> tm_mon = month - 1 ;
208+ r -> tm_mday = day ;
203209 if (year == -1 ) {
204- tm -> tm_mon = month - 1 ;
205- tm -> tm_mday = day ;
206- return 1 ;
210+ if (! now_tm )
211+ return 1 ;
212+ r -> tm_year = now_tm -> tm_year ;
207213 }
208- if (year >= 1970 && year < 2100 ) {
209- year -= 1900 ;
210- } else if (year > 70 && year < 100 ) {
211- /* ok */
212- } else if (year < 38 ) {
213- year += 100 ;
214- } else
214+ else if (year >= 1970 && year < 2100 )
215+ r -> tm_year = year - 1900 ;
216+ else if (year > 70 && year < 100 )
217+ r -> tm_year = year ;
218+ else if (year < 38 )
219+ r -> tm_year = year + 100 ;
220+ else
215221 return 0 ;
222+ if (!now_tm )
223+ return 1 ;
224+
225+ specified = my_mktime (r );
216226
217- tm -> tm_mon = month - 1 ;
218- tm -> tm_mday = day ;
219- tm -> tm_year = year ;
227+ /* Be it commit time or author time, it does not make
228+ * sense to specify timestamp way into the future. Make
229+ * sure it is not later than ten days from now...
230+ */
231+ if (now + 10 * 24 * 3600 < specified )
232+ return 0 ;
233+ tm -> tm_mon = r -> tm_mon ;
234+ tm -> tm_mday = r -> tm_mday ;
235+ if (year != -1 )
236+ tm -> tm_year = r -> tm_year ;
220237 return 1 ;
221238 }
222239 return 0 ;
223240}
224241
225242static int match_multi_number (unsigned long num , char c , const char * date , char * end , struct tm * tm )
226243{
244+ time_t now ;
245+ struct tm now_tm ;
246+ struct tm * refuse_future ;
227247 long num2 , num3 ;
228248
229249 num2 = strtol (end + 1 , & end , 10 );
@@ -246,19 +266,33 @@ static int match_multi_number(unsigned long num, char c, const char *date, char
246266
247267 case '-' :
248268 case '/' :
269+ case '.' :
270+ now = time (NULL );
271+ refuse_future = NULL ;
272+ if (gmtime_r (& now , & now_tm ))
273+ refuse_future = & now_tm ;
274+
249275 if (num > 70 ) {
250276 /* yyyy-mm-dd? */
251- if (is_date (num , num2 , num3 , tm ))
277+ if (is_date (num , num2 , num3 , refuse_future , now , tm ))
252278 break ;
253279 /* yyyy-dd-mm? */
254- if (is_date (num , num3 , num2 , tm ))
280+ if (is_date (num , num3 , num2 , refuse_future , now , tm ))
255281 break ;
256282 }
257- /* mm/dd/yy ? */
258- if (is_date (num3 , num , num2 , tm ))
283+ /* Our eastern European friends say dd.mm.yy[yy]
284+ * is the norm there, so giving precedence to
285+ * mm/dd/yy[yy] form only when separator is not '.'
286+ */
287+ if (c != '.' &&
288+ is_date (num3 , num , num2 , refuse_future , now , tm ))
289+ break ;
290+ /* European dd.mm.yy[yy] or funny US dd/mm/yy[yy] */
291+ if (is_date (num3 , num2 , num , refuse_future , now , tm ))
259292 break ;
260- /* dd/mm/yy ? */
261- if (is_date (num3 , num2 , num , tm ))
293+ /* Funny European mm.dd.yy */
294+ if (c == '.' &&
295+ is_date (num3 , num , num2 , refuse_future , now , tm ))
262296 break ;
263297 return 0 ;
264298 }
@@ -288,10 +322,11 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
288322 }
289323
290324 /*
291- * Check for special formats: num[:- /]num[same]num
325+ * Check for special formats: num[-.: /]num[same]num
292326 */
293327 switch (* end ) {
294328 case ':' :
329+ case '.' :
295330 case '/' :
296331 case '-' :
297332 if (isdigit (end [1 ])) {
0 commit comments