LCOV - code coverage report
Current view: top level - libgnucash/engine - gnc-datetime.hpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 100.0 % 6 6
Test Date: 2026-06-14 17:52:35 Functions: 100.0 % 3 3
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /********************************************************************\
       2                 :             :  * gnc-datetime.cpp -- Date and Time classes for GnuCash            *
       3                 :             :  *                                                                  *
       4                 :             :  * Copyright 2015 John Ralls <jralls@ceridwen.us>                   *
       5                 :             :  *                                                                  *
       6                 :             :  * This program is free software; you can redistribute it and/or    *
       7                 :             :  * modify it under the terms of the GNU General Public License as   *
       8                 :             :  * published by the Free Software Foundation; either version 2 of   *
       9                 :             :  * the License, or (at your option) any later version.              *
      10                 :             :  *                                                                  *
      11                 :             :  * This program is distributed in the hope that it will be useful,  *
      12                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
      13                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
      14                 :             :  * GNU General Public License for more details.                     *
      15                 :             :  *                                                                  *
      16                 :             :  * You should have received a copy of the GNU General Public License*
      17                 :             :  * along with this program; if not, contact:                        *
      18                 :             :  *                                                                  *
      19                 :             :  * Free Software Foundation           Voice:  +1-617-542-5942       *
      20                 :             :  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
      21                 :             :  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
      22                 :             :  *                                                                  *
      23                 :             : \********************************************************************/
      24                 :             : 
      25                 :             : #ifndef __GNC_DATETIME_HPP__
      26                 :             : #define  __GNC_DATETIME_HPP__
      27                 :             : 
      28                 :             : #include <cstdint>
      29                 :             : #include <memory>
      30                 :             : #include <string>
      31                 :             : #include <vector>
      32                 :             : #include <functional>
      33                 :             : #include <optional>
      34                 :             : 
      35                 :             : #include <boost/date_time/gregorian/gregorian.hpp>
      36                 :             : #include <boost/regex.hpp>
      37                 :             : 
      38                 :             : typedef struct
      39                 :             : {
      40                 :             :     int year;  //1400-9999
      41                 :             :     int month; //1-12
      42                 :             :     int day; //1-31
      43                 :             : } gnc_ymd;
      44                 :             : 
      45                 :             : enum class DayPart {
      46                 :             :     start,    // 00:00 local
      47                 :             :     neutral,  // 10:59 UTC
      48                 :             :     end,      // 23:59 local
      49                 :             : };
      50                 :             : 
      51                 :             : class GncDateTimeImpl;
      52                 :             : class GncDateImpl;
      53                 :             : class GncDate;
      54                 :             : using time64 = int64_t;
      55                 :             : constexpr const time64 MINTIME = -17987443200;
      56                 :             : constexpr const time64 MAXTIME = 253402214400;
      57                 :             : 
      58                 :             : /** GnuCash DateTime class
      59                 :             :  *
      60                 :             :  * Represents local time in the current timezone.
      61                 :             :  * As with GncDate, the represented time is limited to the period
      62                 :             :  * between 1400 and 9999 CE.
      63                 :             :  *
      64                 :             :  * Be careful when using times: A particular time is represented
      65                 :             :  * differently depending on the timezone, which can shift the displayed
      66                 :             :  * date. Accounting is generally not sensitive to the time of day, but
      67                 :             :  * is sensitive to the recorded day. Since GncDates are not timezone
      68                 :             :  * dependent they should be preferred for accounting entries.
      69                 :             :  */
      70                 :             : 
      71                 :             : class GncDateTime
      72                 :             : {
      73                 :             : public:
      74                 :             : /** Construct a GncDateTime representing the current time in the
      75                 :             :  * current timezone.
      76                 :             :  */
      77                 :             :     GncDateTime();
      78                 :             : /** Construct a GncDateTime in the current timezone representing the
      79                 :             :  * timestamp as seconds from the POSIX epoch (1970-01-01T00:00:00UTC).
      80                 :             :  * @param time Seconds from the POSIX epoch.
      81                 :             :  * @exception std::invalid_argument if the year is outside the constraints.
      82                 :             :  */
      83                 :             :     GncDateTime(const time64 time);
      84                 :             : /** Construct a GncDateTime in the current timezone representing the
      85                 :             :  * standard struct tm provided.
      86                 :             :  * @param tm A C-standard struct tm representing the date and
      87                 :             :  * time. Note that the timezone and offset are ignored on those
      88                 :             :  * systems which include them in struct tm.
      89                 :             :  * @exception std::invalid_argument if the year is outside the constraints.
      90                 :             :  */
      91                 :             :     GncDateTime(const struct tm tm);
      92                 :             : /** Construct a GncDateTime from a GncDate. As a GncDate doesn't contain time
      93                 :             :  * information, the time will be set depending on the second parameter
      94                 :             :  * to start of day, neutral or end of day.
      95                 :             :  * @param date A GncDate representing a date.
      96                 :             :  * @param part An optinoal DayPart indicating which time to use in the conversion.
      97                 :             :  * This can be "DayPart::start" for start of day (00:00 local time),
      98                 :             :  *             "DayPart::neutral" for a neutral time (10:59 UTC, chosen to have the
      99                 :             :  *              least chance of date changes when crossing timezone borders),
     100                 :             :  *             "DayPart::end" for end of day (23:59 local time).
     101                 :             :  * If omitted part defaults to DayPart::neutral.
     102                 :             :  * Note the different timezone used for DayPart::neutral compared to the other
     103                 :             :  * two options!
     104                 :             :  * @exception std::invalid_argument if the year is outside the constraints.
     105                 :             :  */
     106                 :             :     GncDateTime(const GncDate& date, DayPart part = DayPart::neutral);
     107                 :             : /** Construct a GncDateTime
     108                 :             :  * @param str A string representing the date and time in some
     109                 :             :  * recognizable format. Note that if a timezone is not specified the
     110                 :             :  * default is UTC, not the local one.
     111                 :             :  * @exception std::invalid_argument if the year is outside the constraints.
     112                 :             :  */
     113                 :             :     GncDateTime(const std::string& str);
     114                 :             :     GncDateTime(const char* str);
     115                 :             :     ~GncDateTime();
     116                 :             : /** Set the GncDateTime to the date and time indicated in the computer's clock.
     117                 :             :  */
     118                 :             :     void now();
     119                 :             : /** Cast the GncDateTime to a time64, seconds from the POSIX epoch. */
     120                 :             :     explicit operator time64() const;
     121                 :             : /** Cast the GncDateTime to a struct tm. Timezone field isn't filled.
     122                 :             :  */
     123                 :             :     explicit operator struct tm() const;
     124                 :             : /** Obtain the UTC offset in seconds
     125                 :             :  *  @return seconds difference between this local time and UTC. West
     126                 :             :  *  is negative.
     127                 :             :  */
     128                 :             :     long offset()const;
     129                 :             : /** Obtain a struct tm representing the time in UTC.
     130                 :             :  * @return struct tm
     131                 :             :  */
     132                 :             :     struct tm utc_tm() const;
     133                 :             : /** Obtain the date from the time, as a GncDate, in the current timezone.
     134                 :             :  *  @return GncDate represented by the GncDateTime.
     135                 :             :  */
     136                 :             :     GncDate date() const;
     137                 :             : /** Test if the GncDateTime has a member pointer. Testing only. */
     138                 :             :     bool isnull (void) { return m_impl == nullptr; }
     139                 :             : /** Format the GncDateTime into a std::string
     140                 :             :  *  @param format A cstr describing the way the date and time are
     141                 :             :  *  presented. Code letters preceded with % stand in for arguments;
     142                 :             :  *  most are the same as described in strftime(3), but there are a few
     143                 :             :  *  differences. Consult the boost::date_time documentation.
     144                 :             :  *  @return a std::string containing a representation of the date and time in
     145                 :             :  *  the locale's time zone according to the format.
     146                 :             :  */
     147                 :             :     std::string format(const char* format) const;
     148                 :             : /** Format the GncDateTime into a std::string in GMT
     149                 :             :  *  @param format A cstr describing the way the date and time are
     150                 :             :  *  presented. Code letters preceded with % stand in for arguments;
     151                 :             :  *  most are the same as described in strftime(3), but there are a few
     152                 :             :  *  differences. Consult the boost::date_time documentation.
     153                 :             :  *  @return a std::string containing a representation of the date and time in
     154                 :             :  *  GMT (timezone Z) according to the format.
     155                 :             :  */
     156                 :             :     std::string format_zulu(const char* format) const;
     157                 :             : /** Format the GncDateTime into a gnucash-style iso8601 string in UTC.
     158                 :             :  *  @return a std::string in the format YYYY-MM-DD HH:MM:SS.
     159                 :             :  */
     160                 :             :     std::string format_iso8601() const;
     161                 :             : /** Get an undelimited string representing the current date and time.
     162                 :             :  *  @return a std::string in the format YYYYMMDDHHMMSS.
     163                 :             :  */
     164                 :             :     static std::string timestamp();
     165                 :             :     
     166                 :             : private:
     167                 :             :     std::unique_ptr<GncDateTimeImpl> m_impl;
     168                 :             : };
     169                 :             : 
     170                 :             : /** GnuCash DateFormat class
     171                 :             :  *
     172                 :             :  * A helper class to represent a date format understood
     173                 :             :  * by the GncDate string/format constructor. Consumers
     174                 :             :  * of this header file are not supposed to create
     175                 :             :  * objects of this class themselves. Instead they
     176                 :             :  * can get a list of the understood formats from the
     177                 :             :  * GncDate::c_formats class variable and work with those.
     178                 :             :  */
     179                 :             : 
     180                 :             : using StringToDate = std::function<boost::gregorian::date(const std::string&)>;
     181                 :             : 
     182                 :             : class GncDateFormat
     183                 :             : {
     184                 :             : public:
     185                 :             :     /** Construct a GncDateFormat with a given format and corresponding
     186                 :             :      * regular expression. This should only be used internally by the
     187                 :             :      * GncDate implementation. Consumers should never construct a GncDateFormat
     188                 :             :      * themselves!
     189                 :             :      */
     190                 :         234 :     GncDateFormat (const char* fmt, const char* re) :
     191                 :         702 :         m_fmt(fmt), m_re(re) {}
     192                 :         351 :     GncDateFormat (const char* fmt, StringToDate str_to_date, const char* re) :
     193                 :        1053 :         m_fmt(fmt), m_re(re), m_str_to_date(str_to_date) {}
     194                 :         117 :     GncDateFormat (const char* fmt, StringToDate str_to_date) :
     195                 :         351 :         m_fmt(fmt), m_str_to_date(str_to_date) {}
     196                 :             :     /** A string representing the format. */
     197                 :             :     const std::string m_fmt;
     198                 :             : private:
     199                 :             :     /** Regular expression associated with the format string. This is to and
     200                 :             :      * only be used internally by the gnc-datetime code.
     201                 :             :      */
     202                 :             :     boost::regex m_re;
     203                 :             :     std::optional<StringToDate> m_str_to_date;
     204                 :             : 
     205                 :             :     friend class GncDateImpl;
     206                 :             : };
     207                 :             : 
     208                 :             : /** GnuCash Date class
     209                 :             :  *
     210                 :             :  * The represented date is limited to the period
     211                 :             :  * between 1400 and 9999 CE.
     212                 :             :  */
     213                 :             : 
     214                 :             : class GncDate
     215                 :             : {
     216                 :             :     public:
     217                 :             :         /** A vector with all the date formats supported by the string constructor.
     218                 :             :          * The currently supported formats are:
     219                 :             :          * "y-m-d" (including yyyymmdd)
     220                 :             :          * "d-m-y" (including ddmmyyyy)
     221                 :             :          * "m-d-y" (including mmddyyyy)
     222                 :             :          * "d-m"   (including ddmm)
     223                 :             :          * "m-d"   (including mmdd)
     224                 :             :          *
     225                 :             :          * Notes:
     226                 :             :          * - while the format names are using a "-" as separator, the
     227                 :             :          * regexes will accept any of "-/.' " and will also work for dates
     228                 :             :          * without separators.
     229                 :             :          * - the format strings are marked for translation so it is possible
     230                 :             :          * to use a localized version of a format string using gettext. Example:
     231                 :             :          * gettext(GncDate::c_formats[0])
     232                 :             :          */
     233                 :             :         static const std::vector<GncDateFormat> c_formats;
     234                 :             :         /** Construct a GncDate representing the current day.
     235                 :             :          */
     236                 :             :         GncDate();
     237                 :             :         /** Construct a GncDate representing the given year, month, and day in
     238                 :             :          * the proleptic Gregorian calendar.
     239                 :             :          *
     240                 :             :          * Years are constrained to be from 1400 - 9999 CE inclusive. Dates
     241                 :             :          * will be normalized if the day or month values are outside of the
     242                 :             :          * normal ranges. e.g. 1994, -3, 47 will be normalized to 1993-10-17.
     243                 :             :          *
     244                 :             :          * @param year The year in the Common Era.
     245                 :             :          * @param month The month, where 1 is January and 12 is December.
     246                 :             :          * @param day The day of the month, beginning with 1.
     247                 :             :          * @exception std::invalid_argument if the calculated year is outside
     248                 :             :          * of the constrained range.
     249                 :             :          */
     250                 :             :         GncDate(int year, int month, int day);
     251                 :             :         /** Construct a GncDate by parsing a string assumed to be in the format
     252                 :             :          * passed in.
     253                 :             :          *
     254                 :             :          * The currently recognized formats are d-m-y, m-d-y, y-m-d, m-d, d-m.
     255                 :             :          * Note while the format descriptions use "-" as separator any of
     256                 :             :          * "-" (hyphen), "/" (slash), "'" (single quote), " " (space) or
     257                 :             :          * "." will be accepted.
     258                 :             :          *
     259                 :             :          * @param str The string to be interpreted.
     260                 :             :          * @param fmt The expected date format of the string passed in.
     261                 :             :          * @exception std::invalid_argument if
     262                 :             :          * - the string couldn't be parsed using the provided format
     263                 :             :          * - any of the date components is outside of its limit
     264                 :             :          *   (like month being 13, or day being 31 in February)
     265                 :             :          * - fmt doesn't specify a year, yet a year was found in the string
     266                 :             :          */
     267                 :             :         GncDate(const std::string str, const std::string fmt);
     268                 :             :         /** Construct a GncDate from a GncDateImpl.
     269                 :             :          */
     270                 :             :         GncDate(std::unique_ptr<GncDateImpl> impl);
     271                 :             :         /** Copy constructor.
     272                 :             :          */
     273                 :             :         GncDate(const GncDate&);
     274                 :             :         /** Move constructor.
     275                 :             :          */
     276                 :             :         GncDate(GncDate&&);
     277                 :             :         /** Default destructor.
     278                 :             :          */
     279                 :             :         ~GncDate();
     280                 :             :         /** Copy assignment operator.
     281                 :             :          */
     282                 :             :         GncDate& operator=(const GncDate&);
     283                 :             :         /** Move assignment operator.
     284                 :             :          */
     285                 :             :         GncDate& operator=(GncDate&&);
     286                 :             :         /** Set the date object to the computer clock's current day. */
     287                 :             :         void today();
     288                 :             :         /** Get the year, month, and day from the date as a gnc_ymd.
     289                 :             :          *  @return gnc_ymd struct
     290                 :             :          */
     291                 :             :         gnc_ymd year_month_day() const;
     292                 :             :         /** Format the GncDate into a std::string
     293                 :             :          *  @param format A cstr describing the way the date and time are
     294                 :             :          *  presented. Code letters preceded with % stand in for arguments;
     295                 :             :          *  most are the same as described in strftime(3), but there are a few
     296                 :             :          *  differences. Consult the boost::date_time documentation.
     297                 :             :          *  @return a std::string containing a representation of the date
     298                 :             :          *  according to the format.
     299                 :             :          */
     300                 :             :         std::string format(const char* format);
     301                 :             :         /** Test that the Date has an implementation. */
     302                 :             :         bool isnull (void) { return m_impl == nullptr; }
     303                 :             : 
     304                 :             : private:
     305                 :             :     std::unique_ptr<GncDateImpl> m_impl;
     306                 :             : 
     307                 :             :     friend GncDateTime::GncDateTime(const GncDate&, DayPart);
     308                 :             :     friend bool operator<(const GncDate&, const GncDate&);
     309                 :             :     friend bool operator>(const GncDate&, const GncDate&);
     310                 :             :     friend bool operator==(const GncDate&, const GncDate&);
     311                 :             :     friend bool operator<=(const GncDate&, const GncDate&);
     312                 :             :     friend bool operator>=(const GncDate&, const GncDate&);
     313                 :             :     friend bool operator!=(const GncDate&, const GncDate&);
     314                 :             : };
     315                 :             : 
     316                 :             : /**@{
     317                 :             :  *  Standard comparison operators working on GncDate objects.
     318                 :             :  */
     319                 :             : bool operator<(const GncDate& a, const GncDate& b);
     320                 :             : bool operator>(const GncDate& a, const GncDate& b);
     321                 :             : bool operator==(const GncDate& a, const GncDate& b);
     322                 :             : bool operator<=(const GncDate& a, const GncDate& b);
     323                 :             : bool operator>=(const GncDate& a, const GncDate& b);
     324                 :             : bool operator!=(const GncDate& a, const GncDate& b);
     325                 :             : /**@}*/
     326                 :             : 
     327                 :             : #endif // __GNC_DATETIME_HPP__
        

Generated by: LCOV version 2.0-1