@remato/personal-code-to-birthday 0.0.0 β†’ 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,21 +28,21 @@ console.log(birthday) // outputs { day: 26, month: 9, year: 1993 }
28
28
  - πŸ‡ΈπŸ‡ͺ Sweden
29
29
  - πŸ‡³πŸ‡΄ Norway
30
30
  - πŸ‡©πŸ‡° Denmark
31
+ - πŸ‡ΊπŸ‡¦ Ukraine
32
+ - πŸ‡΅πŸ‡± Poland
31
33
 
32
34
  Countries we would like to support (PRs are welcome):
33
35
 
34
36
  - Iceland
35
- - South Africa
36
37
  - Romania
37
38
  - Hungary
38
39
  - Bulgaria
40
+ - Moldova
41
+ - Azerbaijan
39
42
  - North Macedonia
40
43
  - Czech Republic
41
44
  - Slovakia
42
- - Poland
43
45
  - South Korea
44
46
  - Turkey
45
- - Moldova
46
- - Azerbaijan
47
+ - South Africa
47
48
  - Russia
48
- - Ukraine
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@remato/personal-code-to-birthday",
3
- "version": "0.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Converts personal identification codes from various countries into birthdate",
5
5
  "license": "MIT",
6
- "main": "index.ts",
6
+ "main": "src/index.ts",
7
7
  "scripts": {
8
- "build": "ncc build index.ts",
8
+ "build": "ncc build src/index.ts",
9
9
  "test": "jest",
10
10
  "prettier": "prettier --list-different \"**/*.ts\"",
11
11
  "lint": "eslint \"**/*.ts\""
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "collectCoverage": true,
42
42
  "collectCoverageFrom": [
43
- "index.ts"
43
+ "src/**"
44
44
  ]
45
45
  },
