python-dateutil 2.4.1__zip

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,450 @@
1
+ # -*- coding: utf-8 -*-
2
+ import datetime
3
+ import calendar
4
+
5
+ from six import integer_types
6
+
7
+ __all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"]
8
+
9
+
10
+ class weekday(object):
11
+ __slots__ = ["weekday", "n"]
12
+
13
+ def __init__(self, weekday, n=None):
14
+ self.weekday = weekday
15
+ self.n = n
16
+
17
+ def __call__(self, n):
18
+ if n == self.n:
19
+ return self
20
+ else:
21
+ return self.__class__(self.weekday, n)
22
+
23
+ def __eq__(self, other):
24
+ try:
25
+ if self.weekday != other.weekday or self.n != other.n:
26
+ return False
27
+ except AttributeError:
28
+ return False
29
+ return True
30
+
31
+ def __repr__(self):
32
+ s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday]
33
+ if not self.n:
34
+ return s
35
+ else:
36
+ return "%s(%+d)" % (s, self.n)
37
+
38
+ MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)])
39
+
40
+
41
+ class relativedelta(object):
42
+ """
43
+ The relativedelta type is based on the specification of the excellent
44
+ work done by M.-A. Lemburg in his
45
+ `mx.DateTime <http://www.egenix.com/files/python/mxDateTime.html>`_ extension.
46
+ However, notice that this type does *NOT* implement the same algorithm as
47
+ his work. Do *NOT* expect it to behave like mx.DateTime's counterpart.
48
+
49
+ There are two different ways to build a relativedelta instance. The
50
+ first one is passing it two date/datetime classes::
51
+
52
+ relativedelta(datetime1, datetime2)
53
+
54
+ The second one is passing it any number of the following keyword arguments::
55
+
56
+ relativedelta(arg1=x,arg2=y,arg3=z...)
57
+
58
+ year, month, day, hour, minute, second, microsecond:
59
+ Absolute information (argument is singular); adding or subtracting a
60
+ relativedelta with absolute information does not perform an aritmetic
61
+ operation, but rather REPLACES the corresponding value in the
62
+ original datetime with the value(s) in relativedelta.
63
+
64
+ years, months, weeks, days, hours, minutes, seconds, microseconds:
65
+ Relative information, may be negative (argument is plural); adding
66
+ or subtracting a relativedelta with relative information performs
67
+ the corresponding aritmetic operation on the original datetime value
68
+ with the information in the relativedelta.
69
+
70
+ weekday:
71
+ One of the weekday instances (MO, TU, etc). These instances may
72
+ receive a parameter N, specifying the Nth weekday, which could
73
+ be positive or negative (like MO(+1) or MO(-2). Not specifying
74
+ it is the same as specifying +1. You can also use an integer,
75
+ where 0=MO.
76
+
77
+ leapdays:
78
+ Will add given days to the date found, if year is a leap
79
+ year, and the date found is post 28 of february.
80
+
81
+ yearday, nlyearday:
82
+ Set the yearday or the non-leap year day (jump leap days).
83
+ These are converted to day/month/leapdays information.
84
+
85
+ Here is the behavior of operations with relativedelta:
86
+
87
+ 1. Calculate the absolute year, using the 'year' argument, or the
88
+ original datetime year, if the argument is not present.
89
+
90
+ 2. Add the relative 'years' argument to the absolute year.
91
+
92
+ 3. Do steps 1 and 2 for month/months.
93
+
94
+ 4. Calculate the absolute day, using the 'day' argument, or the
95
+ original datetime day, if the argument is not present. Then,
96
+ subtract from the day until it fits in the year and month
97
+ found after their operations.
98
+
99
+ 5. Add the relative 'days' argument to the absolute day. Notice
100
+ that the 'weeks' argument is multiplied by 7 and added to
101
+ 'days'.
102
+
103
+ 6. Do steps 1 and 2 for hour/hours, minute/minutes, second/seconds,
104
+ microsecond/microseconds.
105
+
106
+ 7. If the 'weekday' argument is present, calculate the weekday,
107
+ with the given (wday, nth) tuple. wday is the index of the
108
+ weekday (0-6, 0=Mon), and nth is the number of weeks to add
109
+ forward or backward, depending on its signal. Notice that if
110
+ the calculated date is already Monday, for example, using
111
+ (0, 1) or (0, -1) won't change the day.
112
+ """
113
+
114
+ def __init__(self, dt1=None, dt2=None,
115
+ years=0, months=0, days=0, leapdays=0, weeks=0,
116
+ hours=0, minutes=0, seconds=0, microseconds=0,
117
+ year=None, month=None, day=None, weekday=None,
118
+ yearday=None, nlyearday=None,
119
+ hour=None, minute=None, second=None, microsecond=None):
120
+ if dt1 and dt2:
121
+ # datetime is a subclass of date. So both must be date
122
+ if not (isinstance(dt1, datetime.date) and
123
+ isinstance(dt2, datetime.date)):
124
+ raise TypeError("relativedelta only diffs datetime/date")
125
+ # We allow two dates, or two datetimes, so we coerce them to be
126
+ # of the same type
127
+ if (isinstance(dt1, datetime.datetime) !=
128
+ isinstance(dt2, datetime.datetime)):
129
+ if not isinstance(dt1, datetime.datetime):
130
+ dt1 = datetime.datetime.fromordinal(dt1.toordinal())
131
+ elif not isinstance(dt2, datetime.datetime):
132
+ dt2 = datetime.datetime.fromordinal(dt2.toordinal())
133
+ self.years = 0
134
+ self.months = 0
135
+ self.days = 0
136
+ self.leapdays = 0
137
+ self.hours = 0
138
+ self.minutes = 0
139
+ self.seconds = 0
140
+ self.microseconds = 0
141
+ self.year = None
142
+ self.month = None
143
+ self.day = None
144
+ self.weekday = None
145
+ self.hour = None
146
+ self.minute = None
147
+ self.second = None
148
+ self.microsecond = None
149
+ self._has_time = 0
150
+
151
+ months = (dt1.year*12+dt1.month)-(dt2.year*12+dt2.month)
152
+ self._set_months(months)
153
+ dtm = self.__radd__(dt2)
154
+ if dt1 < dt2:
155
+ while dt1 > dtm:
156
+ months += 1
157
+ self._set_months(months)
158
+ dtm = self.__radd__(dt2)
159
+ else:
160
+ while dt1 < dtm:
161
+ months -= 1
162
+ self._set_months(months)
163
+ dtm = self.__radd__(dt2)
164
+ delta = dt1 - dtm
165
+ self.seconds = delta.seconds+delta.days*86400
166
+ self.microseconds = delta.microseconds
167
+ else:
168
+ self.years = years
169
+ self.months = months
170
+ self.days = days+weeks*7
171
+ self.leapdays = leapdays
172
+ self.hours = hours
173
+ self.minutes = minutes
174
+ self.seconds = seconds
175
+ self.microseconds = microseconds
176
+ self.year = year
177
+ self.month = month
178
+ self.day = day
179
+ self.hour = hour
180
+ self.minute = minute
181
+ self.second = second
182
+ self.microsecond = microsecond
183
+
184
+ if isinstance(weekday, integer_types):
185
+ self.weekday = weekdays[weekday]
186
+ else:
187
+ self.weekday = weekday
188
+
189
+ yday = 0
190
+ if nlyearday:
191
+ yday = nlyearday
192
+ elif yearday:
193
+ yday = yearday
194
+ if yearday > 59:
195
+ self.leapdays = -1
196
+ if yday:
197
+ ydayidx = [31, 59, 90, 120, 151, 181, 212,
198
+ 243, 273, 304, 334, 366]
199
+ for idx, ydays in enumerate(ydayidx):
200
+ if yday <= ydays:
201
+ self.month = idx+1
202
+ if idx == 0:
203
+ self.day = yday
204
+ else:
205
+ self.day = yday-ydayidx[idx-1]
206
+ break
207
+ else:
208
+ raise ValueError("invalid year day (%d)" % yday)
209
+
210
+ self._fix()
211
+
212
+ def _fix(self):
213
+ if abs(self.microseconds) > 999999:
214
+ s = self.microseconds//abs(self.microseconds)
215
+ div, mod = divmod(self.microseconds*s, 1000000)
216
+ self.microseconds = mod*s
217
+ self.seconds += div*s
218
+ if abs(self.seconds) > 59:
219
+ s = self.seconds//abs(self.seconds)
220
+ div, mod = divmod(self.seconds*s, 60)
221
+ self.seconds = mod*s
222
+ self.minutes += div*s
223
+ if abs(self.minutes) > 59:
224
+ s = self.minutes//abs(self.minutes)
225
+ div, mod = divmod(self.minutes*s, 60)
226
+ self.minutes = mod*s
227
+ self.hours += div*s
228
+ if abs(self.hours) > 23:
229
+ s = self.hours//abs(self.hours)
230
+ div, mod = divmod(self.hours*s, 24)
231
+ self.hours = mod*s
232
+ self.days += div*s
233
+ if abs(self.months) > 11:
234
+ s = self.months//abs(self.months)
235
+ div, mod = divmod(self.months*s, 12)
236
+ self.months = mod*s
237
+ self.years += div*s
238
+ if (self.hours or self.minutes or self.seconds or self.microseconds
239
+ or self.hour is not None or self.minute is not None or
240
+ self.second is not None or self.microsecond is not None):
241
+ self._has_time = 1
242
+ else:
243
+ self._has_time = 0
244
+
245
+ def _set_months(self, months):
246
+ self.months = months
247
+ if abs(self.months) > 11:
248
+ s = self.months//abs(self.months)
249
+ div, mod = divmod(self.months*s, 12)
250
+ self.months = mod*s
251
+ self.years = div*s
252
+ else:
253
+ self.years = 0
254
+
255
+ def __add__(self, other):
256
+ if isinstance(other, relativedelta):
257
+ return relativedelta(years=other.years+self.years,
258
+ months=other.months+self.months,
259
+ days=other.days+self.days,
260
+ hours=other.hours+self.hours,
261
+ minutes=other.minutes+self.minutes,
262
+ seconds=other.seconds+self.seconds,
263
+ microseconds=(other.microseconds +
264
+ self.microseconds),
265
+ leapdays=other.leapdays or self.leapdays,
266
+ year=other.year or self.year,
267
+ month=other.month or self.month,
268
+ day=other.day or self.day,
269
+ weekday=other.weekday or self.weekday,
270
+ hour=other.hour or self.hour,
271
+ minute=other.minute or self.minute,
272
+ second=other.second or self.second,
273
+ microsecond=(other.microsecond or
274
+ self.microsecond))
275
+ if not isinstance(other, datetime.date):
276
+ raise TypeError("unsupported type for add operation")
277
+ elif self._has_time and not isinstance(other, datetime.datetime):
278
+ other = datetime.datetime.fromordinal(other.toordinal())
279
+ year = (self.year or other.year)+self.years
280
+ month = self.month or other.month
281
+ if self.months:
282
+ assert 1 <= abs(self.months) <= 12
283
+ month += self.months
284
+ if month > 12:
285
+ year += 1
286
+ month -= 12
287
+ elif month < 1:
288
+ year -= 1
289
+ month += 12
290
+ day = min(calendar.monthrange(year, month)[1],
291
+ self.day or other.day)
292
+ repl = {"year": year, "month": month, "day": day}
293
+ for attr in ["hour", "minute", "second", "microsecond"]:
294
+ value = getattr(self, attr)
295
+ if value is not None:
296
+ repl[attr] = value
297
+ days = self.days
298
+ if self.leapdays and month > 2 and calendar.isleap(year):
299
+ days += self.leapdays
300
+ ret = (other.replace(**repl)
301
+ + datetime.timedelta(days=days,
302
+ hours=self.hours,
303
+ minutes=self.minutes,
304
+ seconds=self.seconds,
305
+ microseconds=self.microseconds))
306
+ if self.weekday:
307
+ weekday, nth = self.weekday.weekday, self.weekday.n or 1
308
+ jumpdays = (abs(nth)-1)*7
309
+ if nth > 0:
310
+ jumpdays += (7-ret.weekday()+weekday) % 7
311
+ else:
312
+ jumpdays += (ret.weekday()-weekday) % 7
313
+ jumpdays *= -1
314
+ ret += datetime.timedelta(days=jumpdays)
315
+ return ret
316
+
317
+ def __radd__(self, other):
318
+ return self.__add__(other)
319
+
320
+ def __rsub__(self, other):
321
+ return self.__neg__().__radd__(other)
322
+
323
+ def __sub__(self, other):
324
+ if not isinstance(other, relativedelta):
325
+ raise TypeError("unsupported type for sub operation")
326
+ return relativedelta(years=self.years-other.years,
327
+ months=self.months-other.months,
328
+ days=self.days-other.days,
329
+ hours=self.hours-other.hours,
330
+ minutes=self.minutes-other.minutes,
331
+ seconds=self.seconds-other.seconds,
332
+ microseconds=self.microseconds-other.microseconds,
333
+ leapdays=self.leapdays or other.leapdays,
334
+ year=self.year or other.year,
335
+ month=self.month or other.month,
336
+ day=self.day or other.day,
337
+ weekday=self.weekday or other.weekday,
338
+ hour=self.hour or other.hour,
339
+ minute=self.minute or other.minute,
340
+ second=self.second or other.second,
341
+ microsecond=self.microsecond or other.microsecond)
342
+
343
+ def __neg__(self):
344
+ return relativedelta(years=-self.years,
345
+ months=-self.months,
346
+ days=-self.days,
347
+ hours=-self.hours,
348
+ minutes=-self.minutes,
349
+ seconds=-self.seconds,
350
+ microseconds=-self.microseconds,
351
+ leapdays=self.leapdays,
352
+ year=self.year,
353
+ month=self.month,
354
+ day=self.day,
355
+ weekday=self.weekday,
356
+ hour=self.hour,
357
+ minute=self.minute,
358
+ second=self.second,
359
+ microsecond=self.microsecond)
360
+
361
+ def __bool__(self):
362
+ return not (not self.years and
363
+ not self.months and
364
+ not self.days and
365
+ not self.hours and
366
+ not self.minutes and
367
+ not self.seconds and
368
+ not self.microseconds and
369
+ not self.leapdays and
370
+ self.year is None and
371
+ self.month is None and
372
+ self.day is None and
373
+ self.weekday is None and
374
+ self.hour is None and
375
+ self.minute is None and
376
+ self.second is None and
377
+ self.microsecond is None)
378
+ # Compatibility with Python 2.x
379
+ __nonzero__ = __bool__
380
+
381
+ def __mul__(self, other):
382
+ f = float(other)
383
+ return relativedelta(years=int(self.years*f),
384
+ months=int(self.months*f),
385
+ days=int(self.days*f),
386
+ hours=int(self.hours*f),
387
+ minutes=int(self.minutes*f),
388
+ seconds=int(self.seconds*f),
389
+ microseconds=int(self.microseconds*f),
390
+ leapdays=self.leapdays,
391
+ year=self.year,
392
+ month=self.month,
393
+ day=self.day,
394
+ weekday=self.weekday,
395
+ hour=self.hour,
396
+ minute=self.minute,
397
+ second=self.second,
398
+ microsecond=self.microsecond)
399
+
400
+ __rmul__ = __mul__
401
+
402
+ def __eq__(self, other):
403
+ if not isinstance(other, relativedelta):
404
+ return False
405
+ if self.weekday or other.weekday:
406
+ if not self.weekday or not other.weekday:
407
+ return False
408
+ if self.weekday.weekday != other.weekday.weekday:
409
+ return False
410
+ n1, n2 = self.weekday.n, other.weekday.n
411
+ if n1 != n2 and not ((not n1 or n1 == 1) and (not n2 or n2 == 1)):
412
+ return False
413
+ return (self.years == other.years and
414
+ self.months == other.months and
415
+ self.days == other.days and
416
+ self.hours == other.hours and
417
+ self.minutes == other.minutes and
418
+ self.seconds == other.seconds and
419
+ self.leapdays == other.leapdays and
420
+ self.year == other.year and
421
+ self.month == other.month and
422
+ self.day == other.day and
423
+ self.hour == other.hour and
424
+ self.minute == other.minute and
425
+ self.second == other.second and
426
+ self.microsecond == other.microsecond)
427
+
428
+ def __ne__(self, other):
429
+ return not self.__eq__(other)
430
+
431
+ def __div__(self, other):
432
+ return self.__mul__(1/float(other))
433
+
434
+ __truediv__ = __div__
435
+
436
+ def __repr__(self):
437
+ l = []
438
+ for attr in ["years", "months", "days", "leapdays",
439
+ "hours", "minutes", "seconds", "microseconds"]:
440
+ value = getattr(self, attr)
441
+ if value:
442
+ l.append("%s=%+d" % (attr, value))
443
+ for attr in ["year", "month", "day", "weekday",
444
+ "hour", "minute", "second", "microsecond"]:
445
+ value = getattr(self, attr)
446
+ if value is not None:
447
+ l.append("%s=%s" % (attr, repr(value)))
448
+ return "%s(%s)" % (self.__class__.__name__, ", ".join(l))
449
+
450
+ # vim:ts=4:sw=4:et