gnucash stable: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Thu Dec 7 19:57:41 EST 2023


Updated	 via  https://github.com/Gnucash/gnucash/commit/c473ae0e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/07e94b42 (commit)
	from  https://github.com/Gnucash/gnucash/commit/dc2c794e (commit)



commit c473ae0e38d502ffaf4c2352f06e1d6f26b0e096
Merge: dc2c794e80 07e94b4222
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Dec 7 16:57:05 2023 -0800

    Merge Sherlock's 'bug-799152' into stable.


commit 07e94b4222a26cf049b02ff4acdaf54c01340a29
Author: Sherlock <119709043+agwekixj at users.noreply.github.com>
Date:   Tue Dec 5 14:12:51 2023 -0800

    Bug 799152 - normalize_reldate_tm() does not handle dates with...
    
    months greater than 11 or less than -11 correctly.

diff --git a/libgnucash/engine/gnc-option-date.cpp b/libgnucash/engine/gnc-option-date.cpp
index 918ca3ba59..6fb28da550 100644
--- a/libgnucash/engine/gnc-option-date.cpp
+++ b/libgnucash/engine/gnc-option-date.cpp
@@ -420,7 +420,11 @@ reldate_offset(RelativeDatePeriod per)
     return checked_reldate(per).m_offset;
 }
 
-static constexpr int days_in_month[12]{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+static int
+days_in_month(int month, int year)
+{
+    return gnc_date_get_last_mday(month, year + 1900);
+}
 
 /* Normalize the modified struct tm computed in gnc_relative_date_to_time64
  * before setting the time and perhaps beginning/end of the month. Using the
@@ -429,43 +433,33 @@ static constexpr int days_in_month[12]{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 3
 static void
 normalize_reldate_tm(struct tm& now)
 {
-    auto factor{abs(now.tm_mon) / 12};
-    now.tm_mon /= factor > 0 ? factor : 1;
-    now.tm_year += now.tm_mon < 0 ? -factor: factor;
-
-    auto days = [](auto month, int year)
-    {
-        auto mon{month % 12 + (month < 0 ? 12 : 0)};
-        auto num_days{days_in_month[mon]};
-        //Leap year check.
-        if (mon == 1 && year % 4 == 0 && !(year % 100 == 0 && (year + 1900) % 400 != 0))
-            ++num_days;
-        return num_days;
-    };
-
-    while (now.tm_mday < 1)
-        now.tm_mday += days(--now.tm_mon, now.tm_year);
-
-    while (now.tm_mday > days(now.tm_mon, now.tm_year))
-        now.tm_mday -= days(now.tm_mon++, now.tm_year);
-
-    while (now.tm_mon < 0)
+    auto delta = (now.tm_mon / 12) + (now.tm_mon < 0 ? -1 : 0);
+    now.tm_mon -= 12 * delta;
+    now.tm_year += delta;
+  
+    if (now.tm_mday < 1)
     {
-        now.tm_mon += 12;
-        --now.tm_year;
+        do
+        {
+            if (now.tm_mon-- == 0)
+            {
+                now.tm_mon = 11;
+                now.tm_year--;
+            }
+            now.tm_mday += days_in_month(now.tm_mon, now.tm_year);
+        } while (now.tm_mday < 1) ;
+        return;
     }
-    while (now.tm_mon > 11)
+
+    while (now.tm_mday > (delta = days_in_month(now.tm_mon, now.tm_year)))
     {
-        now.tm_mon -= 12;
-        ++now.tm_year;
+        if (now.tm_mon++ == 11)
+        {
+            now.tm_mon = 0;
+            now.tm_year++;
+        }
+        now.tm_mday -= delta;
     }
-
-    /* This would happen only if we moved from Feb 29 in a leap year while
-     * adjusting the months so we don't need to worry about adjusting the year
-     * again.
-     */
-    if (now.tm_mday > days_in_month[now.tm_mon])
-        now.tm_mday -= days_in_month[now.tm_mon++];
 }
 
 static void
@@ -478,11 +472,11 @@ reldate_set_day_and_time(struct tm& now, RelativeDateType type)
     }
     else if (type == RelativeDateType::END)
     {
-        /* Ensure that the month is between 0 and 12*/
-        auto year_delta = now.tm_mon / 12 + now.tm_mon < 0 ? -1 : 0;
-        auto month = now.tm_mon - 12 * year_delta;
-        auto year = now.tm_year + year_delta + 1900;
-        now.tm_mday = gnc_date_get_last_mday(month, year);
+        /* Ensure that the month is between 0 and 11*/
+        auto year_delta = (now.tm_mon / 12) + (now.tm_mon < 0 ? -1 : 0);
+        auto month = now.tm_mon - (12 * year_delta);
+        auto year = now.tm_year + year_delta;
+        now.tm_mday = days_in_month(month, year);
         gnc_tm_set_day_end(&now);
     }
     // Do nothing for LAST and NEXT.



Summary of changes:
 libgnucash/engine/gnc-option-date.cpp | 72 ++++++++++++++++-------------------
 1 file changed, 33 insertions(+), 39 deletions(-)



More information about the gnucash-changes mailing list