1use crate::datatype::{Data, DataRef, ExcelDateTime, ExcelDateTimeType};
2
3#[derive(Debug, Clone, Copy, PartialEq)]
4pub enum CellFormat {
5 Other,
6 DateTime,
7 TimeDelta,
8}
9
10pub fn detect_custom_number_format(format: &str) -> CellFormat {
12 let mut escaped = false;
13 let mut is_quote = false;
14 let mut brackets = 0u8;
15 let mut prev = ' ';
16 let mut hms = false;
17 let mut ap = false;
18 for s in format.chars() {
19 match (s, escaped, is_quote, ap, brackets) {
20 (_, true, ..) => escaped = false, ('_' | '\\', ..) => escaped = true,
22 ('"', _, true, _, _) => is_quote = false,
23 (_, _, true, _, _) => (),
24 ('"', _, _, _, _) => is_quote = true,
25 (';', ..) => return CellFormat::Other, ('[', ..) => brackets += 1,
27 (']', .., 1) if hms => return CellFormat::TimeDelta, (']', ..) => brackets = brackets.saturating_sub(1),
29 ('a' | 'A', _, _, false, 0) => ap = true,
30 ('p' | 'm' | '/' | 'P' | 'M', _, _, true, 0) => return CellFormat::DateTime,
31 ('d' | 'm' | 'h' | 'y' | 's' | 'D' | 'M' | 'H' | 'Y' | 'S', _, _, false, 0) => {
32 return CellFormat::DateTime
33 }
34 _ => {
35 if hms && s.eq_ignore_ascii_case(&prev) {
36 } else {
38 hms = prev == '[' && matches!(s, 'm' | 'h' | 's' | 'M' | 'H' | 'S');
39 }
40 }
41 }
42 prev = s;
43 }
44 CellFormat::Other
45}
46
47pub fn builtin_format_by_id(id: &[u8]) -> CellFormat {
48 match id {
49 b"14" |
51 b"15" |
53 b"16" |
55 b"17" |
57 b"18" |
59 b"19" |
61 b"20" |
63 b"21" |
65 b"22" |
67 b"45" |
69 b"47" => CellFormat::DateTime,
71 b"46" => CellFormat::TimeDelta,
73 _ => CellFormat::Other
74}
75}
76
77pub fn builtin_format_by_code(code: u16) -> CellFormat {
81 match code {
82 14..=22 | 45 | 47 => CellFormat::DateTime,
83 46 => CellFormat::TimeDelta,
84 _ => CellFormat::Other,
85 }
86}
87
88pub fn format_excel_i64(value: i64, format: Option<&CellFormat>, is_1904: bool) -> Data {
90 match format {
91 Some(CellFormat::DateTime) => Data::DateTime(ExcelDateTime::new(
92 value as f64,
93 ExcelDateTimeType::DateTime,
94 is_1904,
95 )),
96 Some(CellFormat::TimeDelta) => Data::DateTime(ExcelDateTime::new(
97 value as f64,
98 ExcelDateTimeType::TimeDelta,
99 is_1904,
100 )),
101 _ => Data::Int(value),
102 }
103}
104
105#[inline]
107pub fn format_excel_f64_ref(
108 value: f64,
109 format: Option<&CellFormat>,
110 is_1904: bool,
111) -> DataRef<'static> {
112 match format {
113 Some(CellFormat::DateTime) => DataRef::DateTime(ExcelDateTime::new(
114 value,
115 ExcelDateTimeType::DateTime,
116 is_1904,
117 )),
118 Some(CellFormat::TimeDelta) => DataRef::DateTime(ExcelDateTime::new(
119 value,
120 ExcelDateTimeType::TimeDelta,
121 is_1904,
122 )),
123 _ => DataRef::Float(value),
124 }
125}
126
127pub fn format_excel_f64(value: f64, format: Option<&CellFormat>, is_1904: bool) -> Data {
129 format_excel_f64_ref(value, format, is_1904).into()
130}
131
132#[test]
135fn test_is_date_format() {
136 assert_eq!(
137 detect_custom_number_format("DD/MM/YY"),
138 CellFormat::DateTime
139 );
140 assert_eq!(
141 detect_custom_number_format("H:MM:SS;@"),
142 CellFormat::DateTime
143 );
144 assert_eq!(
145 detect_custom_number_format("#,##0\\ [$\\u20bd-46D]"),
146 CellFormat::Other
147 );
148 assert_eq!(
149 detect_custom_number_format("m\"M\"d\"D\";@"),
150 CellFormat::DateTime
151 );
152 assert_eq!(
153 detect_custom_number_format("[h]:mm:ss"),
154 CellFormat::TimeDelta
155 );
156 assert_eq!(
157 detect_custom_number_format("\"Y: \"0.00\"m\";\"Y: \"-0.00\"m\";\"Y: <num>m\";@"),
158 CellFormat::Other
159 );
160 assert_eq!(
161 detect_custom_number_format("#,##0\\ [$''u20bd-46D]"),
162 CellFormat::Other
163 );
164 assert_eq!(
165 detect_custom_number_format("\"$\"#,##0_);[Red](\"$\"#,##0)"),
166 CellFormat::Other
167 );
168 assert_eq!(
169 detect_custom_number_format("[$-404]e\"\\xfc\"m\"\\xfc\"d\"\\xfc\""),
170 CellFormat::DateTime
171 );
172 assert_eq!(
173 detect_custom_number_format("0_ ;[Red]\\-0\\ "),
174 CellFormat::Other
175 );
176 assert_eq!(detect_custom_number_format("\\Y000000"), CellFormat::Other);
177 assert_eq!(
178 detect_custom_number_format("#,##0.0####\" YMD\""),
179 CellFormat::Other
180 );
181 assert_eq!(detect_custom_number_format("[h]"), CellFormat::TimeDelta);
182 assert_eq!(detect_custom_number_format("[ss]"), CellFormat::TimeDelta);
183 assert_eq!(
184 detect_custom_number_format("[s].000"),
185 CellFormat::TimeDelta
186 );
187 assert_eq!(detect_custom_number_format("[m]"), CellFormat::TimeDelta);
188 assert_eq!(detect_custom_number_format("[mm]"), CellFormat::TimeDelta);
189 assert_eq!(
190 detect_custom_number_format("[Blue]\\+[h]:mm;[Red]\\-[h]:mm;[Green][h]:mm"),
191 CellFormat::TimeDelta
192 );
193 assert_eq!(
194 detect_custom_number_format("[>=100][Magenta][s].00"),
195 CellFormat::TimeDelta
196 );
197 assert_eq!(
198 detect_custom_number_format("[h]:mm;[=0]\\-"),
199 CellFormat::TimeDelta
200 );
201 assert_eq!(
202 detect_custom_number_format("[>=100][Magenta].00"),
203 CellFormat::Other
204 );
205 assert_eq!(
206 detect_custom_number_format("[>=100][Magenta]General"),
207 CellFormat::Other
208 );
209 assert_eq!(
210 detect_custom_number_format("ha/p\\\\m"),
211 CellFormat::DateTime
212 );
213 assert_eq!(
214 detect_custom_number_format("#,##0.00\\ _M\"H\"_);[Red]#,##0.00\\ _M\"S\"_)"),
215 CellFormat::Other
216 );
217}