Claro que eu poderia escrever isso sozinho, mas antes de reinventar a roda, há uma função que já faz isso?
pandas.Series.dt.quarter
.
Claro que eu poderia escrever isso sozinho, mas antes de reinventar a roda, há uma função que já faz isso?
pandas.Series.dt.quarter
.
Respostas:
Dada uma instância x
de datetime.date , (x.month-1)//3
fornecerá o trimestre (0 para o primeiro trimestre, 1 para o segundo trimestre, etc. - adicione 1 se precisar contar a partir de 1 ;-).
Originalmente, duas respostas, com votos positivos multiplicados e até mesmo aceitas originalmente (ambas atualmente excluídas), apresentavam erros - não fazendo o -1
antes da divisão e dividindo por 4 em vez de 3. Como .month
vai de 1 a 12, é fácil verificar por si mesmo qual é a fórmula certo:
for m in range(1, 13):
print m//4 + 1,
print
dá 1 1 1 2 2 2 2 3 3 3 3 4
- dois trimestres de quatro meses e um de um mês (eep).
for m in range(1, 13):
print (m-1)//3 + 1,
print
dá 1 1 1 2 2 2 3 3 3 4 4 4
- agora isso não parece muito preferível para você? -)
Isso prova que a questão é bem justificada, eu acho ;-).
Não acho que o módulo datetime deva necessariamente ter todas as funções de calendário úteis possíveis, mas sei que mantenho um datetools
módulo (bem testado ;-) para o uso de meus (e de outros) projetos no trabalho, que tem muitos poucos funções para realizar todos esses cálculos do calendário - alguns são complexos, outros simples, mas não há razão para fazer o trabalho repetidamente (mesmo o trabalho simples) ou arriscar bugs em tais cálculos ;-).
(m+2)//3
vez de(m-1)//3 + 1
SE você já está usando pandas
, é bem simples.
import datetime as dt
import pandas as pd
quarter = pd.Timestamp(dt.date(2016, 2, 29)).quarter
assert quarter == 1
Se você tem uma date
coluna em um dataframe, pode facilmente criar uma nova quarter
coluna:
df['quarter'] = df['date'].dt.quarter
pandas.Series.dt.quarter
é uma solução ideal quando você tem valores de data e hora em um objeto Dataframe ou Series .
Eu sugeriria outra solução indiscutivelmente mais limpa. Se X for uma datetime.datetime.now()
instância, o quarto será:
import math
Q=math.ceil(X.month/3.)
ceil deve ser importado do módulo matemático, pois não pode ser acessado diretamente.
math.ceil(float(4)/3) = 2.0
enquantomath.ceil(4/3) = 1.0
.
depois do 3 fez. math.ceil(4/3.) = 2.0
Para quem está tentando obter o trimestre do ano fiscal , que pode ser diferente do ano civil , escrevi um módulo Python para fazer exatamente isso.
A instalação é simples. Apenas corra:
$ pip install fiscalyear
Não há dependências e fiscalyear
deve funcionar tanto no Python 2 quanto no 3.
É basicamente um invólucro em torno do módulo datetime integrado , portanto, todos os datetime
comandos com os quais você já está familiarizado funcionarão. Aqui está uma demonstração:
>>> 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
está hospedado no GitHub e PyPI . A documentação pode ser encontrada em Read the Docs . Se você estiver procurando por algum recurso que ele não tenha atualmente, me avise!
Aqui está um exemplo de uma função que obtém um objeto datetime.datetime e retorna uma string exclusiva para cada trimestre:
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_q(d))
d2 = d - timedelta(90)
print(d2.strftime("%Y-%m-%d"), get_q(d2))
d3 = d - timedelta(180 + 365)
print(d3.strftime("%Y-%m-%d"), get_q(d3))
E o resultado é:
2019-02-14 Q1_2019
2018-11-16 Q4_2018
2017-08-18 Q3_2017
Este método funciona para qualquer mapeamento:
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
Acabamos de gerar uma função int->int
month2quarter(9) # returns 3
Este método também é infalível
month2quarter(-1) # returns None
month2quarter('July') # returns None
Para aqueles que procuram dados trimestrais do ano financeiro, usando o pandas,
import datetime
import pandas as pd
today_date = datetime.date.today()
quarter = pd.PeriodIndex(today_date, freq='Q-MAR').strftime('Q%q')
referência: índice do período dos pandas
Esta é uma questão antiga, mas ainda digna de discussão.
Aqui está minha solução, usando o excelente módulo dateutil .
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)
Assim first_day
é o primeiro dia do trimestre e last_day
é o último dia do trimestre (calculado encontrando o primeiro dia do próximo trimestre, menos um dia).
hmmm então os cálculos podem dar errado, aqui está uma versão melhor (apenas por causa dela)
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]
"it is difficult to see correctness except by testing it"
. Você deve escrever testes, como todos os bons desenvolvedores deveriam. Os testes ajudam a evitar que você cometa erros e a detectar os erros cometidos. Um desenvolvedor nunca deve sacrificar o desempenho e a legibilidade para evitar cometer erros. Além disso, isso é menos legível do que se você simplesmente fizesse um dicionário estático usando literais.
(m-1)//3 + 1
também não é tão legível, muitas pessoas não sabem o que //
significa. Meu comentário original foi apenas sobre a afirmação "calculations can go wrong"
que soa estranho para mim.
Aqui está uma solução detalhada, mas também legível, que funcionará para instâncias de data e hora
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