1 """Date manipulation helper functions.
2
3 :copyright: 2006-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
4 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
5 :license: General Public License version 2 - http://www.gnu.org/licenses
6 """
7 __docformat__ = "restructuredtext en"
8
9 import math
10
11 from datetime import date, datetime, timedelta
12 try:
13 from mx.DateTime import RelativeDateTime, Date
14 except ImportError:
15 from warnings import warn
16 warn("mxDateTime not found, endsOfMonth won't be available")
17 from datetime import date, timedelta
20 endOfMonth = None
21 else:
22 endOfMonth = RelativeDateTime(months=1, day=-1)
23
24
25
26
27 PYDATE_STEP = timedelta(days=1)
28
29 FRENCH_FIXED_HOLIDAYS = {
30 'jour_an' : '%s-01-01',
31 'fete_travail' : '%s-05-01',
32 'armistice1945' : '%s-05-08',
33 'fete_nat' : '%s-07-14',
34 'assomption' : '%s-08-15',
35 'toussaint' : '%s-11-01',
36 'armistice1918' : '%s-11-11',
37 'noel' : '%s-12-25',
38 }
39
40 FRENCH_MOBILE_HOLIDAYS = {
41 'paques2004' : '2004-04-12',
42 'ascension2004' : '2004-05-20',
43 'pentecote2004' : '2004-05-31',
44
45 'paques2005' : '2005-03-28',
46 'ascension2005' : '2005-05-05',
47 'pentecote2005' : '2005-05-16',
48
49 'paques2006' : '2006-04-17',
50 'ascension2006' : '2006-05-25',
51 'pentecote2006' : '2006-06-05',
52
53 'paques2007' : '2007-04-09',
54 'ascension2007' : '2007-05-17',
55 'pentecote2007' : '2007-05-28',
56
57 'paques2008' : '2008-03-24',
58 'ascension2008' : '2008-05-01',
59 'pentecote2008' : '2008-05-12',
60
61 'paques2009' : '2009-04-13',
62 'ascension2009' : '2009-05-21',
63 'pentecote2009' : '2009-06-01',
64
65 'paques2010' : '2010-04-05',
66 'ascension2010' : '2010-05-13',
67 'pentecote2010' : '2010-05-24',
68
69 'paques2011' : '2011-04-25',
70 'ascension2011' : '2011-06-02',
71 'pentecote2011' : '2011-06-13',
72
73 'paques2012' : '2012-04-09',
74 'ascension2012' : '2012-05-17',
75 'pentecote2012' : '2012-05-28',
76 }
77
78
79
85
87
88 if isinstance(sampledate, datetime):
89 return datetime(year, month, day)
90 if isinstance(sampledate, date):
91 return date(year, month, day)
92 return Date(year, month, day)
93
95
96 if isinstance(dateobj, date):
97 return dateobj.weekday()
98 return dateobj.day_of_week
99
101
102 year, month, day = [int(chunk) for chunk in datestr.split('-')]
103 return datefactory(year, month, day, sampledate)
104
106 if isinstance(start, date):
107 delta = end - start
108
109 if delta.seconds:
110 return delta.days + 1
111 return delta.days
112 else:
113 return int(math.ceil((end - start).days))
114
116 """return french national days off between begin and end"""
117 begin = datefactory(begin.year, begin.month, begin.day, begin)
118 end = datefactory(end.year, end.month, end.day, end)
119 holidays = [str2date(datestr, begin)
120 for datestr in FRENCH_MOBILE_HOLIDAYS.values()]
121 for year in xrange(begin.year, end.year+1):
122 for datestr in FRENCH_FIXED_HOLIDAYS.values():
123 date = str2date(datestr % year, begin)
124 if date not in holidays:
125 holidays.append(date)
126 return [day for day in holidays if begin <= day < end]
127
129 """adds date but try to only take days worked into account"""
130 step = get_step(start)
131 weeks, plus = divmod(days, 5)
132 end = start + ((weeks * 7) + plus) * step
133 if weekday(end) >= 5:
134 end += (2 * step)
135 end += len([x for x in get_national_holidays(start, end + step)
136 if weekday(x) < 5]) * step
137 if weekday(end) >= 5:
138 end += (2 * step)
139 return end
140
154
156 """
157 enumerate dates between begin and end dates.
158
159 step can either be oneDay, oneHour, oneMinute, oneSecond, oneWeek
160 use endOfMonth to enumerate months
161 """
162 if step is None:
163 step = get_step(begin)
164 date = begin
165 while date < end :
166 yield date
167 date += step
168