使用 Python 将一个月添加到给定日期(后一天四舍五入)
Add one month to a given date (rounded day after) with Python
我想在给定的日期上加一个月
import datetime
dt = datetime.datetime(year=2014, month=5, day=2)
所以我应该
datetime.datetime(year=2014, month=6, day=2)
但是
dt = datetime.datetime(year=2015, month=1, day=31)
我应该得到
datetime.datetime(year=2015, month=3, day=1)
因为没有 2015-02-31(而且我希望我的结果在之后)
有些月份有 31 天,有些月份有 30 天,有些月份有 29 天,有些月份有 28 天!
所以添加 datetime.timedelta
可能不是一个好的做法(因为我们不知道要添加的天数)
我注意到 Pandas 有一个有趣的概念 DateOffset
http://pandas.pydata.org/pandas-docs/stable/timeseries.html#dateoffset-objects
但我没有找到 Month
偏移量,只有 MonthBegin
或 MonthEnd
我也看到这个post
How do I calculate the date six months from the current date using the datetime Python module?
所以我尝试了 dateutil.relativedelta
但是
from dateutil.relativedelta import relativedelta
datetime.datetime(year=2015, month=1, day=31)+relativedelta(months=1)
returns
datetime.datetime(2015, 2, 28, 0, 0)
所以结果在 前 .
前一天四舍五入
在之后是否有一种(干净的)方式来圆整一天?
编辑:
我给出了一个要添加一个月的示例,但我也希望能够添加例如:2 年零 6 个月(使用 relativedelta(years=2, months=6)
)
快速解决方案:
import datetime
import calendar
dt = datetime.datetime(year=2014, month=5, day=2)
d = calendar.monthrange(dt.year,dt.month+1)[1]
print dt+datetime.timedelta(days=d+1)
第一个输入的输出 (year=2014, month=5, day=2)
:
2014-06-02 00:00:00
第二个输入的输出 (year=2015, month=1, day=31)
:
2015-03-01 00:00:00
可以使用dateutil.relativedelta.relativedelta
and manually check the datetime.day
属性,如果原来的日期大于新的日期,则添加一天。
下面的函数接受一个 datetime
对象和 relativedelta
对象。请注意,下面的代码仅适用于数年和数月,我认为如果您使用低于该代码的任何内容(天数、小时数等),它就不会起作用。您可以轻松修改此函数以将 years
和 months
作为参数,然后在函数本身内部构造 relativedelta
。
from datetime import datetime
from dateutil.relativedelta import relativedelta
def add_time(d, rd):
day = relativedelta(days=+1)
out = d + rd
if d.day > out.day:
out = out + day
return out
# Check that it "rolls over"
print(add_time(datetime(year=2015, month=1, day=29), relativedelta(years=+4, months=+1))) # 2019-03-01 00:00:00
print(add_time(datetime(year=2015, month=3, day=31), relativedelta(years=+0, months=+2))) # 2015-05-01 00:00:00
# Check that it handles "normal" scenarios
print(add_time(datetime(year=2015, month=6, day=19), relativedelta(months=+1))) # 2015-07-19 00:00:00
print(add_time(datetime(year=2015, month=6, day=30), relativedelta(years=+2, months=+1))) # 2017-07-30 00:00:00
# Check across years
print(add_time(datetime(year=2015, month=12, day=25), relativedelta(months=+1))) # 2016-01-25 00:00:00
# Check leap years
print(add_time(datetime(year=2016, month=1, day=29), relativedelta(years=+4, months=+1))) # 2020-02-29 00:00:00
这似乎有效。挺干净的,就是不漂亮:
def add_month(now):
try:
then = (now + relativedelta(months=1)).replace(day=now.day)
except ValueError:
then = (now + relativedelta(months=2)).replace(day=1)
return then
for now in [datetime(2015, 1, 20), datetime(2015, 1, 31), datetime(2015, 2, 28)]:
print now, add_month(now)
打印:
2015-01-20 00:00:00 2015-02-20 00:00:00
2015-01-31 00:00:00 2015-03-01 00:00:00
2015-02-28 00:00:00 2015-03-28 00:00:00
增加一个月并尝试用原来的日期替换日期。如果成功,那不是特例。如果失败(ValueError),我们必须再增加一个月并转到它的第一天。
使用下面的方法:
def datetime_offset_by_months(datetime_origin, n=1):
"""
datetime offset by months
:param datetime_origin: the original datetime
:param n: count of months
:return: after offset datetime
"""
# create a shortcut object for one day
one_day = datetime.timedelta(days=1)
# first use div and mod to determine year cycle
q, r = divmod(datetime_origin.month + n, 12)
# create a datetime_offset
# to be the last day of the target month
datetime_offset = datetime.datetime(
datetime_origin.year + q, r + 1, 1) - one_day
'''
if input date is the last day of this month
then the output date should also be the last
day of the target month, although the day
www.iplaypy.com
may be different.
for example:
datetime_origin = 8.31
datetime_offset = 9.30
'''
if datetime_origin.month != (datetime_origin + one_day).month:
return datetime_offset
'''
if datetime_origin day is bigger than last day of
target month, then, use datetime_offset
for example:
datetime_origin = 10.31
datetime_offset = 11.30
'''
if datetime_origin.day >= datetime_offset.day:
return datetime_offset
'''
then, here, we just replace datetime_offset's day
with the same of datetime_origin, that's ok.
'''
return datetime_offset.replace(day= datetime_origin.day)
它的用法:
import datetime
now_date = datetime.datetime.now()
off_set_datetime = datetime_offset_by_months(now_date, -2)
print(off_set_datetime)
我想在给定的日期上加一个月
import datetime
dt = datetime.datetime(year=2014, month=5, day=2)
所以我应该
datetime.datetime(year=2014, month=6, day=2)
但是
dt = datetime.datetime(year=2015, month=1, day=31)
我应该得到
datetime.datetime(year=2015, month=3, day=1)
因为没有 2015-02-31(而且我希望我的结果在之后)
有些月份有 31 天,有些月份有 30 天,有些月份有 29 天,有些月份有 28 天!
所以添加 datetime.timedelta
可能不是一个好的做法(因为我们不知道要添加的天数)
我注意到 Pandas 有一个有趣的概念 DateOffset
http://pandas.pydata.org/pandas-docs/stable/timeseries.html#dateoffset-objects
但我没有找到 Month
偏移量,只有 MonthBegin
或 MonthEnd
我也看到这个post How do I calculate the date six months from the current date using the datetime Python module?
所以我尝试了 dateutil.relativedelta
但是
from dateutil.relativedelta import relativedelta
datetime.datetime(year=2015, month=1, day=31)+relativedelta(months=1)
returns
datetime.datetime(2015, 2, 28, 0, 0)
所以结果在 前 .
前一天四舍五入在之后是否有一种(干净的)方式来圆整一天?
编辑:
我给出了一个要添加一个月的示例,但我也希望能够添加例如:2 年零 6 个月(使用 relativedelta(years=2, months=6)
)
快速解决方案:
import datetime
import calendar
dt = datetime.datetime(year=2014, month=5, day=2)
d = calendar.monthrange(dt.year,dt.month+1)[1]
print dt+datetime.timedelta(days=d+1)
第一个输入的输出 (year=2014, month=5, day=2)
:
2014-06-02 00:00:00
第二个输入的输出 (year=2015, month=1, day=31)
:
2015-03-01 00:00:00
可以使用dateutil.relativedelta.relativedelta
and manually check the datetime.day
属性,如果原来的日期大于新的日期,则添加一天。
下面的函数接受一个 datetime
对象和 relativedelta
对象。请注意,下面的代码仅适用于数年和数月,我认为如果您使用低于该代码的任何内容(天数、小时数等),它就不会起作用。您可以轻松修改此函数以将 years
和 months
作为参数,然后在函数本身内部构造 relativedelta
。
from datetime import datetime
from dateutil.relativedelta import relativedelta
def add_time(d, rd):
day = relativedelta(days=+1)
out = d + rd
if d.day > out.day:
out = out + day
return out
# Check that it "rolls over"
print(add_time(datetime(year=2015, month=1, day=29), relativedelta(years=+4, months=+1))) # 2019-03-01 00:00:00
print(add_time(datetime(year=2015, month=3, day=31), relativedelta(years=+0, months=+2))) # 2015-05-01 00:00:00
# Check that it handles "normal" scenarios
print(add_time(datetime(year=2015, month=6, day=19), relativedelta(months=+1))) # 2015-07-19 00:00:00
print(add_time(datetime(year=2015, month=6, day=30), relativedelta(years=+2, months=+1))) # 2017-07-30 00:00:00
# Check across years
print(add_time(datetime(year=2015, month=12, day=25), relativedelta(months=+1))) # 2016-01-25 00:00:00
# Check leap years
print(add_time(datetime(year=2016, month=1, day=29), relativedelta(years=+4, months=+1))) # 2020-02-29 00:00:00
这似乎有效。挺干净的,就是不漂亮:
def add_month(now):
try:
then = (now + relativedelta(months=1)).replace(day=now.day)
except ValueError:
then = (now + relativedelta(months=2)).replace(day=1)
return then
for now in [datetime(2015, 1, 20), datetime(2015, 1, 31), datetime(2015, 2, 28)]:
print now, add_month(now)
打印:
2015-01-20 00:00:00 2015-02-20 00:00:00
2015-01-31 00:00:00 2015-03-01 00:00:00
2015-02-28 00:00:00 2015-03-28 00:00:00
增加一个月并尝试用原来的日期替换日期。如果成功,那不是特例。如果失败(ValueError),我们必须再增加一个月并转到它的第一天。
使用下面的方法:
def datetime_offset_by_months(datetime_origin, n=1):
"""
datetime offset by months
:param datetime_origin: the original datetime
:param n: count of months
:return: after offset datetime
"""
# create a shortcut object for one day
one_day = datetime.timedelta(days=1)
# first use div and mod to determine year cycle
q, r = divmod(datetime_origin.month + n, 12)
# create a datetime_offset
# to be the last day of the target month
datetime_offset = datetime.datetime(
datetime_origin.year + q, r + 1, 1) - one_day
'''
if input date is the last day of this month
then the output date should also be the last
day of the target month, although the day
www.iplaypy.com
may be different.
for example:
datetime_origin = 8.31
datetime_offset = 9.30
'''
if datetime_origin.month != (datetime_origin + one_day).month:
return datetime_offset
'''
if datetime_origin day is bigger than last day of
target month, then, use datetime_offset
for example:
datetime_origin = 10.31
datetime_offset = 11.30
'''
if datetime_origin.day >= datetime_offset.day:
return datetime_offset
'''
then, here, we just replace datetime_offset's day
with the same of datetime_origin, that's ok.
'''
return datetime_offset.replace(day= datetime_origin.day)
它的用法:
import datetime
now_date = datetime.datetime.now()
off_set_datetime = datetime_offset_by_months(now_date, -2)
print(off_set_datetime)