|
1 | | -============================ |
2 | | -3.14 寻找当前月份的某个日期范围 |
3 | | -============================ |
| 1 | +========================== |
| 2 | +3.14 计算当前月份的日期范围 |
| 3 | +========================== |
4 | 4 |
|
5 | 5 | ---------- |
6 | 6 | 问题 |
7 | 7 | ---------- |
8 | | -todo... |
| 8 | +你的代码需要在当前月份中循环每一天,想找到一个计算这个日期范围的高效方法。 |
| 9 | + |
| 10 | +| |
9 | 11 |
|
10 | 12 | ---------- |
11 | 13 | 解决方案 |
12 | 14 | ---------- |
13 | | -todo... |
| 15 | +在这样的日期上循环并需要事先构造一个包含所有日期的列表。 |
| 16 | +你可以先计算出开始日期和结束日期,然后在你步进的时候使用datetime.timedelta对象递增这个日期变量即可。 |
| 17 | + |
| 18 | +下面是一个接受任意datetime对象并返回一个由当前月份开始日和下个月开始日组成的元组对象。 |
| 19 | + |
| 20 | +.. code-block:: python |
| 21 | +
|
| 22 | + from datetime import datetime, date, timedelta |
| 23 | + import calendar |
| 24 | +
|
| 25 | + def get_month_range(start_date=None): |
| 26 | + if start_date is None: |
| 27 | + start_date = date.today().replace(day=1) |
| 28 | + _, days_in_month = calendar.monthrange(start_date.year, start_date.month) |
| 29 | + end_date = start_date + timedelta(days=days_in_month) |
| 30 | + return (start_date, end_date) |
| 31 | +
|
| 32 | +有了这个就可以很容易的在返回的日期范围上面做循环操作了: |
| 33 | + |
| 34 | +.. code-block:: python |
| 35 | +
|
| 36 | + >>> a_day = timedelta(days=1) |
| 37 | + >>> first_day, last_day = get_month_range() |
| 38 | + >>> while first_day < last_day: |
| 39 | + ... print(first_day) |
| 40 | + ... first_day += a_day |
| 41 | + ... |
| 42 | + 2012-08-01 |
| 43 | + 2012-08-02 |
| 44 | + 2012-08-03 |
| 45 | + 2012-08-04 |
| 46 | + 2012-08-05 |
| 47 | + 2012-08-06 |
| 48 | + 2012-08-07 |
| 49 | + 2012-08-08 |
| 50 | + 2012-08-09 |
| 51 | + #... and so on... |
| 52 | +
|
| 53 | +| |
14 | 54 |
|
15 | 55 | ---------- |
16 | 56 | 讨论 |
17 | 57 | ---------- |
18 | | -todo... |
| 58 | +上面的代码先计算出一个对应月份第一天的日期。 |
| 59 | +一个快速的方法就是使用date或datetime对象的replace()方法简单的将days属性设置成1即可。 |
| 60 | +replace()方法一个好处就是它会创建和你开始传入对象类型相同的对象。 |
| 61 | +所以,如果输入参数是一个date实例,那么结果也是一个date实例。 |
| 62 | +同样的,如果输入是一个datetime实例,那么你得到的就是一个datetime实例。 |
| 63 | + |
| 64 | +然后,使用calendar.monthrange()函数来找出该月的总天数。 |
| 65 | +任何时候只要你想获得日历信息,那么calendar模块就非常有用了。 |
| 66 | +monthrange()函数会返回包含星期和该月天数的元组。 |
| 67 | + |
| 68 | +一旦该月的天数已知了,那么结束日期就可以通过在开始日期上面加上这个天数获得。 |
| 69 | +有个需要注意的是结束日期并不包含在这个日期范围内(事实上它是下个月的开始日期)。 |
| 70 | +这个和Python的slice与range操作行为保持一致,同样也不包含结尾。 |
| 71 | + |
| 72 | +为了在日期范围上循环,要使用到标准的数学和比较操作。 |
| 73 | +比如,可以利用timedelta实例来递增日期,小于号<用来检查一个日期是否在结束日期之前。 |
| 74 | + |
| 75 | +理想情况下,如果能为日期迭代创建一个同内置的range()函数一样的函数就好了。 |
| 76 | +幸运的是,可以使用一个生成器来很容易的实现这个目标: |
| 77 | + |
| 78 | +.. code-block:: python |
| 79 | +
|
| 80 | + def date_range(start, stop, step): |
| 81 | + while start < stop: |
| 82 | + yield start |
| 83 | + start += step |
| 84 | +
|
| 85 | +下面是使用这个生成器的例子: |
| 86 | + |
| 87 | +.. code-block:: python |
| 88 | +
|
| 89 | + >>> for d in date_range(datetime(2012, 9, 1), datetime(2012,10,1), |
| 90 | + timedelta(hours=6)): |
| 91 | + ... print(d) |
| 92 | + ... |
| 93 | + 2012-09-01 00:00:00 |
| 94 | + 2012-09-01 06:00:00 |
| 95 | + 2012-09-01 12:00:00 |
| 96 | + 2012-09-01 18:00:00 |
| 97 | + 2012-09-02 00:00:00 |
| 98 | + 2012-09-02 06:00:00 |
| 99 | + ... |
| 100 | + >>> |
| 101 | +
|
| 102 | +这种实现之所以这么简单,还得归功于Python中的日期和时间能够使用标准的数学和比较操作符来进行运算。 |
| 103 | + |
0 commit comments