@@ -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
729743static 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+
869899unsigned 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