@matheusbsbs / matheus-bagliano / commits / 9029055207
Fork 0

Improve on 'approxidate'

This is not a new failure mode - approxidate has always been kind of random in the input it accepts, but some of the randomness is more irritating than others. For example: Jun 6, 5AM -> Mon Jun 22 05:00:00 2009 5AM Jun 6 -> Sat Jun 6 05:00:00 2009 Whaa? The reason for the above is that approxidate squirrells away the '6' from "Jun 6" to see if it's going to be a relative number, and then forgets about it when it sees a new number (the '5' in '5AM'). So the odd "June 22" date is because today is July 22nd, and if it doesn't have another day of the month, it will just pick todays mday - having ignored the '6' entirely due to getting all excited about seeing a new number (5). There are other oddnesses. This does not fix them all, but I think it makes for fewer _really_ perplexing cases. At least now we have Jun 6, 5AM -> Sat Jun 6 05:00:00 2009 5AM, Jun 6 -> Sat Jun 6 05:00:00 2009 which makes me happier. I can still point to cases that don't work as well, but those are separate issues. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Linus Torvalds committed Aug 22, 2009 at 15:10 UTC 9029055207443c28ca65a705d1a1b96cce3995fd
1 file changed +63 -30
date.c
+63 -30
@@ -525,11 +525,8 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
525 }
526 }
527
528 - if (num > 0 && num < 32) {
529 - tm->tm_mday = num;
530 - } else if (num > 0 && num < 13) {
528 + if (num > 0 && num < 13 && tm->tm_mon < 0)
529 tm->tm_mon = num-1;
532 - }
530
531 return n;
532 }
@@ -657,42 +654,59 @@ void datestamp(char *buf, int bufsize)
654 date_string(now, offset, buf, bufsize);
655 }
656
660 -static void update_tm(struct tm *tm, unsigned long sec)
657 +/*
658 + * Relative time update (eg "2 days ago"). If we haven't set the time
659 + * yet, we need to set it from current time.
660 + */
661 +static unsigned long update_tm(struct tm *tm, struct tm *now, unsigned long sec)
662 {
662 - time_t n = mktime(tm) - sec;
663 + time_t n;
664 +
665 + if (tm->tm_mday < 0)
666 + tm->tm_mday = now->tm_mday;
667 + if (tm->tm_mon < 0)
668 + tm->tm_mon = now->tm_mon;
669 + if (tm->tm_year < 0) {
670 + tm->tm_year = now->tm_year;
671 + if (tm->tm_mon > now->tm_mon)
672 + tm->tm_year--;
673 + }
674 +
675 + n = mktime(tm) - sec;
676 localtime_r(&n, tm);
677 + return n;
678 }
679
666 -static void date_yesterday(struct tm *tm, int *num)
680 +static void date_yesterday(struct tm *tm, struct tm *now, int *num)
681 {
668 - update_tm(tm, 24*60*60);
682 + update_tm(tm, now, 24*60*60);
683 }
684
671 -static void date_time(struct tm *tm, int hour)
685 +static void date_time(struct tm *tm, struct tm *now, int hour)
686 {
687 if (tm->tm_hour < hour)
674 - date_yesterday(tm, NULL);
688 + date_yesterday(tm, now, NULL);
689 tm->tm_hour = hour;
690 tm->tm_min = 0;
691 tm->tm_sec = 0;
692 }
693
680 -static void date_midnight(struct tm *tm, int *num)
694 +static void date_midnight(struct tm *tm, struct tm *now, int *num)
695 {
682 - date_time(tm, 0);
696 + date_time(tm, now, 0);
697 }
698
685 -static void date_noon(struct tm *tm, int *num)
699 +static void date_noon(struct tm *tm, struct tm *now, int *num)
700 {
687 - date_time(tm, 12);
701 + date_time(tm, now, 12);
702 }
703
690 -static void date_tea(struct tm *tm, int *num)
704 +static void date_tea(struct tm *tm, struct tm *now, int *num)
705 {
692 - date_time(tm, 17);
706 + date_time(tm, now, 17);
707 }
708
695 -static void date_pm(struct tm *tm, int *num)
709 +static void date_pm(struct tm *tm, struct tm *now, int *num)
710 {
711 int hour, n = *num;
712 *num = 0;
@@ -706,7 +720,7 @@ static void date_pm(struct tm *tm, int *num)
720 tm->tm_hour = (hour % 12) + 12;
721 }
722
709 -static void date_am(struct tm *tm, int *num)
723 +static void date_am(struct tm *tm, struct tm *now, int *num)
724 {
725 int hour, n = *num;
726 *num = 0;
@@ -720,7 +734,7 @@ static void date_am(struct tm *tm, int *num)
734 tm->tm_hour = (hour % 12);
735 }
736
723 -static void date_never(struct tm *tm, int *num)
737 +static void date_never(struct tm *tm, struct tm *now, int *num)
738 {
739 time_t n = 0;
740 localtime_r(&n, tm);
@@ -728,7 +742,7 @@ static void date_never(struct tm *tm, int *num)
742
743 static const struct special {
744 const char *name;
731 - void (*fn)(struct tm *, int *);
745 + void (*fn)(struct tm *, struct tm *, int *);
746 } special[] = {
747 { "yesterday", date_yesterday },
748 { "noon", date_noon },
@@ -757,7 +771,7 @@ static const struct typelen {
771 { NULL }
772 };
773
760 -static const char *approxidate_alpha(const char *date, struct tm *tm, int *num)
774 +static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm *now, int *num)
775 {
776 const struct typelen *tl;
777 const struct special *s;
@@ -778,7 +792,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, int *num)
792 for (s = special; s->name; s++) {
793 int len = strlen(s->name);
794 if (match_string(date, s->name) == len) {
781 - s->fn(tm, num);
795 + s->fn(tm, now, num);
796 return end;
797 }
798 }
@@ -800,7 +814,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, int *num)
814 while (tl->type) {
815 int len = strlen(tl->type);
816 if (match_string(date, tl->type) >= len-1) {
803 - update_tm(tm, tl->length * *num);
817 + update_tm(tm, now, tl->length * *num);
818 *num = 0;
819 return end;
820 }
@@ -818,7 +832,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, int *num)
832 n++;
833 diff += 7*n;
834
821 - update_tm(tm, diff * 24 * 60 * 60);
835 + update_tm(tm, now, diff * 24 * 60 * 60);
836 return end;
837 }
838 }
@@ -866,6 +880,22 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num)
880 return end;
881 }
882
883 +/*
884 + * Do we have a pending number at the end, or when
885 + * we see a new one? Let's assume it's a month day,
886 + * as in "Dec 6, 1992"
887 + */
888 +static void pending_number(struct tm *tm, int *num)
889 +{
890 + int number = *num;
891 +
892 + if (number) {
893 + *num = 0;
894 + if (tm->tm_mday < 0 && number < 32)
895 + tm->tm_mday = number;
896 + }
897 +}
898 +
899 unsigned long approxidate(const char *date)
900 {
901 int number = 0;
@@ -881,21 +911,24 @@ unsigned long approxidate(const char *date)
911 time_sec = tv.tv_sec;
912 localtime_r(&time_sec, &tm);
913 now = tm;
914 +
915 + tm.tm_year = -1;
916 + tm.tm_mon = -1;
917 + tm.tm_mday = -1;
918 +
919 for (;;) {
920 unsigned char c = *date;
921 if (!c)
922 break;
923 date++;
924 if (isdigit(c)) {
925 + pending_number(&tm, &number);
926 date = approxidate_digit(date-1, &tm, &number);
927 continue;
928 }
929 if (isalpha(c))
894 - date = approxidate_alpha(date-1, &tm, &number);
930 + date = approxidate_alpha(date-1, &tm, &now, &number);
931 }
896 - if (number > 0 && number < 32)
897 - tm.tm_mday = number;
898 - if (tm.tm_mon > now.tm_mon && tm.tm_year == now.tm_year)
899 - tm.tm_year--;
900 - return mktime(&tm);
932 + pending_number(&tm, &number);
933 + return update_tm(&tm, &now, 0);
934 }