diff --git a/src/at/vnr.ts b/src/at/vnr.ts index 515e56f7..c4eed15d 100644 --- a/src/at/vnr.ts +++ b/src/at/vnr.ts @@ -56,7 +56,7 @@ const impl: Validator = { const [front, check, dob] = strings.splitAt(value, 3, 4); - if (!isValidDateCompactDDMMYY(dob)) { + if (!isValidDateCompactDDMMYY(dob, true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } diff --git a/src/ba/jmbg.ts b/src/ba/jmbg.ts index 0ff0748b..456620c3 100644 --- a/src/ba/jmbg.ts +++ b/src/ba/jmbg.ts @@ -8,7 +8,7 @@ */ import * as exceptions from '../exceptions'; -import { isValidDateCompactYYYYMMDD, strings } from '../util'; +import { isValidDate, strings } from '../util'; import { Validator, ValidateReturn } from '../types'; import { weightedSum } from '../util/checksum'; @@ -55,7 +55,7 @@ const impl: Validator = { const [dd, mm, yyy] = strings.splitAt(value, 2, 4, 7); const yyyy = `${parseInt(yyy, 10) < 800 ? '2' : '1'}${yyy}`; - if (!isValidDateCompactYYYYMMDD(`${yyyy}${mm}${dd}`)) { + if (!isValidDate(yyyy, mm, dd, true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } diff --git a/src/cn/ric.ts b/src/cn/ric.ts index 9ad54f2e..3ec11cd4 100644 --- a/src/cn/ric.ts +++ b/src/cn/ric.ts @@ -58,7 +58,7 @@ const impl: Validator = { return { isValid: false, error: new exceptions.InvalidFormat() }; } - if (!isValidDateCompactYYYYMMDD(front.substr(6, 8))) { + if (!isValidDateCompactYYYYMMDD(front.substring(6, 14), true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } diff --git a/src/cu/ni.ts b/src/cu/ni.ts index 00989434..9e4f7101 100644 --- a/src/cu/ni.ts +++ b/src/cu/ni.ts @@ -5,7 +5,7 @@ */ import * as exceptions from '../exceptions'; -import { isValidDateCompactYYYYMMDD, strings } from '../util'; +import { isValidDate, strings } from '../util'; import { Validator, ValidateReturn } from '../types'; function clean(input: string): ReturnType { @@ -57,7 +57,7 @@ const impl: Validator = { return { isValid: false, error: new exceptions.InvalidComponent() }; } - if (!isValidDateCompactYYYYMMDD(`${year}${mm}${dd}`)) { + if (!isValidDate(year, mm, dd, true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } diff --git a/src/cz/rc.ts b/src/cz/rc.ts index a8c4604b..fd4d056a 100644 --- a/src/cz/rc.ts +++ b/src/cz/rc.ts @@ -12,7 +12,7 @@ */ import * as exceptions from '../exceptions'; -import { isValidDateCompactYYYYMMDD, strings } from '../util'; +import { isValidDate, strings } from '../util'; import { Validator, ValidateReturn } from '../types'; function clean(input: string): ReturnType { @@ -66,9 +66,7 @@ const impl: Validator = { } else if (year < 1954) { year += 100; } - if ( - !isValidDateCompactYYYYMMDD(`${year}${String(mon).padStart(2, '0')}${dd}`) - ) { + if (!isValidDate(String(year), String(mon), dd, true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } diff --git a/src/de/pwnr.ts b/src/de/pwnr.ts index 7e9108b5..21356182 100644 --- a/src/de/pwnr.ts +++ b/src/de/pwnr.ts @@ -83,7 +83,7 @@ export function validateNew(value: string): ValidateReturn { checksum, ] = strings.splitAt(value, 9, 10, 16, 17, 23, 24, 25); - if (!isValidDateCompactYYMMDD(birth)) { + if (!isValidDateCompactYYMMDD(birth, true)) { return { isValid: false, error: new exceptions.InvalidComponent('birthdate'), diff --git a/src/dk/cpr.ts b/src/dk/cpr.ts index 2672738f..34194fdf 100644 --- a/src/dk/cpr.ts +++ b/src/dk/cpr.ts @@ -20,13 +20,14 @@ */ import * as exceptions from '../exceptions'; -import { strings } from '../util'; +import { isValidDate, buildDate, validBirthdate, strings } from '../util'; import { Validator, ValidateReturn } from '../types'; export function getBirthDate(value: string): Date { const [dob] = strings.splitAt(value, 6); - // eslint-disable-next-line prefer-const - let [day, month, year] = strings.splitAt(dob, 2, 4).map(v => Number(v)); + const [day, month, yearStr] = strings.splitAt(dob, 2, 4); + + let year = parseInt(yearStr); if ('5678'.includes(value[6]) && year >= 58) { year += 1800; @@ -38,19 +39,16 @@ export function getBirthDate(value: string): Date { } else { year += 2000; } - const date = new Date(year, month - 1, day); - if ( - Number.isNaN(date.getTime()) || - [year, String(month).padStart(2, '0'), String(day).padStart(2, '0')].join( - '-', - ) !== date.toISOString().substr(0, 10) - ) { + + const d = buildDate(String(year), month, day); + + if (d === null || !isValidDate(String(year), month, day)) { throw new exceptions.InvalidComponent( 'The number does not contain valid birth date information.', ); } - return date; + return d; } function clean(input: string): ReturnType { @@ -97,7 +95,7 @@ const impl: Validator = { try { const date = getBirthDate(value); - if (date.getTime() > new Date().getTime()) { + if (!validBirthdate(date)) { return { isValid: false, error: new exceptions.InvalidComponent( diff --git a/src/ee/ik.ts b/src/ee/ik.ts index 8e312e7a..8319c8ac 100644 --- a/src/ee/ik.ts +++ b/src/ee/ik.ts @@ -61,7 +61,7 @@ export function ikCheckDate(value: string): boolean { return false; } - return isValidDateCompactYYYYMMDD(`${century}${value.substr(1, 6)}`); + return isValidDateCompactYYYYMMDD(`${century}${value.substr(1, 6)}`, true); } const impl: Validator = { diff --git a/src/fi/hetu.spec.ts b/src/fi/hetu.spec.ts index 70ef7537..22befce7 100644 --- a/src/fi/hetu.spec.ts +++ b/src/fi/hetu.spec.ts @@ -14,7 +14,7 @@ describe('fi/hetu', () => { expect(result.isValid && result.compact).toEqual('131052-308T'); }); - test.each(['131052B308T', '131052X308T', '131052-308T'])( + test.each(['131022B3082', '131052X308T', '131052-308T'])( 'validate:%s', value => { const result = validate(value); diff --git a/src/fi/hetu.ts b/src/fi/hetu.ts index af3e33e9..b968e21e 100644 --- a/src/fi/hetu.ts +++ b/src/fi/hetu.ts @@ -10,7 +10,7 @@ */ import * as exceptions from '../exceptions'; -import { isValidDateCompactYYYYMMDD, strings } from '../util'; +import { isValidDate, strings } from '../util'; import { Validator, ValidateReturn } from '../types'; function clean(input: string): ReturnType { @@ -86,8 +86,7 @@ const impl: Validator = { 7, 10, ); - const dstr = `${CENTURY[century]}${yy}${mm}${dd}`; - if (!isValidDateCompactYYYYMMDD(dstr)) { + if (!isValidDate(`${CENTURY[century]}${yy}`, mm, dd, true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } diff --git a/src/gr/amka.ts b/src/gr/amka.ts index db7afe50..9ba9fcbf 100644 --- a/src/gr/amka.ts +++ b/src/gr/amka.ts @@ -13,7 +13,7 @@ */ import * as exceptions from '../exceptions'; -import { isValidDateCompactYYMMDD, strings } from '../util'; +import { isValidDate, strings } from '../util'; import { Validator, ValidateReturn } from '../types'; import { luhnChecksumValidate } from '../util/checksum'; @@ -56,7 +56,7 @@ const impl: Validator = { const [dd, mm, yy] = strings.splitAt(value, 2, 4, 6); - if (!isValidDateCompactYYMMDD(`${yy}${mm}${dd}`)) { + if (!isValidDate(yy, mm, dd)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } if (!luhnChecksumValidate(value)) { diff --git a/src/is/kennitala.ts b/src/is/kennitala.ts index 513220ca..c33b0d6d 100644 --- a/src/is/kennitala.ts +++ b/src/is/kennitala.ts @@ -8,7 +8,7 @@ */ import * as exceptions from '../exceptions'; -import { isValidDateCompactYYYYMMDD, strings, weightedSum } from '../util'; +import { isValidDate, strings, weightedSum } from '../util'; import { Validator, ValidateReturn } from '../types'; function clean(input: string): ReturnType { @@ -54,7 +54,7 @@ const impl: Validator = { const day = dayValue > 40 ? String(dayValue - 40).padStart(2, '0') : dd; const year = centry === '9' ? `19${yy}` : `20${yy}`; - if (!isValidDateCompactYYYYMMDD(`${year}${mm}${day}`)) { + if (!isValidDate(year, mm, day)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } diff --git a/src/kr/rrn.ts b/src/kr/rrn.ts index 605920da..b4de8c1e 100644 --- a/src/kr/rrn.ts +++ b/src/kr/rrn.ts @@ -76,7 +76,7 @@ const impl: Validator = { const [dob, century, place, , check] = strings.splitAt(value, 6, 7, 9, 12); - if (!isValidDateCompactYYYYMMDD(`${centuryPrefix[century]}${dob}`)) { + if (!isValidDateCompactYYYYMMDD(`${centuryPrefix[century]}${dob}`, true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } if (parseInt(place, 10) > 96) { diff --git a/src/lv/pvn.ts b/src/lv/pvn.ts index 394d6b92..a724b7a1 100644 --- a/src/lv/pvn.ts +++ b/src/lv/pvn.ts @@ -12,7 +12,7 @@ */ import * as exceptions from '../exceptions'; -import { isValidDateCompactYYYYMMDD, strings } from '../util'; +import { isValidDate, strings } from '../util'; import { Validator, ValidateReturn } from '../types'; import { weightedSum } from '../util/checksum'; @@ -62,11 +62,7 @@ const impl: Validator = { if (isIndividual) { const [dd, mm, yy, century] = strings.splitAt(value, 2, 4, 6, 7); - if ( - !isValidDateCompactYYYYMMDD( - `${18 + parseInt(century, 10)}${yy}${mm}${dd}`, - ) - ) { + if (!isValidDate(`${18 + parseInt(century, 10)}${yy}`, mm, dd, true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } diff --git a/src/mx/curp.spec.ts b/src/mx/curp.spec.ts index 1bbd76e3..272e6447 100644 --- a/src/mx/curp.spec.ts +++ b/src/mx/curp.spec.ts @@ -17,7 +17,7 @@ describe('mx/curp', () => { it('getBirthDate:BOXW310820HNERXN09', () => { const result = getBirthDate('BOXW310820HNERXN09'); - expect(result.toISOString().substr(0, 10)).toEqual('1931-08-20'); + expect(result?.toISOString().substr(0, 10)).toEqual('1931-08-20'); }); it('getGender:BOXW310820HNERXN09', () => { diff --git a/src/mx/curp.ts b/src/mx/curp.ts index d6b3e82d..24dacfcd 100644 --- a/src/mx/curp.ts +++ b/src/mx/curp.ts @@ -14,7 +14,12 @@ */ import * as exceptions from '../exceptions'; -import { isValidDateCompactYYMMDD, strings } from '../util'; +import { + buildDate, + isValidDateCompactYYMMDD, + strings, + validBirthdate, +} from '../util'; import { Validator, ValidateReturn } from '../types'; function clean(input: string): ReturnType { @@ -184,7 +189,7 @@ const impl: Validator = { if (!/^[A-Z]{4}[0-9]{6}[A-Z]{6}[0-9A-Z][0-9]$/.test(value)) { return { isValid: false, error: new exceptions.InvalidFormat() }; } - if (!isValidDateCompactYYMMDD(value.substr(4, 6))) { + if (!isValidDateCompactYYMMDD(value.substr(4, 6), true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } if (nameBlacklist.has(value.substr(0, 4))) { @@ -219,17 +224,12 @@ const impl: Validator = { }, }; -function getBirthDateImpl(value: string) { - const parts = strings.splitAt(value, 4, 6, 8); +function getBirthDateImpl(value: string): Date | null { + const [, year, mm, dd] = strings.splitAt(value, 4, 6, 8); - const yyN = parseInt(parts[1], 10); - const mmN = parseInt(parts[2], 10) - 1; - const ddN = parseInt(parts[3], 10); + const century = !Number.isNaN(parseInt(value[16], 10)) ? '19' : '20'; - if (!Number.isNaN(parseInt(value[16], 10))) { - return new Date(yyN + 1900, mmN, ddN); - } - return new Date(yyN + 2000, mmN, ddN); + return buildDate(`${century}${year}`, mm, dd); } /// @@ -249,10 +249,12 @@ export function getGender(input: string): 'M' | 'F' | 'X' { return 'F'; } -export function getBirthDate(input: string): Date { +export function getBirthDate(input: string): Date | null { const value = impl.compact(input); - return getBirthDateImpl(value); + const date = getBirthDateImpl(value); + + return validBirthdate(date) ? date : null; } export const { name, localName, abbreviation, validate, format, compact } = diff --git a/src/mx/rfc.ts b/src/mx/rfc.ts index e7a0b594..94057417 100644 --- a/src/mx/rfc.ts +++ b/src/mx/rfc.ts @@ -129,7 +129,7 @@ const impl: Validator = { if (nameBlacklist.has(value.substr(0, 4))) { return { isValid: false, error: new exceptions.InvalidComponent() }; } - if (!isValidDateCompactYYMMDD(value.substr(4, 6))) { + if (!isValidDateCompactYYMMDD(value.substr(4, 6), true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } } else if (value.length === 12) { diff --git a/src/my/nric.ts b/src/my/nric.ts index fadee8c9..35be1396 100644 --- a/src/my/nric.ts +++ b/src/my/nric.ts @@ -71,7 +71,7 @@ const impl: Validator = { const [bdate, place] = strings.splitAt(value, 6, 8); - if (!isValidDateCompactYYMMDD(bdate)) { + if (!isValidDateCompactYYMMDD(bdate, true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } if (UNASSIGNED.includes(place)) { diff --git a/src/no/fodselsnummer.ts b/src/no/fodselsnummer.ts index f3b26f62..e3bfdf23 100644 --- a/src/no/fodselsnummer.ts +++ b/src/no/fodselsnummer.ts @@ -48,7 +48,7 @@ function checkBirthdate(value: string) { return false; } - return isValidDate(String(yy), String(mm), String(dd)); + return isValidDate(String(yy), String(mm), String(dd), true); } const impl: Validator = { diff --git a/src/pl/pesel.ts b/src/pl/pesel.ts index 2ef6700e..4c4199d0 100644 --- a/src/pl/pesel.ts +++ b/src/pl/pesel.ts @@ -69,7 +69,7 @@ const impl: Validator = { century = '19'; } - if (!isValidDate(`${century}${yy}`, String(month % 20), dd)) { + if (!isValidDate(`${century}${yy}`, String(month % 20), dd, true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } diff --git a/src/ro/cnp.ts b/src/ro/cnp.ts index 454d6636..f78428db 100644 --- a/src/ro/cnp.ts +++ b/src/ro/cnp.ts @@ -126,7 +126,7 @@ const impl: Validator = { const [first, dvalue, county] = strings.splitAt(value, 1, 7, 9); - if (!isValidDateCompactYYYYMMDD(`${century[first]}${dvalue}`)) { + if (!isValidDateCompactYYYYMMDD(`${century[first]}${dvalue}`, true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } if (!VALID_COUNTIES.includes(county)) { diff --git a/src/se/personnummer.spec.ts b/src/se/personnummer.spec.ts index a4410ffc..f2826d41 100644 --- a/src/se/personnummer.spec.ts +++ b/src/se/personnummer.spec.ts @@ -2,10 +2,18 @@ import { validate, format } from './personnummer'; import { InvalidLength, InvalidChecksum } from '../exceptions'; describe('se/personnummer', () => { - it('format:8803200016', () => { - const result = format('8803200016'); - - expect(result).toEqual('880320-0016'); + test.each([ + ['8803200017', '880320-0017'], // no hyphen assume young person + ['880320-0017', '880320-0017'], // standard format + ['880320+0017', '880320+0017'], // standard format, person over 100 + ['19200901-0000', '200901+0000'], // 4digit year, hypen that's useless person over 100 + ['192009010000', '200901+0000'], // 4digit year, no hyphen, person over 100 + ['20200901-0000', '200901-0000'], // 4digit year, hyphen + ['202009010000', '200901-0000'], // 4digit year, no hyphen + ])('format:%s', (given, want) => { + const result = format(given); + + expect(result).toEqual(want); }); it('validate:880320-0016', () => { diff --git a/src/se/personnummer.ts b/src/se/personnummer.ts index 6cdb29b0..d0e65283 100644 --- a/src/se/personnummer.ts +++ b/src/se/personnummer.ts @@ -13,10 +13,12 @@ */ import * as exceptions from '../exceptions'; -import { isValidDateCompactYYYYMMDD, strings } from '../util'; +import { isValidDateCompactYYYYMMDD, buildDate, strings } from '../util'; import { Validator, ValidateReturn } from '../types'; import { luhnChecksumValidate } from '../util/checksum'; +const ONE_HUNDRED_YEARS_IN_MS = 100 * 365 * 24 * 60 * 60 * 1_000; + function clean(input: string): ReturnType { const [value, err] = strings.cleanUnicode(input, ' :'); @@ -29,6 +31,43 @@ function clean(input: string): ReturnType { return [`${a.replace(/[-+]/g, '')}${b}${c}`, null]; } +function formatImpl(input: string): string { + const [value] = clean(input); + + let front, + back, + sep = '-'; + + if (value.length === 12 || value.length === 13) { + const [yyyy, mm, dd] = strings.splitAt(value, 0, 4, 6, 8); + + const d = buildDate(yyyy, mm, dd); + if (d === null) { + // bad date :( + return value; + } + + if (new Date().getTime() - d.getTime() > ONE_HUNDRED_YEARS_IN_MS) { + sep = '+'; + } + + front = `${yyyy.substring(2)}${mm}${dd}`; + + back = value.substring(value.length - 4); + } else if (value.length === 10) { + front = value.substring(0, 6); + back = value.substring(6); + } else if (value.length === 11) { + front = value.substring(0, 6); + sep = value[6]; + back = value.substring(7); + } else { + return value; + } + + return `${front}${sep}${back}`; +} + const impl: Validator = { name: 'Swedish Personal Identity Number', localName: 'Personnummer', @@ -42,11 +81,7 @@ const impl: Validator = { return value; }, - format(input: string): string { - const [value] = clean(input); - - return strings.splitAt(value, -4).join('-'); - }, + format: formatImpl, validate(input: string): ValidateReturn { const [value, error] = clean(input); @@ -87,7 +122,7 @@ const impl: Validator = { yyyymmdd = `${century}${yymmdd}`; } - if (!isValidDateCompactYYYYMMDD(yyyymmdd)) { + if (!isValidDateCompactYYYYMMDD(yyyymmdd, true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } @@ -97,7 +132,7 @@ const impl: Validator = { return { isValid: true, - compact: value, + compact: formatImpl(input), isIndividual: true, isCompany: false, }; diff --git a/src/tw/tax_code.ts b/src/tw/tax_code.ts index 266500bb..bd8fa007 100644 --- a/src/tw/tax_code.ts +++ b/src/tw/tax_code.ts @@ -71,12 +71,12 @@ const impl = { if (!strings.isdigits(yymmdd)) { return { isValid: false, error: new exceptions.InvalidFormat() }; } - if (!isValidDateCompactYYMMDD(yymmdd)) { + if (!isValidDateCompactYYMMDD(yymmdd, true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } } else { const [yyyymmdd, name] = strings.splitAt(value, 8); - if (!isValidDateCompactYYYYMMDD(yyyymmdd)) { + if (!isValidDateCompactYYYYMMDD(yyyymmdd, true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; } if (!/^[A-Z]+$/i.test(name)) { diff --git a/src/util/index.ts b/src/util/index.ts index 0c76ba64..28e53d80 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -2,6 +2,8 @@ import * as strings from './strings'; export { weightedSum, mod97base10Validate } from './checksum'; export { + buildDate, + validBirthdate, isValidDate, isValidDateCompactYYYYMMDD, isValidDateCompactYYMMDD, diff --git a/src/util/isValidDate.spec.ts b/src/util/isValidDate.spec.ts index 1671284b..05febcb0 100644 --- a/src/util/isValidDate.spec.ts +++ b/src/util/isValidDate.spec.ts @@ -1,4 +1,4 @@ -import { isValidDate } from './isValidDate'; +import { isValidDate, validBirthdate } from './isValidDate'; describe('isValidDate', () => { it('2020-01-02', () => { @@ -16,4 +16,34 @@ describe('isValidDate', () => { it('20-02-29', () => { expect(isValidDate('20', '02', '29')).toEqual(true); }); + + describe('birthdates', () => { + describe('validBirthdate', () => { + it('today', () => { + const now = new Date(); + // remove those pesky minutes... + const date = new Date(now.toISOString().substring(0, 10)); + expect(validBirthdate(date)).toEqual(true); + }); + + it('tomorrow', () => { + const now = new Date(); + now.setDate(now.getDate() + 1); + const date = new Date(now.toISOString().substring(0, 10)); + expect(validBirthdate(date)).toEqual(false); + }); + + it('2010-01-01', () => { + expect(validBirthdate(new Date('2010-01-01'))).toEqual(true); + }); + + it('2030-01-01', () => { + expect(validBirthdate(new Date('2030-01-01'))).toEqual(false); + }); + }); + + it('2090-02-29', () => { + expect(isValidDate('2090', '02', '29', true)).toEqual(false); + }); + }); }); diff --git a/src/util/isValidDate.ts b/src/util/isValidDate.ts index 04c48318..f02f22bd 100644 --- a/src/util/isValidDate.ts +++ b/src/util/isValidDate.ts @@ -1,13 +1,21 @@ import { splitAt } from './strings'; -/** Check to make sure this is a valid date */ -export function isValidDate(yy: string, mm: string, dd: string): boolean { +export function validBirthdate(date: Date | null): boolean { + if (date === null) { + return false; + } + + const now = new Date(); + return date.getTime() <= now.getTime(); +} + +export function buildDate(yy: string, mm: string, dd: string): Date | null { const yyN = parseInt(yy, 10); const mmN = parseInt(mm, 10) - 1; const ddN = parseInt(dd, 10); if (Number.isNaN(yyN) || Number.isNaN(mmN) || Number.isNaN(ddN)) { - return false; + return null; } let d; @@ -20,32 +28,60 @@ export function isValidDate(yy: string, mm: string, dd: string): boolean { } if (Number.isNaN(d.getFullYear())) { - return false; + return null; } // Date will convert Jan 30 -> Feb 9, make sure this didn't happen if (d.getDate() !== ddN || d.getMonth() !== mmN) { + return null; + } + + return d; +} + +/** Check to make sure this is a valid date + * isBefore checks to make sure that the date is today or before, this + * typically is used for birtdays (you could be born today) + */ +export function isValidDate( + yy: string, + mm: string, + dd: string, + isBefore = false, +): boolean { + const d = buildDate(yy, mm, dd); + + if (d === null) { return false; } - return true; + return isBefore ? validBirthdate(d) : true; } /** Check to make sure this is a valid date */ -export function isValidDateCompactYYMMDD(yymmdd: string): boolean { +export function isValidDateCompactYYMMDD( + yymmdd: string, + isBefore = false, +): boolean { const [year, mon, day] = splitAt(yymmdd, 2, 4); - return isValidDate(year, mon, day); + return isValidDate(year, mon, day, isBefore); } -export function isValidDateCompactDDMMYY(ddmmyy: string): boolean { +export function isValidDateCompactDDMMYY( + ddmmyy: string, + isBefore = false, +): boolean { const [day, mon, year] = splitAt(ddmmyy, 2, 4); - return isValidDate(year, mon, day); + return isValidDate(year, mon, day, isBefore); } -export function isValidDateCompactYYYYMMDD(yyyymmdd: string): boolean { +export function isValidDateCompactYYYYMMDD( + yyyymmdd: string, + isBefore = false, +): boolean { const [year, mon, day] = splitAt(yyyymmdd, 4, 6); - return isValidDate(year, mon, day); + return isValidDate(year, mon, day, isBefore); } diff --git a/src/za/idnr.ts b/src/za/idnr.ts index acd8a20c..9e3aa7df 100644 --- a/src/za/idnr.ts +++ b/src/za/idnr.ts @@ -13,9 +13,8 @@ */ import * as exceptions from '../exceptions'; -import { strings } from '../util'; +import { strings, isValidDateCompactYYMMDD } from '../util'; import { Validator, ValidateReturn } from '../types'; -import { isValidDateCompactYYMMDD } from '../util/isValidDate'; import { luhnChecksumValidate } from '../util/checksum'; function clean(input: string): ReturnType { @@ -64,7 +63,7 @@ const impl: Validator = { return { isValid: false, error: new exceptions.InvalidComponent() }; } - if (!isValidDateCompactYYMMDD(bdate)) { + if (!isValidDateCompactYYMMDD(bdate, true)) { return { isValid: false, error: new exceptions.InvalidComponent() }; }