baltic-id 0.0.2

Baltic ID-Card, Smart-ID & Mobile-ID Api client library for Rust
Documentation
use chrono::{DateTime, NaiveDate, NaiveTime, TimeZone, Utc};

use crate::smart_id::errors::SmartIdError;
use crate::smart_id::errors::SmartIdError::UnprocessableSmartIdResponseException;
use crate::smart_id::models::AuthenticationIdentity;

pub struct NationalIdentityNumber;

impl NationalIdentityNumber {
    pub fn new() -> NationalIdentityNumber {
        NationalIdentityNumber {}
    }

    pub fn get_date_of_birth(
        &self,
        authentication_identity: &AuthenticationIdentity,
    ) -> Result<Option<DateTime<Utc>>, SmartIdError> {
        let identity_number = authentication_identity.get_identity_code();
        match authentication_identity
            .get_country()
            .to_uppercase()
            .as_str()
        {
            "EE" | "LT" => self.parse_ee_lt_date_of_birth(identity_number),
            "LV" => self.parse_lv_date_of_birth(identity_number),
            _ => Err(UnprocessableSmartIdResponseException(format!(
                "Unknown country: {}",
                authentication_identity.get_country()
            ))),
        }
    }

    fn parse_ee_lt_date_of_birth(
        &self,
        ee_or_lt_national_identity_number: &str,
    ) -> Result<Option<DateTime<Utc>>, SmartIdError> {
        let birth_day = &ee_or_lt_national_identity_number[5..7];
        let birth_month = &ee_or_lt_national_identity_number[3..5];
        let birth_year_two_digit = &ee_or_lt_national_identity_number[1..3];
        let birth_year_four_digit = match &ee_or_lt_national_identity_number[..1] {
            "1" | "2" => format!("18{}", birth_year_two_digit),
            "3" | "4" => format!("19{}", birth_year_two_digit),
            "5" | "6" => format!("20{}", birth_year_two_digit),
            _ => {
                return Err(UnprocessableSmartIdResponseException(format!(
                    "Invalid personal code {}",
                    ee_or_lt_national_identity_number
                )));
            }
        };

        let date = NaiveDate::from_ymd_opt(
            birth_year_four_digit.parse::<i32>().unwrap(),
            birth_month.parse::<u32>().unwrap(),
            birth_day.parse::<u32>().unwrap(),
        )
            .unwrap();
        let datetime =
            Utc.from_utc_datetime(&date.and_time(NaiveTime::from_hms_opt(0, 0, 0).unwrap()));
        Ok(Some(datetime))
    }

    fn parse_lv_date_of_birth(
        &self,
        lv_national_identity_number: &str,
    ) -> Result<Option<DateTime<Utc>>, SmartIdError> {
        let birth_day = &lv_national_identity_number[0..2];
        if birth_day == "32" {
            return Ok(None);
        }

        let birth_month = &lv_national_identity_number[2..4];
        let birth_year_two_digit = &lv_national_identity_number[4..6];
        let century = &lv_national_identity_number[7..8];
        let birth_year_four_digit = match century {
            "0" => format!("18{}", birth_year_two_digit),
            "1" => format!("19{}", birth_year_two_digit),
            "2" => format!("20{}", birth_year_two_digit),
            _ => {
                return Err(UnprocessableSmartIdResponseException(format!(
                    "Invalid personal code: {}",
                    lv_national_identity_number
                )));
            }
        };

        let date = NaiveDate::from_ymd_opt(
            birth_year_four_digit.parse::<i32>().unwrap(),
            birth_month.parse::<u32>().unwrap(),
            birth_day.parse::<u32>().unwrap(),
        )
            .unwrap();
        let datetime =
            Utc.from_utc_datetime(&date.and_time(NaiveTime::from_hms_opt(0, 0, 0).unwrap()));
        Ok(Some(datetime))
    }
}