Skip to content

Commit 59e71a1

Browse files
committed
feat(pipes): parse date pipe
1 parent ce3d047 commit 59e71a1

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed

lib/pipes/parseDate.pipe.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { BadRequestException } from '../exceptions';
2+
import type { PipeMetadata, PipeOptions } from './ParameterPipe';
3+
import { validatePipeOptions } from './validatePipeOptions';
4+
5+
// The following variables and functions are taken from the validator.js (https://github.com/validatorjs/validator.js/blob/master/src/lib/isISO8601.js)
6+
7+
// from http://goo.gl/0ejHHW
8+
const iso8601 = /^([+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([.,]\d+(?!:))?)?(\17[0-5]\d([.,]\d+)?)?([zZ]|([+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
9+
// same as above, except with a strict 'T' separator between date and time
10+
const iso8601StrictSeparator = /^([+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([.,]\d+(?!:))?)?(\17[0-5]\d([.,]\d+)?)?([zZ]|([+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
11+
12+
const isValidDate = (str: string) => {
13+
// str must have passed the ISO8601 check
14+
// this check is meant to catch invalid dates
15+
// like 2009-02-31
16+
const match = (str.match(/(\d{4})-?(\d{0,2})-?(\d*)/) ?? []).map(Number);
17+
const year = match[1];
18+
const month = match[2];
19+
const day = match[3];
20+
const monthString = month ? `0${month}`.slice(-2) : month;
21+
const dayString = day ? `0${day}`.slice(-2) : day;
22+
23+
// create a date object and compare
24+
const d = new Date(`${year}-${monthString || '01'}-${dayString || '01'}`);
25+
if (month && day) {
26+
return d.getUTCFullYear() === year && d.getUTCMonth() + 1 === month && d.getUTCDate() === day;
27+
}
28+
29+
return true;
30+
};
31+
32+
function isISO8601(str: string, options: { strictSeparator?: boolean; strict?: boolean } = {}) {
33+
const check = options.strictSeparator ? iso8601StrictSeparator.test(str) : iso8601.test(str);
34+
35+
if (check && options.strict) {
36+
return isValidDate(str);
37+
}
38+
39+
return check;
40+
}
41+
42+
export function ParseDatePipe(options?: PipeOptions) {
43+
return (value: any, metadata?: PipeMetadata) => {
44+
validatePipeOptions(value, metadata?.name, options);
45+
46+
if (value && !isISO8601(value, { strict: true })) {
47+
throw new BadRequestException(
48+
`Validation failed${metadata?.name ? ` for ${metadata.name}` : ''} (date string is expected)`
49+
);
50+
}
51+
52+
return new Date(value);
53+
};
54+
}

0 commit comments

Comments
 (0)