Skip to content

Commit f447b17

Browse files
authored
Merge pull request #54 from zanerock/work-liquid-labs/regex-repo/53
Drop the 'day' and 'time' only ISO 8601 and RFC 2822 regex and replace with usDateRE, intlDateRE, and timeOfDayRE
2 parents ac82cb6 + 8b0cac6 commit f447b17

File tree

6 files changed

+230
-84
lines changed

6 files changed

+230
-84
lines changed

src/date-times.mjs

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,45 +18,50 @@ import { lockdownRE } from './lib/lockdown-re'
1818
// Started RE based on https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/
1919
// Made some corrections, rearranged capture groups.
2020

21-
export const iso8601DayOnlyREString = '([+-]?\\d{4})(?:(-?)(?:(0[1-9]|1[0-2])(?:\\2([12]\\d|0[1-9]|3[01])?)?|W([0-4]\\d|5[0-3])\\2([1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3(?:[0-5]\\d|6[1-6])))?)?'
22-
// Date/Times: Matches as [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) consisting of dates only, like '2024-01-01'. Provides matching groups 1 (year), 3 (month), and 4 (day of month), 5 (week date), 6 (day of week date), and 7 (ordinal or Julian date). (Group 2 is an internal backreference.)
23-
export const iso8601DayOnlyRE = lockdownRE(iso8601DayOnlyREString)
21+
const iso8601DayOnlyREString = '([+-]?\\d{4})(?:(-?)(?:(0[1-9]|1[0-2])(?:\\2([12]\\d|0[1-9]|3[01])?)?|W([0-4]\\d|5[0-3])\\2([1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3(?:[0-5]\\d|6[1-6])))?)?'
2422

2523
const eod = '(24(?<endSep>:?)00\\k<endSep>00)'
26-
const frac = '([.,]\\d+)'
24+
const frac = '(?:[.,](\\d+))'
2725
const hr = `(?:([01]\\d|2[0-3])${frac}?)`
2826
const min = `(?:([0-5]\\d)${frac}?)`
2927
const sec = `(?:([0-5]\\d|60)${frac}?)`
3028
const tz = '([zZ]|(?:[+-](?!00(?::?00)?)(?:[01]\\d|2[0-3])(?::?[0-5]\\d)?))'
3129

32-
export const iso8601TimeOnlyREString = `(?:${eod}|${hr}(?:(?<timeSep>:?)${min}(?:\\k<timeSep>${sec})?)?)${tz}?`
33-
// Date/Time: Matches an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) style time designation, like '12:12Z'. Provides matching 1 (special instant end of day time), 3 (hour), 4 (decimal fraction of hour), 6 (minute), 7 (decimal fraction of minute), 8 (seconds), 9 (decimal fraction of a second), and 10 (timezone designation). (Groups 2 and 5 are internal back references.)
34-
export const iso8601TimeOnlyRE = lockdownRE(iso8601TimeOnlyREString)
30+
const iso8601TimeOnlyREString = `(?:${eod}|${hr}(?:(?<timeSep>:?)${min}(?:\\k<timeSep>${sec})?)?)${tz}?`
3531

3632
export const iso8601DateREString = `${iso8601DayOnlyREString}(?:T${iso8601TimeOnlyREString})?`
37-
// Date/Time: Matches an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date time like '20240101T1212Z. Provides matching groups 1 (year), 3 (month), and 4 (day of month), 5 (week date), 6 (day of week date), and 7 (ordinal or Julian date), 8 (special instant end of day time), 10 (hour), 12 (decimal fraction of hour), 14 (minute), 15(decimal fraction of minute), 16 (seconds), 17 (decimal fraction of a second), and 18 (timezone designation). (Groups 2, 11, and 13 are internal back references.)
33+
// Date/Time: Matches an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date time like '20240101T1212Z. Provides matching groups 1 (year), 3 (month), and 4 (day of month), 5 (week date), 6 (day of week date), and 7 (ordinal or Julian date), 8 (special instant end of day time), 10 (hour), 11 (decimal fraction of hour), 13 (minute), 14 (decimal fraction of minute), 15 (seconds), 16 (decimal fraction of a second), and 17 (timezone designation). (Groups 2, 11, and 13 are internal back references.)
3834
export const iso8601DateRE = lockdownRE(iso8601DateREString)
3935

