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>

Jeff King committed Nov 2, 2018 at 01:23 UTC c27cc94fad36ba46fea4a031d6df9d45b931f421
2 files changed +34 -27
date.c
+33 -27
@@ -887,13 +887,42 @@ static time_t update_tm(struct tm *tm, struct tm *now, time_t sec)
887 return n;
888 }
889
890 +/*
891 + * Do we have a pending number at the end, or when
892 + * we see a new one? Let's assume it's a month day,
893 + * as in "Dec 6, 1992"
894 + */
895 +static void pending_number(struct tm *tm, int *num)
896 +{
897 + int number = *num;
898 +
899 + if (number) {
900 + *num = 0;
901 + if (tm->tm_mday < 0 && number < 32)
902 + tm->tm_mday = number;
903 + else if (tm->tm_mon < 0 && number < 13)
904 + tm->tm_mon = number-1;
905 + else if (tm->tm_year < 0) {
906 + if (number > 1969 && number < 2100)
907 + tm->tm_year = number - 1900;
908 + else if (number > 69 && number < 100)
909 + tm->tm_year = number;
910 + else if (number < 38)
911 + tm->tm_year = 100 + number;
912 + /* We screw up for number = 00 ? */
913 + }
914 + }
915 +}
916 +
917 static void date_now(struct tm *tm, struct tm *now, int *num)
918 {
919 + *num = 0;
920 update_tm(tm, now, 0);
921 }
922
923 static void date_yesterday(struct tm *tm, struct tm *now, int *num)
924 {
925 + *num = 0;
926 update_tm(tm, now, 24*60*60);
927 }
928
@@ -908,16 +937,19 @@ static void date_time(struct tm *tm, struct tm *now, int hour)
937
938 static void date_midnight(struct tm *tm, struct tm *now, int *num)
939 {
940 + pending_number(tm, num);
941 date_time(tm, now, 0);
942 }
943
944 static void date_noon(struct tm *tm, struct tm *now, int *num)
945 {
946 + pending_number(tm, num);
947 date_time(tm, now, 12);
948 }
949
950 static void date_tea(struct tm *tm, struct tm *now, int *num)
951 {
952 + pending_number(tm, num);
953 date_time(tm, now, 17);
954 }
955
@@ -953,6 +985,7 @@ static void date_never(struct tm *tm, struct tm *now, int *num)
985 {
986 time_t n = 0;
987 localtime_r(&n, tm);
988 + *num = 0;
989 }
990
991 static const struct special {
@@ -1110,33 +1143,6 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,
1143 return end;
1144 }
1145
1113 -/*
1114 - * Do we have a pending number at the end, or when
1115 - * we see a new one? Let's assume it's a month day,
1116 - * as in "Dec 6, 1992"
1117 - */
1118 -static void pending_number(struct tm *tm, int *num)
1119 -{
1120 - int number = *num;
1121 -
1122 - if (number) {
1123 - *num = 0;
1124 - if (tm->tm_mday < 0 && number < 32)
1125 - tm->tm_mday = number;
1126 - else if (tm->tm_mon < 0 && number < 13)
1127 - tm->tm_mon = number-1;
1128 - else if (tm->tm_year < 0) {
1129 - if (number > 1969 && number < 2100)
1130 - tm->tm_year = number - 1900;
1131 - else if (number > 69 && number < 100)
1132 - tm->tm_year = number;
1133 - else if (number < 38)
1134 - tm->tm_year = 100 + number;
1135 - /* We screw up for number = 00 ? */
1136 - }
1137 - }
1138 -}
1139 -
1146 static timestamp_t approxidate_str(const char *date,
1147 const struct timeval *tv,
1148 int *error_ret)
t/t0006-date.sh
+1
@@ -113,6 +113,7 @@ check_approxidate '3:00' '2009-08-30 03:00:00'
113 check_approxidate '15:00' '2009-08-30 15:00:00'
114 check_approxidate 'noon today' '2009-08-30 12:00:00'
115 check_approxidate 'noon yesterday' '2009-08-29 12:00:00'
116 +check_approxidate 'January 5th noon pm' '2009-01-05 12:00:00'
117
118 check_approxidate 'last tuesday' '2009-08-25 19:20:00'
119 check_approxidate 'July 5th' '2009-07-05 19:20:00'