Index: third_party/recipe_engine/third_party/dateutil/relativedelta.py |
diff --git a/third_party/recipe_engine/third_party/dateutil/relativedelta.py b/third_party/recipe_engine/third_party/dateutil/relativedelta.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0c72a8180fb707eef4a1072edb171bad42f4d294 |
--- /dev/null |
+++ b/third_party/recipe_engine/third_party/dateutil/relativedelta.py |
@@ -0,0 +1,432 @@ |
+""" |
+Copyright (c) 2003-2010 Gustavo Niemeyer <gustavo@niemeyer.net> |
+ |
+This module offers extensions to the standard python 2.3+ |
+datetime module. |
+""" |
+__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>" |
+__license__ = "PSF License" |
+ |
+import datetime |
+import calendar |
+ |
+__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"] |
+ |
+class weekday(object): |
+ __slots__ = ["weekday", "n"] |
+ |
+ def __init__(self, weekday, n=None): |
+ self.weekday = weekday |
+ self.n = n |
+ |
+ def __call__(self, n): |
+ if n == self.n: |
+ return self |
+ else: |
+ return self.__class__(self.weekday, n) |
+ |
+ def __eq__(self, other): |
+ try: |
+ if self.weekday != other.weekday or self.n != other.n: |
+ return False |
+ except AttributeError: |
+ return False |
+ return True |
+ |
+ def __repr__(self): |
+ s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday] |
+ if not self.n: |
+ return s |
+ else: |
+ return "%s(%+d)" % (s, self.n) |
+ |
+MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)]) |
+ |
+class relativedelta: |
+ """ |
+The relativedelta type is based on the specification of the excelent |
+work done by M.-A. Lemburg in his mx.DateTime extension. However, |
+notice that this type does *NOT* implement the same algorithm as |
+his work. Do *NOT* expect it to behave like mx.DateTime's counterpart. |
+ |
+There's two different ways to build a relativedelta instance. The |
+first one is passing it two date/datetime classes: |
+ |
+ relativedelta(datetime1, datetime2) |
+ |
+And the other way is to use the following keyword arguments: |
+ |
+ year, month, day, hour, minute, second, microsecond: |
+ Absolute information. |
+ |
+ years, months, weeks, days, hours, minutes, seconds, microseconds: |
+ Relative information, may be negative. |
+ |
+ weekday: |
+ One of the weekday instances (MO, TU, etc). These instances may |
+ receive a parameter N, specifying the Nth weekday, which could |
+ be positive or negative (like MO(+1) or MO(-2). Not specifying |
+ it is the same as specifying +1. You can also use an integer, |
+ where 0=MO. |
+ |
+ leapdays: |
+ Will add given days to the date found, if year is a leap |
+ year, and the date found is post 28 of february. |
+ |
+ yearday, nlyearday: |
+ Set the yearday or the non-leap year day (jump leap days). |
+ These are converted to day/month/leapdays information. |
+ |
+Here is the behavior of operations with relativedelta: |
+ |
+1) Calculate the absolute year, using the 'year' argument, or the |
+ original datetime year, if the argument is not present. |
+ |
+2) Add the relative 'years' argument to the absolute year. |
+ |
+3) Do steps 1 and 2 for month/months. |
+ |
+4) Calculate the absolute day, using the 'day' argument, or the |
+ original datetime day, if the argument is not present. Then, |
+ subtract from the day until it fits in the year and month |
+ found after their operations. |
+ |
+5) Add the relative 'days' argument to the absolute day. Notice |
+ that the 'weeks' argument is multiplied by 7 and added to |
+ 'days'. |
+ |
+6) Do steps 1 and 2 for hour/hours, minute/minutes, second/seconds, |
+ microsecond/microseconds. |
+ |
+7) If the 'weekday' argument is present, calculate the weekday, |
+ with the given (wday, nth) tuple. wday is the index of the |
+ weekday (0-6, 0=Mon), and nth is the number of weeks to add |
+ forward or backward, depending on its signal. Notice that if |
+ the calculated date is already Monday, for example, using |
+ (0, 1) or (0, -1) won't change the day. |
+ """ |
+ |
+ def __init__(self, dt1=None, dt2=None, |
+ years=0, months=0, days=0, leapdays=0, weeks=0, |
+ hours=0, minutes=0, seconds=0, microseconds=0, |
+ year=None, month=None, day=None, weekday=None, |
+ yearday=None, nlyearday=None, |
+ hour=None, minute=None, second=None, microsecond=None): |
+ if dt1 and dt2: |
+ if not isinstance(dt1, datetime.date) or \ |
+ not isinstance(dt2, datetime.date): |
+ raise TypeError, "relativedelta only diffs datetime/date" |
+ if type(dt1) is not type(dt2): |
+ if not isinstance(dt1, datetime.datetime): |
+ dt1 = datetime.datetime.fromordinal(dt1.toordinal()) |
+ elif not isinstance(dt2, datetime.datetime): |
+ dt2 = datetime.datetime.fromordinal(dt2.toordinal()) |
+ self.years = 0 |
+ self.months = 0 |
+ self.days = 0 |
+ self.leapdays = 0 |
+ self.hours = 0 |
+ self.minutes = 0 |
+ self.seconds = 0 |
+ self.microseconds = 0 |
+ self.year = None |
+ self.month = None |
+ self.day = None |
+ self.weekday = None |
+ self.hour = None |
+ self.minute = None |
+ self.second = None |
+ self.microsecond = None |
+ self._has_time = 0 |
+ |
+ months = (dt1.year*12+dt1.month)-(dt2.year*12+dt2.month) |
+ self._set_months(months) |
+ dtm = self.__radd__(dt2) |
+ if dt1 < dt2: |
+ while dt1 > dtm: |
+ months += 1 |
+ self._set_months(months) |
+ dtm = self.__radd__(dt2) |
+ else: |
+ while dt1 < dtm: |
+ months -= 1 |
+ self._set_months(months) |
+ dtm = self.__radd__(dt2) |
+ delta = dt1 - dtm |
+ self.seconds = delta.seconds+delta.days*86400 |
+ self.microseconds = delta.microseconds |
+ else: |
+ self.years = years |
+ self.months = months |
+ self.days = days+weeks*7 |
+ self.leapdays = leapdays |
+ self.hours = hours |
+ self.minutes = minutes |
+ self.seconds = seconds |
+ self.microseconds = microseconds |
+ self.year = year |
+ self.month = month |
+ self.day = day |
+ self.hour = hour |
+ self.minute = minute |
+ self.second = second |
+ self.microsecond = microsecond |
+ |
+ if type(weekday) is int: |
+ self.weekday = weekdays[weekday] |
+ else: |
+ self.weekday = weekday |
+ |
+ yday = 0 |
+ if nlyearday: |
+ yday = nlyearday |
+ elif yearday: |
+ yday = yearday |
+ if yearday > 59: |
+ self.leapdays = -1 |
+ if yday: |
+ ydayidx = [31,59,90,120,151,181,212,243,273,304,334,366] |
+ for idx, ydays in enumerate(ydayidx): |
+ if yday <= ydays: |
+ self.month = idx+1 |
+ if idx == 0: |
+ self.day = yday |
+ else: |
+ self.day = yday-ydayidx[idx-1] |
+ break |
+ else: |
+ raise ValueError, "invalid year day (%d)" % yday |
+ |
+ self._fix() |
+ |
+ def _fix(self): |
+ if abs(self.microseconds) > 999999: |
+ s = self.microseconds//abs(self.microseconds) |
+ div, mod = divmod(self.microseconds*s, 1000000) |
+ self.microseconds = mod*s |
+ self.seconds += div*s |
+ if abs(self.seconds) > 59: |
+ s = self.seconds//abs(self.seconds) |
+ div, mod = divmod(self.seconds*s, 60) |
+ self.seconds = mod*s |
+ self.minutes += div*s |
+ if abs(self.minutes) > 59: |
+ s = self.minutes//abs(self.minutes) |
+ div, mod = divmod(self.minutes*s, 60) |
+ self.minutes = mod*s |
+ self.hours += div*s |
+ if abs(self.hours) > 23: |
+ s = self.hours//abs(self.hours) |
+ div, mod = divmod(self.hours*s, 24) |
+ self.hours = mod*s |
+ self.days += div*s |
+ if abs(self.months) > 11: |
+ s = self.months//abs(self.months) |
+ div, mod = divmod(self.months*s, 12) |
+ self.months = mod*s |
+ self.years += div*s |
+ if (self.hours or self.minutes or self.seconds or self.microseconds or |
+ self.hour is not None or self.minute is not None or |
+ self.second is not None or self.microsecond is not None): |
+ self._has_time = 1 |
+ else: |
+ self._has_time = 0 |
+ |
+ def _set_months(self, months): |
+ self.months = months |
+ if abs(self.months) > 11: |
+ s = self.months//abs(self.months) |
+ div, mod = divmod(self.months*s, 12) |
+ self.months = mod*s |
+ self.years = div*s |
+ else: |
+ self.years = 0 |
+ |
+ def __radd__(self, other): |
+ if not isinstance(other, datetime.date): |
+ raise TypeError, "unsupported type for add operation" |
+ elif self._has_time and not isinstance(other, datetime.datetime): |
+ other = datetime.datetime.fromordinal(other.toordinal()) |
+ year = (self.year or other.year)+self.years |
+ month = self.month or other.month |
+ if self.months: |
+ assert 1 <= abs(self.months) <= 12 |
+ month += self.months |
+ if month > 12: |
+ year += 1 |
+ month -= 12 |
+ elif month < 1: |
+ year -= 1 |
+ month += 12 |
+ day = min(calendar.monthrange(year, month)[1], |
+ self.day or other.day) |
+ repl = {"year": year, "month": month, "day": day} |
+ for attr in ["hour", "minute", "second", "microsecond"]: |
+ value = getattr(self, attr) |
+ if value is not None: |
+ repl[attr] = value |
+ days = self.days |
+ if self.leapdays and month > 2 and calendar.isleap(year): |
+ days += self.leapdays |
+ ret = (other.replace(**repl) |
+ + datetime.timedelta(days=days, |
+ hours=self.hours, |
+ minutes=self.minutes, |
+ seconds=self.seconds, |
+ microseconds=self.microseconds)) |
+ if self.weekday: |
+ weekday, nth = self.weekday.weekday, self.weekday.n or 1 |
+ jumpdays = (abs(nth)-1)*7 |
+ if nth > 0: |
+ jumpdays += (7-ret.weekday()+weekday)%7 |
+ else: |
+ jumpdays += (ret.weekday()-weekday)%7 |
+ jumpdays *= -1 |
+ ret += datetime.timedelta(days=jumpdays) |
+ return ret |
+ |
+ def __rsub__(self, other): |
+ return self.__neg__().__radd__(other) |
+ |
+ def __add__(self, other): |
+ if not isinstance(other, relativedelta): |
+ raise TypeError, "unsupported type for add operation" |
+ return relativedelta(years=other.years+self.years, |
+ months=other.months+self.months, |
+ days=other.days+self.days, |
+ hours=other.hours+self.hours, |
+ minutes=other.minutes+self.minutes, |
+ seconds=other.seconds+self.seconds, |
+ microseconds=other.microseconds+self.microseconds, |
+ leapdays=other.leapdays or self.leapdays, |
+ year=other.year or self.year, |
+ month=other.month or self.month, |
+ day=other.day or self.day, |
+ weekday=other.weekday or self.weekday, |
+ hour=other.hour or self.hour, |
+ minute=other.minute or self.minute, |
+ second=other.second or self.second, |
+ microsecond=other.second or self.microsecond) |
+ |
+ def __sub__(self, other): |
+ if not isinstance(other, relativedelta): |
+ raise TypeError, "unsupported type for sub operation" |
+ return relativedelta(years=other.years-self.years, |
+ months=other.months-self.months, |
+ days=other.days-self.days, |
+ hours=other.hours-self.hours, |
+ minutes=other.minutes-self.minutes, |
+ seconds=other.seconds-self.seconds, |
+ microseconds=other.microseconds-self.microseconds, |
+ leapdays=other.leapdays or self.leapdays, |
+ year=other.year or self.year, |
+ month=other.month or self.month, |
+ day=other.day or self.day, |
+ weekday=other.weekday or self.weekday, |
+ hour=other.hour or self.hour, |
+ minute=other.minute or self.minute, |
+ second=other.second or self.second, |
+ microsecond=other.second or self.microsecond) |
+ |
+ def __neg__(self): |
+ return relativedelta(years=-self.years, |
+ months=-self.months, |
+ days=-self.days, |
+ hours=-self.hours, |
+ minutes=-self.minutes, |
+ seconds=-self.seconds, |
+ microseconds=-self.microseconds, |
+ leapdays=self.leapdays, |
+ year=self.year, |
+ month=self.month, |
+ day=self.day, |
+ weekday=self.weekday, |
+ hour=self.hour, |
+ minute=self.minute, |
+ second=self.second, |
+ microsecond=self.microsecond) |
+ |
+ def __nonzero__(self): |
+ return not (not self.years and |
+ not self.months and |
+ not self.days and |
+ not self.hours and |
+ not self.minutes and |
+ not self.seconds and |
+ not self.microseconds and |
+ not self.leapdays and |
+ self.year is None and |
+ self.month is None and |
+ self.day is None and |
+ self.weekday is None and |
+ self.hour is None and |
+ self.minute is None and |
+ self.second is None and |
+ self.microsecond is None) |
+ |
+ def __mul__(self, other): |
+ f = float(other) |
+ return relativedelta(years=self.years*f, |
+ months=self.months*f, |
+ days=self.days*f, |
+ hours=self.hours*f, |
+ minutes=self.minutes*f, |
+ seconds=self.seconds*f, |
+ microseconds=self.microseconds*f, |
+ leapdays=self.leapdays, |
+ year=self.year, |
+ month=self.month, |
+ day=self.day, |
+ weekday=self.weekday, |
+ hour=self.hour, |
+ minute=self.minute, |
+ second=self.second, |
+ microsecond=self.microsecond) |
+ |
+ def __eq__(self, other): |
+ if not isinstance(other, relativedelta): |
+ return False |
+ if self.weekday or other.weekday: |
+ if not self.weekday or not other.weekday: |
+ return False |
+ if self.weekday.weekday != other.weekday.weekday: |
+ return False |
+ n1, n2 = self.weekday.n, other.weekday.n |
+ if n1 != n2 and not ((not n1 or n1 == 1) and (not n2 or n2 == 1)): |
+ return False |
+ return (self.years == other.years and |
+ self.months == other.months and |
+ self.days == other.days and |
+ self.hours == other.hours and |
+ self.minutes == other.minutes and |
+ self.seconds == other.seconds and |
+ self.leapdays == other.leapdays and |
+ self.year == other.year and |
+ self.month == other.month and |
+ self.day == other.day and |
+ self.hour == other.hour and |
+ self.minute == other.minute and |
+ self.second == other.second and |
+ self.microsecond == other.microsecond) |
+ |
+ def __ne__(self, other): |
+ return not self.__eq__(other) |
+ |
+ def __div__(self, other): |
+ return self.__mul__(1/float(other)) |
+ |
+ def __repr__(self): |
+ l = [] |
+ for attr in ["years", "months", "days", "leapdays", |
+ "hours", "minutes", "seconds", "microseconds"]: |
+ value = getattr(self, attr) |
+ if value: |
+ l.append("%s=%+d" % (attr, value)) |
+ for attr in ["year", "month", "day", "weekday", |
+ "hour", "minute", "second", "microsecond"]: |
+ value = getattr(self, attr) |
+ if value is not None: |
+ l.append("%s=%s" % (attr, `value`)) |
+ return "%s(%s)" % (self.__class__.__name__, ", ".join(l)) |
+ |
+# vim:ts=4:sw=4:et |