• 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

91.55
./source/utils/time.cpp
1
// Copyright (c) 2014-2022 Thomas Fussell
2
// Copyright (c) 2024-2025 xlnt-community
3
//
4
// Permission is hereby granted, free of charge, to any person obtaining a copy
5
// of this software and associated documentation files (the "Software"), to deal
6
// in the Software without restriction, including without limitation the rights
7
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
// copies of the Software, and to permit persons to whom the Software is
9
// furnished to do so, subject to the following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included in
12
// all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
// THE SOFTWARE
21
//
22
// @license: http://www.opensource.org/licenses/mit-license.php
23
// @author: see AUTHORS file
24
#include <cmath>
25
#include <cstdint>
26
#include <ctime>
27

28
#include <xlnt/utils/time.hpp>
29
#include <detail/time_helpers.hpp>
30
#include <detail/serialization/parsers.hpp>
31

32
namespace xlnt {
33

34
time time::from_number(double raw_time)
50✔
35
{
36
    time result;
50✔
37

38
    double integer_part;
39
    double fractional_part = std::modf(static_cast<double>(raw_time), &integer_part);
50✔
40

41
    fractional_part *= 24;
50✔
42
    result.hour = static_cast<int>(fractional_part);
50✔
43
    fractional_part = 60 * (fractional_part - result.hour);
50✔
44
    result.minute = static_cast<int>(fractional_part);
50✔
45
    fractional_part = 60 * (fractional_part - result.minute);
50✔
46
    result.second = static_cast<int>(fractional_part);
50✔
47
    fractional_part = 1000000 * (fractional_part - result.second);
50✔
48
    result.microsecond = static_cast<int>(fractional_part);
50✔
49

50
    if (result.microsecond == 999999 && fractional_part - result.microsecond > 0.5)
50✔
51
    {
52
        result.microsecond = 0;
12✔
53
        result.second += 1;
12✔
54

55
        if (result.second == 60)
12✔
56
        {
57
            result.second = 0;
1✔
58
            result.minute += 1;
1✔
59

60
            // TODO: too much nesting
61
            if (result.minute == 60)
1✔
62
            {
63
                result.minute = 0;
1✔
64
                result.hour += 1;
1✔
65
            }
66
        }
67
    }
68

69
    return result;
50✔
70
}
71

72
time::time(int hour_, int minute_, int second_, int microsecond_)
92✔
73
    : hour(hour_), minute(minute_), second(second_), microsecond(microsecond_)
92✔
74
{
75
}
92✔
76

77
bool time::operator==(const time &comparand) const
3✔
78
{
79
    return hour == comparand.hour && minute == comparand.minute && second == comparand.second
3✔
80
        && microsecond == comparand.microsecond;
6✔
81
}
82

83
time::time(const std::string &time_string)
8✔
84
{
85
    bool ok = true;
8✔
86
    auto next_separator_index = time_string.find(':');
8✔
87
    next_separator_index =  time_string.find(':');
8✔
88
    ok = ok && detail::parse(time_string.substr(0, next_separator_index), hour) == std::errc();
8✔
89
    auto previous_separator_index = next_separator_index;
8✔
90
    next_separator_index = ok ? time_string.find(':', previous_separator_index + 1) : next_separator_index;
8✔
91
    ok = ok && detail::parse(time_string.substr(previous_separator_index + 1, next_separator_index), minute) == std::errc();
8✔
92
    previous_separator_index = next_separator_index;
8✔
93
    next_separator_index = ok ? time_string.find('.', previous_separator_index + 1) : next_separator_index;
8✔
94
    bool subseconds_available = next_separator_index != std::string::npos;
8✔
95
    if (subseconds_available)
8✔
96
    {
97
        // First parse the seconds.
98
        ok = ok && detail::parse(time_string.substr(previous_separator_index + 1, next_separator_index), second) == std::errc();
6✔
99
        previous_separator_index = next_separator_index;
6✔
100
    }
101
    next_separator_index = ok ? std::string::npos : next_separator_index;
8✔
102
    size_t num_characters_parsed = 0;
8✔
103
    ok = ok && detail::parse(time_string.substr(previous_separator_index + 1, next_separator_index), subseconds_available ? microsecond : second, &num_characters_parsed) == std::errc();
8✔
104

105
    if (subseconds_available)
8✔
106
    {
107
        constexpr size_t expected_digits = 6; // microseconds have 6 digits
6✔
108
        size_t actual_digits = num_characters_parsed;
6✔
109

110
        while (actual_digits > expected_digits)
12✔
111
        {
112
            microsecond /= 10;
6✔
113
            --actual_digits;
6✔
114
        }
115

116
        while (actual_digits < expected_digits)
12✔
117
        {
118
            microsecond *= 10;
6✔
119
            ++actual_digits;
6✔
120
        }
121
    }
122

123
    if (!ok)
8✔
124
    {
125
        throw xlnt::invalid_parameter("invalid ISO time");
1✔
126
    }
127
}
7✔
128

129
double time::to_number() const
26✔
130
{
131
    std::uint64_t microseconds = static_cast<std::uint64_t>(microsecond);
26✔
132
    microseconds += static_cast<std::uint64_t>(second * 1e6);
26✔
133
    microseconds += static_cast<std::uint64_t>(minute * 1e6 * 60);
26✔
134
    auto microseconds_per_hour = static_cast<std::uint64_t>(1e6) * 60 * 60;
26✔
135
    microseconds += static_cast<std::uint64_t>(hour) * microseconds_per_hour;
26✔
136
    auto number = static_cast<double>(microseconds) / (24.0 * static_cast<double>(microseconds_per_hour));
26✔
137
    number = std::floor(number * 100e9 + 0.5) / 100e9;
26✔
138

139
    return number;
26✔
140
}
141

142
time time::now()
×
143
{
144
    optional<std::tm> now = detail::localtime_safe(std::time(nullptr));
×
145

146
    if (now.is_set())
×
147
    {
148
        return time(now.get().tm_hour, now.get().tm_min, now.get().tm_sec);
×
149
    }
150
    else
151
    {
152
        return time();
×
153
    }
UNCOV
154
}
×
155

156
} // 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