Sure I could write this myself, but before I go reinventing the wheel is there a function that already does this?
-
2If the datetime objects are stored in a **Pandas Series or Dataframe**, there is a method which returns the respective quarter(s): `pandas.Series.dt.quarter`. – Sumax Aug 11 '20 at 05:01
18 Answers
Given an instance x
of datetime.date, (x.month-1)//3
will give you the quarter (0 for first quarter, 1 for second quarter, etc -- add 1 if you need to count from 1 instead;-).
Originally two answers, multiply upvoted and even originally accepted (both currently deleted), were buggy -- not doing the -1
before the division, and dividing by 4 instead of 3. Since .month
goes 1 to 12, it's easy to check for yourself what formula is right:
for m in range(1, 13):
print m//4 + 1,
print
gives 1 1 1 2 2 2 2 3 3 3 3 4
-- two four-month quarters and a single-month one (eep).
for m in range(1, 13):
print (m-1)//3 + 1,
print
gives 1 1 1 2 2 2 3 3 3 4 4 4
-- now doesn't this look vastly preferable to you?-)
This proves that the question is well warranted, I think;-).
I don't think the datetime module should necessarily have every possible useful calendric function, but I do know I maintain a (well-tested;-) datetools
module for the use of my (and others') projects at work, which has many little functions to perform all of these calendric computations -- some are complex, some simple, but there's no reason to do the work over and over (even simple work) or risk bugs in such computations;-).

- 275,237
- 103
- 548
- 598

- 854,459
- 170
- 1,222
- 1,395
-
3Thanks Alex. This is why there should be a function. Look how many people got it wrong. – Jason Christa Sep 10 '09 at 16:14
-
I think you proved your point. It's unnecessary to pollute the entire page with repeated comments. – João Silva Sep 10 '09 at 16:17
-
1@Jason, yes, exactly -- that's why I upvoted your question once I saw the other buggy answers (currently deleted), even though somebody else seem to have downvoted to counted my upvote, ah well. – Alex Martelli Sep 10 '09 at 16:17
-
2@JG, what "repeated comments"? As the buggy answers were deleted, the comments went away with them, so I brought their contents into the answer -- it's important to be aware of how easy it is to be distracted or hurried and get an avoidable bug even in a simple computation, and it has consequences (in terms of making and solidly testing reusable functions) for programming best-practices; this case is a good example (which I think proves the question was warranted). – Alex Martelli Sep 10 '09 at 16:24
-
@JG, Alex was right with his comments. I admit I answered too quickly and I should have thought about this more. I've seen this happen before were the OP accepts an answer and then disappears. – Nadia Alramli Sep 10 '09 at 16:54
-
@AM is your 'datetools' module available under open license for use outside your org? – myroslav Feb 08 '10 at 13:31
-
@myroslav, haven't open-sourced it, but it wouldn't be hard if there was demand, e.g. it would fit as part of http://code.google.com/p/just-the-time/ . What parts are you interested in? – Alex Martelli Feb 08 '10 at 16:17
-
I'd be interested in such functions as what quarter is the current date in, and other functions you might have hidden there such as "what part of the hour is this minute" and stuff like that. – Daniel Goldberg Apr 18 '14 at 13:42
-
8
IF you are already using pandas
, it's quite simple.
import datetime as dt
import pandas as pd
quarter = pd.Timestamp(dt.date(2016, 2, 29)).quarter
assert quarter == 1
If you have a date
column in a dataframe, you can easily create a new quarter
column:
df['quarter'] = df['date'].dt.quarter

- 4,577
- 3
- 25
- 33
-
-
The Pandas method `pandas.Series.dt.quarter` is an ideal solution when you have datetime values in either a **Dataframe** or **Series** object. – Sumax Aug 11 '20 at 05:03
I would suggest another arguably cleaner solution. If X is a datetime.datetime.now()
instance, then the quarter is:
import math
Q=math.ceil(X.month/3.)
ceil has to be imported from math module as it can't be accessed directly.

- 49
- 3
- 13

