approxidate: handle pending number for "specials"
The approxidate parser has a table of special keywords like
"yesterday", "noon", "pm", etc. Some of these, like "pm", do
the right thing if we've recently seen a number: "3pm" is
what you'd think.
However, most of them do not look at or modify the
pending-number flag at all, which means a number may "jump"
across a significant keyword and be used unexpectedly. For
example, when parsing:
  January 5th noon pm
we'd connect the "5" to "pm", and ignore it as a
day-of-month. This is obviously a bit silly, as "noon"
already implies "pm". And other mis-parsed things are
generally as silly ("January 5th noon, years ago" would
connect the 5 to "years", but probably nobody would type
that).
However, the fix is simple: when we see a keyword like
"noon", we should flush the pending number (as we would if
we hit another number, or the end of the string). In a few
of the specials that actually modify the day, we can simply
throw away the number (saying "Jan 5 yesterday" should not
respect the number at all).
Note that we have to either move or forward-declare the
static pending_number() to make it accessible to these
functions; this patch moves it.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
			
			
				maint
			
			
		
							parent
							
								
									b4cfcde4db
								
							
						
					
					
						commit
						c27cc94fad
					
				
							
								
								
									
										60
									
								
								date.c
								
								
								
								
							
							
						
						
									
										60
									
								
								date.c
								
								
								
								
							|  | @ -887,13 +887,42 @@ static time_t update_tm(struct tm *tm, struct tm *now, time_t sec) | ||||||
| 	return n; | 	return n; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Do we have a pending number at the end, or when | ||||||
|  |  * we see a new one? Let's assume it's a month day, | ||||||
|  |  * as in "Dec 6, 1992" | ||||||
|  |  */ | ||||||
|  | static void pending_number(struct tm *tm, int *num) | ||||||
|  | { | ||||||
|  | 	int number = *num; | ||||||
|  |  | ||||||
|  | 	if (number) { | ||||||
|  | 		*num = 0; | ||||||
|  | 		if (tm->tm_mday < 0 && number < 32) | ||||||
|  | 			tm->tm_mday = number; | ||||||
|  | 		else if (tm->tm_mon < 0 && number < 13) | ||||||
|  | 			tm->tm_mon = number-1; | ||||||
|  | 		else if (tm->tm_year < 0) { | ||||||
|  | 			if (number > 1969 && number < 2100) | ||||||
|  | 				tm->tm_year = number - 1900; | ||||||
|  | 			else if (number > 69 && number < 100) | ||||||
|  | 				tm->tm_year = number; | ||||||
|  | 			else if (number < 38) | ||||||
|  | 				tm->tm_year = 100 + number; | ||||||
|  | 			/* We screw up for number = 00 ? */ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| static void date_now(struct tm *tm, struct tm *now, int *num) | static void date_now(struct tm *tm, struct tm *now, int *num) | ||||||
| { | { | ||||||
|  | 	*num = 0; | ||||||
| 	update_tm(tm, now, 0); | 	update_tm(tm, now, 0); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void date_yesterday(struct tm *tm, struct tm *now, int *num) | static void date_yesterday(struct tm *tm, struct tm *now, int *num) | ||||||
| { | { | ||||||
|  | 	*num = 0; | ||||||
| 	update_tm(tm, now, 24*60*60); | 	update_tm(tm, now, 24*60*60); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -908,16 +937,19 @@ static void date_time(struct tm *tm, struct tm *now, int hour) | ||||||
|  |  | ||||||
| static void date_midnight(struct tm *tm, struct tm *now, int *num) | static void date_midnight(struct tm *tm, struct tm *now, int *num) | ||||||
| { | { | ||||||
|  | 	pending_number(tm, num); | ||||||
| 	date_time(tm, now, 0); | 	date_time(tm, now, 0); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void date_noon(struct tm *tm, struct tm *now, int *num) | static void date_noon(struct tm *tm, struct tm *now, int *num) | ||||||
| { | { | ||||||
|  | 	pending_number(tm, num); | ||||||
| 	date_time(tm, now, 12); | 	date_time(tm, now, 12); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void date_tea(struct tm *tm, struct tm *now, int *num) | static void date_tea(struct tm *tm, struct tm *now, int *num) | ||||||
| { | { | ||||||
|  | 	pending_number(tm, num); | ||||||
| 	date_time(tm, now, 17); | 	date_time(tm, now, 17); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -953,6 +985,7 @@ static void date_never(struct tm *tm, struct tm *now, int *num) | ||||||
| { | { | ||||||
| 	time_t n = 0; | 	time_t n = 0; | ||||||
| 	localtime_r(&n, tm); | 	localtime_r(&n, tm); | ||||||
|  | 	*num = 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static const struct special { | static const struct special { | ||||||
|  | @ -1110,33 +1143,6 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num, | ||||||
| 	return end; | 	return end; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Do we have a pending number at the end, or when |  | ||||||
|  * we see a new one? Let's assume it's a month day, |  | ||||||
|  * as in "Dec 6, 1992" |  | ||||||
|  */ |  | ||||||
| static void pending_number(struct tm *tm, int *num) |  | ||||||
| { |  | ||||||
| 	int number = *num; |  | ||||||
|  |  | ||||||
| 	if (number) { |  | ||||||
| 		*num = 0; |  | ||||||
| 		if (tm->tm_mday < 0 && number < 32) |  | ||||||
| 			tm->tm_mday = number; |  | ||||||
| 		else if (tm->tm_mon < 0 && number < 13) |  | ||||||
| 			tm->tm_mon = number-1; |  | ||||||
| 		else if (tm->tm_year < 0) { |  | ||||||
| 			if (number > 1969 && number < 2100) |  | ||||||
| 				tm->tm_year = number - 1900; |  | ||||||
| 			else if (number > 69 && number < 100) |  | ||||||
| 				tm->tm_year = number; |  | ||||||
| 			else if (number < 38) |  | ||||||
| 				tm->tm_year = 100 + number; |  | ||||||
| 			/* We screw up for number = 00 ? */ |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static timestamp_t approxidate_str(const char *date, | static timestamp_t approxidate_str(const char *date, | ||||||
| 				   const struct timeval *tv, | 				   const struct timeval *tv, | ||||||
| 				   int *error_ret) | 				   int *error_ret) | ||||||
|  |  | ||||||
|  | @ -113,6 +113,7 @@ check_approxidate '3:00' '2009-08-30 03:00:00' | ||||||
| check_approxidate '15:00' '2009-08-30 15:00:00' | check_approxidate '15:00' '2009-08-30 15:00:00' | ||||||
| check_approxidate 'noon today' '2009-08-30 12:00:00' | check_approxidate 'noon today' '2009-08-30 12:00:00' | ||||||
| check_approxidate 'noon yesterday' '2009-08-29 12:00:00' | check_approxidate 'noon yesterday' '2009-08-29 12:00:00' | ||||||
|  | check_approxidate 'January 5th noon pm' '2009-01-05 12:00:00' | ||||||
|  |  | ||||||
| check_approxidate 'last tuesday' '2009-08-25 19:20:00' | check_approxidate 'last tuesday' '2009-08-25 19:20:00' | ||||||
| check_approxidate 'July 5th' '2009-07-05 19:20:00' | check_approxidate 'July 5th' '2009-07-05 19:20:00' | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Jeff King
						Jeff King