Python timedelta 日期时间的加减等运算示例

摘自Python3-CookBook

问题一

你需要执行简单的时间转换,比如天到秒,小时到分钟等的转换

解决方案

为了执行不同时间单位的转换和计算,请使用datatime模块。比如,为了表示一个时间段,可以创建一个timedelta实例,就像下面这样:

from datetime import timedelta, datetime

a = timedelta(days=2, hours=6)
b = timedelta(hours=4.5)

c = a + b
print(c.days)
# 2
print(c.seconds)
# 37800
# seconds只是时间差的秒数,忽略天数、微秒数。
print(c.seconds / 3600)
# 10.5
# total_seconds()则包含全部,更完整。
print(c.total_seconds() / 3600)
# 58.5

如果你想表示指定的日期和时间,先床创建一个datatime实例然后使用标准的数学运算来操作他们。比如:

a = datetime(2012, 9, 23)
print(a + timedelta(days=10))
# 2012-10-03 00:00:00

b = datetime(2012, 12, 21)
d = b - a
print(d.days)
# 89

now = datetime.today()
print(now)
# 2022-07-25 14:43:44.402538
print(now + timedelta(minutes=10))
# 2022-07-25 14:54:03.393996

在计算的时候,需要注意的是datetime会自动处理闰年。比如:

a = datetime(2012, 3, 1)
b = datetime(2012, 2, 28)
print(a - b)
# 2 days, 0:00:00
c = datetime(2013, 3, 1)
d = datetime(2013, 2, 28)
print((c - d).days)
# 1

讨论

对大多数基本的日期和时间处理问题,datetime模块已经足够了。

如果你需要执行更加复杂的日期操作,比如处理时区,模糊时间范围,节假日计算等等,可以考虑使用dateutil模块

许多类似的时间计算可以使用dateutil.relativedelta()函数代替。但是,有一点需要注意的就是,它会在处理月份(还有它们的天数差距)的时候填充间隙。

'''
a = datetime(2012,9,23)
a + timedelta(months = 1)

Traceback (most recent call last):
  File "/Users/coco/PycharmProjects/CookBook/Chapter3-数字日期和时间/3.12基本的日期与时间转换.py", line 68, in 
    a + timedelta(months = 1)
TypeError: 'months' is an invalid keyword argument for __new__()
'''

from dateutil.relativedelta import relativedelta

print(a + relativedelta(months=+1))
# 2012-04-01 00:00:00

print(a + relativedelta(months=+4))
# 2012-07-01 00:00:00

# Time between two dates
b = datetime(2012, 12, 21)
d = b - a
print(d)
# 295 days, 0:00:00
d = relativedelta(b, a)
print(d)
# relativedelta(months=+9, days=+20)
print(d.months)
# 9
print(d.days)
# 20

问题二

你需要一个通用方法来计算一周中某一天上一次出现的日期,例如上一个周五的日期。

解决方案

Python的 datetime 模块中有工具函数和类可以帮助你执行这样的计算。 下面是对类似这样的问题的一个通用解决方案:

from datetime import datetime, timedelta

weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']


def get_previous_byday(dayname, start_date=None):
    if start_date is None:
        start_date = datetime.today()
    day_num = start_date.weekday()
    day_num_target = weekdays.index(dayname)
    days_ago = (7 + day_num - day_num_target) % 7
    if days_ago == 0:
        days_ago = 7
    target_date = start_date - timedelta(days=days_ago)
    return target_date

print(datetime.today()) # For reference
# 2022-07-25 15:18:33.196422
print(get_previous_byday('Monday'))
# 2022-07-18 15:19:25.348001
print(get_previous_byday('Tuesday')) # Previous week, not today
# 2022-07-19 15:20:06.467114
print(get_previous_byday('Friday'))
# 2022-07-22 15:20:18.710441

# 可选的start_date参数可以由另一个datetime实例来提供。比如:
print(get_previous_byday('Sunday', datetime(2012, 12, 21)))
# 2012-12-16 00:00:00

讨论

上面的算法原理是这样的:先将开始日期和目标日期映射到星期数组的位置上(星期一索引为0), 然后通过模运算计算出目标日期要经过多少天才能到达开始日期。

然后用开始日期减去那个时间差即得到结果日期。

如果你要像这样执行大量的日期计算的话,你最好安装第三方包 python-dateutil 来代替。

比如,下面是是使用 dateutil 模块中的 relativedelta() 函数执行同样的计算:


print('-'*40)
from datetime import datetime
from dateutil.relativedelta import relativedelta
from dateutil.rrule import *

d = datetime.now()
print(d)
# 2022-07-25 15:28:36.824838

# Next Friday
print(d+relativedelta(weekday=FR))
# 2022-07-29 15:28:36.824838

# Last Friday
print(d + relativedelta(weekday=FR(-1)))
# 2022-07-22 15:29:23.974975

你可能感兴趣的:(Python,学习,python,开发语言)