personnummer_erl
Validate, parse and format Swedish personal identity numbers (personnummer) in Erlang/OTP. Implements the personnummer specification v3.1.
Supports:
- Regular personnummer (
YYMMDD-XXXX,YYYYMMDD-XXXX,+separator from the year a person turns 100) - Coordination numbers (samordningsnummer, day = real day + 60)
- Interim numbers (T-numbers, opt-in via options map)
Installation
Add to rebar.config:
{deps, [{personnummer_erl, "3.1.2"}]}.
Requires Erlang/OTP 27 or newer.
Quick start
{ok, Pnr} = personnummer:parse(<<"198608134667">>),
true = personnummer:valid(<<"198608134667">>),
<<"860813-4667">> = personnummer:format(Pnr),
<<"198608134667">> = personnummer:format(Pnr, true),
{1986, 8, 13} = personnummer:get_date(Pnr),
19 = personnummer:get_century(Pnr),
<<"466">> = personnummer:get_serial(Pnr),
7 = personnummer:get_check(Pnr),
<<"-">> = personnummer:get_separator(Pnr),
true = personnummer:is_female(Pnr),
false = personnummer:is_coordination_number(Pnr),
false = personnummer:is_interim_number(Pnr).
Options
%% Reject coordination numbers (samordningsnummer).
personnummer:parse(Input, #{allow_coordination_number => false}).
%% Accept interim numbers (T-numbers). Disabled by default.
personnummer:parse(<<"20000101T220">>, #{allow_interim_number => true}).
Defaults: allow_coordination_number => true,
allow_interim_number => false.
Compliance
The test suite is driven by JSON fixtures vendored from personnummer/meta. See test/testdata/README.md for refresh instructions.
Development
This project uses Mise for tool versions and
task running. Erlang/OTP, rebar3, and ELP are pinned in mise.toml.
Eqwalizer tasks resolve ELP through Mise and unset ELP_EQWALIZER_PATH so
custom PATH entries or unrelated local checker builds cannot override
the pinned toolchain.
$ mise install
$ mise compile
$ mise test
$ mise format # apply erlfmt
$ mise check # compile, fmt-check, eunit, dialyzer, eqwalizer
$ mise eq-all # eqwalizer (installed by Mise)
$ mise cover # test coverage report
$ mise docs # ex_doc
CI runs compilation, formatting checks, EUnit with coverage, Dialyzer, and Eqwalizer on OTP 27, 28, and 29.
Conventions
- Formatting:
erlfmt— CI enforces withrebar3 fmt --check. - Type checking: dialyzer must report 0 warnings; eqwalizer must
report
NO ERRORS(run viaelp). - Tests: prefer one focused EUnit function per behavior. The
compliance suite is driven by JSON fixtures vendored from
personnummer/meta; refresh
with
mise refresh-testdata. - Changelog: describe user-facing changes under
[Unreleased]in CHANGELOG.md.
Releasing
- Bump
vsninsrc/personnummer_erl.app.srcand convert the[Unreleased]heading inCHANGELOG.mdto the new version. Commit and push. - Run
mise checkto confirm everything is green. - Run
mise publish. This publishes to Hex (requiresrebar3 hex user authonce), tagsvX.Y.Z, and pushes the tag.
In memoriam
Fredrik "Frozzare" Forsmo (1991-2026) was the initiator, co-founder and a core contributor of the personnummer project. This library carries his work. He is missed.