Skip to content

Commit b56be49

Browse files
sgngitster
authored andcommitted
date.c: allow ISO 8601 reduced precision times
ISO 8601 permits "reduced precision" time representations to omit the seconds value or both the minutes and the seconds values. The abbreviate times could look like 17:45 or 1745 to omit the seconds, or simply as 17 to omit both the minutes and the seconds. parse_date_basic accepts the 17:45 format but it rejects the other two. Change it to accept 4-digit and 2-digit time values when they follow a recognized date and a 'T'. Before this change: $ TZ=UTC test-tool date approxidate 2022-12-13T23:00 2022-12-13T2300 2022-12-13T23 2022-12-13T23:00 -> 2022-12-13 23:00:00 +0000 2022-12-13T2300 -> 2022-12-13 23:54:13 +0000 2022-12-13T23 -> 2022-12-13 23:54:13 +0000 After this change: $ TZ=UTC helper/test-tool date approxidate 2022-12-13T23:00 2022-12-13T2300 2022-12-13T23 2022-12-13T23:00 -> 2022-12-13 23:00:00 +0000 2022-12-13T2300 -> 2022-12-13 23:00:00 +0000 2022-12-13T23 -> 2022-12-13 23:00:00 +0000 Note: ISO 8601 also allows reduced precision date strings such as "2022-12" and "2022". This patch does not attempt to address these. Reported-by: Pat LaVarre <[email protected]> Signed-off-by: Phil Hord <[email protected]> Signed-off-by: Đoàn Trần Công Danh <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent a38d39a commit b56be49

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

date.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,12 @@ static int match_alpha(const char *date, struct tm *tm, int *offset)
493493
return 2;
494494
}
495495

496+
/* ISO-8601 allows yyyymmDD'T'HHMMSS, with less precision */
497+
if (*date == 'T' && isdigit(date[1]) && tm->tm_hour == -1) {
498+
tm->tm_min = tm->tm_sec = 0;
499+
return 1;
500+
}
501+
496502
/* BAD CRAP */
497503
return skip_alpha(date);
498504
}
@@ -638,6 +644,18 @@ static inline int nodate(struct tm *tm)
638644
tm->tm_sec) < 0;
639645
}
640646

647+
/*
648+
* Have we seen an ISO-8601-alike date, i.e. 20220101T0,
649+
* In which, hour is still unset,
650+
* and minutes and second has been set to 0.
651+
*/
652+
static inline int maybeiso8601(struct tm *tm)
653+
{
654+
return tm->tm_hour == -1 &&
655+
tm->tm_min == 0 &&
656+
tm->tm_sec == 0;
657+
}
658+
641659
/*
642660
* We've seen a digit. Time? Year? Date?
643661
*/
@@ -701,6 +719,25 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
701719
return end - date;
702720
}
703721

722+
/* reduced precision of ISO-8601's time: HHMM or HH */
723+
if (maybeiso8601(tm)) {
724+
unsigned int num1 = num;
725+
unsigned int num2 = 0;
726+
if (n == 4) {
727+
num1 = num / 100;
728+
num2 = num % 100;
729+
}
730+
if ((n == 4 || n == 2) && !nodate(tm) &&
731+
set_time(num1, num2, 0, tm) == 0)
732+
return n;
733+
/*
734+
* We thought this is an ISO-8601 time string,
735+
* we set minutes and seconds to 0,
736+
* turn out it isn't, rollback the change.
737+
*/
738+
tm->tm_min = tm->tm_sec = -1;
739+
}
740+
704741
/* Four-digit year or a timezone? */
705742
if (n == 4) {
706743
if (num <= 1400 && *offset == -1) {

t/t0006-date.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ check_parse 2008-02-14 bad
8888
check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 +0000'
8989
check_parse '2008-02-14 20:30:45 -0500' '2008-02-14 20:30:45 -0500'
9090
check_parse '2008.02.14 20:30:45 -0500' '2008-02-14 20:30:45 -0500'
91+
check_parse '20080214T20:30:45' '2008-02-14 20:30:45 +0000'
92+
check_parse '20080214T20:30' '2008-02-14 20:30:00 +0000'
93+
check_parse '20080214T20' '2008-02-14 20:00:00 +0000'
94+
check_parse '20080214T203045' '2008-02-14 20:30:45 +0000'
95+
check_parse '20080214T2030' '2008-02-14 20:30:00 +0000'
96+
check_parse '20080214T000000.20' '2008-02-14 00:00:00 +0000'
97+
check_parse '20080214T00:00:00.20' '2008-02-14 00:00:00 +0000'
9198
check_parse '20080214T203045-04:00' '2008-02-14 20:30:45 -0400'
9299
check_parse '20080214T203045 -04:00' '2008-02-14 20:30:45 -0400'
93100
check_parse '20080214T203045.019-04:00' '2008-02-14 20:30:45 -0400'
@@ -99,6 +106,7 @@ check_parse '2008-02-14 20:30:45 -05' '2008-02-14 20:30:45 -0500'
99106
check_parse '2008-02-14 20:30:45 -:30' '2008-02-14 20:30:45 +0000'
100107
check_parse '2008-02-14 20:30:45 -05:00' '2008-02-14 20:30:45 -0500'
101108
check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 -0500' EST5
109+
check_parse 'Thu, 7 Apr 2005 15:14:13 -0700' '2005-04-07 15:14:13 -0700'
102110

103111
check_approxidate() {
104112
echo "$1 -> $2 +0000" >expect

0 commit comments

Comments
 (0)