4036
export const iso8601DateTimeREString = `${iso8601DayOnlyREString}T${iso8601TimeOnlyREString}`
41-
// Date/Time: Matches an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) _requiring_ both date and time components.
37+
// Date/Time: Matches an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) _requiring_ both date and time components. See [`iso8601DateRE`](#iso8601datere) for matching groups.
4238
export const iso8601DateTimeRE = lockdownRE(iso8601DateTimeREString)
4339

44-
export const iso8601LooseDateREString = `${iso8601DayOnlyREString}(?:[T\\s]${iso8601TimeOnlyREString})?`
45-
// Date/Time: Matches an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)-like date time allowing for a space to separate the date and time components instead of requiring a 'T' as the ISO 8601 spec requires, like '20240101 1212Z'. See [`iso8601DateRE`](#iso8601datere) for capture groups.`
46-
export const iso8601LooseDateRE = lockdownRE(iso8601LooseDateREString)
47-
48-
export const iso8601LooseDateTimeREString = `${iso8601DayOnlyREString}[T\\s]${iso8601TimeOnlyREString}`
49-
// Date/Time: Matches an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)-lke date time allowing for a space to separate the date and time instead of requiring a 'T' and _requiring_ both date and time components, like '20240101 1212Z'. See [`iso8601DateRE`](#iso8601datere) for capture groups.
50-
export const iso8601LooseDateTimeRE = lockdownRE(iso8601LooseDateTimeREString)
51-
52-
export const rfc2822DayOnlyREString = '(?:(Sun|Mon|Tue|Wed|Thu|Fri|Sat),\\s+)?(0[1-9]|[1-2]?[0-9]|3[01])\\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\\s+(\\d{2,4})'
53-
// Date/Tmie: Matches an [RFC 2822](https://datatracker.ietf.org/doc/html/rfc2822#section-3.3) style date like 'Mon, 6 Jan 1992'. Provides matching groups 1 (day of week), 2 (day of month), 3 (month), and 4 (year).
54-
export const rfc2822DayOnlyRE = lockdownRE(rfc2822DayOnlyREString)
55-
56-
export const rfc2822TimeOnlyREString = '(2[0-3]|[0-1][0-9]):([0-5][0-9])(?::(60|[0-5][0-9]))?(?:\\s+([+-][0-9]{2}[0-5][0-9]|(?:UT|GMT|[A-Z]{3,5}|[A-IK-Z])))?'
57-
export const rfc2822TimeOnlyRE = lockdownRE(rfc2822TimeOnlyREString)
58-
// Date/Time: Matches an [RFC 2822](https://datatracker.ietf.org/doc/html/rfc2822#section-3.3) style time designation like '12:12 UTC'. Provides matching groups 1 (hour), 2 (min), 3 (second), and 4 (time zone).
40+
const rfc2822DayOnlyREString = '(?:(Sun|Mon|Tue|Wed|Thu|Fri|Sat),\\s+)?(0[1-9]|[1-2]?[0-9]|3[01])\\s+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\\s+(\\d{2,4})'
41+
const rfc2822TimeOnlyREString = '(2[0-3]|[0-1][0-9]):([0-5][0-9])(?::(60|[0-5][0-9]))?(?:\\s+([+-][0-9]{2}[0-5][0-9]|(?:UT|GMT|[A-Z]{3,5}|[A-IK-Z])))?'
5942

