Parse and verify Swedish personal identity numbers, "personnummer" in Swedish, or PNR for short in this library.
The Swedish Tax Agency ("Skatteverket" in Swedish) has a description of the format, but it basically boils down to this:
-
A PNR comprises 10 digits and a separator on the form
yyMMdd-nnnc
whereyyMMdd
denotes the date of birth,nnn
is a sequence number called "birth number", andc
is a checksum of the previous nine digits. -
The date of birth of a PNR lacks its century! So, the actual date of birth has to be deduced relative a reference date. In all normal uses, that reference date is today. Right now.
-
Temporary PNRs called coordination numbers ("sammordningsnummer" in Swedish) can be issued to people not listed in the Swedish Population Register. A listed person is "folkbokförd" in Swedish; an unlisted person is... not "folkbokförd"... umm, let's move on. These numbers follow the same rules as normal PNRs but have the number 60 added to the day number (
dd
in the format above). -
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) - 11 characters:
yyMMdd-nnnc
(the "standard" form) - 11 characters:
yyMMdd+nnnc
(centennials) - 12 characters:
yyyyMMddnnnc
- 13 characters:
yyyyMMdd-nnnc
- 10 characters:
Other curiosities:
-
As there are only 999 distinct birth numbers available1 for a given date, Skatteverket may run out of numbers! If that's the case identity numbers will apparently be selected from neighbouring dates. Thus, some people have PNRs with dates of birth that aren't their actual dates of birth.
-
Because the century is not part of the PNR, it is also not included in the checksum calculation. Two PNRs of the longer form that differ only by a century (or a multiple thereof) have identical checksums. Don't skip the age check!
-
Speaking of age, short form PNRs can't be used for really, really old people. Sorry, Bicentennial Man.
To make use of this library, declare a dependency in your Package.swift:
// 🇸🇪 Swedish personal identity number validation
.package(url: "https://github.com/Oops-AB/swedish-pnr.git", from: "1.0.0"),
and to your target:
.executableTarget(name: "Smorgasbord", dependencies: [
.product(name: "SwedishPNR", package: "swedish-pnr")
],
Let's get going:
let pnr = try! SwedishPNR.parse(input: " 20171210-0005\t")
print("\(pnr.normalized)")
Output
20171210-0005
The parse()
function either returns a PNR or throws a Parser.ParseError
.
A successful parse returns a SwedishPNR
. This type has a few properties:
input
is the original string, including leading or trailing space,normalized
is the full, 13 character version of the PNR,birthDateComponents
is aDateComponents
instance holdingyear
,month
andday
,birthDate
is aDate
instance representing the first instant of the birth date in the Sweden time zone.
The SwedishPNR
also has a method age(at:) -> Int
that calculates the age in years relative a reference date (which defaults to now).
Note that all date calculations (age and deducing century) are performed in the Sweden time zone.
Footnotes
-
There may very well be fewer birth numbers available as some might be reserved or excluded. I've not found a definite list. Skatteverket may know. ↩