Jos*_*unz 81 python datetime monthcalendar date-math
我需要能够准确地找到python中两个日期之间的月份.我有一个解决方案,但它不是很好(如优雅)或快速.
dateRange = [datetime.strptime(dateRanges[0], "%Y-%m-%d"), datetime.strptime(dateRanges[1], "%Y-%m-%d")]
months = []
tmpTime = dateRange[0]
oneWeek = timedelta(weeks=1)
tmpTime = tmpTime.replace(day=1)
dateRange[0] = tmpTime
dateRange[1] = dateRange[1].replace(day=1)
lastMonth = tmpTime.month
months.append(tmpTime)
while tmpTime < dateRange[1]:
if lastMonth != 12:
while tmpTime.month <= lastMonth:
tmpTime += oneWeek
tmpTime = tmpTime.replace(day=1)
months.append(tmpTime)
lastMonth = tmpTime.month
else:
while tmpTime.month >= lastMonth:
tmpTime += oneWeek
tmpTime = tmpTime.replace(day=1)
months.append(tmpTime)
lastMonth = tmpTime.month
Run Code Online (Sandbox Code Playgroud)
所以只是为了解释一下,我在这里做的是将两个日期转换为iso格式转换为python datetime对象.然后我循环通过在开始日期时间对象中添加一周,并检查月份的数值是否更大(除非月份是12月,然后检查日期是否更少),如果值更大,我将其附加到列表几个月,并一直循环,直到我到达我的结束日期.
它完美地工作它似乎不是一个好方法...
Joh*_*ooy 175
首先定义一些测试用例,然后你会发现函数非常简单,不需要循环
from datetime import datetime
def diff_month(d1, d2):
return (d1.year - d2.year) * 12 + d1.month - d2.month
assert diff_month(datetime(2010,10,1), datetime(2010,9,1)) == 1
assert diff_month(datetime(2010,10,1), datetime(2009,10,1)) == 12
assert diff_month(datetime(2010,10,1), datetime(2009,11,1)) == 11
assert diff_month(datetime(2010,10,1), datetime(2009,8,1)) == 14
Run Code Online (Sandbox Code Playgroud)
您应该在问题中添加一些测试用例,因为有很多潜在的案例要涵盖 - 有两种方法可以定义两个日期之间的月数.
N1B*_*1B4 36
一个班轮,用于查找两个日期之间按月递增的日期时间列表.
import datetime
from dateutil.rrule import rrule, MONTHLY
strt_dt = datetime.date(2001,1,1)
end_dt = datetime.date(2005,6,1)
dates = [dt for dt in rrule(MONTHLY, dtstart=strt_dt, until=end_dt)]
Run Code Online (Sandbox Code Playgroud)
aam*_*r23 24
这对我有用 -
from datetime import datetime
from dateutil import relativedelta
date1 = datetime.strptime('2011-08-15 12:00:00', '%Y-%m-%d %H:%M:%S')
date2 = datetime.strptime('2012-02-15', '%Y-%m-%d')
r = relativedelta.relativedelta(date2, date1)
r.months + (12*r.years)
Run Code Online (Sandbox Code Playgroud)
Vin*_*n-G 10
获取结束月份(相对于开始月份的年份和月份,例如2011年1月= 13,如果您的开始日期从2010年10月开始),然后生成开始月份和结束月份的日期时间,如下所示:
dt1, dt2 = dateRange
start_month=dt1.month
end_months=(dt2.year-dt1.year)*12 + dt2.month+1
dates=[datetime.datetime(year=yr, month=mn, day=1) for (yr, mn) in (
((m - 1) / 12 + dt1.year, (m - 1) % 12 + 1) for m in range(start_month, end_months)
)]
Run Code Online (Sandbox Code Playgroud)
如果两个日期都在同一年,它也可以简单地写成:
dates=[datetime.datetime(year=dt1.year, month=mn, day=1) for mn in range(dt1.month, dt2.month + 1)]
Run Code Online (Sandbox Code Playgroud)
小智 10
您可以使用dateutil模块中的rrule轻松计算:
from dateutil import rrule
from datetime import date
print(list(rrule.rrule(rrule.MONTHLY, dtstart=date(2013, 11, 1), until=date(2014, 2, 1))))
Run Code Online (Sandbox Code Playgroud)
会给你:
[datetime.datetime(2013, 11, 1, 0, 0),
datetime.datetime(2013, 12, 1, 0, 0),
datetime.datetime(2014, 1, 1, 0, 0),
datetime.datetime(2014, 2, 1, 0, 0)]
Run Code Online (Sandbox Code Playgroud)
小智 8
我的简单解决方案:
import datetime
def months(d1, d2):
return d1.month - d2.month + 12*(d1.year - d2.year)
d1 = datetime.datetime(2009, 9, 26)
d2 = datetime.datetime(2019, 9, 26)
print(months(d1, d2))
Run Code Online (Sandbox Code Playgroud)
from dateutil import relativedelta
r = relativedelta.relativedelta(date1, date2)
months_difference = (r.years * 12) + r.months
Run Code Online (Sandbox Code Playgroud)
将“月份”定义为1 / 12年,然后执行以下操作:
def month_diff(d1, d2):
"""Return the number of months between d1 and d2,
such that d2 + month_diff(d1, d2) == d1
"""
diff = (12 * d1.year + d1.month) - (12 * d2.year + d2.month)
return diff
Run Code Online (Sandbox Code Playgroud)
您可能会尝试将一个月定义为“29、28、30 或 31 天的时间段(取决于年份)”。但是你这样做了,你还有一个额外的问题需要解决。
虽然通常很清楚 6 月 15日+ 1 个月应该是 7 月 15日,但通常不清楚 1 月 30日+ 1 个月是在 2 月还是 3 月。在后一种情况下,你可能被迫来计算日期为2月30日日,那么“正确”它3月2日第二。但是,当你这样做,你会发现,3月2日第二- 1个月显然是2月2日第二。Ergo,reductio ad absurdum(这个操作没有很好的定义)。
这个帖子钉了它!使用dateutil.relativedelta.
from datetime import datetime
from dateutil import relativedelta
date1 = datetime.strptime(str('2011-08-15 12:00:00'), '%Y-%m-%d %H:%M:%S')
date2 = datetime.strptime(str('2012-02-15'), '%Y-%m-%d')
r = relativedelta.relativedelta(date2, date1)
r.months
Run Code Online (Sandbox Code Playgroud)
很多人已经给了你很好的答案来解决这个问题,但我还没有阅读任何使用列表理解的内容,所以我给你我用于类似用例的内容:
def compute_months(first_date: str, second_date: str) -> list:
"""List months between two dates given with the format YYYY-MM"""
year_start = int(first_date[:4])
month_start = int(first_date[5:7])
year_end = int(second_date[:4])
month_end = int(second_date[5:7])
return [
f"{year:0>4}-{month:0>2}"
for year in range(year_start, year_end + 1)
for month in range(
month_start if year == year_start else 1,
month_end + 1 if year == year_end else 13,
)
]
Run Code Online (Sandbox Code Playgroud)
>>> first_date = "2016-05"
>>> second_date = "2017-11"
>>> compute_months(first_date, second_date)
['2016-05',
'2016-06',
'2016-07',
'2016-08',
'2016-09',
'2016-10',
'2016-11',
'2016-12',
'2017-01',
'2017-02',
'2017-03',
'2017-04',
'2017-05',
'2017-06',
'2017-07',
'2017-08',
'2017-09',
'2017-10',
'2017-11']
Run Code Online (Sandbox Code Playgroud)
2018 年 4月20 日更新:似乎 OP @Joshkunz 要求查找两个日期之间的月份,而不是两个日期之间的“多少个月”。所以我不确定为什么@JohnLaRooy 被投票超过 100 次。@Joshkunz 在原始问题下的评论中指出,他想要实际日期 [或月份],而不是找到总月份数。
所以,就出现希望的问题,因为两个日期之间2018-04-11,以2018-06-01
Apr 2018, May 2018, June 2018
Run Code Online (Sandbox Code Playgroud)
如果介于2014-04-11to之间2018-06-01呢?那么答案就是
Apr 2014, May 2014, ..., Dec 2014, Jan 2015, ..., Jan 2018, ..., June 2018
Run Code Online (Sandbox Code Playgroud)
所以这就是多年前我有以下伪代码的原因。它只是建议使用两个月作为终点并循环遍历它们,一次增加一个月。@Joshkunz 提到他想要“月份”,他还提到他想要“日期”,在不确切知道的情况下,很难编写确切的代码,但其想法是使用一个简单的循环来遍历端点,并且一次递增一个月。
8年前的2010年的答案:
如果增加一周,那么它将根据需要大约执行 4.35 倍的工作。为什么不只是:
1. get start date in array of integer, set it to i: [2008, 3, 12],
and change it to [2008, 3, 1]
2. get end date in array: [2010, 10, 26]
3. add the date to your result by parsing i
increment the month in i
if month is >= 13, then set it to 1, and increment the year by 1
until either the year in i is > year in end_date,
or (year in i == year in end_date and month in i > month in end_date)
Run Code Online (Sandbox Code Playgroud)
现在只是伪代码,还没有测试,但我认为沿着同一条线的想法会奏效。
以下是如何使用 Pandas FWIW 执行此操作:
import pandas as pd
pd.date_range("1990/04/03", "2014/12/31", freq="MS")
DatetimeIndex(['1990-05-01', '1990-06-01', '1990-07-01', '1990-08-01',
'1990-09-01', '1990-10-01', '1990-11-01', '1990-12-01',
'1991-01-01', '1991-02-01',
...
'2014-03-01', '2014-04-01', '2014-05-01', '2014-06-01',
'2014-07-01', '2014-08-01', '2014-09-01', '2014-10-01',
'2014-11-01', '2014-12-01'],
dtype='datetime64[ns]', length=296, freq='MS')
Run Code Online (Sandbox Code Playgroud)
请注意,它从给定开始日期之后的月份开始。