- 451
- 4
- 2
-
1
-
3
-
Like @garbanzio answer suggests. I needed to put the month argument through the float function to get this to work ```math.ceil(float(4)/3) = 2.0``` while ```math.ceil(4/3) = 1.0``` – Theo Kouzelis Mar 31 '17 at 16:23
-
1Ignore me I didn't realise what the ```.``` after the 3 did. ```math.ceil(4/3.) = 2.0``` – Theo Kouzelis Mar 31 '17 at 16:25
For anyone trying to get the quarter of the fiscal year, which may differ from the calendar year, I wrote a Python module to do just this.
Installation is simple. Just run:
$ pip install fiscalyear
There are no dependencies, and fiscalyear
should work for both Python 2 and 3.
It's basically a wrapper around the built-in datetime module, so any datetime
commands you are already familiar with will work. Here's a demo:
>>> from fiscalyear import *
>>> a = FiscalDate.today()
>>> a
FiscalDate(2017, 5, 6)
>>> a.fiscal_year
2017
>>> a.quarter
3
>>> b = FiscalYear(2017)
>>> b.start
FiscalDateTime(2016, 10, 1, 0, 0)
>>> b.end
FiscalDateTime(2017, 9, 30, 23, 59, 59)
>>> b.q3
FiscalQuarter(2017, 3)
>>> b.q3.start
FiscalDateTime(2017, 4, 1, 0, 0)
>>> b.q3.end
FiscalDateTime(2017, 6, 30, 23, 59, 59)
fiscalyear
is hosted on GitHub and PyPI. Documentation can be found at Read the Docs. If you're looking for any features that it doesn't currently have, let me know!

- 2,001
- 1
- 16
- 16
This is very simple and works in python3:
from datetime import datetime
# Get current date-time.
now = datetime.now()
# Determine which quarter of the year is now. Returns q1, q2, q3 or q4.
quarter_of_the_year = f'q{(now.month-1)//3+1}'

- 957
- 10
- 16
Here is an example of a function that gets a datetime.datetime object and returns a unique string for each quarter:
from datetime import datetime, timedelta
def get_quarter(d):
return "Q%d_%d" % (math.ceil(d.month/3), d.year)
d = datetime.now()
print(d.strftime("%Y-%m-%d"), get_quarter(d))
d2 = d - timedelta(90)
print(d2.strftime("%Y-%m-%d"), get_quarter(d2))
d3 = d - timedelta(180 + 365)
print(d3.strftime("%Y-%m-%d"), get_quarter(d3))
And the output is:
2019-02-14 Q1_2019
2018-11-16 Q4_2018
2017-08-18 Q3_2017

- 2,127
- 16
- 33

- 3,433
- 2
- 20
- 19
For those, who are looking for financial year quarter data, using pandas,
import datetime
import pandas as pd
today_date = datetime.date.today()
quarter = pd.PeriodIndex(today_date, freq='Q-MAR').strftime('Q%q')
reference: pandas period index

- 327
- 3
- 8

- 1,126
- 12
- 17
This method works for any mapping:
month2quarter = {
1:1,2:1,3:1,
4:2,5:2,6:2,
7:3,8:3,9:3,
10:4,11:4,12:4,
}.get
We have just generated a function int->int
month2quarter(9) # returns 3
This method is also fool-proof
month2quarter(-1) # returns None
month2quarter('July') # returns None

