Class: SwedishPIN::Personnummer

Inherits:
Object
  • Object
show all
Defined in:
lib/swedish_pin/personnummer.rb

Overview

Represents a parsed and valid Personnummer or Samordningsnummer for a particular individual.

Determine if this is a Personnummer or a Samordningsnummer using #coordination_number?.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(year:, month:, day:, sequence_number:, control_digit:) ⇒ Personnummer

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Initializes a new instance from specific values. Please consider using SwedishPIN.generate instead of you want custom instances.


41
42
43
44
45
46
47
48
# File 'lib/swedish_pin/personnummer.rb', line 41

def initialize(year:, month:, day:, sequence_number:, control_digit:)
  @year = year
  @month = month
  @coordination_number = day > 60
  @day = (day > 60 ? day - 60 : day)
  @sequence_number = sequence_number
  @control_digit = control_digit
end

Instance Attribute Details

#control_digitInteger (readonly)

The last digit of the personnummer. It acts as a checksum of the previous numbers.

Returns:

  • (Integer)

12
13
14
# File 'lib/swedish_pin/personnummer.rb', line 12

def control_digit
  @control_digit
end

#dayInteger (readonly)

The day of the month of the personnummer. This will be for the real day, even for coordination numbers.

Returns:

  • (Integer)

See Also:


12
13
14
# File 'lib/swedish_pin/personnummer.rb', line 12

def day
  @day
end

#monthInteger (readonly)

The month digit of the personnummer. 1 for January up until 12 for December.

Returns:

  • (Integer)

12
13
14
# File 'lib/swedish_pin/personnummer.rb', line 12

def month
  @month
end

#sequence_numberInteger (readonly)

Note:

This attribute returns an Integer, but this sequence needs to be zero-padded up to three characters if you intend to display it (i.e. 3 is “003”).

The number after the separator. A common reason to access this is to check the sex of the person. You might want to look at #male? and #female? instead.

Returns:

  • (Integer)

12
13
14
# File 'lib/swedish_pin/personnummer.rb', line 12

def sequence_number
  @sequence_number
end

#yearInteger (readonly)

The full year of the personnummer. For example 1989.

Returns:

  • (Integer)

12
13
14
# File 'lib/swedish_pin/personnummer.rb', line 12

def year
  @year
end

Instance Method Details

#age(now = Time.now) ⇒ Integer

Returns the age of the person this personnummer represents, as an integer of years since birth.

Swedish age could be defined as such: A person will be 0 years old when born, and 1 12 months after that, on the same day or the day after in the case of leap years. This is the same way most western countries count age.

If the #birthday is in the future, then 0 will be returned.

Parameters:

  • now (Time, Date) (defaults to: Time.now)

    The current time.

Returns:

  • (Integer)

    Number of 12 month periods that have passed since the birthdate; 0 or more.


159
160
161
162
# File 'lib/swedish_pin/personnummer.rb', line 159

def age(now = Time.now)
  age = now.year - year - (birthday_passed_this_year?(now) ? 0 : 1)
  [0, age].max
end

#birthdayDate

Return the birthday for the person that is represented by this Personnummer.

Returns:

  • (Date)

    the date of birth


54
55
56
# File 'lib/swedish_pin/personnummer.rb', line 54

def birthday
  Date.civil(year, month, day)
end

#coordination_number?Boolean

Note:

The #day attribute will still return a valid date day, even for coordination numbers.

Returns true if this number is a Samordningsnummer (coordination number). This is a number that is granted to non-Swedish citizens until the time that they become citizens.

Coordination numbers are identical to a PIN, except that the “day” component has 60 added to it (i.e. 28+60=88).

Returns:

  • (Boolean)

See Also:


67
68
69
# File 'lib/swedish_pin/personnummer.rb', line 67

def coordination_number?
  @coordination_number
end

#female?true, false

Returns true if the personnummer represents a person that is legally identified as female.

Returns:

  • (true, false)

174
175
176
# File 'lib/swedish_pin/personnummer.rb', line 174

def female?
  sequence_number.even?
end

#format_longObject

Formats the personnummer in the unofficial “12-digit” format that includes the century and doesn't change separator depending on when the number is supposed to be shown.

This format is being adopted in a lot of places in favor of the “10-digit” format (#format_short), but as of 2020 it remains an unofficial format.

Format: yyyymmdd-nnnn

See Also:


112
113
114
115
116
117
118
119
# File 'lib/swedish_pin/personnummer.rb', line 112

def format_long
  [
    format_date(true),
    "-",
    "%03d" % sequence_number,
    control_digit
  ].join("")
end

#format_short(now = Time.now) ⇒ String

Formats the PIN in the official “10-digit” format. This is the “real” Personnummer string.

Format: yymmdd-nnnn or yymmdd+nnnn

The Personnummer specification says that starting from the year of a person's 100th birthday, the separator in their personnummer will change from a - into a +.

That means that every time you display a personnummer you also must consider the time of this action. Something that was read on date A and outputted on date B might not use the same string representation.

For this reason, the real personnummer is usually not what you want to store, only what you want to display in some cases.

This library recommends that you use #format_long for storage.

Parameters:

  • now (Time, Date) (defaults to: Time.now)

    The time when this personnummer is supposed to be displayed.

Returns:

  • (String)

    the formatted number

See Also:


92
93
94
95
96
97
98
99
# File 'lib/swedish_pin/personnummer.rb', line 92

def format_short(now = Time.now)
  [
    format_date(false),
    short_separator(now),
    "%03d" % sequence_number,
    control_digit
  ].join("")
end

#male?true, false

Returns true if the personnummer represents a person that is legally identified as male.

Returns:

  • (true, false)

167
168
169
# File 'lib/swedish_pin/personnummer.rb', line 167

def male?
  sequence_number.odd?
end

#to_s(length = 10, now = Time.now) ⇒ String

Note:

The length isn't how long the resulting string will be as the resulting string will also have a separator included. The formats are colloquially called “10-digit” and “12-digit”, which is why they are referred to as “length” here.

Formats the PIN into a String.

You can provide the desired length to get different formats.

10 or nil

#format_short

12

#format_long

Parameters:

  • length (Integer, nil) (defaults to: 10)

    The desired format.

  • now (Time, Date) (defaults to: Time.now)

    The current time. Only used by #format_short.

Returns:

  • (String)

Raises:

  • (ArgumentError)

    If not provided a valid length.

See Also:


139
140
141
142
143
144
145
# File 'lib/swedish_pin/personnummer.rb', line 139

def to_s(length = 10, now = Time.now)
  case length
  when 10 then format_short(now)
  when 12 then format_long
  else raise ArgumentError, "The only supported lengths are 10 or 12."
  end
end