1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """Date manipulation helper functions.
19
20
21
22
23 """
24 __docformat__ = "restructuredtext en"
25
26 import math
27 from locale import getpreferredencoding
28 from datetime import date, time, datetime, timedelta
29 from time import strptime as time_strptime
30 from calendar import monthrange, timegm
31
32 try:
33 from mx.DateTime import RelativeDateTime, Date, DateTimeType
34 except ImportError:
35 from warnings import warn
36 warn("mxDateTime not found, endOfMonth won't be available")
37 endOfMonth = None
38 DateTimeType = datetime
39 else:
40 endOfMonth = RelativeDateTime(months=1, day=-1)
41
42
43
44
45 FRENCH_FIXED_HOLIDAYS = {
46 'jour_an' : '%s-01-01',
47 'fete_travail' : '%s-05-01',
48 'armistice1945' : '%s-05-08',
49 'fete_nat' : '%s-07-14',
50 'assomption' : '%s-08-15',
51 'toussaint' : '%s-11-01',
52 'armistice1918' : '%s-11-11',
53 'noel' : '%s-12-25',
54 }
55
56 FRENCH_MOBILE_HOLIDAYS = {
57 'paques2004' : '2004-04-12',
58 'ascension2004' : '2004-05-20',
59 'pentecote2004' : '2004-05-31',
60
61 'paques2005' : '2005-03-28',
62 'ascension2005' : '2005-05-05',
63 'pentecote2005' : '2005-05-16',
64
65 'paques2006' : '2006-04-17',
66 'ascension2006' : '2006-05-25',
67 'pentecote2006' : '2006-06-05',
68
69 'paques2007' : '2007-04-09',
70 'ascension2007' : '2007-05-17',
71 'pentecote2007' : '2007-05-28',
72
73 'paques2008' : '2008-03-24',
74 'ascension2008' : '2008-05-01',
75 'pentecote2008' : '2008-05-12',
76
77 'paques2009' : '2009-04-13',
78 'ascension2009' : '2009-05-21',
79 'pentecote2009' : '2009-06-01',
80
81 'paques2010' : '2010-04-05',
82 'ascension2010' : '2010-05-13',
83 'pentecote2010' : '2010-05-24',
84
85 'paques2011' : '2011-04-25',
86 'ascension2011' : '2011-06-02',
87 'pentecote2011' : '2011-06-13',
88
89 'paques2012' : '2012-04-09',
90 'ascension2012' : '2012-05-17',
91 'pentecote2012' : '2012-05-28',
92 }
93
94
95
97
98 if isinstance(dateobj, date):
99 return ONEDAY * nbdays
100 return nbdays
101
103
104 if isinstance(sampledate, datetime):
105 return datetime(year, month, day)
106 if isinstance(sampledate, date):
107 return date(year, month, day)
108 return Date(year, month, day)
109
111
112 if isinstance(dateobj, date):
113 return dateobj.weekday()
114 return dateobj.day_of_week
115
117
118 year, month, day = [int(chunk) for chunk in datestr.split('-')]
119 return datefactory(year, month, day, sampledate)
120
122 if isinstance(start, date):
123 delta = end - start
124
125 if delta.seconds:
126 return delta.days + 1
127 return delta.days
128 else:
129 return int(math.ceil((end - start).days))
130
132 """return french national days off between begin and end"""
133 begin = datefactory(begin.year, begin.month, begin.day, begin)
134 end = datefactory(end.year, end.month, end.day, end)
135 holidays = [str2date(datestr, begin)
136 for datestr in FRENCH_MOBILE_HOLIDAYS.values()]
137 for year in xrange(begin.year, end.year+1):
138 for datestr in FRENCH_FIXED_HOLIDAYS.values():
139 date = str2date(datestr % year, begin)
140 if date not in holidays:
141 holidays.append(date)
142 return [day for day in holidays if begin <= day < end]
143
145 """adds date but try to only take days worked into account"""
146 step = get_step(start)
147 weeks, plus = divmod(days, 5)
148 end = start + ((weeks * 7) + plus) * step
149 if weekday(end) >= 5:
150 end += (2 * step)
151 end += len([x for x in get_national_holidays(start, end + step)
152 if weekday(x) < 5]) * step
153 if weekday(end) >= 5:
154 end += (2 * step)
155 return end
156
173
174 -def date_range(begin, end, incday=None, incmonth=None):
175 """yields each date between begin and end
176
177 :param begin: the start date
178 :param end: the end date
179 :param incr: the step to use to iterate over dates. Default is
180 one day.
181 :param include: None (means no exclusion) or a function taking a
182 date as parameter, and returning True if the date
183 should be included.
184
185 When using mx datetime, you should *NOT* use incmonth argument, use instead
186 oneDay, oneHour, oneMinute, oneSecond, oneWeek or endOfMonth (to enumerate
187 months) as `incday` argument
188 """
189 assert not (incday and incmonth)
190 begin = todate(begin)
191 end = todate(end)
192 if incmonth:
193 while begin < end:
194 begin = next_month(begin, incmonth)
195 yield begin
196 else:
197 incr = get_step(begin, incday or 1)
198 while begin < end:
199 yield begin
200 begin += incr
201
202
203
204 ONEDAY = timedelta(days=1)
205 ONEWEEK = timedelta(days=7)
206
207 try:
208 strptime = datetime.strptime
209 except AttributeError:
210 from time import strptime as time_strptime
212 return datetime(*time_strptime(value, format)[:6])
213
215 return time(*time_strptime(value, format)[3:6])
216
218 """return a date from a date (leaving unchanged) or a datetime"""
219 if isinstance(somedate, datetime):
220 return date(somedate.year, somedate.month, somedate.day)
221 assert isinstance(somedate, (date, DateTimeType)), repr(somedate)
222 return somedate
223
225 """return a time from a time (leaving unchanged), date or datetime"""
226
227 if not isinstance(somedate, time):
228 return time(somedate.hour, somedate.minute, somedate.second)
229 assert isinstance(somedate, (time)), repr(somedate)
230 return somedate
231
233 """return a date from a date (leaving unchanged) or a datetime"""
234
235 if isinstance(somedate, datetime):
236 return somedate
237 assert isinstance(somedate, (date, DateTimeType)), repr(somedate)
238 return datetime(somedate.year, somedate.month, somedate.day)
239
241 return timegm(somedate.timetuple()) * 1000
242
244 return monthrange(somedate.year, somedate.month)[1]
245
247 feb = date(somedate.year, 2, 1)
248 if days_in_month(feb) == 29:
249 return 366
250 else:
251 return 365
252
254 while nbmonth:
255 somedate = first_day(somedate) - ONEDAY
256 nbmonth -= 1
257 return somedate
258
260 while nbmonth:
261 somedate = last_day(somedate) + ONEDAY
262 nbmonth -= 1
263 return somedate
264
266 return date(somedate.year, somedate.month, 1)
267
270
272 """like strftime, but returns a unicode string instead of an encoded
273 string which' may be problematic with localized date.
274
275 encoding is guessed by locale.getpreferredencoding()
276 """
277
278 encoding = getpreferredencoding(do_setlocale=False) or 'UTF-8'
279 return unicode(somedate.strftime(str(fmt)), encoding)
280