Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wiseplat
GitHub Repository: wiseplat/python-code
Path: blob/master/ invest-robot-contest_TinkoffBotTwitch-main/venv/lib/python3.8/site-packages/dateutil/relativedelta.py
7794 views
1
# -*- coding: utf-8 -*-
2
import datetime
3
import calendar
4
5
import operator
6
from math import copysign
7
8
from six import integer_types
9
from warnings import warn
10
11
from ._common import weekday
12
13
MO, TU, WE, TH, FR, SA, SU = weekdays = tuple(weekday(x) for x in range(7))
14
15
__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"]
16
17
18
class relativedelta(object):
19
"""
20
The relativedelta type is designed to be applied to an existing datetime and
21
can replace specific components of that datetime, or represents an interval
22
of time.
23
24
It is based on the specification of the excellent work done by M.-A. Lemburg
25
in his
26
`mx.DateTime <https://www.egenix.com/products/python/mxBase/mxDateTime/>`_ extension.
27
However, notice that this type does *NOT* implement the same algorithm as
28
his work. Do *NOT* expect it to behave like mx.DateTime's counterpart.
29
30
There are two different ways to build a relativedelta instance. The
31
first one is passing it two date/datetime classes::
32
33
relativedelta(datetime1, datetime2)
34
35
The second one is passing it any number of the following keyword arguments::
36
37
relativedelta(arg1=x,arg2=y,arg3=z...)
38
39
year, month, day, hour, minute, second, microsecond:
40
Absolute information (argument is singular); adding or subtracting a
41
relativedelta with absolute information does not perform an arithmetic
42
operation, but rather REPLACES the corresponding value in the
43
original datetime with the value(s) in relativedelta.
44
45
years, months, weeks, days, hours, minutes, seconds, microseconds:
46
Relative information, may be negative (argument is plural); adding
47
or subtracting a relativedelta with relative information performs
48
the corresponding arithmetic operation on the original datetime value
49
with the information in the relativedelta.
50
51
weekday:
52
One of the weekday instances (MO, TU, etc) available in the
53
relativedelta module. These instances may receive a parameter N,
54
specifying the Nth weekday, which could be positive or negative
55
(like MO(+1) or MO(-2)). Not specifying it is the same as specifying
56
+1. You can also use an integer, where 0=MO. This argument is always
57
relative e.g. if the calculated date is already Monday, using MO(1)
58
or MO(-1) won't change the day. To effectively make it absolute, use
59
it in combination with the day argument (e.g. day=1, MO(1) for first
60
Monday of the month).
61
62
leapdays:
63
Will add given days to the date found, if year is a leap
64
year, and the date found is post 28 of february.
65
66
yearday, nlyearday:
67
Set the yearday or the non-leap year day (jump leap days).
68
These are converted to day/month/leapdays information.
69
70
There are relative and absolute forms of the keyword
71
arguments. The plural is relative, and the singular is
72
absolute. For each argument in the order below, the absolute form
73
is applied first (by setting each attribute to that value) and
74
then the relative form (by adding the value to the attribute).
75
76
The order of attributes considered when this relativedelta is
77
added to a datetime is:
78
79
1. Year
80
2. Month
81
3. Day
82
4. Hours
83
5. Minutes
84
6. Seconds
85
7. Microseconds
86
87
Finally, weekday is applied, using the rule described above.
88
89
For example
90
91
>>> from datetime import datetime
92
>>> from dateutil.relativedelta import relativedelta, MO
93
>>> dt = datetime(2018, 4, 9, 13, 37, 0)
94
>>> delta = relativedelta(hours=25, day=1, weekday=MO(1))
95
>>> dt + delta
96
datetime.datetime(2018, 4, 2, 14, 37)
97
98
First, the day is set to 1 (the first of the month), then 25 hours
99
are added, to get to the 2nd day and 14th hour, finally the
100
weekday is applied, but since the 2nd is already a Monday there is
101
no effect.
102
103
"""
104
105
def __init__(self, dt1=None, dt2=None,
106
years=0, months=0, days=0, leapdays=0, weeks=0,
107
hours=0, minutes=0, seconds=0, microseconds=0,
108
year=None, month=None, day=None, weekday=None,
109
yearday=None, nlyearday=None,
110
hour=None, minute=None, second=None, microsecond=None):
111
112
if dt1 and dt2:
113
# datetime is a subclass of date. So both must be date
114
if not (isinstance(dt1, datetime.date) and
115
isinstance(dt2, datetime.date)):
116
raise TypeError("relativedelta only diffs datetime/date")
117
118
# We allow two dates, or two datetimes, so we coerce them to be
119
# of the same type
120
if (isinstance(dt1, datetime.datetime) !=
121
isinstance(dt2, datetime.datetime)):
122
if not isinstance(dt1, datetime.datetime):
123
dt1 = datetime.datetime.fromordinal(dt1.toordinal())
124
elif not isinstance(dt2, datetime.datetime):
125
dt2 = datetime.datetime.fromordinal(dt2.toordinal())
126
127
self.years = 0
128
self.months = 0
129
self.days = 0
130
self.leapdays = 0
131
self.hours = 0
132
self.minutes = 0
133
self.seconds = 0
134
self.microseconds = 0
135
self.year = None
136
self.month = None
137
self.day = None
138
self.weekday = None
139
self.hour = None
140
self.minute = None
141
self.second = None
142
self.microsecond = None
143
self._has_time = 0
144
145
# Get year / month delta between the two
146
months = (dt1.year - dt2.year) * 12 + (dt1.month - dt2.month)
147
self._set_months(months)
148
149
# Remove the year/month delta so the timedelta is just well-defined
150
# time units (seconds, days and microseconds)
151
dtm = self.__radd__(dt2)
152
153
# If we've overshot our target, make an adjustment
154
if dt1 < dt2:
155
compare = operator.gt
156
increment = 1
157
else:
158
compare = operator.lt
159
increment = -1
160
161
while compare(dt1, dtm):
162
months += increment
163
self._set_months(months)
164
dtm = self.__radd__(dt2)
165
166
# Get the timedelta between the "months-adjusted" date and dt1
167
delta = dt1 - dtm
168
self.seconds = delta.seconds + delta.days * 86400
169
self.microseconds = delta.microseconds
170
else:
171
# Check for non-integer values in integer-only quantities
172
if any(x is not None and x != int(x) for x in (years, months)):
173
raise ValueError("Non-integer years and months are "
174
"ambiguous and not currently supported.")
175
176
# Relative information
177
self.years = int(years)
178
self.months = int(months)
179
self.days = days + weeks * 7
180
self.leapdays = leapdays
181
self.hours = hours
182
self.minutes = minutes
183
self.seconds = seconds
184
self.microseconds = microseconds
185
186
# Absolute information
187
self.year = year
188
self.month = month
189
self.day = day
190
self.hour = hour
191
self.minute = minute
192
self.second = second
193
self.microsecond = microsecond
194
195
if any(x is not None and int(x) != x
196
for x in (year, month, day, hour,
197
minute, second, microsecond)):
198
# For now we'll deprecate floats - later it'll be an error.
199
warn("Non-integer value passed as absolute information. " +
200
"This is not a well-defined condition and will raise " +
201
"errors in future versions.", DeprecationWarning)
202
203
if isinstance(weekday, integer_types):
204
self.weekday = weekdays[weekday]
205
else:
206
self.weekday = weekday
207
208
yday = 0
209
if nlyearday:
210
yday = nlyearday
211
elif yearday:
212
yday = yearday
213
if yearday > 59:
214
self.leapdays = -1
215
if yday:
216
ydayidx = [31, 59, 90, 120, 151, 181, 212,
217
243, 273, 304, 334, 366]
218
for idx, ydays in enumerate(ydayidx):
219
if yday <= ydays:
220
self.month = idx+1
221
if idx == 0:
222
self.day = yday
223
else:
224
self.day = yday-ydayidx[idx-1]
225
break
226
else:
227
raise ValueError("invalid year day (%d)" % yday)
228
229
self._fix()
230
231
def _fix(self):
232
if abs(self.microseconds) > 999999:
233
s = _sign(self.microseconds)
234
div, mod = divmod(self.microseconds * s, 1000000)
235
self.microseconds = mod * s
236
self.seconds += div * s
237
if abs(self.seconds) > 59:
238
s = _sign(self.seconds)
239
div, mod = divmod(self.seconds * s, 60)
240
self.seconds = mod * s
241
self.minutes += div * s
242
if abs(self.minutes) > 59:
243
s = _sign(self.minutes)
244
div, mod = divmod(self.minutes * s, 60)
245
self.minutes = mod * s
246
self.hours += div * s
247
if abs(self.hours) > 23:
248
s = _sign(self.hours)
249
div, mod = divmod(self.hours * s, 24)
250
self.hours = mod * s
251
self.days += div * s
252
if abs(self.months) > 11:
253
s = _sign(self.months)
254
div, mod = divmod(self.months * s, 12)
255
self.months = mod * s
256
self.years += div * s
257
if (self.hours or self.minutes or self.seconds or self.microseconds
258
or self.hour is not None or self.minute is not None or
259
self.second is not None or self.microsecond is not None):
260
self._has_time = 1
261
else:
262
self._has_time = 0
263
264
@property
265
def weeks(self):
266
return int(self.days / 7.0)
267
268
@weeks.setter
269
def weeks(self, value):
270
self.days = self.days - (self.weeks * 7) + value * 7
271
272
def _set_months(self, months):
273
self.months = months
274
if abs(self.months) > 11:
275
s = _sign(self.months)
276
div, mod = divmod(self.months * s, 12)
277
self.months = mod * s
278
self.years = div * s
279
else:
280
self.years = 0
281
282
def normalized(self):
283
"""
284
Return a version of this object represented entirely using integer
285
values for the relative attributes.
286
287
>>> relativedelta(days=1.5, hours=2).normalized()
288
relativedelta(days=+1, hours=+14)
289
290
:return:
291
Returns a :class:`dateutil.relativedelta.relativedelta` object.
292
"""
293
# Cascade remainders down (rounding each to roughly nearest microsecond)
294
days = int(self.days)
295
296
hours_f = round(self.hours + 24 * (self.days - days), 11)
297
hours = int(hours_f)
298
299
minutes_f = round(self.minutes + 60 * (hours_f - hours), 10)
300
minutes = int(minutes_f)
301
302
seconds_f = round(self.seconds + 60 * (minutes_f - minutes), 8)
303
seconds = int(seconds_f)
304
305
microseconds = round(self.microseconds + 1e6 * (seconds_f - seconds))
306
307
# Constructor carries overflow back up with call to _fix()
308
return self.__class__(years=self.years, months=self.months,
309
days=days, hours=hours, minutes=minutes,
310
seconds=seconds, microseconds=microseconds,
311
leapdays=self.leapdays, year=self.year,
312
month=self.month, day=self.day,
313
weekday=self.weekday, hour=self.hour,
314
minute=self.minute, second=self.second,
315
microsecond=self.microsecond)
316
317
def __add__(self, other):
318
if isinstance(other, relativedelta):
319
return self.__class__(years=other.years + self.years,
320
months=other.months + self.months,
321
days=other.days + self.days,
322
hours=other.hours + self.hours,
323
minutes=other.minutes + self.minutes,
324
seconds=other.seconds + self.seconds,
325
microseconds=(other.microseconds +
326
self.microseconds),
327
leapdays=other.leapdays or self.leapdays,
328
year=(other.year if other.year is not None
329
else self.year),
330
month=(other.month if other.month is not None
331
else self.month),
332
day=(other.day if other.day is not None
333
else self.day),
334
weekday=(other.weekday if other.weekday is not None
335
else self.weekday),
336
hour=(other.hour if other.hour is not None
337
else self.hour),
338
minute=(other.minute if other.minute is not None
339
else self.minute),
340
second=(other.second if other.second is not None
341
else self.second),
342
microsecond=(other.microsecond if other.microsecond
343
is not None else
344
self.microsecond))
345
if isinstance(other, datetime.timedelta):
346
return self.__class__(years=self.years,
347
months=self.months,
348
days=self.days + other.days,
349
hours=self.hours,
350
minutes=self.minutes,
351
seconds=self.seconds + other.seconds,
352
microseconds=self.microseconds + other.microseconds,
353
leapdays=self.leapdays,
354
year=self.year,
355
month=self.month,
356
day=self.day,
357
weekday=self.weekday,
358
hour=self.hour,
359
minute=self.minute,
360
second=self.second,
361
microsecond=self.microsecond)
362
if not isinstance(other, datetime.date):
363
return NotImplemented
364
elif self._has_time and not isinstance(other, datetime.datetime):
365
other = datetime.datetime.fromordinal(other.toordinal())
366
year = (self.year or other.year)+self.years
367
month = self.month or other.month
368
if self.months:
369
assert 1 <= abs(self.months) <= 12
370
month += self.months
371
if month > 12:
372
year += 1
373
month -= 12
374
elif month < 1:
375
year -= 1
376
month += 12
377
day = min(calendar.monthrange(year, month)[1],
378
self.day or other.day)
379
repl = {"year": year, "month": month, "day": day}
380
for attr in ["hour", "minute", "second", "microsecond"]:
381
value = getattr(self, attr)
382
if value is not None:
383
repl[attr] = value
384
days = self.days
385
if self.leapdays and month > 2 and calendar.isleap(year):
386
days += self.leapdays
387
ret = (other.replace(**repl)
388
+ datetime.timedelta(days=days,
389
hours=self.hours,
390
minutes=self.minutes,
391
seconds=self.seconds,
392
microseconds=self.microseconds))
393
if self.weekday:
394
weekday, nth = self.weekday.weekday, self.weekday.n or 1
395
jumpdays = (abs(nth) - 1) * 7
396
if nth > 0:
397
jumpdays += (7 - ret.weekday() + weekday) % 7
398
else:
399
jumpdays += (ret.weekday() - weekday) % 7
400
jumpdays *= -1
401
ret += datetime.timedelta(days=jumpdays)
402
return ret
403
404
def __radd__(self, other):
405
return self.__add__(other)
406
407
def __rsub__(self, other):
408
return self.__neg__().__radd__(other)
409
410
def __sub__(self, other):
411
if not isinstance(other, relativedelta):
412
return NotImplemented # In case the other object defines __rsub__
413
return self.__class__(years=self.years - other.years,
414
months=self.months - other.months,
415
days=self.days - other.days,
416
hours=self.hours - other.hours,
417
minutes=self.minutes - other.minutes,
418
seconds=self.seconds - other.seconds,
419
microseconds=self.microseconds - other.microseconds,
420
leapdays=self.leapdays or other.leapdays,
421
year=(self.year if self.year is not None
422
else other.year),
423
month=(self.month if self.month is not None else
424
other.month),
425
day=(self.day if self.day is not None else
426
other.day),
427
weekday=(self.weekday if self.weekday is not None else
428
other.weekday),
429
hour=(self.hour if self.hour is not None else
430
other.hour),
431
minute=(self.minute if self.minute is not None else
432
other.minute),
433
second=(self.second if self.second is not None else
434
other.second),
435
microsecond=(self.microsecond if self.microsecond
436
is not None else
437
other.microsecond))
438
439
def __abs__(self):
440
return self.__class__(years=abs(self.years),
441
months=abs(self.months),
442
days=abs(self.days),
443
hours=abs(self.hours),
444
minutes=abs(self.minutes),
445
seconds=abs(self.seconds),
446
microseconds=abs(self.microseconds),
447
leapdays=self.leapdays,
448
year=self.year,
449
month=self.month,
450
day=self.day,
451
weekday=self.weekday,
452
hour=self.hour,
453
minute=self.minute,
454
second=self.second,
455
microsecond=self.microsecond)
456
457
def __neg__(self):
458
return self.__class__(years=-self.years,
459
months=-self.months,
460
days=-self.days,
461
hours=-self.hours,
462
minutes=-self.minutes,
463
seconds=-self.seconds,
464
microseconds=-self.microseconds,
465
leapdays=self.leapdays,
466
year=self.year,
467
month=self.month,
468
day=self.day,
469
weekday=self.weekday,
470
hour=self.hour,
471
minute=self.minute,
472
second=self.second,
473
microsecond=self.microsecond)
474
475
def __bool__(self):
476
return not (not self.years and
477
not self.months and
478
not self.days and
479
not self.hours and
480
not self.minutes and
481
not self.seconds and
482
not self.microseconds and
483
not self.leapdays and
484
self.year is None and
485
self.month is None and
486
self.day is None and
487
self.weekday is None and
488
self.hour is None and
489
self.minute is None and
490
self.second is None and
491
self.microsecond is None)
492
# Compatibility with Python 2.x
493
__nonzero__ = __bool__
494
495
def __mul__(self, other):
496
try:
497
f = float(other)
498
except TypeError:
499
return NotImplemented
500
501
return self.__class__(years=int(self.years * f),
502
months=int(self.months * f),
503
days=int(self.days * f),
504
hours=int(self.hours * f),
505
minutes=int(self.minutes * f),
506
seconds=int(self.seconds * f),
507
microseconds=int(self.microseconds * f),
508
leapdays=self.leapdays,
509
year=self.year,
510
month=self.month,
511
day=self.day,
512
weekday=self.weekday,
513
hour=self.hour,
514
minute=self.minute,
515
second=self.second,
516
microsecond=self.microsecond)
517
518
__rmul__ = __mul__
519
520
def __eq__(self, other):
521
if not isinstance(other, relativedelta):
522
return NotImplemented
523
if self.weekday or other.weekday:
524
if not self.weekday or not other.weekday:
525
return False
526
if self.weekday.weekday != other.weekday.weekday:
527
return False
528
n1, n2 = self.weekday.n, other.weekday.n
529
if n1 != n2 and not ((not n1 or n1 == 1) and (not n2 or n2 == 1)):
530
return False
531
return (self.years == other.years and
532
self.months == other.months and
533
self.days == other.days and
534
self.hours == other.hours and
535
self.minutes == other.minutes and
536
self.seconds == other.seconds and
537
self.microseconds == other.microseconds and
538
self.leapdays == other.leapdays and
539
self.year == other.year and
540
self.month == other.month and
541
self.day == other.day and
542
self.hour == other.hour and
543
self.minute == other.minute and
544
self.second == other.second and
545
self.microsecond == other.microsecond)
546
547
def __hash__(self):
548
return hash((
549
self.weekday,
550
self.years,
551
self.months,
552
self.days,
553
self.hours,
554
self.minutes,
555
self.seconds,
556
self.microseconds,
557
self.leapdays,
558
self.year,
559
self.month,
560
self.day,
561
self.hour,
562
self.minute,
563
self.second,
564
self.microsecond,
565
))
566
567
def __ne__(self, other):
568
return not self.__eq__(other)
569
570
def __div__(self, other):
571
try:
572
reciprocal = 1 / float(other)
573
except TypeError:
574
return NotImplemented
575
576
return self.__mul__(reciprocal)
577
578
__truediv__ = __div__
579
580
def __repr__(self):
581
l = []
582
for attr in ["years", "months", "days", "leapdays",
583
"hours", "minutes", "seconds", "microseconds"]:
584
value = getattr(self, attr)
585
if value:
586
l.append("{attr}={value:+g}".format(attr=attr, value=value))
587
for attr in ["year", "month", "day", "weekday",
588
"hour", "minute", "second", "microsecond"]:
589
value = getattr(self, attr)
590
if value is not None:
591
l.append("{attr}={value}".format(attr=attr, value=repr(value)))
592
return "{classname}({attrs})".format(classname=self.__class__.__name__,
593
attrs=", ".join(l))
594
595
596
def _sign(x):
597
return int(copysign(1, x))
598
599
# vim:ts=4:sw=4:et
600
601