Skip to main content

excel_cli/json_export/
converters.rs

1use chrono::{Duration, NaiveDate, NaiveDateTime};
2use serde_json::{json, Value};
3
4use crate::excel::{Cell, CellType, DataTypeInfo};
5
6// Convert Excel date number to ISO date string
7pub fn excel_date_to_iso_string(excel_date: f64) -> String {
8    let days = if excel_date > 59.0 {
9        excel_date - 1.0
10    } else {
11        excel_date
12    };
13
14    let base_date = NaiveDate::from_ymd_opt(1900, 1, 1).unwrap();
15    let whole_days = days.trunc() as i64;
16    let fractional_day = days.fract();
17
18    let date = base_date + Duration::days(whole_days - 1); // Subtract 1 because Excel day 1 is 1900-01-01
19
20    if fractional_day > 0.0 {
21        let seconds_in_day = 24.0 * 60.0 * 60.0;
22        let seconds = (fractional_day * seconds_in_day).round() as u32;
23
24        let hours = seconds / 3600;
25        let minutes = (seconds % 3600) / 60;
26        let secs = seconds % 60;
27
28        let datetime = NaiveDateTime::new(
29            date,
30            chrono::NaiveTime::from_hms_opt(hours, minutes, secs).unwrap(),
31        );
32
33        datetime.format("%Y-%m-%dT%H:%M:%S").to_string()
34    } else {
35        date.format("%Y-%m-%d").to_string()
36    }
37}
38
39// Process cell value based on its type
40pub fn process_cell_value(cell: &Cell) -> Value {
41    if cell.value.is_empty() {
42        return Value::Null;
43    }
44
45    if let Some(original_type) = &cell.original_type {
46        match original_type {
47            DataTypeInfo::Float(f) => {
48                if f.fract() == 0.0 {
49                    json!(f.trunc() as i64)
50                } else {
51                    json!(f)
52                }
53            }
54            DataTypeInfo::Int(i) => json!(i),
55            DataTypeInfo::DateTime(dt) => {
56                if *dt >= 0.0 {
57                    json!(excel_date_to_iso_string(*dt))
58                } else {
59                    json!(cell.value)
60                }
61            }
62            DataTypeInfo::DateTimeIso(s) => json!(s),
63            DataTypeInfo::Bool(b) => json!(b),
64            DataTypeInfo::Empty => Value::Null,
65            _ => json!(cell.value),
66        }
67    } else {
68        match cell.cell_type {
69            CellType::Number => {
70                if let Ok(num) = cell.value.parse::<f64>() {
71                    if num.fract() == 0.0 {
72                        json!(num.trunc() as i64)
73                    } else {
74                        json!(num)
75                    }
76                } else {
77                    json!(cell.value)
78                }
79            }
80            CellType::Boolean => {
81                if cell.value.to_lowercase() == "true" {
82                    json!(true)
83                } else if cell.value.to_lowercase() == "false" {
84                    json!(false)
85                } else {
86                    json!(cell.value)
87                }
88            }
89            CellType::Date => {
90                if let Ok(excel_date) = cell.value.parse::<f64>() {
91                    if excel_date >= 0.0 {
92                        json!(excel_date_to_iso_string(excel_date))
93                    } else {
94                        json!(cell.value)
95                    }
96                } else {
97                    json!(cell.value)
98                }
99            }
100            CellType::Empty => Value::Null,
101            _ => json!(cell.value), // Text, etc.
102        }
103    }
104}