• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

xlnt-community / xlnt / b5325487-b953-4fb3-ae7c-12335ef12dcb

02 Feb 2025 07:13PM UTC coverage: 81.7% (-1.8%) from 83.482%
b5325487-b953-4fb3-ae7c-12335ef12dcb

Pull #55

circleci

doomlaur
Fix CI to use the correct Docker image for code coverage tests
Pull Request #55: Add support for C++20 and C++23, and experimental support for C++26

78 of 142 new or added lines in 8 files covered. (54.93%)

304 existing lines in 28 files now uncovered.

11460 of 14027 relevant lines covered (81.7%)

1191795.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.27
./source/styles/number_format.cpp
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 <algorithm>
27
#include <cctype>
28
#include <unordered_map>
29
#include <vector>
30

31
#include <xlnt/styles/number_format.hpp>
32
#include <xlnt/utils/datetime.hpp>
33
#include <xlnt/utils/exceptions.hpp>
34
#include <detail/number_format/number_formatter.hpp>
35

36
namespace {
37

38
const std::unordered_map<std::size_t, xlnt::number_format> &builtin_formats()
760✔
39
{
40
    static std::unordered_map<std::size_t, xlnt::number_format> formats;
760✔
41

42
    if (formats.size() == 0)
760✔
43
    {
44
        const std::unordered_map<std::size_t, std::string> format_strings{
UNCOV
45
            {0, "General"},
×
UNCOV
46
            {1, "0"},
×
UNCOV
47
            {2, "0.00"},
×
UNCOV
48
            {3, "#,##0"},
×
UNCOV
49
            {4, "#,##0.00"},
×
UNCOV
50
            {9, "0%"},
×
UNCOV
51
            {10, "0.00%"},
×
UNCOV
52
            {11, "0.00E+00"},
×
UNCOV
53
            {12, "# ?/?"},
×
UNCOV
54
            {13, "# \?\?/??"}, // escape trigraph
×
UNCOV
55
            {14, "mm-dd-yy"},
×
UNCOV
56
            {15, "d-mmm-yy"},
×
UNCOV
57
            {16, "d-mmm"},
×
UNCOV
58
            {17, "mmm-yy"},
×
UNCOV
59
            {18, "h:mm AM/PM"},
×
UNCOV
60
            {19, "h:mm:ss AM/PM"},
×
UNCOV
61
            {20, "h:mm"},
×
UNCOV
62
            {21, "h:mm:ss"},
×
UNCOV
63
            {22, "m/d/yy h:mm"},
×
UNCOV
64
            {37, "#,##0 ;(#,##0)"},
×
UNCOV
65
            {38, "#,##0 ;[Red](#,##0)"},
×
UNCOV
66
            {39, "#,##0.00;(#,##0.00)"},
×
UNCOV
67
            {40, "#,##0.00;[Red](#,##0.00)"},
×
68

69
            // 41-44 aren't in the ECMA 376 v4 standard, but Libre Office uses them
UNCOV
70
            {41, "_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)"},
×
UNCOV
71
            {42, "_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)"},
×
UNCOV
72
            {43, "_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)"},
×
UNCOV
73
            {44, "_(\"$\"* #,##0.00_)_(\"$\"* \\(#,##0.00\\)_(\"$\"* \"-\"??_)_(@_)"},
×
74

UNCOV
75
            {45, "mm:ss"},
×
UNCOV
76
            {46, "[h]:mm:ss"},
×
UNCOV
77
            {47, "mmss.0"},
×
UNCOV
78
            {48, "##0.0E+0"},
×
79
            {49, "@"}};
238✔
80

81
        for (auto format_string_pair : format_strings)
231✔
82
        {
83
            formats[format_string_pair.first] =
224✔
84
                xlnt::number_format(format_string_pair.second, format_string_pair.first);
448✔
85
        }
224✔
86
    }
7✔
87

88
    return formats;
760✔
89
}
7✔
90

91
} // namespace
92

