Existe uma função Python para determinar em qual trimestre do ano está uma data?

113

Claro que eu poderia escrever isso sozinho, mas antes de reinventar a roda, há uma função que já faz isso?

Jason Christa
fonte
22
Pergunta MUITO justificada, embora as primeiras respostas pareçam um pouco desdenhosas ("apenas uma questão de", "parece muito simples"): duas das respostas (incluindo uma REALIZADA!) São terrivelmente bugadas, mostrando que NÃO é tão simples ou " apenas "...
Alex Martelli
Tenho certeza que ele vai voltar e consertar isso
Nadia Alramli
Esta pergunta é muito útil em 2018: D
wdfc
Se os objetos de data e hora são armazenados em uma série Pandas ou trama de dados , há um método que retorna o respectivo trimestre (s): pandas.Series.dt.quarter.
Sumanth Lazarus

Respostas:

162

Dada uma instância xde datetime.date , (x.month-1)//3fornecerá 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 -1antes da divisão e dividindo por 4 em vez de 3. Como .monthvai 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

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

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 datetoolsmó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 ;-).

Alex Martelli
fonte
3
Obrigado Alex. É por isso que deve haver uma função. Veja quantas pessoas erraram.
Jason Christa
Eu acho que você provou seu ponto. Não é necessário poluir a página inteira com comentários repetidos.
João Silva
1
@Jason, sim, exatamente - é por isso que votei positivamente em sua pergunta quando vi as outras respostas problemáticas (atualmente excluídas), embora outra pessoa pareça ter votado negativamente para contar meu voto positivo, ah, bem.
Alex Martelli
1
@JG, quais são os "comentários repetidos"? Como as respostas com erros foram excluídas, os comentários foram embora com eles, então eu trouxe seu conteúdo para a resposta - é importante estar ciente de como é fácil se distrair ou se apressar e obter um bug evitável, mesmo em um cálculo simples, e tem consequências (em termos de fazer e testar solidamente funções reutilizáveis) para as melhores práticas de programação; este caso é um bom exemplo (o que eu acho que prova que a questão era justificada).
Alex Martelli
7
Também pode usar: em (m+2)//3vez de(m-1)//3 + 1
Ben
49

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 datecoluna em um dataframe, pode facilmente criar uma nova quartercoluna:

df['quarter'] = df['date'].dt.quarter
chishaku
fonte
E se o trimestre do meu ano fiscal começar em setembro?
Arthur D. Howland
O método Pandas pandas.Series.dt.quarteré uma solução ideal quando você tem valores de data e hora em um objeto Dataframe ou Series .
Sumanth Lazarus
31

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.

Jonathan Rocher
fonte
1
O melhor até agora. Muito obrigado!
curlyreggie de
3
Provavelmente deve envolver isso em um int ()
Pablojim
Como a resposta de @garbanzio sugere. Eu precisava colocar o argumento do mês por meio da função float para fazer isso funcionar math.ceil(float(4)/3) = 2.0enquantomath.ceil(4/3) = 1.0
Theo Kouzelis
1
Ignore-me, não percebi o que o .depois do 3 fez. math.ceil(4/3.) = 2.0
Theo Kouzelis
11

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 fiscalyeardeve funcionar tanto no Python 2 quanto no 3.

É basicamente um invólucro em torno do módulo datetime integrado , portanto, todos os datetimecomandos 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)

fiscalyearestá 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!

Adam Stewart
fonte
4

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
Roei Bahumi
fonte
2

se mé o número do mês ...

import math
math.ceil(float(m) / 3)
garbanzio
fonte
2

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
Uri Goren
fonte
2

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

Siddaram H
fonte
1

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).

MikeHoss
fonte
1

Isso é muito simples e funciona em 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 = 'q'+str((now.month-1)//3+1)
JavDomGom
fonte
0

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]
Anurag Uniyal
fonte
@RussBradberry neste caso pode estar certo, mas às vezes a legibilidade e o fato de ser explícito contam e levam a menos erros, em vez de um cálculo conciso
Anurag Uniyal
1
@RussBradberry também veja respostas deletadas e comentários sobre isso, veja um cálculo simples pode ser complicado para bons programadores também e é difícil ver a correção exceto testando-o, na minha solução você pode ver e ter certeza de que funcionará
Anurag Uniyal
1
exatamente como você disse "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.
Russ Bradberry
Não me interpretem mal (m-1)//3 + 1també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.
Russ Bradberry
@RussBradberry na verdade, eu concordo com você, minha resposta foi como uma alternativa e às vezes há alternativas. Eu vi muito código onde as pessoas estão tentando calcular / deduzir algo que pode ser codificado em um mapa
Anurag Uniyal
0

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
igniteflow
fonte
0

usando dicionários, você pode fazer isso

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))
Conduziu
fonte