Class: SwedishPIN::Personnummer

Inherits:
Object
  • Object
show all
Includes:
Comparable
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.



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

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)


14
15
16
# File 'lib/swedish_pin/personnummer.rb', line 14

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:



14
15
16
# File 'lib/swedish_pin/personnummer.rb', line 14

def day
  @day
end

#monthInteger (readonly)

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

Returns:

  • (Integer)


14
15
16
# File 'lib/swedish_pin/personnummer.rb', line 14

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)


14
15
16
# File 'lib/swedish_pin/personnummer.rb', line 14

def sequence_number
  @sequence_number
end

#yearInteger (readonly)

The full year of the personnummer. For example 1989.

Returns:

  • (Integer)


14
15
16
# File 'lib/swedish_pin/personnummer.rb', line 14

def year
  @year
end

Instance Method Details

#<=>(other) ⇒ Object



188
189
190
191
192
193
194
# File 'lib/swedish_pin/personnummer.rb', line 188

def <=>(other)
  if other.is_a?(self.class)
    format_long <=> other.format_long
  else
    super
  end
end

#==(other) ⇒ Object Also known as: eql?



180
181
182
183
184
185
186
# File 'lib/swedish_pin/personnummer.rb', line 180

def ==(other)
  if other.is_a?(self.class)
    format_long == other.format_long
  else
    super
  end
end

#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.



161
162
163
164
# File 'lib/swedish_pin/personnummer.rb', line 161

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



56
57
58
# File 'lib/swedish_pin/personnummer.rb', line 56

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:



69
70
71
# File 'lib/swedish_pin/personnummer.rb', line 69

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)


176
177
178
# File 'lib/swedish_pin/personnummer.rb', line 176

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:



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

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:



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

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

#hashObject



196
197
198
# File 'lib/swedish_pin/personnummer.rb', line 196

def hash
  [self.class, format_long].hash
end

#male?true, false

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

Returns:

  • (true, false)


169
170
171
# File 'lib/swedish_pin/personnummer.rb', line 169

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:



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

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