gnucash master: Multiple changes pushed

Geert Janssens gjanssens at code.gnucash.org
Wed May 3 06:21:07 EDT 2017


Updated	 via  https://github.com/Gnucash/gnucash/commit/e0af43d4 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/3603ec1a (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9af57849 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/7df29b57 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/50700373 (commit)
	from  https://github.com/Gnucash/gnucash/commit/1a3595cb (commit)



commit e0af43d413bb6d41f36e91f52e2c7db031db8079
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Wed May 3 12:19:04 2017 +0200

    Properly handle import of reconcile state.
    
    Gnucash exports this state localized it should expect a localized state on import.

diff --git a/src/import-export/csv-imp/gnc-trans-props.cpp b/src/import-export/csv-imp/gnc-trans-props.cpp
index 363a629..de0d886 100644
--- a/src/import-export/csv-imp/gnc-trans-props.cpp
+++ b/src/import-export/csv-imp/gnc-trans-props.cpp
@@ -136,16 +136,16 @@ GncNumeric parse_amount (const std::string &str, int currency_format)
 
 static char parse_reconciled (const std::string& reconcile)
 {
-    if (g_strcmp0 (reconcile.c_str(), _("n")) == 0) // Not reconciled
+    if (g_strcmp0 (reconcile.c_str(), gnc_get_reconcile_str(NREC)) == 0) // Not reconciled
         return NREC;
-    else if (g_strcmp0 (reconcile.c_str(), _("c")) == 0) // Cleared
+    else if (g_strcmp0 (reconcile.c_str(), gnc_get_reconcile_str(CREC)) == 0) // Cleared
         return CREC;
-    else if (g_strcmp0 (reconcile.c_str(), _("y")) == 0) // Reconciled
+    else if (g_strcmp0 (reconcile.c_str(), gnc_get_reconcile_str(YREC)) == 0) // Reconciled
         return YREC;
-    else if (g_strcmp0 (reconcile.c_str(), _("f")) == 0) // Frozen
+    else if (g_strcmp0 (reconcile.c_str(), gnc_get_reconcile_str(FREC)) == 0) // Frozen
         return FREC;
-    else if (g_strcmp0 (reconcile.c_str(), _("v")) == 0) // Voided will be handled at the transaction level
-        return NREC;                                      // so return not reconciled here
+    else if (g_strcmp0 (reconcile.c_str(), gnc_get_reconcile_str(VREC)) == 0) // Voided will be handled at the transaction level
+        return NREC;                                                          // so return not reconciled here
     else
         throw std::invalid_argument (_("Value can't be parsed into a valid reconcile state."));
 }

commit 3603ec1aa857b85ed56b24847300a03ce20a1f4e
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Wed May 3 09:44:36 2017 +0200

    Document supported date formats in the saved csv settings

diff --git a/src/import-export/csv-imp/gnc-csv-trans-settings.cpp b/src/import-export/csv-imp/gnc-csv-trans-settings.cpp
index f3456f0..6278d48 100644
--- a/src/import-export/csv-imp/gnc-csv-trans-settings.cpp
+++ b/src/import-export/csv-imp/gnc-csv-trans-settings.cpp
@@ -27,6 +27,7 @@
 */
 
 #include "gnc-csv-trans-settings.hpp"
+#include <sstream>
 
 extern "C"
 {
@@ -337,6 +338,15 @@ CsvTransSettings::save (void)
 
     g_key_file_set_string (keyfile, group.c_str(), CSV_SEP, m_separators.c_str());
     g_key_file_set_integer (keyfile, group.c_str(), CSV_DATE, m_date_format);
+    std::ostringstream cmt_ss;
+    cmt_ss << "Supported date formats: ";
+    int fmt_num = 0;
+    std::for_each (GncDate::c_formats.cbegin(), GncDate::c_formats.cend(),
+                    [&cmt_ss, &fmt_num](const GncDateFormat& fmt)
+                        { cmt_ss << fmt_num++ << ": '" << fmt.m_fmt << "', "; });
+    auto cmt = cmt_ss.str().substr(0, static_cast<long>(cmt_ss.tellp()) - 2);
+    g_key_file_set_comment (keyfile, group.c_str(), CSV_DATE,
+                            cmt.c_str(), nullptr);
     g_key_file_set_integer (keyfile, group.c_str(), CSV_CURRENCY, m_currency_format);
     g_key_file_set_string (keyfile, group.c_str(), CSV_ENCODING, m_encoding.c_str());
 

commit 9af57849ba1bc6e954f6b5aae61ec85e4c09a0e2
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Mon May 1 20:19:49 2017 +0200

    Use GncDate in csv importer
    
    This removes all date specific functionality from the importer

diff --git a/src/import-export/csv-imp/assistant-csv-trans-import.cpp b/src/import-export/csv-imp/assistant-csv-trans-import.cpp
index 05219da..3cd6c60 100644
--- a/src/import-export/csv-imp/assistant-csv-trans-import.cpp
+++ b/src/import-export/csv-imp/assistant-csv-trans-import.cpp
@@ -521,10 +521,8 @@ CsvImpTransAssist::CsvImpTransAssist ()
 
         /* Add in the date format combo box and hook it up to an event handler. */
         date_format_combo = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new());
-        for (int i = 0; i < num_date_formats; i++)
-        {
-            gtk_combo_box_text_append_text (date_format_combo, _(date_format_user[i]));
-        }
+        for (auto& date_fmt : GncDate::c_formats)
+            gtk_combo_box_text_append_text (date_format_combo, _(date_fmt.m_fmt.c_str()));
         gtk_combo_box_set_active (GTK_COMBO_BOX(date_format_combo), 0);
         g_signal_connect (G_OBJECT(date_format_combo), "changed",
                          G_CALLBACK(csv_tximp_preview_date_fmt_sel_cb), this);
@@ -1560,7 +1558,7 @@ CsvImpTransAssist::preview_refresh ()
     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(fixed_button),
             (tx_imp->file_format() != GncImpFileFormat::CSV));
 
-    // This section deals with the combo's and character encoding
+    // Set Date & Currency Format and Character encoding
     gtk_combo_box_set_active (GTK_COMBO_BOX(date_format_combo),
             tx_imp->date_format());
     gtk_combo_box_set_active (GTK_COMBO_BOX(currency_format_combo),
diff --git a/src/import-export/csv-imp/gnc-trans-props.cpp b/src/import-export/csv-imp/gnc-trans-props.cpp
index c537d54..363a629 100644
--- a/src/import-export/csv-imp/gnc-trans-props.cpp
+++ b/src/import-export/csv-imp/gnc-trans-props.cpp
@@ -93,115 +93,6 @@ GncTransPropType sanitize_trans_prop (GncTransPropType prop, bool multi_split)
         return GncTransPropType::NONE;
 }
 