93
namespace xlnt {
94

95
const number_format number_format::general()
529✔
96
{
97
    return builtin_formats().at(0);
529✔
98
}
99

100
const number_format number_format::text()
1✔
101
{
102
    return builtin_formats().at(49);
1✔
103
}
104

105
const number_format number_format::number()
1✔
106
{
107
    return builtin_formats().at(1);
1✔
108
}
109

110
const number_format number_format::number_00()
1✔
111
{
112
    return builtin_formats().at(2);
1✔
113
}
114

115
const number_format number_format::number_comma_separated1()
1✔
116
{
117
    return builtin_formats().at(4);
1✔
118
}
119

120
const number_format number_format::percentage()
5✔
121
{
122
    return builtin_formats().at(9);
5✔
123
}
124

125
const number_format number_format::percentage_00()
1✔
126
{
127
    return builtin_formats().at(10);
1✔
128
}
129

130
const number_format number_format::date_yyyymmdd2()
3✔
131
{
132
    static const number_format format = number_format("yyyy-mm-dd");
5✔
133
    return format;
3✔
134
}
135

136
const number_format number_format::date_yymmdd()
1✔
137
{
138
    static const number_format format = number_format("yy-mm-dd");
3✔
139
    return format;
1✔
140
}
141

142
const number_format number_format::date_ddmmyyyy()
6✔
143
{
144
    static const number_format format = number_format("dd/mm/yy");
8✔
145
    return format;
6✔
146
}
147

148
const number_format number_format::date_dmyslash()
1✔
149
{
150
    static const number_format format = number_format("d/m/yy");
3✔
151
    return format;
1✔
152
}
153

154
const number_format number_format::date_dmyminus()
1✔
155
{
156
    static const number_format format = number_format("d-m-yy");
3✔
157
    return format;
1✔
158
}
159

160
const number_format number_format::date_dmminus()
3✔
161
{
162
    static const number_format format = number_format("d-m");
5✔
163
    return format;
3✔
164
}
165

166
const number_format number_format::date_myminus()
1✔
167
{
168
    static const number_format format = number_format("m-yy");
3✔
169
    return format;
1✔
170
}
171

172
const number_format number_format::date_xlsx14()
1✔
173
{
174
    return builtin_formats().at(14);
1✔
175
}
176

177
const number_format number_format::date_xlsx15()
1✔
178
{
179
    return builtin_formats().at(15);
1✔
180
}
181

182
const number_format number_format::date_xlsx16()
1✔
183
{
184
    return builtin_formats().at(16);
1✔
185
}
186

187
const number_format number_format::date_xlsx17()
1✔
188
{
189
    return builtin_formats().at(17);
1✔
190
}
191

192
const number_format number_format::date_xlsx22()
1✔
193
{
194
    return builtin_formats().at(22);
1✔
195
}
196

197
const number_format number_format::date_datetime()
7✔
198
{
199
    static const number_format format = number_format("yyyy-mm-dd h:mm:ss");
9✔
200
    return format;
7✔
201
}
202

203
const number_format number_format::date_time1()
1✔
204
{
205
    return builtin_formats().at(18);
1✔
206
}
207

208
const number_format number_format::date_time2()
5✔
209
{
210
    return builtin_formats().at(19);
5✔
211
}
212

213
const number_format number_format::date_time3()
1✔
214
{
215
    return builtin_formats().at(20);
1✔
216
}
217

218
const number_format number_format::date_time4()
2✔
219
{
220
    return builtin_formats().at(21);
2✔
221
}
222

223
const number_format number_format::date_time5()
1✔
224
{
225
    return builtin_formats().at(45);
1✔
226
}
227

228
const number_format number_format::date_time6()
5✔
229
{
230
    return builtin_formats().at(21);
5✔
231
}
232

233
number_format::number_format()
360✔
234
    : number_format("General", 0)
360✔
235
{
236
}
360✔
237

238
number_format::number_format(std::size_t id)
2✔
239
    : number_format(from_builtin_id(id))
2✔
240
{
241
}
2✔
242

243
number_format::number_format(const std::string &format_string)
22✔
244
    : format_string_(format_string)
22✔
245
{
246
}
22✔
247

248
number_format::number_format(const std::string &format, std::size_t id)
586✔
249
{
250
    format_string(format, id);
586✔
251
}
586✔
252

253
bool number_format::is_builtin_format(std::size_t builtin_id)
32✔
254
{
255
    return builtin_formats().find(builtin_id) != builtin_formats().end();
32✔
256
}
257

258
const number_format &number_format::from_builtin_id(std::size_t builtin_id)
15✔
259
{
260
    if (!is_builtin_format(builtin_id))
15✔
261
    {
262
        throw invalid_parameter();
×
263
    }
264

265
    return builtin_formats().at(builtin_id);
15✔
266
}
267

268
std::string number_format::format_string() const
3,883✔
269
{
270
    return format_string_;
3,883✔
271
}
272

273
void number_format::format_string(const std::string &format_string)
122✔
274
{
275
    format_string_ = format_string;
122✔
276
    id_ = 0;
122✔
277

278
    for (const auto &pair : builtin_formats())
3,965✔
279
    {
280
        if (pair.second.format_string() == format_string)
3,860✔
281
        {
282
            id_ = pair.first;
17✔
283
            break;
17✔
284
        }
285
    }
286
}
122✔
287

288
void number_format::format_string(const std::string &format_string, std::size_t id)
586✔
289
{
290
    format_string_ = format_string;
586✔
291
    id_ = id;
586✔
292
}
586✔
293

294
bool number_format::has_id() const
2,886✔
295
{
296
    return id_.is_set();
2,886✔
297
}
298

299
void number_format::id(std::size_t id)
58✔
300
{
301
    id_ = id;
58✔
302
}
58✔
303

304
std::size_t number_format::id() const
2,071✔
305
{
306
    if (!has_id())
2,071✔
307
    {
308
        throw invalid_attribute();
2✔
309
    }
310

311
    return id_.get();
2,069✔
312
}
313

314
bool number_format::is_date_format() const
4✔
315
{
316
    detail::number_format_parser p(format_string_);
4✔
317
    p.parse();
4✔
318
    auto parsed = p.result();
4✔
319

320
    bool any_datetime = false;
4✔
321
    bool any_timedelta = false;
4✔
322

323
    for (const auto &section : parsed)
8✔
324
    {
325
        if (section.is_datetime)
4✔
326
        {
327
            any_datetime = true;
4✔
328
        }
329

330
        if (section.is_timedelta)
4✔
331
        {
332
            any_timedelta = true;
1✔
333
        }
334
    }
335

336
    return any_datetime && !any_timedelta;
8✔
337
}
4✔
338

339
std::string number_format::format(const std::string &text) const
84✔
340
{
341
    return detail::number_formatter(format_string_, calendar::windows_1900).format_text(text);
84✔
342
}
343

344
std::string number_format::format(double number, calendar base_date) const
219✔
345
{
346
    return detail::number_formatter(format_string_, base_date).format_number(number);
219✔
347
}
348

349
bool number_format::operator==(const number_format &other) const
35✔
350
{
351
    return format_string_ == other.format_string_;
35✔
352
}
353

354
bool number_format::operator!=(const number_format &other) const
×
355
{
356
    return !(*this == other);
×
357
}
358

359
} // namespace xlnt
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc