[RFC/PATCH] date parsing: be friendlier to our European friends.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This does three things, only applies to cases where the user
manually tries to override the author/commit time by environment
variables, with non-ISO, non-2822 format date-string:

 - Refuses to use the interpretation to put the date in the
   future; recent kernel history has a commit made with
   10/03/2006 which is recorded as October 3rd.

 - Adds '.' as the possible year-month-date separator.  We
   learned from our European friends on the #git channel that
   dd.mm.yyyy is the norm there.

 - When the separator is '.', we prefer dd.mm.yyyy over
   mm.dd.yyyy; otherwise mm/dd/yy[yy] takes precedence over
   dd/mm/yy[yy].

Signed-off-by: Junio C Hamano <junkio@xxxxxxx>

---

 * This is more of a RFC than ready-to-be-merged patch.
   Alternative patches and improvements are welcome.

 date.c |   77 +++++++++++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 56 insertions(+), 21 deletions(-)

b9065540826426ac0e4959e869ba7e08d1ae65d8
diff --git a/date.c b/date.c
index 376d25d..034d722 100644
--- a/date.c
+++ b/date.c
@@ -197,26 +197,43 @@ static int match_alpha(const char *date,
 	return skip_alpha(date);
 }
 
-static int is_date(int year, int month, int day, struct tm *tm)
+static int is_date(int year, int month, int day, struct tm *now_tm, time_t now, struct tm *tm)
 {
 	if (month > 0 && month < 13 && day > 0 && day < 32) {
+		struct tm check = *tm;
+		struct tm *r = (now_tm ? &check : tm);
+		time_t specified;
+
+		r->tm_mon = month - 1;
+		r->tm_mday = day;
 		if (year == -1) {
-			tm->tm_mon = month-1;
-			tm->tm_mday = day;
-			return 1;
+			if (!now_tm)
+				return 1;
+			r->tm_year = now_tm->tm_year;
 		}
-		if (year >= 1970 && year < 2100) {
-			year -= 1900;
-		} else if (year > 70 && year < 100) {
-			/* ok */
-		} else if (year < 38) {
-			year += 100;
-		} else
+		else if (year >= 1970 && year < 2100)
+			r->tm_year = year - 1900;
+		else if (year > 70 && year < 100)
+			r->tm_year = year;
+		else if (year < 38)
+			r->tm_year = year + 100;
+		else
 			return 0;
+		if (!now_tm)
+			return 1;
+
+		specified = my_mktime(r);
 
-		tm->tm_mon = month-1;
-		tm->tm_mday = day;
-		tm->tm_year = year;
+		/* Be it commit time or author time, it does not make
+		 * sense to specify timestamp way into the future.  Make
+		 * sure it is not later than ten days from now...
+		 */
+		if (now + 10*24*3600 < specified)
+			return 0;
+		tm->tm_mon = r->tm_mon;
+		tm->tm_mday = r->tm_mday;
+		if (year != -1)
+			tm->tm_year = r->tm_year;
 		return 1;
 	}
 	return 0;
@@ -224,6 +241,9 @@ static int is_date(int year, int month, 
 
 static int match_multi_number(unsigned long num, char c, const char *date, char *end, struct tm *tm)
 {
+	time_t now;
+	struct tm now_tm;
+	struct tm *refuse_future;
 	long num2, num3;
 
 	num2 = strtol(end+1, &end, 10);
@@ -246,19 +266,33 @@ static int match_multi_number(unsigned l
 
 	case '-':
 	case '/':
+	case '.':
+		now = time(NULL);
+		refuse_future = NULL;
+		if (gmtime_r(&now, &now_tm))
+			refuse_future = &now_tm;
+
 		if (num > 70) {
 			/* yyyy-mm-dd? */
-			if (is_date(num, num2, num3, tm))
+			if (is_date(num, num2, num3, refuse_future, now, tm))
 				break;
 			/* yyyy-dd-mm? */
-			if (is_date(num, num3, num2, tm))
+			if (is_date(num, num3, num2, refuse_future, now, tm))
 				break;
 		}
-		/* mm/dd/yy ? */
-		if (is_date(num3, num, num2, tm))
+		/* Our eastern European friends say dd.mm.yy[yy]
+		 * is the norm there, so giving precedence to
+		 * mm/dd/yy[yy] form only when separator is not '.'
+		 */
+		if (c != '.' &&
+		    is_date(num3, num, num2, refuse_future, now, tm))
+			break;
+		/* European dd.mm.yy[yy] or funny US dd/mm/yy[yy] */
+		if (is_date(num3, num2, num, refuse_future, now, tm))
 			break;
-		/* dd/mm/yy ? */
-		if (is_date(num3, num2, num, tm))
+		/* Funny European mm.dd.yy */
+		if (c == '.' &&
+		    is_date(num3, num, num2, refuse_future, now, tm))
 			break;
 		return 0;
 	}
@@ -288,10 +322,11 @@ static int match_digit(const char *date,
 	}
 
 	/*
-	 * Check for special formats: num[:-/]num[same]num
+	 * Check for special formats: num[-.:/]num[same]num
 	 */
 	switch (*end) {
 	case ':':
+	case '.':
 	case '/':
 	case '-':
 		if (isdigit(end[1])) {
-- 
1.3.0.rc2.g1b83


-
: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]