-/* Regular expressions used to parse dates per date format */
-const char* date_regex[] = {
-                             "(?:"                                   // either y-m-d
-                                 "(?<YEAR>[0-9]+)[-/.' ]+"
-                                 "(?<MONTH>[0-9]+)[-/.' ]+"
-                                 "(?<DAY>[0-9]+)"
-                             "|"                                     // or CCYYMMDD
-                                 "(?<YEAR>[0-9]{4})"
-                                 "(?<MONTH>[0-9]{2})"
-                                 "(?<DAY>[0-9]{2})"
-                             ")",
-
-                             "(?:"                                   // either d-m-y
-                                 "(?<DAY>[0-9]+)[-/.' ]+"
-                                 "(?<MONTH>[0-9]+)[-/.' ]+"
-                                 "(?<YEAR>[0-9]+)"
-                             "|"                                     // or DDMMCCYY
-                                 "(?<DAY>[0-9]{2})"
-                                 "(?<MONTH>[0-9]{2})"
-                                 "(?<YEAR>[0-9]{4})"
-                             ")",
-
-                             "(?:"                                   // either m-d-y
-                                 "(?<MONTH>[0-9]+)[-/.' ]+"
-                                 "(?<DAY>[0-9]+)[-/.' ]+"
-                                 "(?<YEAR>[0-9]+)"
-                             "|"                                     // or MMDDCCYY
-                                 "(?<MONTH>[0-9]{2})"
-                                 "(?<DAY>[0-9]{2})"
-                                 "(?<YEAR>[0-9]{4})"
-                             ")",
-
-                             "(?:"                                   // either d-m(-y)
-                                 "(?<DAY>[0-9]+)[-/.' ]+"
-                                 "(?<MONTH>[0-9]+)(?:[-/.' ]+"
-                                 "(?<YEAR>[0-9]+))?"
-                             "|"                                     // or DDMM(CCYY)
-                                 "(?<DAY>[0-9]{2})"
-                                 "(?<MONTH>[0-9]{2})"
-                                 "(?<YEAR>[0-9]+)?"
-                             ")",
-
-                             "(?:"                                   // either m-d(-y)
-                                 "(?<MONTH>[0-9]+)[-/.' ]+"
-                                 "(?<DAY>[0-9]+)(?:[-/.' ]+"
-                                 "(?<YEAR>[0-9]+))?"
-                             "|"                                     // or MMDD(CCYY)
-                                 "(?<MONTH>[0-9]{2})"
-                                 "(?<DAY>[0-9]{2})"
-                                 "(?<YEAR>[0-9]+)?"
-                             ")",
-};
-
-/** Parses a string into a date, given a format. This function
- * requires only knowing the order in which the year, month and day
- * appear. For example, 01-02-2003 will be parsed the same way as
- * 01/02/2003.
- * @param date_str The string containing a date being parsed
- * @param format An index specifying a format in date_format_user
- * @exception std::invalid_argument if the string can't be parsed into a date.
- * @return The parsed value of date_str on success, throws on failure
- */
-
-time64 parse_date (const std::string &date_str, int format)
-{
-    boost::regex r(date_regex[format]);
-    boost::smatch what;
-    if(!boost::regex_search(date_str, what, r))
-        throw std::invalid_argument (_("Value can't be parsed into a date using the selected date format."));  // regex didn't find a match
-
-    // Attention: different behavior from 2.6.x series !
-    // If date format without year was selected, the match
-    // should NOT have found a year.
-    if ((format >= 3) && (what.length("YEAR") != 0))
-        throw std::invalid_argument (_("Value appears to contain a year while the selected format forbids this."));
-
-    auto day = std::stoi (what.str("DAY"));
-    auto month = std::stoi (what.str("MONTH"));
-
-    int year;
-    if (format < 3)
-    {
-        /* The input dates have a year, so use that one */
-        year = std::stoi (what.str("YEAR"));
-
-        /* Handle two-digit years. */
-        if (year < 100)
-        {
-            /* We allow two-digit years in the range 1969 - 2068. */
-            if (year < 69)
-                year += 2000;
-            else
-                year += 1900;
-        }
-    }
-    else
-    {
-        /* The input dates don't have a year, so work with today's year.
-         */
-        gnc_timespec2dmy(timespec_now(), nullptr, nullptr, &year);
-    }
-
-    auto ts = gnc_dmy2timespec_neutral(day, month, year);
-    if (ts.tv_sec == INT64_MAX)
-        throw std::invalid_argument (_("Value can't be parsed into a date using the selected date format."));
-
-    return ts.tv_sec;
-}
-
 
 /** Convert str into a GncRational using the user-specified (import) currency format.
  * @param str The string to be parsed
@@ -317,7 +208,7 @@ void GncPreTrans::set (GncTransPropType prop_type, const std::string& value)
 
             case GncTransPropType::DATE:
                 m_date = boost::none;
-                m_date = parse_date (value, m_date_format); // Throws if parsing fails
+                m_date = GncDate(value, GncDate::c_formats[m_date_format].m_fmt); // Throws if parsing fails
                 break;
 
             case GncTransPropType::NUM:
@@ -417,7 +308,8 @@ Transaction* GncPreTrans::create_trans (QofBook* book, gnc_commodity* currency)
     auto trans = xaccMallocTransaction (book);
     xaccTransBeginEdit (trans);
     xaccTransSetCurrency (trans, m_commodity ? *m_commodity : currency);
-    xaccTransSetDatePostedSecsNormalized (trans, *m_date);
+    xaccTransSetDatePostedSecsNormalized (trans,
+                        static_cast<time64>(GncDateTime(*m_date, DayPart::neutral)));
 
     if (m_num)
         xaccTransSetNum (trans, m_num->c_str());
@@ -558,13 +450,15 @@ void GncPreSplit::set (GncTransPropType prop_type, const std::string& value)
             case GncTransPropType::REC_DATE:
                 m_rec_date = boost::none;
                 if (!value.empty())
-                    m_rec_date = parse_date (value, m_date_format); // Throws if parsing fails
+                    m_rec_date = GncDate (value,
+                                          GncDate::c_formats[m_date_format].m_fmt); // Throws if parsing fails
                 break;
 
             case GncTransPropType::TREC_DATE:
                 m_trec_date = boost::none;
                 if (!value.empty())
-                    m_trec_date = parse_date (value, m_date_format); // Throws if parsing fails
+                    m_trec_date = GncDate (value,
+                                           GncDate::c_formats[m_date_format].m_fmt); // Throws if parsing fails
                 break;
 
             default:
@@ -641,7 +535,7 @@ static void trans_add_split (Transaction* trans, Account* account, GncNumeric am
                             const boost::optional<std::string>& action,
                             const boost::optional<std::string>& memo,
                             const boost::optional<char>& rec_state,
-                            const boost::optional<time64> rec_date,
+                            const boost::optional<GncDate>& rec_date,
                             const boost::optional<GncNumeric> price)
 {
     QofBook* book = xaccTransGetBook (trans);
@@ -691,7 +585,8 @@ static void trans_add_split (Transaction* trans, Account* account, GncNumeric am
     if (rec_state && *rec_state != 'n')
         xaccSplitSetReconcile (split, *rec_state);
     if (rec_state && *rec_state == YREC && rec_date)
-        xaccSplitSetDateReconciledSecs (split, *rec_date);
+        xaccSplitSetDateReconciledSecs (split,
+                static_cast<time64>(GncDateTime(*rec_date, DayPart::neutral)));
 
 }
 
diff --git a/src/import-export/csv-imp/gnc-trans-props.hpp b/src/import-export/csv-imp/gnc-trans-props.hpp
index 8188206..47c23ba 100644
--- a/src/import-export/csv-imp/gnc-trans-props.hpp
+++ b/src/import-export/csv-imp/gnc-trans-props.hpp
@@ -41,6 +41,7 @@ extern "C" {
 #include <map>
 #include <memory>
 #include <boost/optional.hpp>
+#include <gnc-datetime.hpp>
 #include <gnc-numeric.hpp>
 
 /** Enumeration for column types. These are the different types of
@@ -103,7 +104,6 @@ private:
 GncTransPropType sanitize_trans_prop (GncTransPropType prop, bool multi_split);
 
 
-time64 parse_date (const std::string &date_str, int format);
 gnc_commodity* parse_commodity (const std::string& comm_str);
 GncNumeric parse_amount (const std::string &str, int currency_format);
 
@@ -139,7 +139,7 @@ public:
 private:
     int m_date_format;
     boost::optional<std::string> m_differ;
-    boost::optional<time64> m_date;
+    boost::optional<GncDate> m_date;
     boost::optional<std::string> m_num;
     boost::optional<std::string> m_desc;
     boost::optional<std::string> m_notes;
@@ -176,12 +176,12 @@ private:
     boost::optional<GncNumeric> m_price;
     boost::optional<std::string> m_memo;
     boost::optional<char> m_rec_state;
-    boost::optional<time64> m_rec_date;
+    boost::optional<GncDate> m_rec_date;
     boost::optional<std::string> m_taction;
     boost::optional<Account*> m_taccount;
     boost::optional<std::string> m_tmemo;
     boost::optional<char> m_trec_state;
-    boost::optional<time64> m_trec_date;
+    boost::optional<GncDate> m_trec_date;
     bool created = false;
 
     std::map<GncTransPropType, std::string> m_errors;
diff --git a/src/import-export/csv-imp/gnc-tx-import.cpp b/src/import-export/csv-imp/gnc-tx-import.cpp
index 7dbaff8..daa85b4 100644
--- a/src/import-export/csv-imp/gnc-tx-import.cpp
+++ b/src/import-export/csv-imp/gnc-tx-import.cpp
@@ -43,14 +43,6 @@ extern "C" {
 
 G_GNUC_UNUSED static QofLogModule log_module = GNC_MOD_IMPORT;
 
-const int num_date_formats = 5;
-const gchar* date_format_user[] = {N_("y-m-d"),
-                                   N_("d-m-y"),
-                                   N_("m-d-y"),
-                                   N_("d-m"),
-                                   N_("m-d")
-                                  };
-
 const int num_currency_formats = 3;
 const gchar* currency_format_user[] = {N_("Locale"),
                                        N_("Period: 123,456.78"),
@@ -742,6 +734,8 @@ void GncTxImport::update_pre_trans_props (uint32_t row, uint32_t col, GncTransPr
     if ((prop_type == GncTransPropType::NONE) || (prop_type > GncTransPropType::TRANS_PROPS))
         return; /* Only deal with transaction related properties. */
 
+    /* Deliberately make a copy of the GncPreTrans. It may be the original one was shared
+     * with a previous line and should no longer be after the transprop is changed. */
     auto trans_props = std::make_shared<GncPreTrans> (*(std::get<PL_PRETRANS>(m_parsed_lines[row])).get());
     auto value = std::string();
 
diff --git a/src/import-export/csv-imp/gnc-tx-import.hpp b/src/import-export/csv-imp/gnc-tx-import.hpp
index fbded6e..4e7482c 100644
--- a/src/import-export/csv-imp/gnc-tx-import.hpp
+++ b/src/import-export/csv-imp/gnc-tx-import.hpp
@@ -64,10 +64,6 @@ struct DraftTransaction
 extern const int num_currency_formats;
 extern const gchar* currency_format_user[];
 
-/* A set of date formats that the user sees. */
-extern const int num_date_formats;
-extern const gchar* date_format_user[];
-
 /** An enum describing the columns found in a parse_line_t. Currently these are:
  *  - a tokenized line of input
  *  - an optional error string
diff --git a/src/import-export/csv-imp/test/test-tx-import.cpp b/src/import-export/csv-imp/test/test-tx-import.cpp
index 1df18a4..76a4362 100644
--- a/src/import-export/csv-imp/test/test-tx-import.cpp
+++ b/src/import-export/csv-imp/test/test-tx-import.cpp
@@ -62,150 +62,3 @@ public:
 protected:
     std::unique_ptr<GncTxImport> tx_importer;
 };
-
-
-/* parse_date
-time64 parse_date (const char* date_str, int format)// C: 14 in 7 SCM: 9 in 2 Local: 1:0:0
-*/
-TEST(GncTxImportTest, parse_date)
-{
-    time64 rawtime = gnc_time (nullptr);
-    struct tm *tm = gnc_gmtime (&rawtime);
-    int curr_year = tm->tm_year;
-
-
-    /* Note: tm_year = year - 1900 and tm_mon = 0-11
-     * I'm writing the expected values as subtractions for easier
-     * comparison with the date string under test
-     */
-    parse_date_data test_dates[] =
-    {
-        // supported combinations  -/.'
-        { 0, "2013-08-01", 2013 - 1900,  8 - 1,  1},
-        { 0,  "2013-8-01", 2013 - 1900,  8 - 1,  1},
-        { 0,  "2013-08-1", 2013 - 1900,  8 - 1,  1},
-        { 0,   "2013-8-1", 2013 - 1900,  8 - 1,  1},
-        { 0,   "13-08-01", 2013 - 1900,  8 - 1,  1},
-        { 0,    "13-8-01", 2013 - 1900,  8 - 1,  1},
-        { 0,    "13-08-1", 2013 - 1900,  8 - 1,  1},
-        { 0,     "13-8-1", 2013 - 1900,  8 - 1,  1},
-        { 0, "2009/11/04", 2009 - 1900, 11 - 1,  4},
-        { 0,  "1985.3.12", 1985 - 1900,  3 - 1, 12},
-        { 0,      "3'6'8", 2003 - 1900,  6 - 1,  8},
-        { 0,   "20130801", 2013 - 1900,  8 - 1,  1},
-        { 1, "01-08-2013", 2013 - 1900,  8 - 1,  1},
-        { 1,  "01-8-2013", 2013 - 1900,  8 - 1,  1},
-        { 1,  "1-08-2013", 2013 - 1900,  8 - 1,  1},
-        { 1,   "1-8-2013", 2013 - 1900,  8 - 1,  1},
-        { 1,   "01-08-13", 2013 - 1900,  8 - 1,  1},
-        { 1,    "01-8-13", 2013 - 1900,  8 - 1,  1},
-        { 1,    "1-08-13", 2013 - 1900,  8 - 1,  1},
-        { 1,     "1-8-13", 2013 - 1900,  8 - 1,  1},
-        { 1, "04/11/2009", 2009 - 1900, 11 - 1,  4},
-        { 1,  "12.3.1985", 1985 - 1900,  3 - 1, 12},
-        { 1,      "8'6'3", 2003 - 1900,  6 - 1,  8},
-        { 1,   "01082013", 2013 - 1900,  8 - 1,  1},
-        { 2, "08-01-2013", 2013 - 1900,  8 - 1,  1},
-        { 2,  "8-01-2013", 2013 - 1900,  8 - 1,  1},
-        { 2,  "08-1-2013", 2013 - 1900,  8 - 1,  1},
-        { 2,   "8-1-2013", 2013 - 1900,  8 - 1,  1},
-        { 2,   "08-01-13", 2013 - 1900,  8 - 1,  1},
-        { 2,    "8-01-13", 2013 - 1900,  8 - 1,  1},
-        { 2,    "08-1-13", 2013 - 1900,  8 - 1,  1},
-        { 2,     "8-1-13", 2013 - 1900,  8 - 1,  1},
-        { 2, "11/04/2009", 2009 - 1900, 11 - 1,  4},
-        { 2,  "3.12.1985", 1985 - 1900,  3 - 1, 12},
-        { 2,      "6'8'3", 2003 - 1900,  6 - 1,  8},
-        { 2,   "08012013", 2013 - 1900,  8 - 1,  1},
-        { 3,      "01-08",   curr_year,  8 - 1,  1},
-        { 3,       "01-8",   curr_year,  8 - 1,  1},
-        { 3,       "1-08",   curr_year,  8 - 1,  1},
-        { 3,        "1-8",   curr_year,  8 - 1,  1},
-        { 3,      "04/11",   curr_year, 11 - 1,  4},
-        { 3,       "12.3",   curr_year,  3 - 1, 12},
-        { 3,        "8'6",   curr_year,  6 - 1,  8},
-        { 3,       "0108",   curr_year,  8 - 1,  1},
-        { 4,      "08-01",   curr_year,  8 - 1,  1},
-        { 4,       "8-01",   curr_year,  8 - 1,  1},
-        { 4,       "08-1",   curr_year,  8 - 1,  1},
-        { 4,        "8-1",   curr_year,  8 - 1,  1},
-        { 4,      "11/04",   curr_year, 11 - 1,  4},
-        { 4,       "3.12",   curr_year,  3 - 1, 12},
-        { 4,        "6'8",   curr_year,  6 - 1,  8},
-        { 4,       "0801",   curr_year,  8 - 1,  1},
-
-        // ambiguous date formats
-        // current parser doesn't know how to disambiguate
-        // and hence refuses to parse
-        // can possibly improved with a smarter parser
-        { 0,     "130801",          -1,     -1, -1},
-        { 1,     "010813",          -1,     -1, -1},
-        { 2,     "080113",          -1,     -1, -1},
-
-        // Combinations that don't make sense
-        // but can still be entered by a user
-        // Should ideally all result in refusal to parse...
-        { 0,      "08-01",          -1,     -1, -1},
-        { 0,       "0801",          -1,     -1, -1},
-        { 1,      "01-08",          -1,     -1, -1},
-        { 1,       "0108",          -1,     -1, -1},
-        { 2,      "08-01",          -1,     -1, -1},
-        { 2,       "0801",          -1,     -1, -1},
-        { 3, "01-08-2013",          -1,     -1, -1},
-        { 3,   "01-08-13",          -1,     -1, -1},
-        { 3,   "08-08-08",          -1,     -1, -1},
-        { 3,   "01082013",          -1,     -1, -1},
-        { 3,     "010813",          -1,     -1, -1},
-        { 3,   "20130108",          -1,     -1, -1},
-        { 4, "08-01-2013",          -1,     -1, -1},
-        { 4,   "08-01-13",          -1,     -1, -1},
-        { 4, "2013-08-01",          -1,     -1, -1},
-        { 4,   "09-08-01",          -1,     -1, -1},
-        { 4,   "08012013",          -1,     -1, -1},
-        { 4,     "080113",          -1,     -1, -1},
-        { 4,   "20130801",          -1,     -1, -1},
-
-        // Sentinel to mark the end of available tests
-        { 0,         NULL,           0,      0,  0},
-
-    };
-    int i = 0;
-
-    gnc_tm_free(tm);
-    while (test_dates[i].date_str)
-    {
-        gboolean success = TRUE;
-        int got_year = 0, got_month = 0, got_day = 0;
-
-        try
-        {
-            rawtime = parse_date (std::string(test_dates[i].date_str), test_dates[i].date_fmt);
-            tm = gnc_gmtime (&rawtime);
-            got_year = tm->tm_year;
-            got_month = tm->tm_mon;
-            got_day = tm->tm_mday;
-            gnc_tm_free(tm);
-        }
-        catch (std::invalid_argument)
-        {
-            got_year = got_month = got_day = -1;
-        }
-
-        if ((got_year  != test_dates[i].exp_year) ||
-            (got_month != test_dates[i].exp_month) ||
-            (got_day   != test_dates[i].exp_day))
-        {
-            g_error ("Parse_date failed for date '%s' and format '%d'.\n"
-                            "Expected result: year %d, month %d, day %d\n"
-                            "Obtained result: year %d, month %d, day %d",
-                            test_dates[i].date_str,
-                            test_dates[i].date_fmt,
-                            test_dates[i].exp_year,
-                            test_dates[i].exp_month,
-                            test_dates[i].exp_day,
-                            got_year, got_month, got_day);
-        }
-
-        i++;
-    }
-}

