Czy istnieje funkcja Pythona do określenia, w którym kwartale roku przypada data?


113

Jasne, mógłbym napisać to sam, ale zanim wymyślę koło na nowo, czy jest jakaś funkcja, która już to robi?


22
Pytanie BARDZO uzasadnione, mimo że wczesne odpowiedzi wydają się odrobinę lekceważące („tylko kwestia”, „wydaje się całkiem proste”): dwie odpowiedzi (w tym jedna ZGŁOSOWANA!) Są okropnie błędne, co oznacza, że ​​NIE jest to takie proste lub „ tylko "...
Alex Martelli

Jestem pewien, że wróci i to naprawi
Nadia Alramli

To pytanie bardzo pomocne w 2018: D
wdfc

Jeśli obiekty datetime są przechowywane w Pandy szeregowo lub Dataframe , istnieje metoda, która zwraca odpowiedni kwartał (y): pandas.Series.dt.quarter.
Sumanth Lazarus

Odpowiedzi:


162

Biorąc pod uwagę wystąpienie xz datetime.date , (x.month-1)//3daje czwartą (0 dla pierwszego kwartału, 1 dla drugiego kwartału, etc - dodać1w jeśli trzeba liczyć od 1 zamiast ;-).


Pierwotnie dwie odpowiedzi, pomnożone za głosami, a nawet pierwotnie zaakceptowane (obie obecnie usunięte), były błędne - nie robiłem tego -1przed podziałem i dzielono przez 4 zamiast 3. Od .month1 do 12 łatwo jest sprawdzić, jaka jest formuła dobrze:

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

daje 1 1 1 2 2 2 2 3 3 3 3 4- dwa kwartały czteromiesięczne i jednomiesięczny (eep).

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

daje 1 1 1 2 2 2 3 3 3 4 4 4- czy to nie wygląda dla ciebie zdecydowanie lepiej? -)

To dowodzi, że pytanie jest, jak sądzę, uzasadnione ;-).

Nie sądzę, że moduł datetime koniecznie powinien mieć każdą możliwą użyteczną funkcję kalendarza, ale wiem, że utrzymuję (dobrze przetestowany ;-) datetoolsmoduł do wykorzystania moich (i innych) projektów w pracy, który ma wiele niewielkich funkcje do wykonywania wszystkich tych obliczeń w kalendarzu - niektóre są złożone, inne proste, ale nie ma powodu, aby wykonywać tę pracę w kółko (nawet prostą pracę) ani ryzykować błędów w takich obliczeniach ;-).


3
Dzięki Alex. Dlatego powinna istnieć funkcja. Zobacz, ile osób pomyliło się.
Jason Christa,

Myślę, że udowodniłeś swój punkt widzenia. Nie trzeba zanieczyszczać całej strony powtarzającymi się komentarzami.
João Silva

1
@Jason, tak, dokładnie - dlatego zagłosowałem za twoim pytaniem, gdy zobaczyłem inne błędne odpowiedzi (obecnie usunięte), chociaż wydaje się, że ktoś inny przegłosował, aby policzyć moje głosy za, hm.
Alex Martelli,

1
@JG, jakie „powtarzające się komentarze”? Ponieważ błędne odpowiedzi zostały usunięte, komentarze zniknęły wraz z nimi, więc dodałem ich treść do odpowiedzi - ważne jest, aby być świadomym, jak łatwo jest się rozproszyć lub spieszyć i uzyskać błąd, którego można uniknąć, nawet w prostym obliczeniu, i ma konsekwencje (w zakresie tworzenia i solidnego testowania funkcji wielokrotnego użytku) dla najlepszych praktyk programowania; ten przypadek jest dobrym przykładem (co moim zdaniem dowodzi, że pytanie było uzasadnione).
Alex Martelli,

7
Można również użyć: (m+2)//3zamiast(m-1)//3 + 1
Ben

49

Jeśli już używasz pandas, jest to dość proste.

import datetime as dt
import pandas as pd

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

Jeśli masz datekolumnę w ramce danych, możesz łatwo utworzyć nową quarterkolumnę:

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

Co się stanie, jeśli kwartał roku podatkowego rozpocznie się we wrześniu?
Arthur D. Howland

Metoda Pandas pandas.Series.dt.quarterjest idealnym rozwiązaniem, gdy masz wartości daty i godziny w obiekcie Dataframe lub Series .
Sumanth Lazarus

