Search code examples
c#.netregexasp.net-mvcregular-language

Swedish SSN Regular expression reject users under a specific age


I Have a problem with my regular expression. I have made it possible to valdiate correct swedish social security number to match these criteria.

  • YYMMDDNNNN
  • YYMMDD-NNNN
  • YYYYMMDDNNNN
  • YYYYMMDD-NNNN

But i would also like to reject a user to register if the user is under 18 years old. My reqular expression is looking like this at the moment: Do anyone encountered the same problem with the age range Swedish SSN?

  private const string RegExForValidation =
        @"^(\d{6}|\d{8})[-|(\s)]{0,1}\d{4}$";

UPDATE

 private const string RegExForValidation = @"^(?<date>\d{6}|\d{8})[-\s]?\d{4}$";
        string date = Regex.Match("19970918-1234", RegExForValidation).Groups["date"].Value;
        DateTime dt;

 [Required(ErrorMessage = "Du måste ange personnummer")]
        [RegularExpression(RegExForValidation, ErrorMessage = "Personnummer anges med 10 siffror (yymmddnnnn)")]
        public string PersonalIdentityNumber { get; set; }

Second Update

 public class ValidateOfAge : ValidationAttribute
{
    public bool IsOfAge(DateTime birthdate)
    {
        DateTime today = DateTime.Today;
        int age = today.Year - 18;
        if (birthdate.AddYears(birthdate.Year) < today.AddYears(-age))
            return false;
        else
            return true;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        string RegExForValidation = @"^(?<date>\d{6}|\d{8})[-\s]?\d{4}$";
        string date = Regex.Match((string)value, RegExForValidation).Groups["date"].Value;
        DateTime dt;
        if (DateTime.TryParseExact(date, new[] { "yyMMdd", "yyyyMMdd" }, CultureInfo.InvariantCulture, DateTimeStyles.None, out dt))
            if (IsOfAge(dt))
                return ValidationResult.Success;
        return new ValidationResult("Personnummer anges med 10 siffror (yymmddnnnn)");
    }
}

Solution

  • You need to get the birthdate from the SSN, parse to DateTime, and then compare with today's date.

    Here is the method checking if a person is of age:

    public bool IsOfAge(DateTime birthdate)
    {
        DateTime today = DateTime.Today;       // Calculating age...
        int age = today.Year - birthdate.Year;
        if (birthdate > today.AddYears(-age)) 
            age--;
        return age < 18 ? false : true;   // If the age is 18+ > true, else false.
    }
    

    And here is how you can use this:

    string RegExForValidation = @"^(?<date>\d{6}|\d{8})[-\s]?\d{4}$";
    string date = Regex.Match("19970918-1234", RegExForValidation).Groups["date"].Value;
    DateTime dt;
    if (DateTime.TryParseExact(date, new[] { "yyMMdd", "yyyyMMdd" }, new CultureInfo("sv-SE"), DateTimeStyles.None, out dt))
       Console.WriteLine(IsOfAge(dt));
    

    Note that [-|(\s)] matches a -, |, (, whitespace or ). I am sure you only want to match a hyphen or whitespace.

    I added a named capture to the regex and removed unnecessary symbols from the character class. Also, note that {0,1} is the same as ?.

    UPDATE

    To make it work in an MVC app, you need to implement a custom validator:

    [Required(ErrorMessage = "Du måste ange personnummer")]
    [ValidateOfAge]  // <---------------------------- HERE
    public string PersonalIdentityNumber { get; set; }
    

    And implement this as follows:

    public class ValidateOfAge: ValidationAttribute
    {
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {                 
            string RegExForValidation = @"^(?<date>\d{6}|\d{8})[-\s]?\d{4}$";
            string date = Regex.Match((string)value, RegExForValidation).Groups["date"].Value;
            DateTime dt;
            if (DateTime.TryParseExact(date, new[] { "yyMMdd", "yyyyMMdd" }, new CultureInfo("sv-SE"), DateTimeStyles.None, out dt))
                if (IsOfAge(dt))
                    return ValidationResult.Success;
            return new ValidationResult("Personnummer anges med 10 siffror (yymmddnnnn)");
        }
    }