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