1
\$\begingroup\$

I have the below

private function yearMenu() {
    $m = date('m');
    $y = date('Y');

    if (($m>3 && $y==2019) || ($m<4 && $y==2020)){
        $menu = 1;
    }
    if (($m>3 && $y==2020) || ($m<4 && $y==2021)){
        $menu = 2;
    }
    if (($m>3 && $y==2021) || ($m<4 && $y==2022)){
        $menu = 3;
    }
    if (($m>3 && $y==2022) || ($m<4 && $y==2023)){
        $menu = 4;
    }
    if (($m>3 && $y==2023) || ($m<4 && $y==2024)){
        $menu = 5;
    }
    if (($m>3 && $y==2024) || ($m<4 && $y==2025)){
        $menu = 6;
    }

    return $menu;
}

This code works as intended i.e. I want to be able to give each financial year an integer based on 2019-2020 being the base at value 1 and it increasing each year onward

I was wondering if there was a more succinct and scalable way to do this?

Thanks

\$\endgroup\$
1
\$\begingroup\$

Ways of improving:

According to information provided the crucial function's purpose is "to return a particular menu number for the current year". Thus, the function name would be more descriptive with name getFinYearMenuNumber.

The preconditions are:

  • your financial year flows through "April to April" month periods
  • there's starting year 2019 and ending year 2015 for the whole interval.
    To make the function more unified those boundaries could be passed as input parameters:

    function getFinYearMenuNumber($yearFrom, $yearTo)
    

The main issue of the current approach is that it'll inevitably perform 5 excessive if checks (they could be at least mutually exclusive if ... else if ... else if ...).

Instead, we can just perform 2 subsequent checks:

  • if the current year falls in the needed interval
  • if the current month is following or preceding the starting month (April)

The final version:

function getFinYearMenuNumber($yearFrom, $yearTo) {
    $curr_month = (int) date('m');    # current month number
    $curr_year = (int) date('Y');     # current year
    $curr_date = new DateTime();

    if ((new DateTime("$yearFrom-04")) <= $curr_date && $curr_date <= (new DateTime("$yearTo-04"))) {
        if ($curr_month > 3) {
            return $curr_year - $yearFrom + 1; 
        } else if ($curr_month < 4) {
            return $curr_year - $yearFrom; 
        }
    }

    return 0;
}

print_r(getFinYearMenuNumber(2019, 2025));
\$\endgroup\$
1
\$\begingroup\$

Your current version is very much a fixed piece of code, as you can see there is a lot of repetition and the result can be summed up as

  • Based on 2019-04-01 being the start of the first year
  • The year counting up as starting on the 4th month of each year.

This code is very much based on that premise, taking the start date (an optional parameter to this method - defaulted to current date) the code takes the difference between the date to test and the date of 2019-04-01 (using diff()). This returns an instance of DateInterval, which you can then extract the year component (y) and add 1 so that 2019 is year 1.

(Altered to be a standalone function for test purposes)...

function getFinanceYear ( DateTime $dateToTest = null)  {
    // Use date passed in, or default to current date
    $dateToTest = $dateToTest ?? new DateTime();
    // Calculate the difference
    $interval = $dateToTest->diff(new DateTime("2019-04-01"));
    // return the difference in years (offset by 1)
    return $interval->y+1;
}

A few test runs...

echo getFinanceYear().PHP_EOL;  // 1
echo getFinanceYear(new DateTime("2029-03-01")).PHP_EOL;   // 10
echo getFinanceYear(new DateTime("2029-04-01")).PHP_EOL;   // 11
\$\endgroup\$
1
  • \$\begingroup\$ Excellent, succinct, scalable, and unconditional (in its calculation). \$\endgroup\$ – mickmackusa Nov 15 '19 at 22:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.