@@ -497,7 +497,7 @@ static int match_alpha(const char *date, struct tm *tm, int *offset)
497497 return skip_alpha (date );
498498}
499499
500- static int is_date (int year , int month , int day , struct tm * now_tm , time_t now , struct tm * tm )
500+ static int set_date (int year , int month , int day , struct tm * now_tm , time_t now , struct tm * tm )
501501{
502502 if (month > 0 && month < 13 && day > 0 && day < 32 ) {
503503 struct tm check = * tm ;
@@ -518,9 +518,9 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,
518518 else if (year < 38 )
519519 r -> tm_year = year + 100 ;
520520 else
521- return 0 ;
521+ return -1 ;
522522 if (!now_tm )
523- return 1 ;
523+ return 0 ;
524524
525525 specified = tm_to_time_t (r );
526526
@@ -529,14 +529,33 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,
529529 * sure it is not later than ten days from now...
530530 */
531531 if ((specified != -1 ) && (now + 10 * 24 * 3600 < specified ))
532- return 0 ;
532+ return -1 ;
533533 tm -> tm_mon = r -> tm_mon ;
534534 tm -> tm_mday = r -> tm_mday ;
535535 if (year != -1 )
536536 tm -> tm_year = r -> tm_year ;
537- return 1 ;
537+ return 0 ;
538538 }
539- return 0 ;
539+ return -1 ;
540+ }
541+
542+ static int set_time (long hour , long minute , long second , struct tm * tm )
543+ {
544+ /* We accept 61st second because of leap second */
545+ if (0 <= hour && hour <= 24 &&
546+ 0 <= minute && minute < 60 &&
547+ 0 <= second && second <= 60 ) {
548+ tm -> tm_hour = hour ;
549+ tm -> tm_min = minute ;
550+ tm -> tm_sec = second ;
551+ return 0 ;
552+ }
553+ return -1 ;
554+ }
555+
556+ static int is_date_known (struct tm * tm )
557+ {
558+ return tm -> tm_year != -1 && tm -> tm_mon != -1 && tm -> tm_mday != -1 ;
540559}
541560
542561static int match_multi_number (timestamp_t num , char c , const char * date ,
@@ -556,10 +575,14 @@ static int match_multi_number(timestamp_t num, char c, const char *date,
556575 case ':' :
557576 if (num3 < 0 )
558577 num3 = 0 ;
559- if (num < 25 && num2 >= 0 && num2 < 60 && num3 >= 0 && num3 <= 60 ) {
560- tm -> tm_hour = num ;
561- tm -> tm_min = num2 ;
562- tm -> tm_sec = num3 ;
578+ if (set_time (num , num2 , num3 , tm ) == 0 ) {
579+ /*
580+ * If %H:%M:%S was just parsed followed by: .<num4>
581+ * Consider (& discard) it as fractional second
582+ * if %Y%m%d is parsed before.
583+ */
584+ if (* end == '.' && isdigit (end [1 ]) && is_date_known (tm ))
585+ strtol (end + 1 , & end , 10 );
563586 break ;
564587 }
565588 return 0 ;
@@ -575,25 +598,25 @@ static int match_multi_number(timestamp_t num, char c, const char *date,
575598
576599 if (num > 70 ) {
577600 /* yyyy-mm-dd? */
578- if (is_date (num , num2 , num3 , NULL , now , tm ))
601+ if (set_date (num , num2 , num3 , NULL , now , tm ) == 0 )
579602 break ;
580603 /* yyyy-dd-mm? */
581- if (is_date (num , num3 , num2 , NULL , now , tm ))
604+ if (set_date (num , num3 , num2 , NULL , now , tm ) == 0 )
582605 break ;
583606 }
584607 /* Our eastern European friends say dd.mm.yy[yy]
585608 * is the norm there, so giving precedence to
586609 * mm/dd/yy[yy] form only when separator is not '.'
587610 */
588611 if (c != '.' &&
589- is_date (num3 , num , num2 , refuse_future , now , tm ))
612+ set_date (num3 , num , num2 , refuse_future , now , tm ) == 0 )
590613 break ;
591614 /* European dd.mm.yy[yy] or funny US dd/mm/yy[yy] */
592- if (is_date (num3 , num2 , num , refuse_future , now , tm ))
615+ if (set_date (num3 , num2 , num , refuse_future , now , tm ) == 0 )
593616 break ;
594617 /* Funny European mm.dd.yy */
595618 if (c == '.' &&
596- is_date (num3 , num , num2 , refuse_future , now , tm ))
619+ set_date (num3 , num , num2 , refuse_future , now , tm ) == 0 )
597620 break ;
598621 return 0 ;
599622 }
@@ -664,6 +687,20 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
664687 n ++ ;
665688 } while (isdigit (date [n ]));
666689
690+ /* 8 digits, compact style of ISO-8601's date: YYYYmmDD */
691+ /* 6 digits, compact style of ISO-8601's time: HHMMSS */
692+ if (n == 8 || n == 6 ) {
693+ unsigned int num1 = num / 10000 ;
694+ unsigned int num2 = (num % 10000 ) / 100 ;
695+ unsigned int num3 = num % 100 ;
696+ if (n == 8 )
697+ set_date (num1 , num2 , num3 , NULL , time (NULL ), tm );
698+ else if (n == 6 && set_time (num1 , num2 , num3 , tm ) == 0 &&
699+ * end == '.' && isdigit (end [1 ]))
700+ strtoul (end + 1 , & end , 10 );
701+ return end - date ;
702+ }
703+
667704 /* Four-digit year or a timezone? */
668705 if (n == 4 ) {
669706 if (num <= 1400 && * offset == -1 ) {
0 commit comments