Skip to content

Commit 9f2700c

Browse files
author
Junio C Hamano
committed
Merge branch 'jc/date'
* jc/date: date parsing: be friendlier to our European friends.
2 parents 028e049 + 38035cf commit 9f2700c

File tree

1 file changed

+56
-21
lines changed

1 file changed

+56
-21
lines changed

date.c

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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

225242
static 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

Comments
 (0)