karo 0.1.2

Spreadsheet export
Documentation
#[cfg(test)]
mod tests;

use chrono::{DateTime, Utc};

pub(crate) trait AsPaletteColor {
    fn as_palette_color(&self) -> String;
}

impl AsPaletteColor for rgb::RGB8 {
    fn as_palette_color(&self) -> String {
        format!("FF{:02X}{:02X}{:02X}", self.r, self.g, self.b)
    }
}

#[derive(Copy, Clone, Debug)]
pub(crate) enum DateMode {
    BasedOn1900,
    BasedOn1904,
}

pub(crate) trait AsExcelDate {
    fn as_excel_date(&self, mode: DateMode) -> f64;
}

impl AsExcelDate for DateTime<Utc> {
    fn as_excel_date(&self, mode: DateMode) -> f64 {
        // See libxlsxwriter lxw_datetime_to_excel_date()
        // TODO: needs to be refined to match the excel functionality

        use chrono::{Datelike, Timelike};
        let year = self.year();
        let month = self.month0();
        let day = self.day();
        let subsec =
            self.nanosecond() as f64 * 0.001f64 * 0.001f64 * 0.001f64;
        let norm = 300;

        let leap = year % 4 == 0 && (year % 100 > 0 || year % 400 == 0);
        let mdays: [i32; 12] = [
            31,
            if leap { 29 } else { 28 },
            31,
            30,
            31,
            30,
            31,
            31,
            30,
            31,
            30,
            31,
        ];
        // Convert the excel seconds to a fraction of the seconds
        // in 24 hours.
        let seconds = (self.num_seconds_from_midnight() as f64 + subsec)
            / (24f64 * 60f64 * 60f64);

        let leap = if leap { 1 } else { 0 };
        let range = year - 1900;
        let days: i32 = mdays.iter().take(month as usize).sum();
        let mut days = days + day as i32 + range * 365 + range / 4
            - range / 100
            + (range + norm) / 400
            - leap;
        // adjust for excel erroneously treating 1900 as a leap year
        if days > 59 {
            days += 1;
        }
        days as f64 + seconds
    }
}