# Python 日期的转换及计算

## 日期的转换及计算

### datetime 模块

#### 日期与时间的简单转换

`datetime` 模块中可以通过创建 `timedelta` 对象表示一个时间段。如下示例：

``````>>> from datetime import timedelta
>>> a = timedelta(days=2, hours=6)
>>> b = timedelta(hours=4.5)
>>> c = a + b
>>> c
datetime.timedelta(2, 37800)
>>> c.days
2
>>> c.seconds
37800
>>> c.seconds / 3600
10.5
>>> c.total_seconds() / 3600
58.5``````

``````>>> from datetime import datetime
>>> a = datetime(2020, 1, 15)
>>> print(a + timedelta(days=10))
2020-01-25 00:00:00
>>> b = datetime(2020, 2, 3)
>>> d = b - a
>>> d
datetime.timedelta(19)
>>> d.days
19
>>> now = datetime.today()
>>> print(now)
2020-01-15 10:59:10.230995
>>> print(now + timedelta(minutes=10))
2020-01-15 11:09:10.230995``````

`datetime` 对象能够自行处理闰年的问题，如下示例：

``````>>> a = datetime(2020, 3, 1)
>>> b = datetime(2020, 2, 28)
>>> a - b
datetime.timedelta(2)
>>> (a - b).days
2
>>> c = datetime(2019, 3, 1)
>>> d = datetime(2019, 2, 28)
>>> c - d
datetime.timedelta(1)
>>> (c - d).days
1``````

#### 字符串与日期的转换

``````>>> from datetime import datetime
>>> text = '2020-01-15'
>>> y = datetime.strptime(text, '%Y-%m-%d')
>>> y
datetime.datetime(2020, 1, 15, 0, 0)
>>> z = datetime.now()
>>> z
datetime.datetime(2020, 1, 15, 11, 10, 11, 71792)
>>> diff = z-y
>>> diff
datetime.timedelta(0, 40211, 71792)``````

%a 当地工作日的缩写
% A 当地工作日的全名
% b 当地月份的缩写
% B 当地月份的全名
% H 补零后十进制表示的小时(24小时制)
% I 补零后十进制表示的小时(12小时制)
% M 补零后十进制表示的分钟
% S 补零后十进制表示的秒

``````>>> z
datetime.datetime(2020, 1, 15, 11, 10, 11, 71792)
>>> format_z = datetime.strftime(z, "%A %B %d, %Y")
>>> format_z
'Wednesday January 15, 2020'``````

`datetime.strftime()` 函数返回一个由显示格式字符串所指定的代表日期的字符串。格式指令，如上述代码中的 `"%A %B %d, %Y"`。其中该函数的第一个参数为 `datetime` 对象。

``````from datetime import datetime
def parse_ymd(s):
year_s, mon_s, day_s = s.split('-')
return datetime(int(year_s), int(mon_s), int(day_s))``````

``````In [1]: from datetime import datetime
...: def parse_ymd(s):
...:      year_s, mon_s, day_s = s.split('-')
...:      return datetime(int(year_s), int(mon_s), int(day_s))

In [2]: text = "2020-01-15"

In [3]: %timeit datetime.strptime(text, '%Y-%m-%d')
7.75 µs ± 31 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [4]: %timeit parse_ymd(text)
1.05 µs ± 3.07 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)``````

#### 计算某个月份的日期范围

Python 提供的 `calendar` 模块提供了与日历相关的函数。可以考虑配合 `datetime` 模块实现需求：

``````#!/usr/bin/env python
# -*- coding:utf-8 -*-
'''
@File: datetime_calendar.py
@Time: 2020/01/15 12:46:58
@Author: 大梦三千秋
@Contact: yiluolion@126.com
'''

# put the import lib here
from datetime import date, timedelta
import calendar

def get_month_range(start_date=None):
'''获取月份的范围

Args:
start_date: 开始的日期，默认为 None

Returns:
返回包含月份开始日期和结束日期的元组
'''
if start_date is None:  # 若 start_date 为空，赋值为当月的第一天
start_date = date.today().replace(day=1)
# 获取月份的天数
_, days_in_month = calendar.monthrange(start_date.year, start_date.month)
# 计算结束日期
end_date = start_date + timedelta(days=days_in_month)
# 返回开始日期和结束日期的元组
return (start_date, end_date)``````

``````In [1]: from datetime import timedelta

In [2]: from datetime_calendar import get_month_range

In [3]: a_day = timedelta(days=1)

In [4]: first_day, last_day = get_month_range()

In [5]: while first_day < last_day:
...:     print(first_day)
...:     first_day += a_day
...:
2020-01-01
2020-01-02
2020-01-03
2020-01-04
2020-01-05
2020-01-06
2020-01-07
2020-01-08
...``````

`calendar.monthrange()` 函数返回指定年份指定月份第一天是星期几，以及这个月的天数。

### 参考资料

#### 来源

1. David M. Beazley;Brian K. Jones.Python Cookbook, 3rd Edtioni.O'Reilly Media.2013.
2. "8.1. datetime — Basic date and time types".docs.python.org.Retrieved 11 January 2020
3. "8.2. calendar — General calendar-related functions".docs.python.org.Retrieved 13 January 2020