Use the fiscal start day of the month for relative quarter reports

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.
pull/2065/head
Sherlock 1 year ago committed by John Ralls
parent 0185a2fec8
commit 4e4dcf1758

@ -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.
@ -464,20 +484,32 @@ 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 > acct_per.tm_mday)
now.tm_mday = acct_per.tm_mday;
--now.tm_mday;
}
gnc_tm_set_day_end(&now);
}
// Do nothing for LAST and NEXT.
@ -497,15 +529,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))
@ -517,14 +550,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))
@ -534,7 +579,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))
@ -546,7 +591,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));
}

@ -941,6 +941,51 @@ TEST(GncOptionDate, test_not_using_32bit_time_t_in_2038)
EXPECT_FALSE(sizeof (time_t) == 4 && time(nullptr) <= 0) << "Time to upgrade 32bit time_t!";
}
// The relative current quarter start date is the date provided.
static void
set_current_quarter_start(GDate *date)
{
}
static GDateDay
get_last_day_of_month(GDate *date)
{
return gnc_date_get_last_mday(g_date_get_month(date) - G_DATE_JANUARY, g_date_get_year(date));
}
static void
set_current_quarter_end(GDate *date)
{
bool is_last_of_month = g_date_is_last_of_month(date);
GDateDay day = g_date_get_day(date);
GDateDay last_day_of_month;
g_date_set_day(date, 1);
g_date_add_months(date, 3);
last_day_of_month = get_last_day_of_month(date);
g_date_set_day(date, is_last_of_month || day > last_day_of_month ? last_day_of_month : day);
g_date_subtract_days(date, 1);
}
static void
set_previous_quarter_start(GDate *date)
{
bool is_last_of_month = g_date_is_last_of_month(date);
GDateDay day = g_date_get_day(date);
GDateDay last_day_of_month;
g_date_set_day(date, 1);
g_date_subtract_months(date, 3);
last_day_of_month = get_last_day_of_month(date);
g_date_set_day(date, is_last_of_month || day > last_day_of_month ? last_day_of_month : day);
}
static void
set_previous_quarter_end(GDate *date)
{
g_date_subtract_days(date, 1);
}
TEST(GncOptionDate, test_gnc_relative_date_to_time64)
{
GDate date;
@ -967,25 +1012,25 @@ TEST(GncOptionDate, test_gnc_relative_date_to_time64)
EXPECT_EQ(time1,
gnc_relative_date_to_time64(RelativeDatePeriod::END_PREV_MONTH));
g_date_set_time_t(&date, time(nullptr));
gnc_gdate_set_quarter_start(&date);
set_current_quarter_start(&date);
time1 = time64_from_gdate(&date, DayPart::start);
EXPECT_EQ(time1,
gnc_relative_date_to_time64(RelativeDatePeriod::START_CURRENT_QUARTER));
g_date_set_time_t(&date, time(nullptr));
gnc_gdate_set_quarter_end(&date);
set_current_quarter_end(&date);
time1 = time64_from_gdate(&date, DayPart::end);
EXPECT_EQ(time1,
gnc_relative_date_to_time64(RelativeDatePeriod::END_CURRENT_QUARTER));
g_date_set_time_t(&date, time(nullptr));
gnc_gdate_set_prev_quarter_start(&date);
set_previous_quarter_start(&date);
time1 = time64_from_gdate(&date, DayPart::start);
EXPECT_EQ(time1,
gnc_relative_date_to_time64(RelativeDatePeriod::START_PREV_QUARTER));
g_date_set_time_t(&date, time(nullptr));
gnc_gdate_set_prev_quarter_end(&date);
set_previous_quarter_end(&date);
time1 = time64_from_gdate(&date, DayPart::end);
EXPECT_EQ(time1,
gnc_relative_date_to_time64(RelativeDatePeriod::END_PREV_QUARTER));
@ -1225,7 +1270,7 @@ TEST_F(GncDateOption, test_stream_in_quarter_start)
{
GDate date;
g_date_set_time_t(&date, time(nullptr));
gnc_gdate_set_quarter_start(&date);
set_current_quarter_start(&date);
time64 time1{time64_from_gdate(&date, DayPart::start)};
std::istringstream iss{"relative . start-current-quarter"};
iss >> m_option;
@ -1236,7 +1281,7 @@ TEST_F(GncDateOption, test_stream_in_quarter_end)
{
GDate date;
g_date_set_time_t(&date, time(nullptr));
gnc_gdate_set_quarter_end(&date);
set_current_quarter_end(&date);
time64 time1{time64_from_gdate(&date, DayPart::end)};
std::istringstream iss{"relative . end-current-quarter"};
iss >> m_option;
@ -1247,7 +1292,7 @@ TEST_F(GncDateOption, test_stream_in_prev_quarter_start)
{
GDate date;
g_date_set_time_t(&date, time(nullptr));
gnc_gdate_set_prev_quarter_start(&date);
set_previous_quarter_start(&date);
time64 time1{time64_from_gdate(&date, DayPart::start)};
std::istringstream iss{"relative . start-prev-quarter"};
iss >> m_option;
@ -1258,7 +1303,7 @@ TEST_F(GncDateOption, test_stream_in_prev_quarter_end)
{
GDate date;
g_date_set_time_t(&date, time(nullptr));
gnc_gdate_set_prev_quarter_end(&date);
set_previous_quarter_end(&date);
time64 time1{time64_from_gdate(&date, DayPart::end)};
std::istringstream iss{"relative . end-prev-quarter"};
iss >> m_option;

Loading…
Cancel
Save