Last active
August 29, 2015 14:19
-
-
Save esson/1c30bd946dd380f2a040 to your computer and use it in GitHub Desktop.
Class for dealing with Swedish personal identity numbers.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public class SwedishPersonalIdentityNumber | |
| { | |
| /// <summary> | |
| /// Pattern for finding common ways of writing a Swedish personal identity number. It is forgiving and will match the format rather than valid numbers. | |
| /// | |
| /// Illustrating how it works: | |
| /// ((19)99)(06)(01)(-)((01)|(TF))(1)(1) | |
| /// </summary> | |
| private const string RegexPattern = @"^(?<year>((19)|(20))?(\d\d))(?<month>[01]\d)(?<day>\d\d)(?<flag>[-]|[\+])?(?<county>(\d\d)|(TF))(?<gender>\d)(?<checksum>\d)$"; | |
| public int BirthYear { get; set; } | |
| public int BirthMonth { get; set; } | |
| public int BirthDay { get; set; } | |
| public int CountyCode { get; set; } | |
| public int GenderCode { get; set; } | |
| public int Checksum { get; set; } | |
| public bool IsCoordinationNumber { get; set; } | |
| public bool IsTemporaryNumber { get; set; } | |
| public DateTime Birthdate | |
| { | |
| get | |
| { | |
| return new DateTime(this.BirthYear, this.BirthMonth, this.BirthDay); | |
| } | |
| set | |
| { | |
| this.BirthYear = value.Year; | |
| this.BirthMonth = value.Month; | |
| this.BirthDay = value.Day; | |
| } | |
| } | |
| public int Age | |
| { | |
| get | |
| { | |
| var birthdate = this.Birthdate; | |
| var today = DateTime.Today; | |
| var result = today.Year - birthdate.Year; | |
| if (today.Month < birthdate.Month || (today.Month == birthdate.Month && today.Day < birthdate.Day)) | |
| { | |
| result--; | |
| } | |
| return result; | |
| } | |
| } | |
| public SwedishPersonalIdentityNumber() | |
| { | |
| this.Birthdate = DateTime.MinValue; | |
| } | |
| public SwedishPersonalIdentityNumber(string swedishPersonalIdentityNumber) | |
| : this() | |
| { | |
| var match = Regex.Match(swedishPersonalIdentityNumber.Trim(), RegexPattern); | |
| if (match.Success == false) | |
| { | |
| throw new FormatException("The provided personal identity number is not a valid Swedish personal identity number."); | |
| } | |
| this.BirthMonth = Convert.ToInt32(match.Groups["month"].Value); | |
| this.BirthDay = Convert.ToInt32(match.Groups["day"].Value); | |
| if (this.BirthDay > 60) | |
| { | |
| // For coordination numbers, the day part is added with 60, so we deduct 60. | |
| this.IsCoordinationNumber = true; | |
| this.BirthDay = this.BirthDay - 60; | |
| } | |
| this.BirthYear = ParseBirthYear(match.Groups["year"].Value, this.BirthMonth, this.BirthDay, match.Groups["flag"] != null ? match.Groups["flag"].Value : null); | |
| // For temporary numbers, the county part is "TF" | |
| if (match.Groups["county"].Value == "TF") | |
| { | |
| this.IsTemporaryNumber = true; | |
| this.CountyCode = 0; | |
| } | |
| else | |
| { | |
| this.CountyCode = Convert.ToInt32(match.Groups["county"].Value); | |
| } | |
| this.GenderCode = Convert.ToInt32(match.Groups["gender"].Value); | |
| this.Checksum = Convert.ToInt32(match.Groups["checksum"].Value); | |
| } | |
| private int ParseBirthYear(string birthYear, int month, int day, string flag) | |
| { | |
| if (birthYear.Length == 4) | |
| { | |
| // String contains full year. | |
| return Convert.ToInt32(birthYear); | |
| } | |
| else | |
| { | |
| // String contains partial year. | |
| var currentDate = DateTime.Today; | |
| var birthdayThisYear = new DateTime(currentDate.Year, month, day); | |
| // Convert the two digit year to four digits. | |
| // | |
| // Create an object with Swedish culture information. | |
| var swedishCultureInfo = new CultureInfo("sv-SE"); | |
| // Set the maximum possible year we can convert to. If this years birthday has occurred, last year will be the maximum year. | |
| swedishCultureInfo.Calendar.TwoDigitYearMax = birthdayThisYear > currentDate ? currentDate.Year - 1 : currentDate.Year; | |
| if (flag == "+") | |
| { | |
| // If the flag is a plus symbol, that means the birthyear is at least 100 years ago. So we can safely remove 100 years from the maximum possible year. | |
| swedishCultureInfo.Calendar.TwoDigitYearMax -= 100; | |
| } | |
| // Calculate the result. | |
| return swedishCultureInfo.Calendar.ToFourDigitYear(Convert.ToInt32(birthYear)); | |
| } | |
| } | |
| #region ToString Methods | |
| public override string ToString() | |
| { | |
| return this.ToString("yymmdd-nnnn"); | |
| } | |
| public string ToLongString(bool useFlag = true) | |
| { | |
| return this.ToString(useFlag ? "yyyymmdd-nnnn" : "yyyymmddnnnn"); | |
| } | |
| public string ToString(string format) | |
| { | |
| var result = format; | |
| result = result.Replace("yyyy", this.Birthdate.ToString("yyyy")); | |
| result = result.Replace("yyy", this.Birthdate.ToString("yyy")); | |
| result = result.Replace("yy", this.Birthdate.ToString("yy")); | |
| result = result.Replace("mm", this.Birthdate.ToString("MM")); | |
| result = result.Replace("m", this.Birthdate.ToString("M")); | |
| result = result.Replace("dd", string.Format("{0:D2}", this.IsCoordinationNumber ? this.BirthDay + 60 : this.BirthDay)); | |
| result = result.Replace("d", string.Format("{0}", this.IsCoordinationNumber ? this.BirthDay + 60 : this.BirthDay)); | |
| result = result.Replace("-", this.Age > 99 ? "+" : "-"); | |
| result = result.Replace("nnnn", string.Format(this.IsTemporaryNumber ? "TF{1}{2}" : "{0:D2}{1}{2}", this.CountyCode, this.GenderCode, this.Checksum)); | |
| return result; | |
| } | |
| #endregion | |
| #region Static Methods | |
| public static SwedishPersonalIdentityNumber Parse(string s) | |
| { | |
| return new SwedishPersonalIdentityNumber(s); | |
| } | |
| public static bool Validate(string s) | |
| { | |
| var match = Regex.Match(s.Trim(), RegexPattern); | |
| return match.Success; | |
| } | |
| #endregion | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment