annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/dateutil/relativedelta.py @ 68:5028fdace37b

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