Esiste una funzione Python per determinare in quale trimestre dell'anno si trova una data?


113

Certo che potrei scriverlo da solo, ma prima di reinventare la ruota c'è una funzione che lo fa già?


22
Domanda MOLTO giustificata anche se le prime risposte sembrano un po 'sprezzanti ("solo una questione di", "sembra piuttosto semplice"): due delle risposte (inclusa una SUPERATA!) Sono terribilmente buggate, dimostrando che NON è tutto così semplice o " solo "...
Alex Martelli

Sono sicuro che tornerà e risolverà questo problema
Nadia Alramli

Questa domanda è molto utile nel 2018: D
wdfc

Se gli oggetti datetime vengono memorizzati in una serie Pandas o dataframe , c'è un metodo che restituisce il rispettivo trimestre (s): pandas.Series.dt.quarter.
Sumanth Lazarus l'

Risposte:


162

Data un'istanza xdi datetime.date , (x.month-1)//3ti darà il trimestre (0 per il primo trimestre, 1 per il secondo trimestre, ecc. - aggiungi 1 se devi invece contare da 1 ;-).


Originariamente due risposte, moltiplicate per voti positivi e persino originariamente accettate (entrambe attualmente cancellate), erano buggy - non facendo la -1prima della divisione e dividendo per 4 invece di 3. Dato che .monthva da 1 a 12, è facile verificare di persona quale sia la formula giusto:

for m in range(1, 13):
  print m//4 + 1,
print

1 1 1 2 2 2 2 3 3 3 3 4- due trimestri di quattro mesi e uno di un mese (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 - ora non ti sembra di gran lunga preferibile? -)

Ciò dimostra che la domanda è ben giustificata, credo ;-).

Non penso che il modulo datetime debba necessariamente avere tutte le possibili utili funzioni di calendario, ma so di mantenere un datetoolsmodulo (ben collaudato ;-) per l'uso dei miei (e di altri) progetti al lavoro, che ha molti piccoli funzioni per eseguire tutti questi calcoli calendrici - alcuni sono complessi, altri semplici, ma non c'è motivo per fare il lavoro più e più volte (anche lavoro semplice) o rischiare bug in tali calcoli ;-).


3
Grazie Alex. Questo è il motivo per cui dovrebbe esserci una funzione. Guarda quante persone hanno sbagliato.
Jason Christa

Penso che tu abbia dimostrato il tuo punto. Non è necessario inquinare l'intera pagina con commenti ripetuti.
João Silva

1
@ Jason, sì, esattamente - è per questo che ho votato positivamente la tua domanda una volta che ho visto le altre risposte errate (attualmente cancellate), anche se qualcun altro sembra aver svalutato per contare il mio voto positivo, ah beh.
Alex Martelli

1
@JG, cosa "commenti ripetuti"? Poiché le risposte errate sono state eliminate, i commenti sono andati via con loro, quindi ho portato il loro contenuto nella risposta: è importante essere consapevoli di quanto sia facile essere distratti o affrettati e ottenere un bug evitabile anche con un semplice calcolo, e ha conseguenze (in termini di creazione e collaudo solido di funzioni riutilizzabili) per la programmazione delle migliori pratiche; questo caso è un buon esempio (che credo dimostri che la domanda era giustificata).
Alex Martelli

7
Può anche usare: (m+2)//3invece di(m-1)//3 + 1
Ben

49

SE stai già usando pandas, è abbastanza semplice.

import datetime as dt
import pandas as pd

quarter = pd.Timestamp(dt.date(2016, 2, 29)).quarter
assert quarter == 1

Se hai una datecolonna in un dataframe, puoi facilmente creare una nuova quartercolonna:

df['quarter'] = df['date'].dt.quarter

E se il mio trimestre dell'anno fiscale inizia a settembre?
Arthur D. Howland

Il metodo Pandas pandas.Series.dt.quarterè una soluzione ideale quando si hanno valori datetime in un oggetto Dataframe o Series .
Sumanth Lazarus l'

31

Suggerirei un'altra soluzione discutibilmente più pulita. Se X è datetime.datetime.now()un'istanza, il trimestre è:

import math
Q=math.ceil(X.month/3.)

ceil deve essere importato dal modulo matematico poiché non è possibile accedervi direttamente.


