如何将日期时间增加一天?

250

如何增加datetime的日期?

for i in range(1, 35)
    date = datetime.datetime(2003, 8, i)
    print(date)

但是我需要正确地跨越月份和年份?有什么想法吗?

8个回答

394
date = datetime.datetime(2003,8,1,12,4,5)
for i in range(5): 
    date += datetime.timedelta(days=1)
    print(date) 

12
如果需要考虑夏令时,则会更加复杂,例如参见如何从Python日期减去一天? - jfs

88

15

所有目前的答案在某些情况下都是错误的,因为它们没有考虑到时区相对于UTC的偏移值会发生变化。因此,在某些情况下,加上24小时与加上一个日历天是不同的。

建议解决方案

以下解决方案适用于萨摩亚,并保持本地时间不变。

def add_day(today):
    """
    Add a day to the current day.

    This takes care of historic offset changes and DST.

    Parameters
    ----------
    today : timezone-aware datetime object

    Returns
    -------
    tomorrow : timezone-aware datetime object
    """
    today_utc = today.astimezone(datetime.timezone.utc)
    tz = today.tzinfo
    tomorrow_utc = today_utc + datetime.timedelta(days=1)
    tomorrow_utc_tz = tomorrow_utc.astimezone(tz)
    tomorrow_utc_tz = tomorrow_utc_tz.replace(hour=today.hour,
                                              minute=today.minute,
                                              second=today.second)
    return tomorrow_utc_tz

测试过的代码

# core modules
import datetime

# 3rd party modules
import pytz


# add_day methods
def add_day(today):
    """
    Add a day to the current day.

    This takes care of historic offset changes and DST.

    Parameters
    ----------
    today : timezone-aware datetime object

    Returns
    -------
    tomorrow : timezone-aware datetime object
    """
    today_utc = today.astimezone(datetime.timezone.utc)
    tz = today.tzinfo
    tomorrow_utc = today_utc + datetime.timedelta(days=1)
    tomorrow_utc_tz = tomorrow_utc.astimezone(tz)
    tomorrow_utc_tz = tomorrow_utc_tz.replace(hour=today.hour,
                                              minute=today.minute,
                                              second=today.second)
    return tomorrow_utc_tz


def add_day_datetime_timedelta_conversion(today):
    # Correct for Samoa, but dst shift
    today_utc = today.astimezone(datetime.timezone.utc)
    tz = today.tzinfo
    tomorrow_utc = today_utc + datetime.timedelta(days=1)
    tomorrow_utc_tz = tomorrow_utc.astimezone(tz)
    return tomorrow_utc_tz


def add_day_dateutil_relativedelta(today):
    # WRONG!
    from dateutil.relativedelta import relativedelta
    return today + relativedelta(days=1)


def add_day_datetime_timedelta(today):
    # WRONG!
    return today + datetime.timedelta(days=1)


# Test cases
def test_samoa(add_day):
    """
    Test if add_day properly increases the calendar day for Samoa.

    Due to economic considerations, Samoa went from 2011-12-30 10:00-11:00
    to 2011-12-30 10:00+13:00. Hence the country skipped 2011-12-30 in its
    local time.

    See https://stackoverflow.com/q/52084423/562769

    A common wrong result here is 2011-12-30T23:59:00-10:00. This date never
    happened in Samoa.
    """
    tz = pytz.timezone('Pacific/Apia')
    today_utc = datetime.datetime(2011, 12, 30, 9, 59,
                                  tzinfo=datetime.timezone.utc)
    today_tz = today_utc.astimezone(tz)  # 2011-12-29T23:59:00-10:00
    tomorrow = add_day(today_tz)
    return tomorrow.isoformat() == '2011-12-31T23:59:00+14:00'


def test_dst(add_day):
    """Test if add_day properly increases the calendar day if DST happens."""
    tz = pytz.timezone('Europe/Berlin')
    today_utc = datetime.datetime(2018, 3, 25, 0, 59,
                                  tzinfo=datetime.timezone.utc)
    today_tz = today_utc.astimezone(tz)  # 2018-03-25T01:59:00+01:00
    tomorrow = add_day(today_tz)
    return tomorrow.isoformat() == '2018-03-26T01:59:00+02:00'


to_test = [(add_day_dateutil_relativedelta, 'relativedelta'),
           (add_day_datetime_timedelta, 'timedelta'),
           (add_day_datetime_timedelta_conversion, 'timedelta+conversion'),
           (add_day, 'timedelta+conversion+dst')]
print('{:<25}: {:>5} {:>5}'.format('Method', 'Samoa', 'DST'))
for method, name in to_test:
    print('{:<25}: {:>5} {:>5}'
          .format(name,
                  test_samoa(method),
                  test_dst(method)))

测试结果

Method                   : Samoa   DST
relativedelta            :     0     0
timedelta                :     0     0
timedelta+conversion     :     1     0
timedelta+conversion+dst :     1     1

5
其他答案并不完全错误,它们在处理协调世界时(UTC)或本地时间(tzinfo == None)日期时间时都很好。 - Delgan

14

这里是使用dateutil的relativedelta添加日期的另一种方法。

from datetime import datetime
from dateutil.relativedelta import relativedelta

print 'Today: ',datetime.now().strftime('%d/%m/%Y %H:%M:%S') 
date_after_month = datetime.now()+ relativedelta(day=1)
print 'After a Days:', date_after_month.strftime('%d/%m/%Y %H:%M:%S')

输出:

今天:25/06/2015 20:41:44

一天后:01/06/2015 20:41:44


1
为什么你会使用它而不是标准库中的timedelta()函数? - jfs
3
@J.F.Sebastian 只是想分享另一种可能的添加日期的方式。 - Atul Arvind
3
如果没有优势的话,我认为这并没有增加价值。 - Tejas Manohar
了解可能性确实会增加价值。例如,没有证据表明哪个更快。因此,Stack Overflow适用于所有有效答案。 - Akaisteph7

10
最简单的解决方案
from datetime import timedelta, datetime
date = datetime(2003,8,1,12,4,5)
for i in range(5):
    date += timedelta(days=1)
    print(date)

9
这对我来说是一个很简单的解决方案:
from datetime import timedelta, datetime

today = datetime.today().strftime("%Y-%m-%d")
tomorrow = datetime.today() + timedelta(1)


这并没有直接回答 OP 的问题,因为它假设了 today(),而且不如被接受的答案好,因为它假设默认的增量单位是 days - MarkHu
@MarkHu 我并不是在争论我的答案应该被接受。但是你能否详细说明一下 today() 的假设是什么,以及为什么这是一个错误的假设?此外,问题不是在问天数吗?那么被接受的答案是否更加通用呢? - Aus_10
  1. OP询问如何找到任意日期后的下一天,而不是今天。您的示例代码将一个名为“today”的变量分配为字符串,然后从未使用它。更好的方法是:date = datetime.today()
  2. 您的最后一行硬编码了“today()”,并假定“timedelta”的第一个参数是“days”(这恰好是正确的,但为什么不为清晰度命名?)。更好的方法是:laterDate = date + timedelta(days=1) # 个人意见 :)
- MarkHu

0

你也可以导入timedelta,这样代码会更清晰。

from datetime import datetime, timedelta
date = datetime.now() + timedelta(seconds=[delta_value])

然后将日期转换为字符串

date = date.strftime('%Y-%m-%d %H:%M:%S')

Python 一行代码是

date = (datetime.now() + timedelta(seconds=[delta_value])).strftime('%Y-%m-%d %H:%M:%S')

-5
一个没有使用任何库的简短解决方案。 :)
d = "8/16/18"
day_value = d[(d.find('/')+1):d.find('/18')]
tomorrow = f"{d[0:d.find('/')]}/{int(day_value)+1}{d[d.find('/18'):len(d)]}".format()
print(tomorrow)
# 8/17/18

确保 "string d" 实际上是以 %m/%d/%Y 格式展现,这样你在月份转换时就不会遇到问题。

4
如果你把 d 设置为 8/31/18,那么这将返回 8/32/18。如果你改变年份从 18 到其他年份,它就会出错。 - andrewsi
datetime 是一个标准库,已经包含在 Python 中,使用它不会有任何惩罚。实际上恰恰相反。 - bluesmonk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接