31

Sugerowałbym inne, prawdopodobnie czystsze rozwiązanie. Jeśli X jest datetime.datetime.now()instancją, to kwartał jest:

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

ceil musi zostać zaimportowany z modułu matematycznego, ponieważ nie można uzyskać do niego bezpośredniego dostępu.


1
Jak dotąd najlepszy. Wielkie dzięki!
curlyreggie

3
Prawdopodobnie powinno to zawinąć w int ()
Pablojim

Jak sugeruje odpowiedź @garbanzio. Musiałem przełożyć argument miesiąca przez funkcję float, aby to zadziałałomath.ceil(float(4)/3) = 2.0 , podczas gdymath.ceil(4/3) = 1.0
Theo Kouzelis

1
Zignoruj ​​mnie Nie zdawałem sobie sprawy, co .zrobili po 3.math.ceil(4/3.) = 2.0
Theo Kouzelis

11

Dla każdego, kto próbuje uzyskać kwartał roku podatkowego , który może różnić się od kalendarza , napisałem moduł Pythona, aby to zrobić.

Instalacja jest prosta. Po prostu biegnij:

$ pip install fiscalyear

Nie ma żadnych zależności i fiscalyear powinno działać zarówno dla Pythona 2, jak i 3.

Zasadniczo jest to otoka wokół wbudowanego modułu datetime , więc wszystkie datetimepolecenia, które już znasz, będą działać. Oto 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)

fiscalyearjest hostowany na GitHub i PyPI . Dokumentację można znaleźć pod adresem Read the Docs . Jeśli szukasz funkcji, których obecnie nie ma, daj mi znać!


4

Oto przykład funkcji, która pobiera obiekt datetime.datetime i zwraca unikalny ciąg dla każdego kwartału:

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

A wynik to:

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


2

Ta metoda działa dla dowolnego mapowania:

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

Właśnie wygenerowaliśmy funkcję int->int

month2quarter(9) # returns 3

Ta metoda jest również niezawodna

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

2

Dla tych, którzy szukają danych za kwartał roku obrotowego, używając pand,

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

odniesienie: indeks okresu pand


1

To stare pytanie, ale nadal warte dyskusji.

Oto moje rozwiązanie, wykorzystujące doskonały moduł 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)

Tak więc first_dayjest to pierwszy dzień kwartału i last_dayostatni dzień kwartału (obliczony poprzez znalezienie pierwszego dnia następnego kwartału minus jeden dzień).


1

To jest bardzo proste i działa w Pythonie3:

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 więc obliczenia mogą się nie udać, tutaj jest lepsza wersja (tylko ze względu na to)

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 w tym przypadku może mieć rację, ale czasami czytelność i bycie wyraźnym liczy się i prowadzi do mniejszej liczby błędów, zamiast
zwięzłych

1
@RussBradberry również widzisz usunięte odpowiedzi i komentarze na ten temat, widzisz proste obliczenia mogą być trudne również dla dobrych programistów i trudno jest zobaczyć poprawność poza testowaniem, w moim rozwiązaniu możesz zobaczyć i mieć pewność, że zadziała
Anurag Uniyal

1
tak jak powiedziałeś "it is difficult to see correctness except by testing it". Powinieneś pisać testy, tak jak wszyscy dobrzy programiści. Testy pomagają powstrzymać Cię od popełnienia błędów i wyłapać te, które robisz. Deweloper nigdy nie powinien poświęcać wydajności i czytelności, aby nie popełnić błędu. Ponadto jest to mniej czytelne, niż gdybyś po prostu utworzył statyczny dykt za pomocą literałów.
Russ Bradberry,

Nie zrozum mnie źle, (m-1)//3 + 1to też nie wszystko, co jest czytelne, niewiele osób wie, co to //robi. Mój pierwotny komentarz dotyczył właśnie oświadczenia"calculations can go wrong" które wydaje mi się dziwne.
Russ Bradberry,

@RussBradberry faktycznie zgadzam się z tobą, moja odpowiedź była alternatywą i czasami istnieją alternatywy. Widziałem wiele kodów, w których ludzie próbują obliczyć / wydedukować coś, co można po prostu zakodować na mapie
Anurag Uniyal

0

Oto rozwlekłe, ale także czytelne rozwiązanie, które będzie działać w przypadku wystąpienia daty i godziny

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

używając słowników, możesz to zrobić przez

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))
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.