File Coverage

blib/lib/No/PersonNr.pm
Criterion Covered Total %
statement 42 47 89.3
branch 16 36 44.4
condition 4 15 26.6
subroutine 8 8 100.0
pod 4 4 100.0
total 74 110 67.2


line stmt bran cond sub pod time code
1             package No::PersonNr;
2              
3             require Exporter;
4             @ISA=qw(Exporter);
5             @EXPORT_OK = qw(personnr_ok er_mann er_kvinne fodt_dato);
6              
7 1     1   479 use Carp qw(croak);
  1         3  
  1         66  
8 1     1   5 use strict;
  1         1  
  1         28  
9 1     1   6 use vars qw($VERSION);
  1         1  
  1         584  
10              
11             $VERSION = sprintf("%d.%02d", q$Revision: 1.17 $ =~ /(\d+)\.(\d+)/);
12              
13              
14             =head1 NAME
15              
16             No::PersonNr - Check Norwegian Social security numbers
17              
18             =head1 SYNOPSIS
19              
20             use No::PersonNr qw(personnr_ok);
21              
22             if (personnr_ok($nr)) {
23             # ...
24             }
25              
26             =head1 DESCRIPTION
27              
28             B
29              
30             Denne modulen kan brukes for å sjekke norske personnummer. De 2 siste
31             siffrene i personnummerene er kontrollsiffre og må stemme overens med
32             resten for at det skal være et gyldig nummer. Modulen inneholder også
33             funksjoner for å bestemme personens kjønn og personens fødselsdato.
34              
35             Ingen av rutinene eksporteres implisitt. Du må be om dem. Følgende
36             funksjoner er tilgjengelig:
37              
38             =over 4
39              
40             =item personnr_ok($nr)
41              
42             Funksjonen personnr_ok() vil returnere FALSE hvis personnummeret gitt
43             som argument ikke er gyldig. Hvis nummeret er gyldig så vil
44             funksjonen returnere $nr på standard form. Nummeret som gis til
45             personnr_ok() kan inneholde ' ' eller '-'.
46              
47             Standard form er her definert som 11 siffer uten noe skilletegn
48             mellom tallgrupper.
49              
50             =cut
51              
52             sub personnr_ok
53             {
54 12     12 1 61 my($nr,$returndate) = @_;
55 12 50       22 return undef unless defined($nr);
56 12         47 $nr =~ s/[\s\-]+//g;
57 12 50       33 return "" if $nr =~ /\D/;
58 12 50       25 return "" if length($nr) != 11;
59 12         58 my @nr = split(//, $nr);
60              
61             # Modulo 11 test
62 12         17 my($vekt);
63 12         51 for $vekt ([ 3, 7, 6, 1, 8, 9, 4, 5, 2, 1, 0 ],
64             [ 5, 4, 3, 2, 7, 6, 5, 4, 3, 2, 1 ]) {
65 24         26 my $sum = 0;
66 24         28 for (0..10) {
67 264         335 $sum += $nr[$_] * $vekt->[$_];
68             }
69 24 50       71 return "" if $sum % 11;
70             }
71              
72             # Extract the date part
73 12         53 my @date = reverse unpack("A2A2A2A3", $nr);
74 12         17 my $pnr = shift(@date);
75              
76             # H-nummer -- hjelpenummer, en virksomhetsintern, unik identifikasjon av
77             # en person som ikke har fødselsnummer/D-nummer eller hvor dette er
78             # ukjent. 4 er lagt til tredje siffer.
79 12 50       31 $date[1] -= 40 if $date[1] > 40;
80              
81             # D-nummer -- For personer som ikke er bosatt i Norge, men som likevel
82             # er skatte- og/eller trygdepliktig. 4 er lagt til første siffer.
83 12 50       25 $date[2] -= 40 if $date[2] > 40;
84              
85             # Så var det det å kjenne igjen hvilket hundreår som er det riktige.
86             #
87             # Individnummer År i fødselsdato Født
88             # 500 - 749 > 54 1855 - 1899
89             # 000 - 499 1900 - 1999
90             # 500 - 999 < 55 2000 - 2054
91             #
92 12 50       21 if ($pnr < 500) {
    0          
93             # ingen tvetydighet; person født 1900 - 1999
94 12         18 $date[0] += 1900;
95             } elsif ($pnr >= 750) {
96             # ingen tvetydighet; person født 2000 - 2054
97 0         0 $date[0] += 2000;
98             } else {
99             # tvetydig; må se på de to sifrene for fødselsår
100 0 0       0 if ($date[0] > 54) {
101             # person født 1855 - 1899
102 0         0 $date[0] += 1800;
103             } else {
104             # person født 2000 - 2054
105 0         0 $date[0] += 2000;
106             }
107             }
108 12 50       23 return "" unless _is_legal_date(@date);
109              
110 12 100       57 return $returndate ? join("-", @date) : $nr;
111             }
112              
113              
114             sub _is_legal_date
115             {
116 12     12   18 my($y,$m,$d) = @_;
117 12 50       22 return if $d < 1;
118 12 50 33     47 return if $m < 1 || $m > 12;
119              
120 12         14 my $mdays = 31;
121 12 50 33     85 if ($m == 2) {
    50 33        
      33        
122 0 0 0     0 $mdays = (($y % 4 == 0) && ($y % 100 != 0)) || ($y % 400 == 0)
123             ? 29 : 28;
124             } elsif ($m == 4 || $m == 6 || $m == 9 || $m == 11) {
125 12         16 $mdays = 30;
126             }
127 12 50       21 return if $d > $mdays;
128 12         27 1;
129             }
130              
131              
132             =item er_mann($nr)
133              
134             Vil returnere TRUE hvis $nr tilhører en mann. Rutinen vil croake hvis
135             nummeret er ugyldig.
136              
137             =cut
138              
139             sub er_mann
140             {
141 6     6 1 23 my $nr = personnr_ok(shift);
142 6 50       14 croak "Feil i personnummer" unless $nr;
143 6         18 substr($nr, 8, 1) % 2;
144             }
145              
146              
147             =item er_kvinne($nr)
148              
149             Vil returnere TRUE hvis $nr tilhører en kvinne. Rutinen vil croake
150             hvis nummeret er ugyldig.
151              
152             =cut
153              
154 3     3 1 15 sub er_kvinne { !er_mann(@_); }
155              
156              
157             =item fodt_dato($nr)
158              
159             Vil returnere personens fødselsdato på formen "ÅÅÅÅ-MM-DD". Rutinen
160             returnerer C<""> hvis nummeret er ugyldig.
161              
162             =cut
163              
164             sub fodt_dato
165             {
166 3     3 1 12 personnr_ok(shift, 1);
167             }
168              
169             1;
170              
171             =back
172              
173             =head1 REFERENCES
174              
175             =over 4
176              
177             =item [1]
178              
179             "Hjelpenummer for personer uten kjent fødselsnummer", Torbjørn Nystadnes,
180             Kompetansesenter for IT i helsevesenet AS (KITH). KITH-rapport,
181             Rapportnummer 11/98, ISBN 82-7846-051-5, 1998-12-11.
182              
183             =item [2]
184              
185             "Fødselsnummeret, oppbygging - kontrollsiffer - løsning etter år 2000".
186             Brosjyre fra Skattedirektoratet.
187              
188             =item [3]
189              
190             Skattedirektoratet, Sentralkontoret for folkeregistrering,
191              
192             =back
193              
194             =head1 LIMITATIONS
195              
196             Personnummersystemet håndterer kun årstall fra og med 1855 til og med 2054.
197              
198             =head1 AUTHORS
199              
200             Gisle Aas , Peter J. Acklam , Petter
201             Reinholdtsen , Hallvard B. Furuseth
202             .
203              
204             =cut