我已经建立了一个功能来获得当前季度的第一天和最后一天,但它有点长啰嗦。我想知道,有没有更简洁的方法来实现这个目标?
我理解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")
编辑:如果这更适合Code Review
,请告诉我答案 0 :(得分:6)
为什么这么复杂: - )
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])
答案 1 :(得分:4)
你可以这样做:
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])
这解决了“第一”案件;我将“最后”的情况作为练习而离开,但我建议将其作为一个独立的功能保持清晰(对于原始版本,如果没有参数传递会发生什么,这很奇怪。)。
答案 2 :(得分:4)
为什么要自己动手?
import pandas as pd
quarter_start = pd.to_datetime(pd.datetime.today() - pd.tseries.offsets.QuarterBegin(startingMonth=1)).date()
答案 3 :(得分:2)
if last
分支在问题中一样。相反,返回一个日期对象并仅在必要时转换为字符串(更容易访问对象属性,如.year
,.month
,而不是解析其字符串表示以提取相同的信息)first
,last
)。它是一个容易出错的界面,它会导致代码重复。这里很容易返回两个结果并稍后访问相应的属性,例如.first_day
。或者是否存在(不太可能的)性能问题;您可以创建两个函数,例如get_first_day_of_the_quarter()
而不是quarter_first_days
(1
在月份列表中提到两次) - 允许使用{ {1}}无条件地: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
)。四分之一指数公式来自Is there a Python function to determine which quarter of the year a date is in?
示例:
MINYEAR < MAXYEAR
答案 4 :(得分:1)
您不应该使用不必要的循环或像pandas这样的大型库来执行此操作。您可以使用简单的整数除法/算术和日期时间库(尽管使用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)