Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(58)

Side by Side Diff: third_party/logilab/common/date.py

Issue 10447014: Add pylint to depot_tools. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Fix unittests. Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/logilab/common/daemon.py ('k') | third_party/logilab/common/dbf.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 #
4 # This file is part of logilab-common.
5 #
6 # logilab-common is free software: you can redistribute it and/or modify it unde r
7 # the terms of the GNU Lesser General Public License as published by the Free
8 # Software Foundation, either version 2.1 of the License, or (at your option) an y
9 # later version.
10 #
11 # logilab-common is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 # details.
15 #
16 # You should have received a copy of the GNU Lesser General Public License along
17 # with logilab-common. If not, see <http://www.gnu.org/licenses/>.
18 """Date manipulation helper functions."""
19 from __future__ import division
20
21 __docformat__ = "restructuredtext en"
22
23 import math
24 import re
25 from locale import getpreferredencoding
26 from datetime import date, time, datetime, timedelta
27 from time import strptime as time_strptime
28 from calendar import monthrange, timegm
29
30 try:
31 from mx.DateTime import RelativeDateTime, Date, DateTimeType
32 except ImportError:
33 endOfMonth = None
34 DateTimeType = datetime
35 else:
36 endOfMonth = RelativeDateTime(months=1, day=-1)
37
38 # NOTE: should we implement a compatibility layer between date representations
39 # as we have in lgc.db ?
40
41 FRENCH_FIXED_HOLIDAYS = {
42 'jour_an': '%s-01-01',
43 'fete_travail': '%s-05-01',
44 'armistice1945': '%s-05-08',
45 'fete_nat': '%s-07-14',
46 'assomption': '%s-08-15',
47 'toussaint': '%s-11-01',
48 'armistice1918': '%s-11-11',
49 'noel': '%s-12-25',
50 }
51
52 FRENCH_MOBILE_HOLIDAYS = {
53 'paques2004': '2004-04-12',
54 'ascension2004': '2004-05-20',
55 'pentecote2004': '2004-05-31',
56
57 'paques2005': '2005-03-28',
58 'ascension2005': '2005-05-05',
59 'pentecote2005': '2005-05-16',
60
61 'paques2006': '2006-04-17',
62 'ascension2006': '2006-05-25',
63 'pentecote2006': '2006-06-05',
64
65 'paques2007': '2007-04-09',
66 'ascension2007': '2007-05-17',
67 'pentecote2007': '2007-05-28',
68
69 'paques2008': '2008-03-24',
70 'ascension2008': '2008-05-01',
71 'pentecote2008': '2008-05-12',
72
73 'paques2009': '2009-04-13',
74 'ascension2009': '2009-05-21',
75 'pentecote2009': '2009-06-01',
76
77 'paques2010': '2010-04-05',
78 'ascension2010': '2010-05-13',
79 'pentecote2010': '2010-05-24',
80
81 'paques2011': '2011-04-25',
82 'ascension2011': '2011-06-02',
83 'pentecote2011': '2011-06-13',
84
85 'paques2012': '2012-04-09',
86 'ascension2012': '2012-05-17',
87 'pentecote2012': '2012-05-28',
88 }
89
90 # XXX this implementation cries for multimethod dispatching
91
92 def get_step(dateobj, nbdays=1):
93 # assume date is either a python datetime or a mx.DateTime object
94 if isinstance(dateobj, date):
95 return ONEDAY * nbdays
96 return nbdays # mx.DateTime is ok with integers
97
98 def datefactory(year, month, day, sampledate):
99 # assume date is either a python datetime or a mx.DateTime object
100 if isinstance(sampledate, datetime):
101 return datetime(year, month, day)
102 if isinstance(sampledate, date):
103 return date(year, month, day)
104 return Date(year, month, day)
105
106 def weekday(dateobj):
107 # assume date is either a python datetime or a mx.DateTime object
108 if isinstance(dateobj, date):
109 return dateobj.weekday()
110 return dateobj.day_of_week
111
112 def str2date(datestr, sampledate):
113 # NOTE: datetime.strptime is not an option until we drop py2.4 compat
114 year, month, day = [int(chunk) for chunk in datestr.split('-')]
115 return datefactory(year, month, day, sampledate)
116
117 def days_between(start, end):
118 if isinstance(start, date):
119 delta = end - start
120 # datetime.timedelta.days is always an integer (floored)
121 if delta.seconds:
122 return delta.days + 1
123 return delta.days
124 else:
125 return int(math.ceil((end - start).days))
126
127 def get_national_holidays(begin, end):
128 """return french national days off between begin and end"""
129 begin = datefactory(begin.year, begin.month, begin.day, begin)
130 end = datefactory(end.year, end.month, end.day, end)
131 holidays = [str2date(datestr, begin)
132 for datestr in FRENCH_MOBILE_HOLIDAYS.values()]
133 for year in xrange(begin.year, end.year+1):
134 for datestr in FRENCH_FIXED_HOLIDAYS.values():
135 date = str2date(datestr % year, begin)
136 if date not in holidays:
137 holidays.append(date)
138 return [day for day in holidays if begin <= day < end]
139
140 def add_days_worked(start, days):
141 """adds date but try to only take days worked into account"""
142 step = get_step(start)
143 weeks, plus = divmod(days, 5)
144 end = start + ((weeks * 7) + plus) * step
145 if weekday(end) >= 5: # saturday or sunday
146 end += (2 * step)
147 end += len([x for x in get_national_holidays(start, end + step)
148 if weekday(x) < 5]) * step
149 if weekday(end) >= 5: # saturday or sunday
150 end += (2 * step)
151 return end
152
153 def nb_open_days(start, end):
154 assert start <= end
155 step = get_step(start)
156 days = days_between(start, end)
157 weeks, plus = divmod(days, 7)
158 if weekday(start) > weekday(end):
159 plus -= 2
160 elif weekday(end) == 6:
161 plus -= 1
162 open_days = weeks * 5 + plus
163 nb_week_holidays = len([x for x in get_national_holidays(start, end+step)
164 if weekday(x) < 5 and x < end])
165 open_days -= nb_week_holidays
166 if open_days < 0:
167 return 0
168 return open_days
169
170 def date_range(begin, end, incday=None, incmonth=None):
171 """yields each date between begin and end
172
173 :param begin: the start date
174 :param end: the end date
175 :param incr: the step to use to iterate over dates. Default is
176 one day.
177 :param include: None (means no exclusion) or a function taking a
178 date as parameter, and returning True if the date
179 should be included.
180
181 When using mx datetime, you should *NOT* use incmonth argument, use instead
182 oneDay, oneHour, oneMinute, oneSecond, oneWeek or endOfMonth (to enumerate
183 months) as `incday` argument
184 """
185 assert not (incday and incmonth)
186 begin = todate(begin)
187 end = todate(end)
188 if incmonth:
189 while begin < end:
190 begin = next_month(begin, incmonth)
191 yield begin
192 else:
193 incr = get_step(begin, incday or 1)
194 while begin < end:
195 yield begin
196 begin += incr
197
198 # makes py datetime usable #####################################################
199
200 ONEDAY = timedelta(days=1)
201 ONEWEEK = timedelta(days=7)
202
203 try:
204 strptime = datetime.strptime
205 except AttributeError: # py < 2.5
206 from time import strptime as time_strptime
207 def strptime(value, format):
208 return datetime(*time_strptime(value, format)[:6])
209
210 def strptime_time(value, format='%H:%M'):
211 return time(*time_strptime(value, format)[3:6])
212
213 def todate(somedate):
214 """return a date from a date (leaving unchanged) or a datetime"""
215 if isinstance(somedate, datetime):
216 return date(somedate.year, somedate.month, somedate.day)
217 assert isinstance(somedate, (date, DateTimeType)), repr(somedate)
218 return somedate
219
220 def totime(somedate):
221 """return a time from a time (leaving unchanged), date or datetime"""
222 # XXX mx compat
223 if not isinstance(somedate, time):
224 return time(somedate.hour, somedate.minute, somedate.second)
225 assert isinstance(somedate, (time)), repr(somedate)
226 return somedate
227
228 def todatetime(somedate):
229 """return a date from a date (leaving unchanged) or a datetime"""
230 # take care, datetime is a subclass of date
231 if isinstance(somedate, datetime):
232 return somedate
233 assert isinstance(somedate, (date, DateTimeType)), repr(somedate)
234 return datetime(somedate.year, somedate.month, somedate.day)
235
236 def datetime2ticks(somedate):
237 return timegm(somedate.timetuple()) * 1000
238
239 def ticks2datetime(ticks):
240 miliseconds, microseconds = divmod(ticks, 1000)
241 try:
242 return datetime.fromtimestamp(miliseconds)
243 except (ValueError, OverflowError):
244 epoch = datetime.fromtimestamp(0)
245 nb_days, seconds = divmod(int(miliseconds), 86400)
246 delta = timedelta(nb_days, seconds=seconds, microseconds=microseconds)
247 try:
248 return epoch + delta
249 except (ValueError, OverflowError):
250 raise
251
252 def days_in_month(somedate):
253 return monthrange(somedate.year, somedate.month)[1]
254
255 def days_in_year(somedate):
256 feb = date(somedate.year, 2, 1)
257 if days_in_month(feb) == 29:
258 return 366
259 else:
260 return 365
261
262 def previous_month(somedate, nbmonth=1):
263 while nbmonth:
264 somedate = first_day(somedate) - ONEDAY
265 nbmonth -= 1
266 return somedate
267
268 def next_month(somedate, nbmonth=1):
269 while nbmonth:
270 somedate = last_day(somedate) + ONEDAY
271 nbmonth -= 1
272 return somedate
273
274 def first_day(somedate):
275 return date(somedate.year, somedate.month, 1)
276
277 def last_day(somedate):
278 return date(somedate.year, somedate.month, days_in_month(somedate))
279
280 def ustrftime(somedate, fmt='%Y-%m-%d'):
281 """like strftime, but returns a unicode string instead of an encoded
282 string which' may be problematic with localized date.
283
284 encoding is guessed by locale.getpreferredencoding()
285 """
286 encoding = getpreferredencoding(do_setlocale=False) or 'UTF-8'
287 try:
288 return unicode(somedate.strftime(str(fmt)), encoding)
289 except ValueError, exc:
290 if somedate.year >= 1900:
291 raise
292 # datetime is not happy with dates before 1900
293 # we try to work around this, assuming a simple
294 # format string
295 fields = {'Y': somedate.year,
296 'm': somedate.month,
297 'd': somedate.day,
298 }
299 if isinstance(somedate, datetime):
300 fields.update({'H': somedate.hour,
301 'M': somedate.minute,
302 'S': somedate.second})
303 fmt = re.sub('%([YmdHMS])', r'%(\1)02d', fmt)
304 return unicode(fmt) % fields
305
306 def utcdatetime(dt):
307 if dt.tzinfo is None:
308 return dt
309 return datetime(*dt.utctimetuple()[:7])
310
311 def utctime(dt):
312 if dt.tzinfo is None:
313 return dt
314 return (dt + dt.utcoffset() + dt.dst()).replace(tzinfo=None)
315
316 def datetime_to_seconds(date):
317 """return the number of seconds since the begining of the day for that date
318 """
319 return date.second+60*date.minute + 3600*date.hour
320
321 def timedelta_to_days(delta):
322 """return the time delta as a number of seconds"""
323 return delta.days + delta.seconds / (3600*24)
324
325 def timedelta_to_seconds(delta):
326 """return the time delta as a fraction of days"""
327 return delta.days*(3600*24) + delta.seconds
OLDNEW
« no previous file with comments | « third_party/logilab/common/daemon.py ('k') | third_party/logilab/common/dbf.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698