1
Il migliore finora. Grazie mille!
curlyreggie

3
Probabilmente dovrebbe racchiudere questo in un int ()
Pablojim

Come suggerisce la risposta di @garbanzio. Avevo bisogno di inserire l'argomento del mese attraverso la funzione float per farlo funzionare math.ceil(float(4)/3) = 2.0mentremath.ceil(4/3) = 1.0
Theo Kouzelis

1
Ignorami, non mi sono reso conto di cosa ha fatto il .dopo 3 math.ceil(4/3.) = 2.0
Theo Kouzelis

11

Per chiunque cerchi di ottenere il trimestre dell'anno fiscale , che può differire dall'anno solare , ho scritto un modulo Python per fare proprio questo.

L'installazione è semplice. Corri:

$ pip install fiscalyear

Non ci sono dipendenze e fiscalyeardovrebbe funzionare sia per Python 2 che per 3.

È fondamentalmente un wrapper attorno al modulo datetime integrato, quindi tutti i datetimecomandi con cui hai già familiarità funzioneranno. Ecco una 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è ospitato su GitHub e PyPI . La documentazione può essere trovata in Leggi i documenti . Se stai cercando funzionalità che attualmente non ha, fammelo sapere!


4

Di seguito è riportato un esempio di una funzione che ottiene un oggetto datetime.datetime e restituisce una stringa univoca per ogni 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 l'output è:

2019-02-14 Q1_2019
2018-11-16 Q4_2018
2017-08-18 Q3_2017

2

se mè il numero del mese ...

import math
math.ceil(float(m) / 3)

2

Questo metodo funziona per qualsiasi mappatura:

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

Abbiamo appena generato una funzione int->int

month2quarter(9) # returns 3

Questo metodo è anche infallibile

month2quarter(-1) # returns None
month2quarter('July') # returns None

2

Per coloro che sono alla ricerca di dati trimestrali dell'anno finanziario, utilizzando i panda,

import datetime
import pandas as pd
today_date = datetime.date.today()
quarter = pd.PeriodIndex(today_date, freq='Q-MAR').strftime('Q%q')

riferimento: indice del periodo dei panda


1

Questa è una vecchia domanda ma ancora degna di discussione.

Ecco la mia soluzione, utilizzando l'eccellente modulo 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)

Quindi first_dayè il primo giorno del trimestre ed last_dayè l'ultimo giorno del trimestre (calcolato trovando il primo giorno del trimestre successivo, meno un giorno).


1

Questo è molto semplice e funziona 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 = 'q'+str((now.month-1)//3+1)

0

hmmm quindi i calcoli possono andare storti, ecco una versione migliore (solo per il gusto di farlo)

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]

@RussBradberry in questo caso potresti avere ragione, ma a volte la leggibilità e l'essere espliciti contano e portano a meno errori, invece di un calcolo conciso
Anurag Uniyal

1
@RussBradberry vede anche risposte cancellate e commenti su questo, vedere un semplice calcolo può essere complicato anche per i bravi programmatori ed è difficile vedere la correttezza se non provandola, nella mia soluzione puoi vedere ed essere sicuro che funzionerà
Anurag Uniyal

1
proprio come hai detto tu "it is difficult to see correctness except by testing it". Dovresti scrivere dei test, come dovrebbero fare tutti i bravi sviluppatori. I test sono ciò che ti aiuta a impedirti di commettere errori e a catturare quelli che fai. Uno sviluppatore non dovrebbe mai sacrificare prestazioni e leggibilità per evitare di commettere errori. Inoltre, questo è meno leggibile rispetto a se avessi creato un dict statico usando letterali.
Russ Bradberry

non fraintendetemi (m-1)//3 + 1non è nemmeno tutto leggibile, non molte persone sanno cosa //fa. Il mio commento originale era solo sull'affermazione "calculations can go wrong"che mi suona strana.
Russ Bradberry

@RussBradberry in realtà sono d'accordo con te la mia risposta era come alternativa e al reming a volte ci sono alternative Ho visto molto codice in cui le persone stanno cercando di calcolare / dedurre qualcosa che può essere semplicemente codificato in una mappa
Anurag Uniyal

0

Ecco una soluzione dettagliata, ma anche leggibile che funzionerà per le istanze di data e ora

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

0

usando i dizionari, puoi farcela con

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))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.