commit 7df29b572a2309ae0ee730285f91d2116b8ff426
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Tue May 2 23:09:23 2017 +0200

    Add copy constructor and assignment operator to GncDate

diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp
index 2a193ae..fcd55c5 100644
--- a/src/libqof/qof/gnc-datetime.cpp
+++ b/src/libqof/qof/gnc-datetime.cpp
@@ -509,10 +509,18 @@ GncDate::GncDate(const std::string str, const std::string fmt) :
 m_impl(new GncDateImpl(str, fmt)) {}
 GncDate::GncDate(std::unique_ptr<GncDateImpl> impl) :
 m_impl(std::move(impl)) {}
+GncDate::GncDate(const GncDate& a) :
+m_impl(new GncDateImpl(*a.m_impl)) {}
 GncDate::GncDate(GncDate&&) = default;
 GncDate::~GncDate() = default;
 
 GncDate&
+GncDate::operator=(const GncDate& a)
+{
+    m_impl.reset(new GncDateImpl(*a.m_impl));
+    return *this;
+}
+GncDate&
 GncDate::operator=(GncDate&&) = default;
 
 void
diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp
index 2d879d6..104220d 100644
--- a/src/libqof/qof/gnc-datetime.hpp
+++ b/src/libqof/qof/gnc-datetime.hpp
@@ -244,9 +244,23 @@ class GncDate
          * - fmt doesn't specify a year, yet a year was found in the string
          */
         GncDate(const std::string str, const std::string fmt);
+        /** Construct a GncDate from a GncDateImpl.
+         */
         GncDate(std::unique_ptr<GncDateImpl> impl);
+        /** Copy constructor.
+         */
+        GncDate(const GncDate&);
+        /** Move constructor.
+         */
         GncDate(GncDate&&);
+        /** Default destructor.
+         */
         ~GncDate();
+        /** Copy assignment operator.
+         */
+        GncDate& operator=(const GncDate&);
+        /** Move assignment operator.
+         */
         GncDate& operator=(GncDate&&);
         /** Set the date object to the computer clock's current day. */
         void today();
diff --git a/src/libqof/qof/test/gtest-gnc-datetime.cpp b/src/libqof/qof/test/gtest-gnc-datetime.cpp
index b914896..b334230 100644
--- a/src/libqof/qof/test/gtest-gnc-datetime.cpp
+++ b/src/libqof/qof/test/gtest-gnc-datetime.cpp
@@ -37,6 +37,22 @@ TEST(gnc_date_constructors, test_ymd_constructor)
     EXPECT_FALSE(date.isnull());
 }
 
+TEST(gnc_date_constructors, test_copy_constructor)
+{
+    GncDate a(2045, 11, 13);
+    GncDate b(a);
+    EXPECT_FALSE(a.isnull());
+    EXPECT_TRUE (a == b);
+}
+
+TEST(gnc_date_constructors, test_move_constructor)
+{
+    GncDate a(2045, 11, 13);
+    GncDate b(std::move(a));
+    EXPECT_TRUE(a.isnull());
+    EXPECT_TRUE (b.format("%Y-%m-%d") == "2045-11-13");
+}
+
 typedef struct
 {
     const char* date_fmt;
@@ -46,9 +62,6 @@ typedef struct
     int         exp_day;
 } parse_date_data;
 
-/* parse_date
- * time64 parse_date (const char* date_str, int format)// C: 14 in 7 SCM: 9 in 2 Local: 1:0:0
- */
 TEST(gnc_date_constructors, test_str_format_constructor)
 {
     auto today = GncDate();
@@ -215,6 +228,23 @@ TEST(gnc_date_operators, test_more_less_than)
     EXPECT_FALSE (c >= a);
 }
 
+TEST(gnc_date_operators, test_copy_assignment)
+{
+    GncDate a(2017, 1, 6);
+    GncDate b;
+    b = a;
+    EXPECT_TRUE (a == b);
+}
+
+TEST(gnc_date_operators, test_move_assignment)
+{
+    GncDate a(2045, 11, 13);
+    GncDate b;
+    b = std::move(a);
+    EXPECT_TRUE(a.isnull());
+    EXPECT_TRUE (b.format("%Y-%m-%d") == "2045-11-13");
+}
+
 TEST(gnc_datetime_constructors, test_default_constructor)
 {
     GncDateTime atime;

commit 507003731404820f32ce436b6930ea099aadeead
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sat Apr 29 18:01:12 2017 +0200

    Add comparison operators for GncDate
    
    Note the operands are const GncDate& because the GncDate has no copy
    constructor/assigment operator (any other definition would fail
    when used with variables of type boost::optional<GncDate>)

diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp
index 6191cf7..2a193ae 100644
--- a/src/libqof/qof/gnc-datetime.cpp
+++ b/src/libqof/qof/gnc-datetime.cpp
@@ -213,6 +213,12 @@ private:
     Date m_greg;
 
     friend GncDateTimeImpl::GncDateTimeImpl(const GncDateImpl&, DayPart);
+    friend bool operator<(const GncDateImpl&, const GncDateImpl&);
+    friend bool operator>(const GncDateImpl&, const GncDateImpl&);
+    friend bool operator==(const GncDateImpl&, const GncDateImpl&);
+    friend bool operator<=(const GncDateImpl&, const GncDateImpl&);
+    friend bool operator>=(const GncDateImpl&, const GncDateImpl&);
+    friend bool operator!=(const GncDateImpl&, const GncDateImpl&);
 };
 
 /* Member function definitions for GncDateTimeImpl.
@@ -427,6 +433,13 @@ GncDateImpl::format(const char* format) const
     return ss.str();
 }
 
+bool operator<(const GncDateImpl& a, const GncDateImpl& b) { return a.m_greg < b.m_greg; }
+bool operator>(const GncDateImpl& a, const GncDateImpl& b) { return a.m_greg > b.m_greg; }
+bool operator==(const GncDateImpl& a, const GncDateImpl& b) { return a.m_greg == b.m_greg; }
+bool operator<=(const GncDateImpl& a, const GncDateImpl& b) { return a.m_greg <= b.m_greg; }
+bool operator>=(const GncDateImpl& a, const GncDateImpl& b) { return a.m_greg >= b.m_greg; }
+bool operator!=(const GncDateImpl& a, const GncDateImpl& b) { return a.m_greg != b.m_greg; }
+
 /* =================== Presentation-class Implementations ====================*/
 /* GncDateTime */
 
