All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.datafaker.idnumbers.SwedenIdNumber Maven / Gradle / Ivy

package net.datafaker.idnumbers;

import net.datafaker.providers.base.BaseProviders;

import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;

/**
 * Implementation based on the definition at
 * https://www.skatteverket.se/privat/folkbokforing/personnummer.4.3810a01c150939e893f18c29.html
 * and the description at
 * https://en.wikipedia.org/wiki/Personal_identity_number_(Sweden)
 */
public class SwedenIdNumber implements IdNumberGenerator {
    @Override
    public String countryCode() {
        return "SE";
    }

    private static final String[] VALID_PATTERNS = {"######-####", "######+####"};
    private static final String[] PLUS_MINUS = {"+", "-"};

    @Deprecated
    public String getValidSsn(BaseProviders f) {
        return generateValid(f);
    }

    @Override
    public String generateValid(BaseProviders f) {
        String end = f.numerify("###");
        String candidate = DATE_TIME_FORMATTER.format(f.timeAndDate().birthday(0, 100))
            + f.options().option(PLUS_MINUS)
            + end;
        return candidate + calculateChecksum(candidate);
    }

    @Deprecated
    public String getInvalidSsn(BaseProviders f) {
        return generateInvalid(f);
    }

    @Override
    public String generateInvalid(BaseProviders f) {
        String candidate = "121212-1212"; // Seed with a valid number
        while (isValidSwedishSsn(candidate)) {
            String pattern = getPattern(f);
            candidate = f.numerify(pattern);
        }

        return candidate;
    }

    private String getPattern(BaseProviders faker) {
        return faker.options().option(VALID_PATTERNS);
    }

    public static boolean isValidSwedishSsn(String ssn) {
        if (ssn.length() != 11) {
            return false;
        }

        try {
            if (parseDate(ssn)) {
                return false;
            }
        } catch (DateTimeParseException | NumberFormatException ignore) {
            return false;
        }

        int calculatedChecksum = calculateChecksum(ssn);
        int checksum = Integer.parseInt(ssn.substring(10, 11));
        return checksum == calculatedChecksum;
    }

    private static boolean parseDate(String ssn) {
        String dateString = ssn.substring(0, 6);
        if (ChronoField.YEAR.range().isValidIntValue(Integer.parseInt(dateString.substring(0, 2)))) {
            if (ChronoField.MONTH_OF_YEAR.range().isValidIntValue(Integer.parseInt(dateString.substring(2, 4)))) {
                if (ChronoField.DAY_OF_MONTH.range().isValidIntValue(Integer.parseInt(dateString.substring(4)))) {
                    LocalDate date = LocalDate.parse(dateString, DATE_TIME_FORMATTER);
                    // want to check that the parsed date is equal to the supplied data, most of the attempts will fail
                    String reversed = date.format(DATE_TIME_FORMATTER);
                    return !reversed.equals(dateString);
                }
            }
        }
        return true;
    }

    private static int calculateChecksum(String number) {
        String dateString = number.substring(0, 6);
        String birthNumber = number.substring(7, 10);

        String calculatedNumber = calculateDigits(dateString + birthNumber);
        int sum = calculateDigitSum(calculatedNumber);

        int lastDigit = (sum % 10);
        int difference = 10 - lastDigit;

        return (difference % 10);
    }

    private static String calculateDigits(String numbers) {
        StringBuilder calculatedNumbers = new StringBuilder();
        for (int i = 0; i < 9; i++) {
            int res;
            int n = numbers.charAt(i) - '0';
            if (i % 2 == 0) {
                res = n << 1;
            } else {
                res = n;
            }

            calculatedNumbers.append(res);
        }
        return calculatedNumbers.toString();
    }

    private static int calculateDigitSum(String numbers) {
        int sum = 0;
        final int length = numbers.length();
        for (int i = 0; i < length; i++) {
            int n = numbers.charAt(i) - '0';
            sum += n;
        }
        return sum;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy