Skip to content

Commit 9029055

Browse files
torvaldsgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 32f4cc4 commit 9029055

File tree

1 file changed

+63
-30
lines changed

1 file changed

+63
-30
lines changed

date.c

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -525,11 +525,8 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
525525
}
526526
}
527527

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)
531529
tm->tm_mon = num-1;
532-
}
533530

534531
return n;
535532
}
@@ -657,42 +654,59 @@ void datestamp(char *buf, int bufsize)
657654
date_string(now, offset, buf, bufsize);
658655
}
659656

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)
661662
{
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;
663676
localtime_r(&n, tm);
677+
return n;
664678
}
665679

666-
static void date_yesterday(struct tm *tm, int *num)
680+
static void date_yesterday(struct tm *tm, struct tm *now, int *num)
667681
{
668-
update_tm(tm, 24*60*60);
682+
update_tm(tm, now, 24*60*60);
669683
}
670684

671-
static void date_time(struct tm *tm, int hour)
685+
static void date_time(struct tm *tm, struct tm *now, int hour)
672686
{
673687
if (tm->tm_hour < hour)
674-
date_yesterday(tm, NULL);
688+
date_yesterday(tm, now, NULL);
675689
tm->tm_hour = hour;
676690
tm->tm_min = 0;
677691
tm->tm_sec = 0;
678692
}
679693

680-
static void date_midnight(struct tm *tm, int *num)
694+
static void date_midnight(struct tm *tm, struct tm *now, int *num)
681695
{
682-
date_time(tm, 0);
696+
date_time(tm, now, 0);
683697
}
684698

685-
static void date_noon(struct tm *tm, int *num)
699+
static void date_noon(struct tm *tm, struct tm *now, int *num)
686700
{
687-
date_time(tm, 12);
701+
date_time(tm, now, 12);
688702
}
689703

690-
static void date_tea(struct tm *tm, int *num)
704+
static void date_tea(struct tm *tm, struct tm *now, int *num)
691705
{
692-
date_time(tm, 17);
706+
date_time(tm, now, 17);
693707
}
694708

695-
static void date_pm(struct tm *tm, int *num)
709+
static void date_pm(struct tm *tm, struct tm *now, int *num)
696710
{
697711
int hour, n = *num;
698712
*num = 0;
@@ -706,7 +720,7 @@ static void date_pm(struct tm *tm, int *num)
706720
tm->tm_hour = (hour % 12) + 12;
707721
}
708722

709-
static void date_am(struct tm *tm, int *num)
723+
static void date_am(struct tm *tm, struct tm *now, int *num)
710724
{
711725
int hour, n = *num;
712726
*num = 0;
@@ -720,15 +734,15 @@ static void date_am(struct tm *tm, int *num)
720734
tm->tm_hour = (hour % 12);
721735
}
722736

723-
static void date_never(struct tm *tm, int *num)
737+
static void date_never(struct tm *tm, struct tm *now, int *num)
724738
{
725739
time_t n = 0;
726740
localtime_r(&n, tm);
727741
}
728742

729743
static const struct special {
730744
const char *name;
731-
void (*fn)(struct tm *, int *);
745+
void (*fn)(struct tm *, struct tm *, int *);
732746
} special[] = {
733747
{ "yesterday", date_yesterday },
734748
{ "noon", date_noon },
@@ -757,7 +771,7 @@ static const struct typelen {
757771
{ NULL }
758772
};
759773

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)
761775
{
762776
const struct typelen *tl;
763777
const struct special *s;
@@ -778,7 +792,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, int *num)
778792
for (s = special; s->name; s++) {
779793
int len = strlen(s->name);
780794
if (match_string(date, s->name) == len) {
781-
s->fn(tm, num);
795+
s->fn(tm, now, num);
782796
return end;
783797
}
784798
}
@@ -800,7 +814,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, int *num)
800814
while (tl->type) {
801815
int len = strlen(tl->type);
802816
if (match_string(date, tl->type) >= len-1) {
803-
update_tm(tm, tl->length * *num);
817+
update_tm(tm, now, tl->length * *num);
804818
*num = 0;
805819
return end;
806820
}
@@ -818,7 +832,7 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, int *num)
818832
n++;
819833
diff += 7*n;
820834

821-
update_tm(tm, diff * 24 * 60 * 60);
835+
update_tm(tm, now, diff * 24 * 60 * 60);
822836
return end;
823837
}
824838
}
@@ -866,6 +880,22 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num)
866880
return end;
867881
}
868882

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+
869899
unsigned long approxidate(const char *date)
870900
{
871901
int number = 0;
@@ -881,21 +911,24 @@ unsigned long approxidate(const char *date)
881911
time_sec = tv.tv_sec;
882912
localtime_r(&time_sec, &tm);
883913
now = tm;
914+
915+
tm.tm_year = -1;
916+
tm.tm_mon = -1;
917+
tm.tm_mday = -1;
918+
884919
for (;;) {
885920
unsigned char c = *date;
886921
if (!c)
887922
break;
888923
date++;
889924
if (isdigit(c)) {
925+
pending_number(&tm, &number);
890926
date = approxidate_digit(date-1, &tm, &number);
891927
continue;
892928
}
893929
if (isalpha(c))
894-
date = approxidate_alpha(date-1, &tm, &number);
930+
date = approxidate_alpha(date-1, &tm, &now, &number);
895931
}
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);
901934
}

0 commit comments

Comments
 (0)