@@ -519,3 +532,10 @@ GncDate::year_month_day() const
 {
     return m_impl->year_month_day();
 }
+
+bool operator<(const GncDate& a, const GncDate& b) { return *(a.m_impl) < *(b.m_impl); }
+bool operator>(const GncDate& a, const GncDate& b) { return *(a.m_impl) > *(b.m_impl); }
+bool operator==(const GncDate& a, const GncDate& b) { return *(a.m_impl) == *(b.m_impl); }
+bool operator<=(const GncDate& a, const GncDate& b) { return *(a.m_impl) <= *(b.m_impl); }
+bool operator>=(const GncDate& a, const GncDate& b) { return *(a.m_impl) >= *(b.m_impl); }
+bool operator!=(const GncDate& a, const GncDate& b) { return *(a.m_impl) != *(b.m_impl); }
diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp
index 59fb059..2d879d6 100644
--- a/src/libqof/qof/gnc-datetime.hpp
+++ b/src/libqof/qof/gnc-datetime.hpp
@@ -270,6 +270,23 @@ private:
     std::unique_ptr<GncDateImpl> m_impl;
 
     friend GncDateTime::GncDateTime(const GncDate&, DayPart);
+    friend bool operator<(const GncDate&, const GncDate&);
+    friend bool operator>(const GncDate&, const GncDate&);
+    friend bool operator==(const GncDate&, const GncDate&);
+    friend bool operator<=(const GncDate&, const GncDate&);
+    friend bool operator>=(const GncDate&, const GncDate&);
+    friend bool operator!=(const GncDate&, const GncDate&);
 };
 
+/**@{
+ *  Standard comparison operators working on GncDate objects.
+ */
+bool operator<(const GncDate& a, const GncDate& b);
+bool operator>(const GncDate& a, const GncDate& b);
+bool operator==(const GncDate& a, const GncDate& b);
+bool operator<=(const GncDate& a, const GncDate& b);
+bool operator>=(const GncDate& a, const GncDate& b);
+bool operator!=(const GncDate& a, const GncDate& b);
+/**@}*/
+
 #endif // __GNC_DATETIME_HPP__
diff --git a/src/libqof/qof/test/gtest-gnc-datetime.cpp b/src/libqof/qof/test/gtest-gnc-datetime.cpp
index 0730bd3..b914896 100644
--- a/src/libqof/qof/test/gtest-gnc-datetime.cpp
+++ b/src/libqof/qof/test/gtest-gnc-datetime.cpp
@@ -183,6 +183,38 @@ TEST(gnc_date_constructors, test_str_format_constructor)
     }
 }
 
+TEST(gnc_date_operators, test_equality)
+{
+    GncDate a(2017, 1, 6);
+    GncDate b(2017, 1, 6);
+    GncDate c(2015, 6, 13);
+    EXPECT_TRUE (a == b);
+    EXPECT_FALSE (a == c);
+    EXPECT_TRUE (a != c);
+    EXPECT_FALSE (a != b);
+}
+
+TEST(gnc_date_operators, test_more_less_than)
+{
+    GncDate a(2017, 1, 6);
+    GncDate b(2017, 1, 6);
+    GncDate c(2015, 6, 13);
+    EXPECT_TRUE (a >= b);
+    EXPECT_TRUE (a <= b);
+    EXPECT_FALSE (a > b);
+    EXPECT_FALSE (a < b);
+
+    EXPECT_TRUE (a > c);
+    EXPECT_TRUE (a >= c);
+    EXPECT_FALSE (a < c);
+    EXPECT_FALSE (a <= c);
+
+    EXPECT_TRUE (c < a);
+    EXPECT_TRUE (c <= a);
+    EXPECT_FALSE (c > a);
+    EXPECT_FALSE (c >= a);
+}
+
 TEST(gnc_datetime_constructors, test_default_constructor)
 {
     GncDateTime atime;



Summary of changes:
 .../csv-imp/assistant-csv-trans-import.cpp         |   8 +-
 .../csv-imp/gnc-csv-trans-settings.cpp             |  10 ++
 src/import-export/csv-imp/gnc-trans-props.cpp      | 137 +++----------------
 src/import-export/csv-imp/gnc-trans-props.hpp      |   8 +-
 src/import-export/csv-imp/gnc-tx-import.cpp        |  10 +-
 src/import-export/csv-imp/gnc-tx-import.hpp        |   4 -
 src/import-export/csv-imp/test/test-tx-import.cpp  | 147 ---------------------
 src/libqof/qof/gnc-datetime.cpp                    |  28 ++++
 src/libqof/qof/gnc-datetime.hpp                    |  31 +++++
 src/libqof/qof/test/gtest-gnc-datetime.cpp         |  68 +++++++++-
 10 files changed, 159 insertions(+), 292 deletions(-)



More information about the gnucash-changes mailing list