~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/schoolbell/utils.py

  • Committer: Guilherme Salgado
  • Date: 2010-03-16 23:59:41 UTC
  • mto: This revision was merged to the branch mainline in revision 10537.
  • Revision ID: salgado@canonical.com-20100316235941-8uu1l14c1heo2ae5
Remove the lib/schoolbell/ package, lib/canonical/launchpad/components/cal.py and lib/canonical/launchpad/components/crowd.py

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""
2
 
Utility functions for SchoolBell.
3
 
 
4
 
These include various date manipulation routines.
5
 
"""
6
 
 
7
 
import calendar
8
 
from datetime import datetime, date, timedelta, tzinfo
9
 
 
10
 
 
11
 
def prev_month(date):
12
 
    """Calculate the first day of the previous month for a given date.
13
 
 
14
 
        >>> prev_month(date(2004, 8, 1))
15
 
        datetime.date(2004, 7, 1)
16
 
        >>> prev_month(date(2004, 8, 31))
17
 
        datetime.date(2004, 7, 1)
18
 
        >>> prev_month(date(2004, 12, 15))
19
 
        datetime.date(2004, 11, 1)
20
 
        >>> prev_month(date(2005, 1, 28))
21
 
        datetime.date(2004, 12, 1)
22
 
 
23
 
    """
24
 
    return (date.replace(day=1) - timedelta(1)).replace(day=1)
25
 
 
26
 
 
27
 
def next_month(date):
28
 
    """Calculate the first day of the next month for a given date.
29
 
 
30
 
        >>> next_month(date(2004, 8, 1))
31
 
        datetime.date(2004, 9, 1)
32
 
        >>> next_month(date(2004, 8, 31))
33
 
        datetime.date(2004, 9, 1)
34
 
        >>> next_month(date(2004, 12, 15))
35
 
        datetime.date(2005, 1, 1)
36
 
        >>> next_month(date(2004, 2, 28))
37
 
        datetime.date(2004, 3, 1)
38
 
        >>> next_month(date(2004, 2, 29))
39
 
        datetime.date(2004, 3, 1)
40
 
        >>> next_month(date(2005, 2, 28))
41
 
        datetime.date(2005, 3, 1)
42
 
 
43
 
    """
44
 
    return (date.replace(day=28) + timedelta(7)).replace(day=1)
45
 
 
46
 
 
47
 
def week_start(date, first_day_of_week=0):
48
 
    """Calculate the first day of the week for a given date.
49
 
 
50
 
    Assuming that week starts on Mondays:
51
 
 
52
 
        >>> week_start(date(2004, 8, 19))
53
 
        datetime.date(2004, 8, 16)
54
 
        >>> week_start(date(2004, 8, 15))
55
 
        datetime.date(2004, 8, 9)
56
 
        >>> week_start(date(2004, 8, 14))
57
 
        datetime.date(2004, 8, 9)
58
 
        >>> week_start(date(2004, 8, 21))
59
 
        datetime.date(2004, 8, 16)
60
 
        >>> week_start(date(2004, 8, 22))
61
 
        datetime.date(2004, 8, 16)
62
 
        >>> week_start(date(2004, 8, 23))
63
 
        datetime.date(2004, 8, 23)
64
 
 
65
 
    Assuming that week starts on Sundays:
66
 
 
67
 
        >>> import calendar
68
 
        >>> week_start(date(2004, 8, 19), calendar.SUNDAY)
69
 
        datetime.date(2004, 8, 15)
70
 
        >>> week_start(date(2004, 8, 15), calendar.SUNDAY)
71
 
        datetime.date(2004, 8, 15)
72
 
        >>> week_start(date(2004, 8, 14), calendar.SUNDAY)
73
 
        datetime.date(2004, 8, 8)
74
 
        >>> week_start(date(2004, 8, 21), calendar.SUNDAY)
75
 
        datetime.date(2004, 8, 15)
76
 
        >>> week_start(date(2004, 8, 22), calendar.SUNDAY)
77
 
        datetime.date(2004, 8, 22)
78
 
        >>> week_start(date(2004, 8, 23), calendar.SUNDAY)
79
 
        datetime.date(2004, 8, 22)
80
 
 
81
 
    """
82
 
    assert 0 <= first_day_of_week < 7
83
 
    delta = date.weekday() - first_day_of_week
84
 
    if delta < 0:
85
 
        delta += 7
86
 
    return date - timedelta(delta)
87
 
 
88
 
 
89
 
def weeknum_bounds(year, weeknum):
90
 
    """Calculate the inclusive date bounds for a (year, weeknum) tuple.
91
 
 
92
 
    Week numbers are as defined in ISO 8601 and returned by
93
 
    datetime.date.isocalendar().
94
 
 
95
 
        >>> weeknum_bounds(2003, 52)
96
 
        (datetime.date(2003, 12, 22), datetime.date(2003, 12, 28))
97
 
        >>> weeknum_bounds(2004, 1)
98
 
        (datetime.date(2003, 12, 29), datetime.date(2004, 1, 4))
99
 
        >>> weeknum_bounds(2004, 2)
100
 
        (datetime.date(2004, 1, 5), datetime.date(2004, 1, 11))
101
 
 
102
 
    """
103
 
    # The first week of a year is at least 4 days long, so January 4th
104
 
    # is in the first week.
105
 
    firstweek = week_start(date(year, 1, 4), calendar.MONDAY)
106
 
    # move forward to the right week number
107
 
    weekstart = firstweek + timedelta(weeks=weeknum-1)
108
 
    weekend = weekstart + timedelta(days=6)
109
 
    return (weekstart, weekend)
110
 
 
111
 
 
112
 
def check_weeknum(year, weeknum):
113
 
    """Check to see whether a (year, weeknum) tuple refers to a real
114
 
    ISO week number.
115
 
 
116
 
        >>> check_weeknum(2004, 1)
117
 
        True
118
 
        >>> check_weeknum(2004, 53)
119
 
        True
120
 
        >>> check_weeknum(2004, 0)
121
 
        False
122
 
        >>> check_weeknum(2004, 54)
123
 
        False
124
 
        >>> check_weeknum(2003, 52)
125
 
        True
126
 
        >>> check_weeknum(2003, 53)
127
 
        False
128
 
 
129
 
    """
130
 
    weekstart, weekend = weeknum_bounds(year, weeknum)
131
 
    isoyear, isoweek, isoday = weekstart.isocalendar()
132
 
    return (year, weeknum) == (isoyear, isoweek)
133
 
 
134
 
class Slots(dict):
135
 
    """A dict with automatic key selection.
136
 
 
137
 
    The add method automatically selects the lowest unused numeric key
138
 
    (starting from 0).
139
 
 
140
 
    Example:
141
 
 
142
 
      >>> s = Slots()
143
 
      >>> s.add("first")
144
 
      >>> s
145
 
      {0: 'first'}
146
 
 
147
 
      >>> s.add("second")
148
 
      >>> s
149
 
      {0: 'first', 1: 'second'}
150
 
 
151
 
    The keys can be reused:
152
 
 
153
 
      >>> del s[0]
154
 
      >>> s.add("third")
155
 
      >>> s
156
 
      {0: 'third', 1: 'second'}
157
 
 
158
 
    """
159
 
 
160
 
    def add(self, obj):
161
 
        i = 0
162
 
        while i in self:
163
 
            i += 1
164
 
        self[i] = obj