Search code examples
pythondate

First month of quarter given month in Python


Given a month in numeric form (e.g., 2 for February), how do you find the first month of its respective quarter (e.g., 1 for January)?

I read through the datetime module documentation and the Pandas documentation of their datetime functions, which ought to be relevant, but I could not find a function that solves this problem.

Essentially, what I am trying to understand is how I could produce a function like the one below that, given month x, outputs the number corresponding to the first month of x's quarter.

>> first_month_quarter(5)
4

Solution

  • It's a simple mapping function that needs to convert:

    1 2 3 4 5 6 7 8 9 10 11 12
               |
               V
    1 1 1 4 4 4 7 7 7 10 10 10
    

    This can be done in a number of ways with integral calculations, two of which are:

    def firstMonthInQuarter(month):
        return (month - 1) // 3 * 3 + 1
    

    and:

    def firstMonthInQuarter(month):
        return month - (month - 1) % 3
    

    The first involves integer division of the month converted to a zero-based month to get the zero-based quarter, multiplication to turn that back into a zero-based month (but the month at the start of the quarter), then adding one again to make the range 1..12.

    month  -1  //3  *3  +1
    -----  --  ---  --  --
        1   0    0   0   1
        2   1    0   0   1
        3   2    0   0   1
        4   3    1   3   4
        5   4    1   3   4
        6   5    1   3   4
        7   6    2   6   7
        8   7    2   6   7
        9   8    2   6   7
       10   9    3   9  10
       11  10    3   9  10
       12  11    3   9  10
    

    The second just subtracts the position within a quarter (0, 1, 2) from the month itself to get the starting month.

    month(a)  -1  %3(b)  a-b
    --------  --  -----  ---
           1   0      0    1
           2   1      1    1
           3   2      2    1
           4   3      0    4
           5   4      1    4
           6   5      2    4
           7   6      0    7
           8   7      1    7
           9   8      2    7
          10   9      0   10
          11  10      1   10
          12  11      2   10