@@ -497,7 +497,7 @@ static int match_alpha(const char *date, struct tm *tm, int *offset)
497
497
return skip_alpha (date );
498
498
}
499
499
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 )
501
501
{
502
502
if (month > 0 && month < 13 && day > 0 && day < 32 ) {
503
503
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,
518
518
else if (year < 38 )
519
519
r -> tm_year = year + 100 ;
520
520
else
521
- return 0 ;
521
+ return -1 ;
522
522
if (!now_tm )
523
- return 1 ;
523
+ return 0 ;
524
524
525
525
specified = tm_to_time_t (r );
526
526
@@ -529,14 +529,33 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,
529
529
* sure it is not later than ten days from now...
530
530
*/
531
531
if ((specified != -1 ) && (now + 10 * 24 * 3600 < specified ))
532
- return 0 ;
532
+ return -1 ;
533
533
tm -> tm_mon = r -> tm_mon ;
534
534
tm -> tm_mday = r -> tm_mday ;
535
535
if (year != -1 )
536
536
tm -> tm_year = r -> tm_year ;
537
- return 1 ;
537
+ return 0 ;
538
538
}
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 ;
540
559
}
541
560
542
561
static 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,
556
575
case ':' :
557
576
if (num3 < 0 )
558
577
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 );
563
586
break ;
564
587
}
565
588
return 0 ;
@@ -575,25 +598,25 @@ static int match_multi_number(timestamp_t num, char c, const char *date,
575
598
576
599
if (num > 70 ) {
577
600
/* yyyy-mm-dd? */
578
- if (is_date (num , num2 , num3 , NULL , now , tm ))
601
+ if (set_date (num , num2 , num3 , NULL , now , tm ) == 0 )
579
602
break ;
580
603
/* yyyy-dd-mm? */
581
- if (is_date (num , num3 , num2 , NULL , now , tm ))
604
+ if (set_date (num , num3 , num2 , NULL , now , tm ) == 0 )
582
605
break ;
583
606
}
584
607
/* Our eastern European friends say dd.mm.yy[yy]
585
608
* is the norm there, so giving precedence to
586
609
* mm/dd/yy[yy] form only when separator is not '.'
587
610
*/
588
611
if (c != '.' &&
589
- is_date (num3 , num , num2 , refuse_future , now , tm ))
612
+ set_date (num3 , num , num2 , refuse_future , now , tm ) == 0 )
590
613
break ;
591
614
/* 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 )
593
616
break ;
594
617
/* Funny European mm.dd.yy */
595
618
if (c == '.' &&
596
- is_date (num3 , num , num2 , refuse_future , now , tm ))
619
+ set_date (num3 , num , num2 , refuse_future , now , tm ) == 0 )
597
620
break ;
598
621
return 0 ;
599
622
}
@@ -664,6 +687,20 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
664
687
n ++ ;
665
688
} while (isdigit (date [n ]));
666
689
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
+
667
704
/* Four-digit year or a timezone? */
668
705
if (n == 4 ) {
669
706
if (num <= 1400 && * offset == -1 ) {
0 commit comments