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

Generated by: LCOV version 2.0-1