- 13,386
- 6
- 58
- 110
This is an old question but still worthy of discussion.
Here is my solution, using the excellent dateutil module.
from dateutil import rrule,relativedelta
year = this_date.year
quarters = rrule.rrule(rrule.MONTHLY,
bymonth=(1,4,7,10),
bysetpos=-1,
dtstart=datetime.datetime(year,1,1),
count=8)
first_day = quarters.before(this_date)
last_day = (quarters.after(this_date)
-relativedelta.relativedelta(days=1)
So first_day
is the first day of the quarter, and last_day
is the last day of the quarter (calculated by finding the first day of the next quarter, minus one day).

- 1,477
- 4
- 18
- 35
I tried the solution with x//3+1 and x//4+1, We get incorrect quarter in either case. The correct answer is like this
for i in range(1,13):
print(((i-1)//3)+1)

- 11
- 1
import datetime
def get_quarter_number_and_date_from_choices(p_quarter_choice):
"""
:param p_quarter_choice:
:return:
"""
current_date = datetime.date.today()
# current_quarter = current_date.month - 1 // 3 + 1
if p_quarter_choice == 'Q1':
quarter = 1
q_start_date = datetime.datetime(current_date.year, 3 * quarter - 2, 1)
q_end_date = datetime.datetime(current_date.year, 3 * quarter + 1, 1) + datetime.timedelta(days=-1)
return q_start_date, q_end_date
elif p_quarter_choice == 'Q2':
quarter = 2
q_start_date = datetime.datetime(current_date.year, 3 * quarter - 2, 1)
q_end_date = datetime.datetime(current_date.year, 3 * quarter + 1, 1) + datetime.timedelta(days=-1)
return q_start_date, q_end_date
elif p_quarter_choice == 'Q3':
quarter = 3
q_start_date = datetime.datetime(current_date.year, 3 * quarter - 2, 1)
q_end_date = datetime.datetime(current_date.year, 3 * quarter + 1, 1) + datetime.timedelta(days=-1)
return q_start_date, q_end_date
elif p_quarter_choice == 'Q4':
quarter = 4
q_start_date = datetime.datetime(current_date.year, 3 * quarter - 2, 1)
q_end_date = datetime.datetime(current_date.year, 3 * quarter, 1) + datetime.timedelta(days=30)
return q_start_date, q_end_date
return None

- 3,381
- 6
- 30
- 45
hmmm so calculations can go wrong, here is a better version (just for the sake of it)
first, second, third, fourth=1,2,3,4# you can make strings if you wish :)
quarterMap = {}
quarterMap.update(dict(zip((1,2,3),(first,)*3)))
quarterMap.update(dict(zip((4,5,6),(second,)*3)))
quarterMap.update(dict(zip((7,8,9),(third,)*3)))
quarterMap.update(dict(zip((10,11,12),(fourth,)*3)))
print quarterMap[6]

- 85,954
- 40
- 175
- 219
-
@RussBradberry in this case may be you right, but sometimes readability and being explicit counts and leads to less errors, instead of a terse calculation – Anurag Uniyal Apr 24 '13 at 01:00
-
1@RussBradberry also see deleted answers and comments on that, see a simple calculation can be tricky for good programmers too and it is difficult to see correctness except by testing it, in my solution you can see and be sure that it will work – Anurag Uniyal Apr 24 '13 at 01:02
-
1just as you said `"it is difficult to see correctness except by testing it"`. You should be writing tests, as all good developers should. Tests are what help to keep you from making mistakes, and catch the ones you do. A developer should never sacrifice performance and readability, to prevent themselves from making a mistake. Also, this is less readable than if you would just made a static dict using literals. – Russ Bradberry Apr 24 '13 at 13:26
-
don't get me wrong `(m-1)//3 + 1` is not all that readable either, not many people know what `//` does. My original comment was just on the statement of `"calculations can go wrong"` which just sounds odd to me. – Russ Bradberry Apr 24 '13 at 13:29
-
@RussBradberry actually I agree with you my answer was as an alternative and to reming sometimes there are alternatives I have seen much code where people are trying to calculate/deduce something which can just be hardcoded in a map – Anurag Uniyal Apr 25 '13 at 19:01
Here is a verbose, but also readable solution that will work for datetime and date instances
def get_quarter(date):
for months, quarter in [
([1, 2, 3], 1),
([4, 5, 6], 2),
([7, 8, 9], 3),
([10, 11, 12], 4)
]:
if date.month in months:
return quarter

- 8,404
- 10
- 38
- 46
using dictionaries, you can pull this off by
def get_quarter(month):
quarter_dictionary = {
"Q1" : [1,2,3],
"Q2" : [4,5,6],
"Q3" : [7,8,9],
"Q4" : [10,11,12]
}
for key,values in quarter_dictionary.items():
for value in values:
if value == month:
return key
print(get_quarter(3))

- 662
- 1
- 19
- 41
for m in range(1, 13):
print ((m*3)//10)

- 1,452
- 2
- 18
- 38

- 1
-
Thanks for your answer and welcome to SO; your answer might be correct, but could you please give some explanation about why and how your code will solve the problem. – Benjamin Zach Oct 27 '20 at 08:26
-
A revisited solution using @Alex Martelli formula and creting a quick function as the question asks.
from datetime import timedelta, date
date_from = date(2021, 1, 1)
date_to = date(2021, 12, 31)
get_quarter = lambda dt: (dt.month-1)//3 + 1
quarter_from = get_quarter(date_from)
quarter_to = get_quarter(date_to)
print(quarter_from)
print(quarter_to)
# 1
# 4

- 6,013
- 5
- 30
- 38
def euclid(a,b):
r = a % b
q = int( ( (a + b - 1) - (a - 1) % b ) / b )
return(q,r)
months_per_year = 12
months_per_quarter = 3
for i in range(months_per_year):
print(i+1,euclid(i+1,months_per_quarter)[0])
#1 1
#2 1
#3 1
#4 2
#5 2
#6 2
#7 3
#8 3
#9 3
#10 4
#11 4
#12 4
-
Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 02 '22 at 12:19