web-dev-qa-db-ja.com

Python現在のカレンダー四半期の最初と最後の日を取得します

今四半期の初日と最終日を取得する関数を作成しましたが、少し時間がかかります。私はこれを達成するより簡潔な方法はありますかと思っていましたか?

pandasにはQuarterBegin()関数があることを理解していますが、より簡潔な方法で実装することはできませんでした。

import datetime as dt
from dateutil.relativedelta import relativedelta     

def get_q(first=None,last=None):

    today = dt.date.today()

    qmonth = [1, 4, 7, 10]

    if first:
        for i,v in enumerate(qmonth):
            if (today.month-1)//3 == i:
                return dt.date(today.year,qmonth[i],1).strftime("%Y-%m-%d")

    if last:
        firstday = dt.datetime.strptime(get_q(first=True),"%Y-%m-%d") 
        lastday = firstday + relativedelta(months=3, days=-1)
        return lastday.strftime("%Y-%m-%d")

編集:これがより適しているかどうか教えてください コードレビュー

12
Charon

あなたはこの方法でそれを行うことができます:

import bisect
import datetime as dt

def get_quarter_begin():
    today = dt.date.today()

    qbegins = [dt.date(today.year, month, 1) for month in (1,4,7,10)]

    idx = bisect.bisect(qbegins, today)
    return str(qbegins[idx-1])

これは「最初の」ケースを解決します。 「最後の」ケースは演習として残しますが、わかりやすくするために独立した関数として保持することをお勧めします(元のバージョンでは、引数が渡されないとどうなるかはかなり奇妙です!)。

4
John Zwinck

なぜそんなに複雑なのか:-)

from datetime import date
from calendar import monthrange

quarter = 2
year = 2016
first_month_of_quarter = 3 * quarter - 2
last_month_of_quarter = 3 * quarter
date_of_first_day_of_quarter = date(year, first_month_of_quarter, 1)
date_of_last_day_of_quarter = date(year, last_month_of_quarter, monthrange(year, last_month_of_quarter)[1])
8
oxidworks

なぜあなた自身のものを転がすのですか?

import pandas as pd

quarter_start = pd.to_datetime(pd.datetime.today() - pd.tseries.offsets.QuarterBegin(startingMonth=1)).date()
7
John Redford
  • ヨーヨーコード は避けてください。 if lastブランチが質問で行うように、日付オブジェクトを文字列に変換して、それを再び日付オブジェクトに再度解析することはしないでください。代わりに、日付オブジェクトを返し、必要な場合にのみ文字列に変換します(同じ情報を抽出するために文字列表現を解析するよりも、.year.monthなどのオブジェクト属性にアクセスする方が簡単です)。
  • 相互に排他的なブールキーワード引数(firstlast)を避けます。エラーが発生しやすいインターフェイスであり、コードの重複を引き起こします。ここで両方の結果を返し、後で.first_dayなどの対応する属性にアクセスするのは簡単です。または、(あまりない)パフォーマンスの問題がある場合。代わりにget_first_day_of_the_quarter()などの2つの関数を作成できます
  • アルゴリズムを簡略化するために、入力データに少し冗長性を追加することができます。たとえば、以下のコードのquarter_first_daysを参照してください(1は月のリストで2回言及されています)—無条件にi+1を使用できます:
#!/usr/bin/env python
from collections import namedtuple
from datetime import MINYEAR, date, timedelta

DAY = timedelta(1)
quarter_first_days = [date(MINYEAR+1, month, 1) for month in [1, 4, 7, 10, 1]]    
Quarter = namedtuple('Quarter', 'first_day last_day')

def get_current_quarter():
    today = date.today()
    i = (today.month - 1) // 3 # get quarter index
    days = quarter_first_days[i], quarter_first_days[i+1] - DAY
    return Quarter(*[day.replace(year=today.year) for day in days])

MINYEAR+1は、- DAY式に対応するために使用されます(MINYEAR < MAXYEARを想定しています)。四半期インデックスの式は次のとおりです Python日付がどの四半期にあるかを判断する関数はありますか?

例:

>>> get_current_quarter()
Quarter(first_day=datetime.date(2016, 4, 1), last_day=datetime.date(2016, 6, 30))
>>> str(get_current_quarter().last_day)
'2016-06-30'
3
jfs

pandasのような不要なループや大きなライブラリを使用する必要はありません。これを行うには、単純な整数除算/算術演算とdatetimeライブラリのみを使用できます(ただし、dateutilを使用すると、コードがきれいになります) )。

import datetime

def getQuarterStart(dt=datetime.date.today()):
    return datetime.date(dt.year, (dt.month - 1) // 3 * 3 + 1, 1)

# using just datetime
def getQuarterEnd1(dt=datetime.date.today()):
    nextQtYr = dt.year + (1 if dt.month>9 else 0)
    nextQtFirstMo = (dt.month - 1) // 3 * 3 + 4
    nextQtFirstMo = 1 if nextQtFirstMo==13 else nextQtFirstMo
    nextQtFirstDy = datetime.date(nextQtYr, nextQtFirstMo, 1)
    return nextQtFirstDy - datetime.timedelta(days=1)

# using dateutil
from dateutil.relativedelta import relativedelta

def getQuarterEnd2(dt=datetime.date.today()):
    quarterStart = getQuarterStart(dt)
    return quarterStart + relativedelta(months=3, days=-1)

出力:

>>> d1=datetime.date(2017,2,15)
>>> d2=datetime.date(2017,1,1)
>>> d3=datetime.date(2017,10,1)
>>> d4=datetime.date(2017,12,31)
>>> 
>>> getQuarterStart(d1)
datetime.date(2017, 1, 1)
>>> getQuarterStart(d2)
datetime.date(2017, 1, 1)
>>> getQuarterStart(d3)
datetime.date(2017, 10, 1)
>>> getQuarterStart(d4)
datetime.date(2017, 10, 1)
>>> getQuarterEnd1(d1)
datetime.date(2017, 3, 31)
>>> getQuarterEnd1(d2)
datetime.date(2017, 3, 31)
>>> getQuarterEnd1(d3)
datetime.date(2017, 12, 31)
>>> getQuarterEnd1(d4)
datetime.date(2017, 12, 31)
>>> getQuarterEnd2(d1)
datetime.date(2017, 3, 31)
>>> getQuarterEnd2(d2)
datetime.date(2017, 3, 31)
>>> getQuarterEnd2(d3)
datetime.date(2017, 12, 31)
>>> getQuarterEnd2(d4)
datetime.date(2017, 12, 31)
2