git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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

From
Junio C Hamano <junkio@cox.net>
Date
Apr 5, 2006, 22:39 UTC
Message-ID
<7vlkujzly0.fsf_-_@assigned-by-dhcp.cox.net>
In-Reply-To
<7virpo4jxf.fsf@assigned-by-dhcp.cox.net>

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@cox.net>
---
 * 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
Previous: Andrew MortonNext: Sam Ravnborg
Message 5 of 8 in “parse_date(): fix parsing 03/10/2006”
  1. parse_date(): fix parsing 03/10/2006Junio C Hamano, Apr 5, 2006
  2. Andrew MortonApr 5, 2006
  3. Junio C HamanoApr 5, 2006
  4. Andrew MortonApr 5, 2006
  5. date parsing: be friendlier to our European friends.Junio C Hamano, Apr 5, 2006
  6. Sam RavnborgApr 5, 2006
  7. Junio C HamanoApr 5, 2006
  8. David WoodhouseJul 14, 2006

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.