differential code coverage report with master
Current view: top level - source/utils - datetime.cpp (source / functions) Coverage Total Hit UBC CBC
Current: coverage.info Lines: 97.4 % 151 147 4 147
Current Date: 2025-12-15 23:01:28 Functions: 90.0 % 20 18 2 18
Baseline: coverage_master.info Branches: 81.3 % 198 161 74 322
Baseline Date: 2025-12-15 23:01:27

             Branch data    TLA  Line data    Source code
       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 <ctime>
      26                 :                : 
      27                 :                : #include <xlnt/utils/date.hpp>
      28                 :                : #include <xlnt/utils/datetime.hpp>
      29                 :                : #include <xlnt/utils/time.hpp>
      30                 :                : #include <detail/serialization/parsers.hpp>
      31                 :                : 
      32                 :                : #include <xlnt/utils/optional.hpp>
      33                 :                : 
      34                 :                : namespace {
      35                 :                : 
      36                 :CBC        2674 : std::string fill(const std::string &string, std::size_t length = 2)
      37                 :                : {
      38         [ +  + ]:           2674 :     if (string.size() >= length)
      39                 :                :     {
      40                 :           1604 :         return string;
      41                 :                :     }
      42                 :                : 
      43         [ +  + ]:           2140 :     return std::string(length - string.size(), '0') + string;
      44                 :                : }
      45                 :                : 
      46                 :                : } // namespace
      47                 :                : 
      48                 :                : namespace xlnt {
      49                 :                : 
      50                 :             47 : datetime datetime::from_number(double raw_time, calendar base_date)
      51                 :                : {
      52            [ + ]:             47 :     auto date_part = date::from_number(static_cast<int>(raw_time), base_date);
      53            [ + ]:             47 :     auto time_part = time::from_number(raw_time);
      54                 :                : 
      55            [ + ]:             94 :     return datetime(date_part, time_part);
      56                 :                : }
      57                 :                : 
      58                 :              1 : bool datetime::operator==(const datetime &comparand) const
      59                 :                : {
      60                 :              1 :     return year == comparand.year
      61         [ +  - ]:              1 :         && month == comparand.month
      62         [ +  - ]:              1 :         && day == comparand.day
      63         [ +  - ]:              1 :         && hour == comparand.hour
      64         [ +  - ]:              1 :         && minute == comparand.minute
      65         [ +  - ]:              1 :         && second == comparand.second
      66         [ +  - ]:              1 :         && microsecond == comparand.microsecond
      67   [ +  -  +  - ]:              2 :         && _is_null == comparand._is_null;
      68                 :                : }
      69                 :                : 
      70                 :UBC           0 : bool datetime::operator!=(const datetime &comparand) const
      71                 :                : {
      72                 :              0 :     return !(*this == comparand);
      73                 :                : }
      74                 :                : 
      75                 :CBC           8 : double datetime::to_number(calendar base_date) const
      76                 :                : {
      77         [ +  + ]:              8 :     if (_is_null)
      78                 :                :     {
      79            [ + ]:              1 :         throw xlnt::invalid_attribute("cannot convert invalid/empty datetime to a number");
      80                 :                :     }
      81                 :                : 
      82         [ +  + ]:              7 :     return date(year, month, day).to_number(base_date)
      83         [ +  + ]:              7 :         + time(hour, minute, second, microsecond).to_number();
      84                 :                : }
      85                 :                : 
      86                 :              3 : std::string datetime::to_string() const
      87                 :                : {
      88         [ +  + ]:              3 :     if (_is_null)
      89                 :                :     {
      90                 :              1 :         return {};
      91                 :                :     }
      92                 :                :     else
      93                 :                :     {
      94                 :              2 :         std::string str = std::to_string(year);
      95            [ + ]:              2 :         str.push_back('/');
      96            [ + ]:              2 :         str.append(std::to_string(month));
      97            [ + ]:              2 :         str.push_back('/');
      98            [ + ]:              2 :         str.append(std::to_string(day));
      99            [ + ]:              2 :         str.push_back(' ');
     100            [ + ]:              2 :         str.append(std::to_string(hour));
     101            [ + ]:              2 :         str.push_back(':');
     102            [ + ]:              2 :         str.append(std::to_string(minute));
     103            [ + ]:              2 :         str.push_back(':');
     104            [ + ]:              2 :         str.append(std::to_string(second));
     105                 :                : 
     106         [ +  - ]:              2 :         if (microsecond != 0)
     107                 :                :         {
     108            [ + ]:              2 :             str.push_back('.');
     109         [ +  + ]:              2 :             str.append(fill(std::to_string(microsecond), 6));
     110                 :                :         }
     111                 :                : 
     112                 :              2 :         return str;
     113                 :              2 :     }
     114                 :                : }
     115                 :                : 
     116                 :UBC           0 : datetime datetime::now()
     117                 :                : {
     118      [ #  #  # ]:              0 :     return datetime(date::today(), time::now());
     119                 :                : }
     120                 :                : 
     121                 :CBC           3 : datetime datetime::today()
     122                 :                : {
     123      [ +  +  + ]:              3 :     return datetime(date::today(), time(0, 0, 0, 0));
     124                 :                : }
     125                 :                : 
     126                 :            723 : datetime::datetime(int year_, int month_, int day_, int hour_, int minute_, int second_, int microsecond_)
     127                 :            723 :     : year(year_), month(month_), day(day_), hour(hour_), minute(minute_), second(second_), microsecond(microsecond_), _is_null(false)
     128                 :                : {
     129                 :            723 : }
     130                 :                : 
     131                 :             50 : datetime::datetime(const date &d, const time &t)
     132                 :             50 :     : hour(t.hour),
     133                 :             50 :       minute(t.minute),
     134                 :             50 :       second(t.second),
     135                 :             50 :       microsecond(t.microsecond),
     136                 :             50 :       _is_null(d.is_null())
     137                 :                : {
     138         [ +  - ]:             50 :     if (!d.is_null())
     139                 :                :     {
     140                 :             50 :         year = d.get_year();
     141                 :             50 :         month = d.get_month();
     142                 :             50 :         day = d.get_day();
     143                 :                :     }
     144                 :             50 : }
     145                 :                : 
     146                 :              3 : int datetime::weekday() const
     147                 :                : {
     148         [ +  + ]:              3 :     if (!_is_null)
     149                 :                :     {
     150         [ +  + ]:              2 :         return date(year, month, day).weekday();
     151                 :                :     }
     152                 :                :     else
     153                 :                :     {
     154                 :              1 :         return -1;
     155                 :                :     }
     156                 :                : }
     157                 :                : 
     158                 :             39 : int datetime::get_year() const
     159                 :                : {
     160         [ +  + ]:             39 :     if (_is_null)
     161                 :                :     {
     162            [ + ]:              1 :         throw xlnt::invalid_attribute("access to invalid/empty year of xlnt::datetime");
     163                 :                :     }
     164                 :                : 
     165                 :             38 :     return year;
     166                 :                : }
     167                 :                : 
     168                 :             35 : int datetime::get_month() const
     169                 :                : {
     170         [ +  + ]:             35 :     if (_is_null)
     171                 :                :     {
     172            [ + ]:              1 :         throw xlnt::invalid_attribute("access to invalid/empty month of xlnt::datetime");
     173                 :                :     }
     174                 :                : 
     175                 :             34 :     return month;
     176                 :                : }
     177                 :                : 
     178                 :             30 : int datetime::get_day() const
     179                 :                : {
     180         [ +  + ]:             30 :     if (_is_null)
     181                 :                :     {
     182            [ + ]:              1 :         throw xlnt::invalid_attribute("access to invalid/empty day of xlnt::datetime");
     183                 :                :     }
     184                 :                : 
     185                 :             29 :     return day;
     186                 :                : }
     187                 :                : 
     188                 :             77 : int datetime::get_hour() const
     189                 :                : {
     190         [ +  + ]:             77 :     if (_is_null)
     191                 :                :     {
     192            [ + ]:              1 :         throw xlnt::invalid_attribute("access to invalid/empty hour of xlnt::datetime");
     193                 :                :     }
     194                 :                : 
     195                 :             76 :     return hour;
     196                 :                : }
     197                 :                : 
     198                 :             48 : int datetime::get_minute() const
     199                 :                : {
     200         [ +  + ]:             48 :     if (_is_null)
     201                 :                :     {
     202            [ + ]:              1 :         throw xlnt::invalid_attribute("access to invalid/empty minute of xlnt::datetime");
     203                 :                :     }
     204                 :                : 
     205                 :             47 :     return minute;
     206                 :                : }
     207                 :                : 
     208                 :             39 : int datetime::get_second() const
     209                 :                : {
     210         [ +  + ]:             39 :     if (_is_null)
     211                 :                :     {
     212            [ + ]:              1 :         throw xlnt::invalid_attribute("access to invalid/empty second of xlnt::datetime");
     213                 :                :     }
     214                 :                : 
     215                 :             38 :     return second;
     216                 :                : }
     217                 :                : 
     218                 :             35 : int datetime::get_microsecond() const
     219                 :                : {
     220         [ +  + ]:             35 :     if (_is_null)
     221                 :                :     {
     222            [ + ]:              1 :         throw xlnt::invalid_attribute("access to invalid/empty microsecond of xlnt::datetime");
     223                 :                :     }
     224                 :                : 
     225                 :             34 :     return microsecond;
     226                 :                : }
     227                 :                : 
     228                 :             28 : datetime datetime::from_iso_string(const std::string &string)
     229                 :                : {
     230                 :             28 :     xlnt::datetime result(1900, 1, 1);
     231                 :                : 
     232                 :             28 :     bool ok = true;
     233                 :             28 :     auto next_separator_index = string.find('-');
     234   [ +  -  +  +  :             28 :     ok = ok && detail::parse(string.substr(0, next_separator_index), result.year) == std::errc();
          +  +  +  -  -  
                      - ]
     235                 :             28 :     auto previous_separator_index = next_separator_index;
     236         [ +  + ]:             28 :     next_separator_index = ok ? string.find('-', previous_separator_index + 1) : next_separator_index;
     237   [ +  +  +  +  :             28 :     ok = ok && detail::parse(string.substr(previous_separator_index + 1, next_separator_index), result.month) == std::errc();
          +  -  +  +  -  
                      - ]
     238                 :             28 :     previous_separator_index = next_separator_index;
     239         [ +  + ]:             28 :     next_separator_index = ok ? string.find('T', previous_separator_index + 1) : next_separator_index;
     240   [ +  +  +  +  :             28 :     ok = ok && detail::parse(string.substr(previous_separator_index + 1, next_separator_index), result.day) == std::errc();
          +  -  +  +  -  
                      - ]
     241                 :             28 :     previous_separator_index = next_separator_index;
     242         [ +  + ]:             28 :     next_separator_index = ok ? string.find(':', previous_separator_index + 1) : next_separator_index;
     243   [ +  +  +  +  :             28 :     ok = ok && detail::parse(string.substr(previous_separator_index + 1, next_separator_index), result.hour) == std::errc();
          +  -  +  +  -  
                      - ]
     244                 :             28 :     previous_separator_index = next_separator_index;
     245         [ +  + ]:             28 :     next_separator_index = ok ? string.find(':', previous_separator_index + 1) : next_separator_index;
     246   [ +  +  +  +  :             28 :     ok = ok && detail::parse(string.substr(previous_separator_index + 1, next_separator_index), result.minute) == std::errc();
          +  -  +  +  -  
                      - ]
     247                 :             28 :     previous_separator_index = next_separator_index;
     248         [ +  + ]:             28 :     next_separator_index = ok ? string.find('.', previous_separator_index + 1) : next_separator_index;
     249                 :             28 :     bool subseconds_available = next_separator_index != std::string::npos;
     250         [ +  + ]:             28 :     if (subseconds_available)
     251                 :                :     {
     252                 :                :         // First parse the seconds.
     253   [ +  -  +  +  :              6 :         ok = ok && detail::parse(string.substr(previous_separator_index + 1, next_separator_index), result.second) == std::errc();
          +  -  +  -  -  
                      - ]
     254                 :              6 :         previous_separator_index = next_separator_index;
     255                 :                : 
     256                 :                :     }
     257         [ +  + ]:             28 :     next_separator_index = ok ? string.find('Z', previous_separator_index + 1) : next_separator_index;
     258                 :             28 :     size_t num_characters_parsed = 0;
     259   [ +  +  +  +  :             28 :     ok = ok && detail::parse(string.substr(previous_separator_index + 1, next_separator_index), subseconds_available ? result.microsecond : result.second, &num_characters_parsed) == std::errc();
          +  +  +  -  +  
                +  -  - ]
     260                 :                : 
     261         [ +  + ]:             28 :     if (subseconds_available)
     262                 :                :     {
     263                 :              6 :         constexpr size_t expected_digits = 6; // microseconds have 6 digits
     264                 :              6 :         size_t actual_digits = num_characters_parsed;
     265                 :                : 
     266         [ +  + ]:             12 :         while (actual_digits > expected_digits)
     267                 :                :         {
     268                 :              6 :             result.microsecond /= 10;
     269                 :              6 :             --actual_digits;
     270                 :                :         }
     271                 :                : 
     272         [ +  + ]:             12 :         while (actual_digits < expected_digits)
     273                 :                :         {
     274                 :              6 :             result.microsecond *= 10;
     275                 :              6 :             ++actual_digits;
     276                 :                :         }
     277                 :                :     }
     278                 :                : 
     279         [ +  + ]:             28 :     if (!ok)
     280                 :                :     {
     281            [ + ]:              1 :         throw xlnt::invalid_parameter("invalid ISO date");
     282                 :                :     }
     283                 :                : 
     284                 :             54 :     return result;
     285                 :                : }
     286                 :                : 
     287                 :            535 : std::string datetime::to_iso_string() const
     288                 :                : {
     289         [ +  + ]:            535 :     if (_is_null)
     290                 :                :     {
     291                 :              1 :         return {};
     292                 :                :     }
     293                 :                :     else
     294                 :                :     {
     295                 :            534 :         std::string iso = std::to_string(year);
     296            [ + ]:            534 :         iso.push_back('-');
     297         [ +  + ]:            534 :         iso.append(fill(std::to_string(month)));
     298            [ + ]:            534 :         iso.push_back('-');
     299         [ +  + ]:            534 :         iso.append(fill(std::to_string(day)));
     300            [ + ]:            534 :         iso.push_back('T');
     301         [ +  + ]:            534 :         iso.append(fill(std::to_string(hour)));
     302            [ + ]:            534 :         iso.push_back(':');
     303         [ +  + ]:            534 :         iso.append(fill(std::to_string(minute)));
     304            [ + ]:            534 :         iso.push_back(':');
     305         [ +  + ]:            534 :         iso.append(fill(std::to_string(second)));
     306                 :                : 
     307         [ +  + ]:            534 :         if (microsecond != 0)
     308                 :                :         {
     309            [ + ]:              2 :             iso.push_back('.');
     310         [ +  + ]:              2 :             iso.append(fill(std::to_string(microsecond), 6));
     311                 :                :         }
     312                 :                : 
     313            [ + ]:            534 :         iso.push_back('Z');
     314                 :                : 
     315                 :            534 :         return iso;
     316                 :            534 :     }
     317                 :                : }
     318                 :                : 
     319                 :                : } // namespace xlnt
        

Generated by: LCOV version 2.3.1-beta