From 7e256d7611f10ca8ddecfcf9c812b3b2412013ad Mon Sep 17 00:00:00 2001 From: Malte Tancred Date: Mon, 30 Sep 2024 12:18:59 +0200 Subject: [PATCH] :sparkles: Add property `gender`. --- README.md | 6 ++++++ Sources/SwedishPNR/SwedishPNR.swift | 12 +++++++++++- Tests/SwedishPNRTests/SwedishPNRTests.swift | 16 ++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2945959..31496a8 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,12 @@ The Swedish Tax Agency ("Skatteverket" in Swedish) has a [description of the for * When a person reaches the honorable age of 100 years, a plus sign (`+`) is used for the separator in their PNR, i.e., `yyMMdd+nnnc`. +* The last digit of the birth number + (i.e, the penultimate digit, you know, the one followed by the checksum) + reveals the gender of the person. + Even and odd numbers + denote females and males, respectively. + * Although the standard form of a PNR is the eleven character version described so far, other forms are also in common use. This library handles PNRs on the following forms. Note that the last two forms include the century, so no deduction is necessary, neither is the plus separator allowed; unsurprisingly these forms are popular, if not required in many apps and sites today. * 10 characters: `yyMMddnnnc` (standard form but lacking separator) diff --git a/Sources/SwedishPNR/SwedishPNR.swift b/Sources/SwedishPNR/SwedishPNR.swift index dc05d91..76e8423 100644 --- a/Sources/SwedishPNR/SwedishPNR.swift +++ b/Sources/SwedishPNR/SwedishPNR.swift @@ -5,10 +5,16 @@ public struct SwedishPNR { public let normalized: String public let birthDateComponents: DateComponents public let birthDate: Date + public let gender: Gender public func age(at reference: Date = Date()) -> Int { return calculateAge(for: birthDate, at: reference, in: makeSwedishCalendar()) } + + public enum Gender { + case female + case male + } } @@ -70,11 +76,15 @@ public struct Parser { let bday = swedishCalendar.date(from: birthDateComponents)! + let penultimateDigitIdx = normalized.index(normalized.startIndex, offsetBy: 11) + let penultimateDigit = Int(normalized[penultimateDigitIdx.. DateComponents { diff --git a/Tests/SwedishPNRTests/SwedishPNRTests.swift b/Tests/SwedishPNRTests/SwedishPNRTests.swift index 57fae38..8d32941 100644 --- a/Tests/SwedishPNRTests/SwedishPNRTests.swift +++ b/Tests/SwedishPNRTests/SwedishPNRTests.swift @@ -371,6 +371,22 @@ final class SwedishPNRTests: XCTestCase { XCTAssertEqual(try SwedishPNR.parse(input: "10000101-0008", relative: ref).age(at: ref), 1122) } + func testGender() throws { + let ref = formatterForSweden!.date(from: "2024-09-30")! + + XCTAssertEqual(try SwedishPNR.parse(input: "240101-1008", relative: ref).gender, .female) + XCTAssertEqual(try SwedishPNR.parse(input: "240101-1024", relative: ref).gender, .female) + XCTAssertEqual(try SwedishPNR.parse(input: "240101-1040", relative: ref).gender, .female) + XCTAssertEqual(try SwedishPNR.parse(input: "240101-1065", relative: ref).gender, .female) + XCTAssertEqual(try SwedishPNR.parse(input: "240101-1081", relative: ref).gender, .female) + + XCTAssertEqual(try SwedishPNR.parse(input: "240101-1016", relative: ref).gender, .male) + XCTAssertEqual(try SwedishPNR.parse(input: "240101-1032", relative: ref).gender, .male) + XCTAssertEqual(try SwedishPNR.parse(input: "240101-1057", relative: ref).gender, .male) + XCTAssertEqual(try SwedishPNR.parse(input: "240101-1073", relative: ref).gender, .male) + XCTAssertEqual(try SwedishPNR.parse(input: "240101-1099", relative: ref).gender, .male) + } + func testDefaultRefTime() throws { let pnr = try SwedishPNR.parse(input: "20000101-0008")