46
46
  "eslintConfig": {
@@ -2,8 +2,10 @@ import personalCodeToBirthday from './index'
2
2
 
3
3
  describe('valid codes', () => {
4
4
  test('Estonia', () => {
5
- expect(personalCodeToBirthday('39405280299')).toEqual({ day: 28, month: 5, year: 1994 })
6
- expect(personalCodeToBirthday('60105280299')).toEqual({ day: 28, month: 5, year: 2001 })
5
+ expect(personalCodeToBirthday('39309262754')).toEqual({ day: 26, month: 9, year: 1993 })
6
+ expect(personalCodeToBirthday('49111012217')).toEqual({ day: 1, month: 11, year: 1991 })
7
+ expect(personalCodeToBirthday('30001010060')).toEqual({ day: 1, month: 1, year: 1900 })
8
+ expect(personalCodeToBirthday('62305060020')).toEqual({ day: 6, month: 5, year: 2023 })
7
9
  })
8
10
 
9
11
  test('Latvia', () => {
@@ -12,7 +14,7 @@ describe('valid codes', () => {
12
14
  })
13
15
 
14
16
  test('Lithuania', () => {
15
- expect(personalCodeToBirthday('39905280217')).toEqual({ day: 28, month: 5, year: 1999 })
17
+ expect(personalCodeToBirthday('39905280216')).toEqual({ day: 28, month: 5, year: 1999 })
16
18
  })
17
19
 
18
20
  test('Finland', () => {
@@ -31,17 +33,27 @@ describe('valid codes', () => {
31
33
  })
32
34
 
33
35
  test('Denmark', () => {
34
- expect(personalCodeToBirthday('0503054567')).toEqual({ day: 5, month: 3, year: 2005 })
35
- expect(personalCodeToBirthday('0503841235')).toEqual({ day: 5, month: 3, year: 1984 })
36
+ expect(personalCodeToBirthday('050305-4567')).toEqual({ day: 5, month: 3, year: 2005 })
36
37
  expect(personalCodeToBirthday('050384-1235')).toEqual({ day: 5, month: 3, year: 1984 })
37
- expect(personalCodeToBirthday('0503844567')).toEqual({ day: 5, month: 3, year: 1984 })
38
+ expect(personalCodeToBirthday('050384-4567')).toEqual({ day: 5, month: 3, year: 1984 })
39
+ })
40
+
41
+ test('Ukraine', () => {
42
+ expect(personalCodeToBirthday('3406105372')).toEqual({ day: 3, month: 4, year: 1993 })
43
+ expect(personalCodeToBirthday('3406105350')).toEqual({ day: 3, month: 4, year: 1993 })
44
+ })
45
+
46
+ test('Poland', () => {
47
+ expect(personalCodeToBirthday('44051401359')).toEqual({ day: 14, month: 5, year: 1944 })
48
+ expect(personalCodeToBirthday('02070803628')).toEqual({ day: 8, month: 7, year: 1902 })
49
+ expect(personalCodeToBirthday('24231012344')).toEqual({ day: 10, month: 3, year: 2024 })
38
50
  })
39
51
  })
40
52
 
41
53
  describe('invalid personal code', () => {
42
54
  test('Estonia', () => {
43
- const result = personalCodeToBirthday('39913025555')
44
- expect(result).toBeNull()
55
+ expect(personalCodeToBirthday('39911025555')).toBeNull()
56
+ expect(personalCodeToBirthday('39913035552')).toBeNull()
45
57
  })
46
58
 
47
59
  test('Latvia', () => {
@@ -56,6 +68,7 @@ describe('invalid personal code', () => {
56
68
  expect(personalCodeToBirthday('999999A123T')).toBeNull()
57
69
  expect(personalCodeToBirthday('131052Z3087')).toBeNull()
58
70
  expect(personalCodeToBirthday('321052A3087')).toBeNull()
71
+ expect(personalCodeToBirthday('910100A123F')).toBeNull()
59
72
  })
60
73
 
61
74
  test('Sweden', () => {
@@ -69,11 +82,19 @@ describe('invalid personal code', () => {
69
82
  })
70
83
 
71
84
  test('Denmark', () => {
72
- expect(personalCodeToBirthday('9999991234')).toBeNull()
85
+ expect(personalCodeToBirthday('999999-1234')).toBeNull()
86
+ })
87
+
88
+ test('Ukraine', () => {
89
+ expect(personalCodeToBirthday('3406105373')).toBeNull()
90
+ })
91
+
92
+ test('Poland', () => {
93
+ expect(personalCodeToBirthday('24231012343')).toBeNull()
94
+ expect(personalCodeToBirthday('24234012341')).toBeNull()
73
95
  })
74
96
 
75
- test('unsupported personal code format', () => {
76
- const result = personalCodeToBirthday('abcd1234')
77
- expect(result).toBeNull()
97
+ test('unidentified personal code format', () => {
98
+ expect(personalCodeToBirthday('abcd1234')).toBeNull()
78
99
  })
79
100
  })
package/src/index.ts ADDED
@@ -0,0 +1,27 @@
1
+ import denmarkParser from './parsers/denmark'
2
+ import estoniaLithuaniaParser from './parsers/estoniaLithuania'
3
+ import finlandParser from './parsers/finland'
4
+ import latviaParser from './parsers/latvia'
5
+ import norwayParser from './parsers/norway'
6
+ import polandParser from './parsers/poland'
7
+ import swedenParser from './parsers/sweden'
8
+ import ukraineParser from './parsers/ukraine'
9
+ import { ParsedDate } from './types'
10
+
11
+ export default function personalCodeToBirthday(code: string): ParsedDate | null {
12
+ if (/^\d{10}$/.test(code)) {
13
+ return ukraineParser(code)
14
+ } else if (/^\d{11}$/.test(code)) {
15
+ return estoniaLithuaniaParser(code) || polandParser(code) || norwayParser(code)
16
+ } else if (/^\d{12}$/.test(code)) {
17
+ return swedenParser(code)
18
+ } else if (/^\d{6}-\d{5}$/.test(code)) {
19
+ return latviaParser(code)
20
+ } else if (/^\d{6}[+-A]\d{3}[A-Za-z]$/.test(code)) {
21
+ return finlandParser(code)
22
+ } else if (/^\d{6}[+-A]\d{4}$/.test(code)) {
23
+ return finlandParser(code) || denmarkParser(code)
24
+ }
25
+
26
+ return null
27
+ }
@@ -0,0 +1,30 @@
1
+ import { ParsedDate } from '../types'
2
+ import { isValidDate } from '../utils'
3
+
4
+ export default function denmarkParser(code: string): ParsedDate | null {
5
+ if (code.includes('-')) {
6
+ code = code.replace('-', '')
7
+ }
8
+
9
+ const day = parseInt(code.slice(0, 2), 10)
10
+ const month = parseInt(code.slice(2, 4), 10)
11
+ let year = parseInt(code.slice(4, 6), 10)
12
+ const centuryIndicator = parseInt(code.slice(6, 7), 10)
13
+
14
+ // Determine century based on the 7th digit and the year
15
+ if (centuryIndicator >= 0 && centuryIndicator <= 3) {
16
+ year += 1900
17
+ } else if (centuryIndicator >= 4 && centuryIndicator <= 9) {
18
+ if (year >= 0 && year <= 36) {
19
+ year += 2000
20
+ } else {
21
+ year += 1900
22
+ }
23
+ }
24
+
25
+ if (!isValidDate(day, month, year)) {
26
+ return null
27
+ }
28
+
29
+ return { day, month, year }
30
+ }
@@ -0,0 +1,52 @@
1
+ import { ParsedDate } from '../types'
2
+ import { isValidDate } from '../utils'
3
+
4
+ export default function estoniaLithuaniaParser(code: string): ParsedDate | null {
5
+ if (!isValidChecksum(code)) {
6
+ return null
7
+ }
8
+
9
+ const centuryCode = parseInt(code[0], 10)
10
+ const day = parseInt(code.slice(5, 7), 10)
11
+ const month = parseInt(code.slice(3, 5), 10)
12
+ let year = parseInt(code.slice(1, 3), 10)
13
+
14
+ if (centuryCode === 3 || centuryCode === 4) {
15
+ year += 1900
16
+ }
17
+ if (centuryCode === 5 || centuryCode === 6) {
18
+ year += 2000
19
+ }
20
+
21
+ if (!isValidDate(day, month, year)) {
22
+ return null
23
+ }
24
+
25
+ return { day, month, year }
26
+ }
27
+
28
+ function isValidChecksum(code: string): boolean {
29
+ const weights1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1]
30
+ const weights2 = [3, 4, 5, 6, 7, 8, 9, 1, 2, 3]
31
+ let checksum = 0
32
+ let total = 0
33
+
34
+ for (let i = 0; i < 10; ++i) {
35
+ total += Number(code.charAt(i)) * weights1[i]
36
+ }
37
+ checksum = total % 11
38
+
39
+ total = 0
40
+ if (checksum === 10) {
41
+ for (let i = 0; i < 10; ++i) {
42
+ total += Number(code.charAt(i)) * weights2[i]
43
+ }
44
+ checksum = total % 11
45
+
46
+ if (10 === checksum) {
47
+ checksum = 0
48
+ }
49
+ }
50
+
51
+ return checksum === Number(code[10])
52
+ }
@@ -0,0 +1,43 @@
1
+ import { ParsedDate } from '../types'
2
+ import { isValidDate } from '../utils'
3
+
4
+ export default function finlandParser(code: string): ParsedDate | null {
5
+ if (!isValidChecksum(code)) {
6
+ return null
7
+ }
8
+
9
+ const day = parseInt(code.slice(0, 2), 10)
10
+ const month = parseInt(code.slice(2, 4), 10)
11
+ const yearSuffix = parseInt(code.slice(4, 6), 10)
12
+ const centuryMarker = code[6]
13
+
14
+ let year = yearSuffix
15
+
16
+ // Handle the century based on the marker
17
+ if (centuryMarker === '+') {
18
+ year += 1800
19
+ } else if (centuryMarker === '-') {
20
+ year += 1900
21
+ } else if (centuryMarker === 'A') {
22
+ year += 2000
23
+ }
24
+
25
+ // Validate the parsed date
26
+ if (!isValidDate(day, month, year)) {
27
+ return null
28
+ }
29
+
30
+ return { day, month, year }
31
+ }
32
+
33
+ function isValidChecksum(code: string): boolean {
34
+ const validChars = '0123456789ABCDEFHJKLMNPRSTUVWXY'
35
+
36
+ const serial = code.slice(0, 6) + code.slice(7, 10)
37
+ const checksum = code[10]
38
+ const num = parseInt(serial, 10)
39
+ const remainder = num % 31
40
+ const expectedChecksum = validChars.charAt(remainder)
41
+
42
+ return expectedChecksum === checksum.toUpperCase()
43
+ }
@@ -0,0 +1,24 @@
1
+ import { ParsedDate } from '../types'
2
+ import { isValidDate } from '../utils'
3
+
4
+ // Correct old school format is DDMMYY-CXXXX
5
+ export default function latviaParser(code: string): ParsedDate | null {
6
+ const day = parseInt(code.slice(0, 2), 10)
7
+ const month = parseInt(code.slice(2, 4), 10)
8
+ let year = parseInt(code.slice(4, 6), 10)
9
+ const centuryCode = parseInt(code[7], 10)
10
+
11
+ // Latvian codes are always from the 20th century, so add 1900
12
+ if (centuryCode === 2) {
13
+ year += 2000
14
+ } else {
15
+ year += 1900
16
+ }
17
+
18
+ // Validate the parsed date
19
+ if (!isValidDate(day, month, year)) {
20
+ return null
21
+ }
22
+
23
+ return { day, month, year }
24
+ }
@@ -0,0 +1,24 @@
1
+ import { ParsedDate } from '../types'
2
+ import { isValidDate } from '../utils'
3
+
4
+ export default function norwayParser(code: string): ParsedDate | null {
5
+ const day = parseInt(code.slice(0, 2), 10)
6
+ const month = parseInt(code.slice(2, 4), 10)
7
+ let year = parseInt(code.slice(4, 6), 10)
8
+
9
+ const individual = parseInt(code.slice(6, 9), 10)
10
+
11
+ // Determine century based on individual number and year
12
+ if (individual <= 499 || (individual >= 500 && year >= 40)) {
13
+ year += 1900
14
+ } else if (individual <= 999 && year <= 39) {
15
+ year += 2000
16
+ }
17
+
18
+ // Now validate the date after adjusting the century
19
+ if (!isValidDate(day, month, year)) {
20
+ return null
21
+ }
22
+
23
+ return { day, month, year }
24
+ }
@@ -0,0 +1,37 @@
1
+ import { ParsedDate } from '../types'
2
+ import { isValidDate } from '../utils'
3
+
4
+ export default function polandParser(code: string): ParsedDate | null {
5
+ if (!isValidChecksum(code)) {
6
+ return null
7
+ }
8
+
9
+ const day = parseInt(code.slice(4, 6), 10)
10
+ let month = parseInt(code.slice(2, 4), 10)
11
+ let year = parseInt(code.slice(0, 2), 10)
12
+
13
+ // Determine the century based on the month encoding
14
+ if (month >= 1 && month <= 12) {
15
+ year += 1900
16
+ } else if (month >= 21 && month <= 32) {
17
+ year += 2000
18
+ month -= 20
19
+ }
20
+
21
+ if (!isValidDate(day, month, year)) {
22
+ return null
23
+ }
24
+
25
+ return { day, month, year }
26
+ }
27
+
28
+ function isValidChecksum(code: string): boolean {
29
+ const weights = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3]
30
+ const digits = code.slice(0, 10).split('').map(Number)
31
+
32
+ const sum = digits.reduce((acc, digit, index) => acc + digit * weights[index], 0)
33
+
34
+ const expectedChecksum = (10 - (sum % 10)) % 10
35
+
36
+ return expectedChecksum === parseInt(code[10], 10)
37
+ }
@@ -0,0 +1,14 @@
1
+ import { ParsedDate } from '../types'
2
+ import { isValidDate } from '../utils'
3
+
4
+ export default function swedenParser(code: string): ParsedDate | null {
5
+ const year = parseInt(code.slice(0, 4), 10)
6
+ const month = parseInt(code.slice(4, 6), 10)
7
+ const day = parseInt(code.slice(6, 8), 10)
8
+
9
+ if (!isValidDate(day, month, year)) {
10
+ return null
11
+ }
12
+
13
+ return { day, month, year }
14
+ }
@@ -0,0 +1,35 @@
1
+ import { ParsedDate } from '../types'
2
+
3
+ export default function ukrainianParser(code: string): ParsedDate | null {
4
+ if (!isValidChecksum(code)) {
5
+ return null
6
+ }
7
+
8
+ // The first 5 digits represent the number of days since 31-12-1899
9
+ const daysSinceBaseDate = parseInt(code.slice(0, 5), 10)
10
+ const baseDate = new Date(1899, 11, 31) // Dec 31, 1899
11
+
12
+ // Calculate the birthdate from the number of days since the base date
13
+ const birthDate = new Date(baseDate.getTime() + daysSinceBaseDate * 24 * 60 * 60 * 1000)
14
+
15
+ const day = birthDate.getDate()
16
+ const month = birthDate.getMonth() + 1 // getMonth is zero-based
17
+ const year = birthDate.getFullYear()
18
+
19
+ return { day, month, year }
20
+ }
21
+
22
+ function isValidChecksum(code: string): boolean {
23
+ const digits = code.slice(0, 9).split('').map(Number)
24
+
25
+ const weights = [-1, 5, 7, 9, 4, 6, 10, 5, 7]
26
+ const controlSum = digits.reduce((sum, digit, index) => sum + digit * weights[index], 0)
27
+
28
+ let controlNumber = controlSum % 11
29
+
30
+ if (controlNumber === 10) {
31
+ controlNumber = 0
32
+ }
33
+
34
+ return controlNumber === parseInt(code[9], 10)
35
+ }
package/src/types.ts ADDED
@@ -0,0 +1,5 @@
1
+ export interface ParsedDate {
2
+ day: number
3
+ month: number
4
+ year: number
5
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,5 @@
1
+ export function isValidDate(day: number, month: number, year: number): boolean {
2
+ const date = new Date(year, month - 1, day) // month is zero-indexed in JS Date
3
+
4
+ return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day
5
+ }
package/tsconfig.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "compilerOptions": {
4
4
  "target": "ES2022",
5
5
  "module": "NodeNext",
6
- "rootDir": "./",
6
+ "rootDir": "./src",
7
7
  "moduleResolution": "NodeNext",
8
8
  "baseUrl": "./",
9
9
  "sourceMap": true,
package/index.ts DELETED
@@ -1,192 +0,0 @@
1
- interface ParsedDate {
2
- day: number
3
- month: number
4
- year: number
5
- }
6
-
7
- export default function personalCodeToBirthday(code: string): ParsedDate | null {
8
- if (/^\d{11}$/.test(code)) {
9
- // Could be Estonia, Lithuania, or Norway
10
- const birthday = estonianLithuanianParser(code)
11
- if (birthday) {
12
- return birthday
13
- }
14
-
15
- return norwayParser(code)
16
- } else if (/^\d{6}-\d{5}$/.test(code)) {
17
- return latvianParser(code)
18
- } else if (/^\d{6}[+-A]\d{3}[A-Za-z]$/.test(code)) {
19
- return finlandParser(code)
20
- } else if (/^\d{6}[+-A]\d{4}$/.test(code)) {
21
- // Could be Finland or Denmark
22
- const birthday = finlandParser(code)
23
- if (birthday) {
24
- return birthday
25
- }
26
-
27
- return denmarkParser(code)
28
- } else if (/^\d{12}$/.test(code)) {
29
- return swedenParser(code)
30
- } else if (/^\d{10}$/.test(code)) {
31
- return denmarkParser(code)
32
- }
33
-
34
- return null
35
- }
36
-
37
- // Estonia (EE) and Lithuanian (LT) Parser
38
- function estonianLithuanianParser(code: string): ParsedDate | null {
39
- const centuryCode = parseInt(code[0], 10)
40
- const day = parseInt(code.slice(5, 7), 10)
41
- const month = parseInt(code.slice(3, 5), 10)
42
- let year = parseInt(code.slice(1, 3), 10)
43
-
44
- if (centuryCode === 3 || centuryCode === 4) {
45
- year += 1900
46
- }
47
- if (centuryCode === 5 || centuryCode === 6) {
48
- year += 2000
49
- }
50
-
51
- if (!isValidDate(day, month, year)) {
52
- return null
53
- }
54
-
55
- return { day, month, year }
56
- }
57
-
58
- // Latvia (LV) Parser
59
- // Correct old school format is DDMMYY-CXXXX
60
- function latvianParser(code: string): ParsedDate | null {
61
- const day = parseInt(code.slice(0, 2), 10)
62
- const month = parseInt(code.slice(2, 4), 10)
63
- let year = parseInt(code.slice(4, 6), 10)
64
- const centuryCode = parseInt(code[7], 10)
65
-
66
- // Latvian codes are always from the 20th century, so add 1900
67
- if (centuryCode === 2) {
68
- year += 2000
69
- } else {
70
- year += 1900
71
- }
72
-
73
- // Validate the parsed date
74
- if (!isValidDate(day, month, year)) {
75
- return null
76
- }
77
-
78
- return { day, month, year }
79
- }
80
-
81
- // Finland (FI) Parser
82
- function finlandParser(code: string): ParsedDate | null {
83
- const day = parseInt(code.slice(0, 2), 10)
84
- const month = parseInt(code.slice(2, 4), 10)
85
- const yearSuffix = parseInt(code.slice(4, 6), 10)
86
- const centuryMarker = code[6]
87
-
88
- let year = yearSuffix
89
-
90
- // Handle the century based on the marker
91
- if (centuryMarker === '+') {
92
- year += 1800
93
- } else if (centuryMarker === '-') {
94
- year += 1900
95
- } else if (centuryMarker === 'A') {
96
- year += 2000
97
- }
98
-
99
- // Validate the parsed date
100
- if (!isValidDate(day, month, year)) {
101
- return null
102
- }
103
-
104
- if (!isValidFinnishChecksum(code)) {
105
- return null
106
- }
107
-
108
- return { day, month, year }
109
- }
110
-
111
- function isValidFinnishChecksum(code: string): boolean {
112
- const validChars = '0123456789ABCDEFHJKLMNPRSTUVWXY'
113
-
114
- const serial = code.slice(0, 6) + code.slice(7, 10)
115
- const checksum = code[10]
116
- const num = parseInt(serial, 10)
117
- const remainder = num % 31
118
- const expectedChecksum = validChars.charAt(remainder)
119
-
120
- return expectedChecksum === checksum.toUpperCase()
121
- }
122
-
123
- // Sweden (SE) Parser
124
- function swedenParser(code: string): ParsedDate | null {
125
- const year = parseInt(code.slice(0, 4), 10)
126
- const month = parseInt(code.slice(4, 6), 10)
127
- const day = parseInt(code.slice(6, 8), 10)
128
-
129
- if (!isValidDate(day, month, year)) {
130
- return null
131
- }
132
-
133
- return { day, month, year }
134
- }
135
-
136
- // Norway (NO) Parser
137
- function norwayParser(code: string): ParsedDate | null {
138
- const day = parseInt(code.slice(0, 2), 10)
139
- const month = parseInt(code.slice(2, 4), 10)
140
- let year = parseInt(code.slice(4, 6), 10)
141
-
142
- const individual = parseInt(code.slice(6, 9), 10)
143
-
144
- // Determine century based on individual number and year
145
- if (individual <= 499 || (individual >= 500 && year >= 40)) {
146
- year += 1900
147
- } else if (individual <= 999 && year <= 39) {
148
- year += 2000
149
- }
150
-
151
- // Now validate the date after adjusting the century
152
- if (!isValidDate(day, month, year)) {
153
- return null
154
- }
155
-
156
- return { day, month, year }
157
- }
158
-
159
- // Denmark (DK) Parser
160
- function denmarkParser(code: string): ParsedDate | null {
161
- if (code.includes('-')) {
162
- code = code.replace('-', '')
163
- }
164
-
165
- const day = parseInt(code.slice(0, 2), 10)
166
- const month = parseInt(code.slice(2, 4), 10)
167
- let year = parseInt(code.slice(4, 6), 10)
168
- const centuryIndicator = parseInt(code.slice(6, 7), 10)
169
-
170
- // Determine century based on the 7th digit and the year
171
- if (centuryIndicator >= 0 && centuryIndicator <= 3) {
172
- year += 1900
173
- } else if (centuryIndicator >= 4 && centuryIndicator <= 9) {
174
- if (year >= 0 && year <= 36) {
175
- year += 2000
176
- } else {
177
- year += 1900
178
- }
179
- }
180
-
181
- if (!isValidDate(day, month, year)) {
182
- return null
183
- }
184
-
185
- return { day, month, year }
186
- }
187
-
188
- function isValidDate(day: number, month: number, year: number): boolean {
189
- const date = new Date(year, month - 1, day) // month is zero-indexed in JS Date
190
-
191
- return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day
192
- }