6043
export const rfc2822DateREString = `${rfc2822DayOnlyREString}\\s+${rfc2822TimeOnlyREString}`
6144
// Date/Tmie: Matches an [RFC 2822](https://datatracker.ietf.org/doc/html/rfc2822#section-3.3) style date like 'Mon, 6 Jan 1992 12:12 UTC'. Provides matching groups 1 (day of week), 2 (day of month), 3 (month), and 4 (year), 5 (hour), 6 (min), 7 (second), and 8 (time zone).
6245
export const rfc2822DateRE = lockdownRE(rfc2822DateREString)
46+
47+
const seps = '[./-]'
48+
49+
export const usDateREString = `(0?[1-9]|1[0-2])${seps}(0?[1-9]|[1-2][0-9]|3[0-1])${seps}([+-])?(\\d{1,})`
50+
// Date/Time: Matches a US style 'MM/DD/YYYY' string. Accepts separators '.', '/', '-'. Will except 1 or 2 digits for month and day and 1-4 digits for the year. Also accepts a + or - before the year. Provides capture groups 1 (month), 2 (day of month), 3 (BCE/CE indicator), and 4 (year).
51+
export const usDateRE = lockdownRE(usDateREString)
52+
53+
export const intlDateREString = `([+-])?(\\d{1,})${seps}(0?[1-9]|1[0-2])${seps}(0?[1-9]|[1-2][0-9]|3[0-1])`
54+
// Date/Time: Matches an international style 'YYYY/MM/DD' string. Accepts separators '.', '/', '-'. Will except 1 or 2 digits for month and day and 1-4 digits for the year. Also accepts a + or - before the year. Provides capture groups 1 (BCE/CE indicator), 2 (year), 3 (month), 4 (day).
55+
export const intlDateRE = lockdownRE(intlDateREString)
56+
57+
export const militaryTimeREString = '(?:(2400)|([0-1][0-9]|2[0-3])([0-5]\\d))'
58+
// Date/Time: Matches military time style 'HHMM' string. Provides capture groups 1 (special 2400 time), 2 (hour), and 3 (minutes).
59+
export const militaryTimeRE = lockdownRE(militaryTimeREString)
60+
61+
export const timeREString = '(?:(0?[1-9]|1[0-2]):([0-5][0-9])(?::([0-5][0-9])(?:[.,](\\d+))?)?\\s*([aApP][mM]))'
62+
// Date/Time: Matches a twelve hour time designation, requires AM or PM designation. Allows optional leading 0 in hour. Provides matching groups 1 (hour), 2 (minutes), 3 (seconds, without decimal fractions), 4 (decimal fraction seconds), and 5 (AM/PM indicator).
63+
export const timeRE = lockdownRE(timeREString)
64+
65+
export const twentyFourHourTimeREString = '(?:(24:00(?::00)?)|(0?[1-9]|1[0-9]|2[0-3]):([0-5][0-9])(?::([0-5][0-9])(?:[.,](\\d+))?)?)'
66+
// Date/Time: Matches a twenty-four hour time designationAllows optional leading 0 in hour. Provides matching groups 1 (special 24:00 designation with optional seconds), 2 (hour), 3 (minutes), 4 (seconds, without decimal fractions), 5 (decimal fraction seconds).
67+
export const twentyFourHourTimeRE = lockdownRE(twentyFourHourTimeREString)

src/test/data/intl-dates.mjs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export const validIntlDates = [
2+
'2024/01/01',
3+
'2024/1/1',
4+
'1/1/1',
5+
'10000/1/1',
6+
'+2024/1/1',
7+
'-2024/1/1'
8+
]
9+
10+
export const invalidIntlDates = [
11+
'2024/13/01',
12+
'2024/01/32',
13+
'01/01/2024'
14+
]

src/test/data/iso-8601-date-times.mjs

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ limitations under the License.
1515
*/
1616

