use crate::datatype::{Data, DataRef, ExcelDateTime, ExcelDateTimeType};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CellFormat {
Other,
DateTime,
TimeDelta,
}
pub fn detect_custom_number_format(format: &str) -> CellFormat {
let mut escaped = false;
let mut is_quote = false;
let mut brackets = 0u8;
let mut prev = ' ';
let mut hms = false;
let mut ap = false;
for s in format.chars() {
match (s, escaped, is_quote, ap, brackets) {
(_, true, ..) => escaped = false, ('_' | '\\', ..) => escaped = true,
('"', _, true, _, _) => is_quote = false,
(_, _, true, _, _) => (),
('"', _, _, _, _) => is_quote = true,
(';', ..) => return CellFormat::Other, ('[', ..) => brackets += 1,
(']', .., 1) if hms => return CellFormat::TimeDelta, (']', ..) => brackets = brackets.saturating_sub(1),
('a' | 'A', _, _, false, 0) => ap = true,
('p' | 'm' | '/' | 'P' | 'M', _, _, true, 0) => return CellFormat::DateTime,
('d' | 'm' | 'h' | 'y' | 's' | 'D' | 'M' | 'H' | 'Y' | 'S', _, _, false, 0) => {
return CellFormat::DateTime
}
_ => {
if hms && s.eq_ignore_ascii_case(&prev) {
} else {
hms = prev == '[' && matches!(s, 'm' | 'h' | 's' | 'M' | 'H' | 'S');
}
}
}
prev = s;
}
CellFormat::Other
}
pub fn builtin_format_by_id(id: &[u8]) -> CellFormat {
match id {
b"14" |
b"15" |
b"16" |
b"17" |
b"18" |
b"19" |
b"20" |
b"21" |
b"22" |
b"45" |
b"47" => CellFormat::DateTime,
b"46" => CellFormat::TimeDelta,
_ => CellFormat::Other
}
}
pub fn builtin_format_by_code(code: u16) -> CellFormat {
match code {
14..=22 | 45 | 47 => CellFormat::DateTime,
46 => CellFormat::TimeDelta,
_ => CellFormat::Other,
}
}
pub fn format_excel_i64(value: i64, format: Option<&CellFormat>, is_1904: bool) -> Data {
match format {
Some(CellFormat::DateTime) => Data::DateTime(ExcelDateTime::new(
value as f64,
ExcelDateTimeType::DateTime,
is_1904,
)),
Some(CellFormat::TimeDelta) => Data::DateTime(ExcelDateTime::new(
value as f64,
ExcelDateTimeType::TimeDelta,
is_1904,
)),
_ => Data::Int(value),
}
}
#[inline]
pub fn format_excel_f64_ref(
value: f64,
format: Option<&CellFormat>,
is_1904: bool,
) -> DataRef<'static> {
match format {
Some(CellFormat::DateTime) => DataRef::DateTime(ExcelDateTime::new(
value,
ExcelDateTimeType::DateTime,
is_1904,
)),
Some(CellFormat::TimeDelta) => DataRef::DateTime(ExcelDateTime::new(
value,
ExcelDateTimeType::TimeDelta,
is_1904,
)),
_ => DataRef::Float(value),
}
}
pub fn format_excel_f64(value: f64, format: Option<&CellFormat>, is_1904: bool) -> Data {
format_excel_f64_ref(value, format, is_1904).into()
}
#[test]
fn test_is_date_format() {
assert_eq!(
detect_custom_number_format("DD/MM/YY"),
CellFormat::DateTime
);
assert_eq!(
detect_custom_number_format("H:MM:SS;@"),
CellFormat::DateTime
);
assert_eq!(
detect_custom_number_format("#,##0\\ [$\\u20bd-46D]"),
CellFormat::Other
);
assert_eq!(
detect_custom_number_format("m\"M\"d\"D\";@"),
CellFormat::DateTime
);
assert_eq!(
detect_custom_number_format("[h]:mm:ss"),
CellFormat::TimeDelta
);
assert_eq!(
detect_custom_number_format("\"Y: \"0.00\"m\";\"Y: \"-0.00\"m\";\"Y: <num>m\";@"),
CellFormat::Other
);
assert_eq!(
detect_custom_number_format("#,##0\\ [$''u20bd-46D]"),
CellFormat::Other
);
assert_eq!(
detect_custom_number_format("\"$\"#,##0_);[Red](\"$\"#,##0)"),
CellFormat::Other
);
assert_eq!(
detect_custom_number_format("[$-404]e\"\\xfc\"m\"\\xfc\"d\"\\xfc\""),
CellFormat::DateTime
);
assert_eq!(
detect_custom_number_format("0_ ;[Red]\\-0\\ "),
CellFormat::Other
);
assert_eq!(detect_custom_number_format("\\Y000000"), CellFormat::Other);
assert_eq!(
detect_custom_number_format("#,##0.0####\" YMD\""),
CellFormat::Other
);
assert_eq!(detect_custom_number_format("[h]"), CellFormat::TimeDelta);
assert_eq!(detect_custom_number_format("[ss]"), CellFormat::TimeDelta);
assert_eq!(
detect_custom_number_format("[s].000"),
CellFormat::TimeDelta
);
assert_eq!(detect_custom_number_format("[m]"), CellFormat::TimeDelta);
assert_eq!(detect_custom_number_format("[mm]"), CellFormat::TimeDelta);
assert_eq!(
detect_custom_number_format("[Blue]\\+[h]:mm;[Red]\\-[h]:mm;[Green][h]:mm"),
CellFormat::TimeDelta
);
assert_eq!(
detect_custom_number_format("[>=100][Magenta][s].00"),
CellFormat::TimeDelta
);
assert_eq!(
detect_custom_number_format("[h]:mm;[=0]\\-"),
CellFormat::TimeDelta
);
assert_eq!(
detect_custom_number_format("[>=100][Magenta].00"),
CellFormat::Other
);
assert_eq!(
detect_custom_number_format("[>=100][Magenta]General"),
CellFormat::Other
);
assert_eq!(
detect_custom_number_format("ha/p\\\\m"),
CellFormat::DateTime
);
assert_eq!(
detect_custom_number_format("#,##0.00\\ _M\"H\"_);[Red]#,##0.00\\ _M\"S\"_)"),
CellFormat::Other
);
}