Branch data TLA Line data Source code
1 : : // Copyright (c) 2014-2022 Thomas Fussell
2 : : // Copyright (c) 2010-2015 openpyxl
3 : : // Copyright (c) 2024-2025 xlnt-community
4 : : //
5 : : // Permission is hereby granted, free of charge, to any person obtaining a copy
6 : : // of this software and associated documentation files (the "Software"), to deal
7 : : // in the Software without restriction, including without limitation the rights
8 : : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : : // copies of the Software, and to permit persons to whom the Software is
10 : : // furnished to do so, subject to the following conditions:
11 : : //
12 : : // The above copyright notice and this permission notice shall be included in
13 : : // all copies or substantial portions of the Software.
14 : : //
15 : : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : : // THE SOFTWARE
22 : : //
23 : : // @license: http://www.opensource.org/licenses/mit-license.php
24 : : // @author: see AUTHORS file
25 : :
26 : : #include <cctype>
27 : : #include <unordered_map>
28 : : #include <vector>
29 : :
30 : : #include <xlnt/styles/number_format.hpp>
31 : : #include <xlnt/utils/datetime.hpp>
32 : : #include <xlnt/utils/exceptions.hpp>
33 : : #include <detail/number_format/number_formatter.hpp>
34 : :
35 : : namespace {
36 : :
37 :CBC 736 : const std::unordered_map<std::size_t, xlnt::number_format> &builtin_formats()
38 : : {
39 [ + + + - ]: 736 : static std::unordered_map<std::size_t, xlnt::number_format> formats;
40 : :
41 [ + + ]: 736 : if (formats.size() == 0)
42 : : {
43 : : const std::unordered_map<std::size_t, std::string> format_strings{
44 :UBC 0 : {0, "General"},
45 : 0 : {1, "0"},
46 : 0 : {2, "0.00"},
47 : 0 : {3, "#,##0"},
48 : 0 : {4, "#,##0.00"},
49 : 0 : {9, "0%"},
50 : 0 : {10, "0.00%"},
51 : 0 : {11, "0.00E+00"},
52 : 0 : {12, "# ?/?"},
53 : 0 : {13, "# \?\?/??"}, // escape trigraph
54 : 0 : {14, "mm-dd-yy"},
55 : 0 : {15, "d-mmm-yy"},
56 : 0 : {16, "d-mmm"},
57 : 0 : {17, "mmm-yy"},
58 : 0 : {18, "h:mm AM/PM"},
59 : 0 : {19, "h:mm:ss AM/PM"},
60 : 0 : {20, "h:mm"},
61 : 0 : {21, "h:mm:ss"},
62 : 0 : {22, "m/d/yy h:mm"},
63 : 0 : {37, "#,##0 ;(#,##0)"},
64 : 0 : {38, "#,##0 ;[Red](#,##0)"},
65 : 0 : {39, "#,##0.00;(#,##0.00)"},
66 : 0 : {40, "#,##0.00;[Red](#,##0.00)"},
67 : :
68 : : // 41-44 aren't in the ECMA 376 v4 standard, but Libre Office uses them
69 : 0 : {41, "_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)"},
70 : 0 : {42, "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)"},
71 : 0 : {43, "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)"},
72 : 0 : {44, "_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)"},
73 : :
74 : 0 : {45, "mm:ss"},
75 : 0 : {46, "[h]:mm:ss"},
76 : 0 : {47, "mmss.0"},
77 : 0 : {48, "##0.0E+0"},
78 [ + + + - :CBC 34 : {49, "@"}};
- ]
79 : :
80 [ + + + ]: 33 : for (auto format_string_pair : format_strings)
81 : : {
82 [ + ]: 32 : formats[format_string_pair.first] =
83 [ + ]: 64 : xlnt::number_format(format_string_pair.second, format_string_pair.first);
84 : 32 : }
85 : 1 : }
86 : :
87 : 736 : return formats;
88 [ + + + + : 1 : }
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + - -
- - ]
89 : :
90 : : } // namespace
91 : :
92 : : namespace xlnt {
93 : :
94 : 515 : const number_format number_format::general()
95 : : {
96 [ + + ]: 515 : return builtin_formats().at(0);
97 : : }
98 : :
99 : 1 : const number_format number_format::text()
100 : : {
101 [ + + ]: 1 : return builtin_formats().at(49);
102 : : }
103 : :
104 : 1 : const number_format number_format::number()
105 : : {
106 [ + + ]: 1 : return builtin_formats().at(1);
107 : : }
108 : :
109 : 1 : const number_format number_format::number_00()
110 : : {
111 [ + + ]: 1 : return builtin_formats().at(2);
112 : : }
113 : :
114 : 1 : const number_format number_format::number_comma_separated1()
115 : : {
116 [ + + ]: 1 : return builtin_formats().at(4);
117 : : }
118 : :
119 : 4 : const number_format number_format::percentage()
120 : : {
121 [ + + ]: 4 : return builtin_formats().at(9);
122 : : }
123 : :
124 : 1 : const number_format number_format::percentage_00()
125 : : {
126 [ + + ]: 1 : return builtin_formats().at(10);
127 : : }
128 : :
129 : 3 : const number_format number_format::date_yyyymmdd2()
130 : : {
131 [ + + + - : 5 : static const number_format format = number_format("yyyy-mm-dd");
+ + - - ]
132 : 3 : return format;
133 : : }
134 : :
135 : 1 : const number_format number_format::date_yymmdd()
136 : : {
137 [ + - + - : 3 : static const number_format format = number_format("yy-mm-dd");
+ + - - ]
138 : 1 : return format;
139 : : }
140 : :
141 : 6 : const number_format number_format::date_ddmmyyyy()
142 : : {
143 [ + + + - : 8 : static const number_format format = number_format("dd/mm/yy");
+ + - - ]
144 : 6 : return format;
145 : : }
146 : :
147 : 1 : const number_format number_format::date_dmyslash()
148 : : {
149 [ + - + - : 3 : static const number_format format = number_format("d/m/yy");
+ + - - ]
150 : 1 : return format;
151 : : }
152 : :
153 : 1 : const number_format number_format::date_dmyminus()
154 : : {
155 [ + - + - : 3 : static const number_format format = number_format("d-m-yy");
+ + - - ]
156 : 1 : return format;
157 : : }
158 : :
159 : 3 : const number_format number_format::date_dmminus()
160 : : {
161 [ + + + - : 5 : static const number_format format = number_format("d-m");
+ + - - ]
162 : 3 : return format;
163 : : }
164 : :
165 : 1 : const number_format number_format::date_myminus()
166 : : {
167 [ + - + - : 3 : static const number_format format = number_format("m-yy");
+ + - - ]
168 : 1 : return format;
169 : : }
170 : :
171 : 1 : const number_format number_format::date_xlsx14()
172 : : {
173 [ + + ]: 1 : return builtin_formats().at(14);
174 : : }
175 : :
176 : 1 : const number_format number_format::date_xlsx15()
177 : : {
178 [ + + ]: 1 : return builtin_formats().at(15);
179 : : }
180 : :
181 : 1 : const number_format number_format::date_xlsx16()
182 : : {
183 [ + + ]: 1 : return builtin_formats().at(16);
184 : : }
185 : :
186 : 1 : const number_format number_format::date_xlsx17()
187 : : {
188 [ + + ]: 1 : return builtin_formats().at(17);
189 : : }
190 : :
191 : 1 : const number_format number_format::date_xlsx22()
192 : : {
193 [ + + ]: 1 : return builtin_formats().at(22);
194 : : }
195 : :
196 : 7 : const number_format number_format::date_datetime()
197 : : {
198 [ + + + - : 9 : static const number_format format = number_format("yyyy-mm-dd h:mm:ss");
+ + - - ]
199 : 7 : return format;
200 : : }
201 : :
202 : 1 : const number_format number_format::date_time1()
203 : : {
204 [ + + ]: 1 : return builtin_formats().at(18);
205 : : }
206 : :
207 : 5 : const number_format number_format::date_time2()
208 : : {
209 [ + + ]: 5 : return builtin_formats().at(19);
210 : : }
211 : :
212 : 1 : const number_format number_format::date_time3()
213 : : {
214 [ + + ]: 1 : return builtin_formats().at(20);
215 : : }
216 : :
217 : 2 : const number_format number_format::date_time4()
218 : : {
219 [ + + ]: 2 : return builtin_formats().at(21);
220 : : }
221 : :
222 : 1 : const number_format number_format::date_time5()
223 : : {
224 [ + + ]: 1 : return builtin_formats().at(45);
225 : : }
226 : :
227 : 5 : const number_format number_format::date_time6()
228 : : {
229 [ + + ]: 5 : return builtin_formats().at(21);
230 : : }
231 : :
232 : 147 : number_format::number_format()
233 [ + + ]: 147 : : number_format("General", 0)
234 : : {
235 : 147 : }
236 : :
237 : 2 : number_format::number_format(std::size_t id)
238 : 2 : : number_format(from_builtin_id(id))
239 : : {
240 : 2 : }
241 : :
242 : 22 : number_format::number_format(const std::string &format_string)
243 [ + ]: 22 : : format_string_(format_string)
244 : : {
245 : 22 : }
246 : :
247 : 181 : number_format::number_format(const std::string &format, std::size_t id)
248 : : {
249 [ + ]: 181 : format_string(format, id);
250 : 181 : }
251 : :
252 : 32 : bool number_format::is_builtin_format(std::size_t builtin_id)
253 : : {
254 [ + + + ]: 32 : return builtin_formats().find(builtin_id) != builtin_formats().end();
255 : : }
256 : :
257 : 15 : const number_format &number_format::from_builtin_id(std::size_t builtin_id)
258 : : {
259 [ - + ]: 15 : if (!is_builtin_format(builtin_id))
260 : : {
261 [ # ]:UBC 0 : throw invalid_parameter();
262 : : }
263 : :
264 :CBC 15 : return builtin_formats().at(builtin_id);
265 : : }
266 : :
267 : 3589 : std::string number_format::format_string() const
268 : : {
269 : 3589 : return format_string_;
270 : : }
271 : :
272 : 113 : void number_format::format_string(const std::string &format_string)
273 : : {
274 : 113 : format_string_ = format_string;
275 : 113 : id_ = 0;
276 : :
277 [ + + + ]: 3674 : for (const auto &pair : builtin_formats())
278 : : {
279 [ + + + ]: 3576 : if (pair.second.format_string() == format_string)
280 : : {
281 [ + ]: 15 : id_ = pair.first;
282 : 15 : break;
283 : : }
284 : : }
285 : 113 : }
286 : :
287 : 181 : void number_format::format_string(const std::string &format_string, std::size_t id)
288 : : {
289 : 181 : format_string_ = format_string;
290 : 181 : id_ = id;
291 : 181 : }
292 : :
293 : 1758 : bool number_format::has_id() const
294 : : {
295 : 1758 : return id_.is_set();
296 : : }
297 : :
298 : 49 : void number_format::id(std::size_t id)
299 : : {
300 : 49 : id_ = id;
301 : 49 : }
302 : :
303 : 1213 : std::size_t number_format::id() const
304 : : {
305 [ + + ]: 1213 : if (!has_id())
306 : : {
307 [ + ]: 2 : throw invalid_attribute();
308 : : }
309 : :
310 : 1211 : return id_.get();
311 : : }
312 : :
313 : 4 : bool number_format::is_date_format() const
314 : : {
315 [ + ]: 4 : detail::number_format_parser p(format_string_);
316 [ + ]: 4 : p.parse();
317 [ + + ]: 4 : auto parsed = p.result();
318 : :
319 : 4 : bool any_datetime = false;
320 : 4 : bool any_timedelta = false;
321 : :
322 [ + + ]: 8 : for (const auto §ion : parsed)
323 : : {
324 [ + - ]: 4 : if (section.is_datetime)
325 : : {
326 : 4 : any_datetime = true;
327 : : }
328 : :
329 [ + + ]: 4 : if (section.is_timedelta)
330 : : {
331 : 1 : any_timedelta = true;
332 : : }
333 : : }
334 : :
335 [ + - + + ]: 8 : return any_datetime && !any_timedelta;
336 : 4 : }
337 : :
338 : 72 : std::string number_format::format(const std::string &text) const
339 : : {
340 [ + + ]: 72 : return detail::number_formatter(format_string_, calendar::windows_1900).format_text(text);
341 : : }
342 : :
343 : 218 : std::string number_format::format(double number, calendar base_date) const
344 : : {
345 [ + + ]: 218 : return detail::number_formatter(format_string_, base_date).format_number(number);
346 : : }
347 : :
348 : 40 : bool number_format::operator==(const number_format &other) const
349 : : {
350 : 40 : return format_string_ == other.format_string_;
351 : : }
352 : :
353 :UBC 0 : bool number_format::operator!=(const number_format &other) const
354 : : {
355 : 0 : return !(*this == other);
356 : : }
357 : :
358 : : } // namespace xlnt
|