Skip to content

Commit

Permalink
Use the fiscal start day of the month for relative quarter reports
Browse files Browse the repository at this point in the history
Only the quarter's start month in reports is adjusted when Absolute is selected in the Start Date on the Accounting Period preferences. This branch adjusts both the quarter's start day and month when Absolute is selected or when Relative and Today, Start of this month, or Start of previous month are selected.
  • Loading branch information
agwekixj committed Mar 3, 2025
1 parent f3b08dd commit 2e320fe
Showing 1 changed file with 66 additions and 17 deletions.
83 changes: 66 additions & 17 deletions libgnucash/engine/gnc-option-date.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,26 @@ days_in_month(int month, int year)
return gnc_date_get_last_mday(month, year + 1900);
}

static int
get_last_day_of_month(struct tm& now)
{
/* Ensure that the month is between 0 and 11*/
auto year_delta = (now.tm_mon / 12) + (now.tm_mon < 0 ? -1 : 0);
return days_in_month(now.tm_mon - (12 * year_delta), now.tm_year + year_delta);
}

static void
set_last_day_in_month(struct tm& now)
{
now.tm_mday = get_last_day_of_month(now);
}

static bool
is_last_day_in_month(struct tm& now)
{
return now.tm_mday == get_last_day_of_month(now);
}

/* 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
* gnc_date API would involve multiple conversions to and from struct tm.
Expand Down Expand Up @@ -464,20 +484,33 @@ normalize_reldate_tm(struct tm& now)
}

static void
reldate_set_day_and_time(struct tm& now, RelativeDateType type)
reldate_set_day_and_time(
struct tm& now,
RelativeDateType type,
bool is_offset_quarter,
struct tm& acct_per)
{
if (type == RelativeDateType::START)
{
gnc_tm_set_day_start(&now);
now.tm_mday = 1;
if (is_offset_quarter)
{
set_last_day_in_month(now);
if (!is_last_day_in_month(acct_per) && now.tm_mday > acct_per.tm_mday)
now.tm_mday = acct_per.tm_mday;
}
gnc_tm_set_day_start(&now);
}
else if (type == RelativeDateType::END)
{
/* 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);
set_last_day_in_month(now);
if (is_offset_quarter)
{
if (is_last_day_in_month(acct_per))
--now.tm_mday;
else if (now.tm_mday >= acct_per.tm_mday)
now.tm_mday = acct_per.tm_mday - 1;
}
gnc_tm_set_day_end(&now);
}
// Do nothing for LAST and NEXT.
Expand All @@ -497,15 +530,16 @@ gnc_relative_date_to_time64(RelativeDatePeriod period)
if (period == RelativeDatePeriod::TODAY)
return static_cast<time64>(now_t);
auto now{static_cast<tm>(now_t)};
struct tm acct_per{};
if (gnc_prefs_get_bool (GNC_PREFS_GROUP_ACCT_SUMMARY,
GNC_PREF_START_CHOICE_ABS))
acct_per = static_cast<tm>(GncDateTime(gnc_accounting_period_fiscal_start()));
struct tm acct_per =
static_cast<tm>(GncDateTime(gnc_accounting_period_fiscal_start()));
auto offset = reldate_offset(period);
bool is_offset_quarter =
offset == RelativeDateOffset::QUARTER && acct_per.tm_mday > 1;

switch(reldate_offset(period))
switch(offset)
{
case RelativeDateOffset::NONE:
// Report on today so nothing to do
// Report on today so nothing to do
break;
case RelativeDateOffset::YEAR:
if (reldate_is_prev(period))
Expand All @@ -517,14 +551,26 @@ gnc_relative_date_to_time64(RelativeDatePeriod period)
else if (gnc_relative_date_is_ending(period))
now.tm_mon = 11;
break;
case RelativeDateOffset::SIX:
case RelativeDateOffset::SIX:
if (reldate_is_prev(period))
now.tm_mon -= 6;
else if (reldate_is_next(period))
now.tm_mon += 6;
break;
case RelativeDateOffset::QUARTER:
now.tm_mon -= (12 + now.tm_mon - acct_per.tm_mon) % 3;
{
auto delta = (12 + now.tm_mon - acct_per.tm_mon) % 3;
if (is_offset_quarter)
{
if (delta == 0 && !is_last_day_in_month(now) &&
(is_last_day_in_month(acct_per) ||
now.tm_mday < acct_per.tm_mday))
delta = 3;
if (gnc_relative_date_is_ending(period))
--delta;
}
now.tm_mon -= delta;
}
[[fallthrough]];
case RelativeDateOffset::THREE:
if (reldate_is_prev(period))
Expand All @@ -534,7 +580,7 @@ gnc_relative_date_to_time64(RelativeDatePeriod period)
if (gnc_relative_date_is_ending(period))
now.tm_mon += 2;
break;
case RelativeDateOffset::MONTH:
case RelativeDateOffset::MONTH:
if (reldate_is_prev(period))
--now.tm_mon;
else if (reldate_is_next(period))
Expand All @@ -546,7 +592,10 @@ gnc_relative_date_to_time64(RelativeDatePeriod period)
else if (reldate_is_next(period))
now.tm_mday += 7;
}
reldate_set_day_and_time(now, checked_reldate(period).m_type);
reldate_set_day_and_time( now,
checked_reldate(period).m_type,
is_offset_quarter,
acct_per);
normalize_reldate_tm(now);
return static_cast<time64>(GncDateTime(now));
}
Expand Down

0 comments on commit 2e320fe

Please sign in to comment.