Shared Rust kernels

ported/discount_bill_yearfrac_family

All modules · quoted at commit 9e1884369a67 of DnaCalc/DnaCalc. Comments are the source's own.

max_excel_serial · 3 lines · calc-func/src/ported/discount_bill_yearfrac_family.rs on GitHub
fn max_excel_serial() -> i64 {
    excel_serial_from_ymd(WorkbookDateSystem::System1900, 9999, 12, 31).unwrap() as i64
}

Used by 7 functions.

parse_basis · 17 lines · calc-func/src/ported/discount_bill_yearfrac_family.rs on GitHub
fn parse_basis(value: f64) -> Result<DayCountBasis, DiscountBillYearfracEvalError> {
    if !value.is_finite() {
        return Err(DiscountBillYearfracEvalError::Domain(
            WorksheetErrorCode::Num,
        ));
    }
    match value.trunc() as i64 {
        0 => Ok(DayCountBasis::Us30_360),
        1 => Ok(DayCountBasis::ActualActual),
        2 => Ok(DayCountBasis::Actual360),
        3 => Ok(DayCountBasis::Actual365),
        4 => Ok(DayCountBasis::European30_360),
        _ => Err(DiscountBillYearfracEvalError::Domain(
            WorksheetErrorCode::Num,
        )),
    }
}

Used by 4 functions.

parse_date_serial · 17 lines · calc-func/src/ported/discount_bill_yearfrac_family.rs on GitHub
fn parse_date_serial(value: f64, minimum: i64) -> Result<i64, DiscountBillYearfracEvalError> {
    if !value.is_finite() {
        return Err(DiscountBillYearfracEvalError::Domain(
            WorksheetErrorCode::Value,
        ));
    }
    let serial = value.trunc() as i64;
    if serial < minimum || serial > max_excel_serial() {
        return Err(DiscountBillYearfracEvalError::Domain(
            WorksheetErrorCode::Value,
        ));
    }
    ymd_from_excel_serial(WorkbookDateSystem::System1900, serial as f64).ok_or(
        DiscountBillYearfracEvalError::Domain(WorksheetErrorCode::Value),
    )?;
    Ok(serial)
}

Used by 7 functions.

actual_days · 3 lines · calc-func/src/ported/discount_bill_yearfrac_family.rs on GitHub
fn actual_days(start: i64, end: i64) -> f64 {
    (end - start) as f64
}

Used by 7 functions.

days360_us · 4 lines · calc-func/src/ported/discount_bill_yearfrac_family.rs on GitHub
fn days360_us(start: i64, end: i64) -> Result<f64, DiscountBillYearfracEvalError> {
    crate::ported::day_count_common::us_30_360(start, end)
        .map_err(DiscountBillYearfracEvalError::Domain)
}

Used by 4 functions.

days360_eu · 17 lines · calc-func/src/ported/discount_bill_yearfrac_family.rs on GitHub
fn days360_eu(start: i64, end: i64) -> Result<f64, DiscountBillYearfracEvalError> {
    let (sy, sm, mut sd) = ymd_from_excel_serial(WorkbookDateSystem::System1900, start as f64)
        .ok_or(DiscountBillYearfracEvalError::Domain(
            WorksheetErrorCode::Value,
        ))?;
    let (ey, em, mut ed) = ymd_from_excel_serial(WorkbookDateSystem::System1900, end as f64)
        .ok_or(DiscountBillYearfracEvalError::Domain(
            WorksheetErrorCode::Value,
        ))?;
    if sd == 31 {
        sd = 30;
    }
    if ed == 31 {
        ed = 30;
    }
    Ok(((ey - sy) * 360 + (em - sm) * 30 + (ed - sd)) as f64)
}

Used by 4 functions.

security_days_and_year · 26 lines · calc-func/src/ported/discount_bill_yearfrac_family.rs on GitHub
/// The security's day count as the pair (days `D`, year basis `B`), whose quotient is
/// [`security_fraction`]: DISC, INTRATE, RECEIVED and PRICEDISC use the two apart (dc-j9k).
fn security_days_and_year(
    settlement: f64,
    maturity: f64,
    basis: Option<f64>,
) -> Result<(f64, f64), DiscountBillYearfracEvalError> {
    let settlement = parse_date_serial(settlement, 1)?;
    let maturity = parse_date_serial(maturity, 1)?;
    let basis = parse_basis(basis.unwrap_or(0.0))?;
    if settlement >= maturity {
        return Err(DiscountBillYearfracEvalError::Domain(
            WorksheetErrorCode::Num,
        ));
    }
    match basis {
        DayCountBasis::Us30_360 => Ok((days360_us(settlement, maturity)?, 360.0)),
        DayCountBasis::ActualActual => {
            crate::ported::day_count_common::excel_actual_actual_year(settlement, maturity)
                .map_err(DiscountBillYearfracEvalError::Domain)
        }
        DayCountBasis::Actual360 => Ok((actual_days(settlement, maturity), 360.0)),
        DayCountBasis::Actual365 => Ok((actual_days(settlement, maturity), 365.0)),
        DayCountBasis::European30_360 => Ok((days360_eu(settlement, maturity)?, 360.0)),
    }
}

Used by 4 functions.

tbill_days · 23 lines · calc-func/src/ported/discount_bill_yearfrac_family.rs on GitHub
fn tbill_days(settlement: f64, maturity: f64) -> Result<f64, DiscountBillYearfracEvalError> {
    let settlement = parse_date_serial(settlement, 0)?;
    let maturity = parse_date_serial(maturity, 0)?;
    if settlement >= maturity {
        return Err(DiscountBillYearfracEvalError::Domain(
            WorksheetErrorCode::Num,
        ));
    }
    // "More than one year after settlement" is DATE(year+1, month, day) with Excel's day
    // rollover, not a month-end-clamped add: from 2044-02-29 the limit is 2045-03-01, and from
    // 1991-02-28 it is 1992-02-28 (live Excel 20430, W111-5 G8-02/G8-03).
    let num = || DiscountBillYearfracEvalError::Domain(WorksheetErrorCode::Num);
    let (year, month, day) =
        ymd_from_excel_serial(WorkbookDateSystem::System1900, settlement as f64).ok_or_else(num)?;
    let one_year_out = excel_serial_from_ymd(WorkbookDateSystem::System1900, year + 1, month, day)
        .ok_or_else(num)? as i64;
    if maturity > one_year_out {
        return Err(DiscountBillYearfracEvalError::Domain(
            WorksheetErrorCode::Num,
        ));
    }
    Ok(actual_days(settlement, maturity))
}

Used by 3 functions.

map_discount_bill_yearfrac_error_to_ws · 8 lines · calc-func/src/ported/discount_bill_yearfrac_family.rs on GitHub
pub fn map_discount_bill_yearfrac_error_to_ws(
    error: &DiscountBillYearfracEvalError,
) -> WorksheetErrorCode {
    match error {
        DiscountBillYearfracEvalError::ArityMismatch { .. } => WorksheetErrorCode::Value,
        DiscountBillYearfracEvalError::Domain(code) => *code,
    }
}

Used by 7 functions.