1717
// Pulled some test data from https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/ (2024-07-15)
18-
export const valid8601DatesOnly = [
18+
const valid8601DatesOnly = [
1919
'2009', // year only
2020
'-0010',
2121
'+0010',
@@ -31,7 +31,7 @@ export const valid8601DatesOnly = [
3131
'2009W011'
3232
]
3333

34-
export const invalid8601DatesOnly = [
34+
const invalid8601DatesOnly = [
3535
'2009-0101', // inconsistent separators
3636
'200901-01',
3737
'2009-W0101',
@@ -43,7 +43,7 @@ export const invalid8601DatesOnly = [
4343
'20090132'
4444
]
4545

46-
export const valid8601TimesOnly = [
46+
const valid8601TimesOnly = [
4747
'24:00:00',
4848
'240000',
4949
'24:00:00Z',
@@ -79,7 +79,7 @@ export const valid8601TimesOnly = [
7979
'232323-05:00'
8080
]
8181

82-
export const invalid8601TimesOnly = [
82+
const invalid8601TimesOnly = [
8383
'24:0000', // inconsistent separators
8484
'2400:00',
8585
'23:2323',
@@ -103,28 +103,20 @@ export const invalid8601TimesOnly = [
103103

104104
export const valid8601DateTimes = [
105105
'2009-12T12:34',
106-
'2009-12T12:34+01'
106+
'2009-12T12:34+01',
107+
...valid8601TimesOnly.map((t) => '2009-12-12T' + t)
107108
]
108109

110+
const invalid8601DateAndTimes = invalid8601TimesOnly.map((t) => '2009-12-12T' + t)
111+
109112
export const invalid8601DateTimes = [
110-
'2009-12-01',
111113
'2009-12 12:34',
112-
'2009-12 12:34+01'
114+
'2009-12 12:34+01',
115+
...invalid8601DateAndTimes,
116+
...valid8601DatesOnly,
117+
...valid8601TimesOnly
113118
]
114119

115120
export const valid8601Dates = [...valid8601DatesOnly, ...valid8601DateTimes]
116121

117-
export const invalid8601Dates = [...invalid8601DatesOnly, ...invalid8601DateTimes.slice(1)]
118-
119-
export const valid8601LooseDateTimes = [
120-
'2009-12 12:34',
121-
'2009-12 12:34+01'
122-
]
123-
124-
// not really a lot of utility in testing much, but testing infra needs something
125-
export const invalid8601LooseDateTimes = ['2009-12-01']
126-
127-
export const valid8601LooseDates = [...valid8601DatesOnly, ...valid8601LooseDateTimes]
128-
129-
// not really a lot of utility in testing much, but testing infra needs something
130-
export const invalid8601LooseDates = invalid8601DatesOnly
122+
export const invalid8601Dates = [...invalid8601DatesOnly, ...invalid8601DateAndTimes]

src/test/data/times.mjs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
export const validMilTimes = [
2+
'2400',
3+
'0000',
4+
'0130'
5+
]
6+
7+
export const invalidMilTimes = [
8+
'2500',
9+
'2060',
10+
'300'
11+
]
12+
13+
export const validTimes = [
14+
'12:00 AM',
15+
'12:00:39 PM',
16+
'2:00:39.383 PM'
17+
]
18+
19+
export const invalidTimes = [
20+
'13:00 AM',
21+
'5:60 PM',
22+
'7:00'
23+
]
24+
25+
export const valid24HrTimes = [
26+
'24:00',
27+
'24:00:00',
28+
'12:00',
29+
'12:00:32.928'
30+
]
31+
32+
export const invalid24HrTimes = [
33+
'24:01',
34+
'25:00',
35+
'12:60',
36+
'12:00:60',
37+
'12:00:10.'
38+
]

src/test/data/us-dates.mjs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export const validUSDates = [
2+
'01/01/2024',
3+
'1/1/2024',
4+
'1/1/1',
5+
'1/1/10000',
6+
'1/1/+2024',
7+
'1/1/-2024'
8+
]
9+
10+
export const invalidUSDates = [
11+
'13/01/2024',
12+
'1/32/2024',
13+
'2024/01/01'
14+
]

0 commit comments

Comments
 (0)