Implemented new scheme to pass weekday information to relativedelta.
diff --git a/dateutil.moin b/dateutil.moin
index c6d9e2e..40147f9 100644
--- a/dateutil.moin
+++ b/dateutil.moin
@@ -63,7 +63,14 @@
Relative information, may be negative.
weekday::
- Tuple with {{{(wday, nth)}}}, specifying the nth relative weekday.
+ One of the weekday instances ({{{MO}}}, {{{TU}}}, etc). These
+ instances may receive a parameter {{{n}}}, specifying the {{{n}}}th
+ weekday, which could be positive or negative (like {{{MO(+2)}}} or
+ {{{MO(-3)}}}. Not specifying it is the same as specifying {{{+1}}}.
+ You can also use an integer, where {{{0=MO}}}. Notice that,
+ for example, if the calculated date is already Monday, using
+ {{{MO}}} or {{{MO(+1)}}} (which is the same thing in this context),
+ won't change the day.
leapdays::
Will add given days to the date found, but only if the computed
@@ -92,18 +99,14 @@
the computed month is after february, remove one day from the found date.
1. Do steps 1 and 2 for {{{hour}}}/{{{hours}}}, {{{minute}}}/{{{minutes}}},
{{{second}}}/{{{seconds}}}, {{{microsecond}}}/{{{microseconds}}}.
- 1. 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.
+ 1. If the {{{weekday}}} argument is present, calculate the {{{n}}}th
+ occurrence of the given weekday.
==== Examples ====
Let's begin our trip.
{{{
->>> from datetime import *; from dtutil import *
+>>> from datetime import *; from dateutil.relativedelta import *
>>> import calendar
}}}
@@ -182,25 +185,28 @@
Next friday.
{{{
->>> TODAY+relativedelta(weekday=(calendar.FRIDAY, +1))
+>>> TODAY+relativedelta(weekday=FR)
+datetime.date(2003, 9, 19)
+
+>>> TODAY+relativedelta(weekday=calendar.FRIDAY)
datetime.date(2003, 9, 19)
}}}
Last friday in this month.
{{{
->>> TODAY+relativedelta(day=31, weekday=(calendar.FRIDAY, -1))
+>>> TODAY+relativedelta(day=31, weekday=FR(-1))
datetime.date(2003, 9, 26)
}}}
Next wednesday (it's today!).
{{{
->>> TODAY+relativedelta(weekday=(calendar.WEDNESDAY, +1))
+>>> TODAY+relativedelta(weekday=WE(+1))
datetime.date(2003, 9, 17)
}}}
Next wednesday, but not today.
{{{
->>> TODAY+relativedelta(days=+1, weekday=(calendar.WEDNESDAY, +1))
+>>> TODAY+relativedelta(days=+1, weekday=WE(+1))
datetime.date(2003, 9, 24)
}}}
@@ -208,7 +214,7 @@
[http://www.cl.cam.ac.uk/~mgk25/iso-time.html ISO year week number notation]
find the first day of the 15th week of 1997.
{{{
->>> datetime(1997,1,1)+relativedelta(day=4, weekday=(0, -1), weeks=+14)
+>>> datetime(1997,1,1)+relativedelta(day=4, weekday=MO(-1), weeks=+14)
datetime.datetime(1997, 4, 7, 0, 0)
}}}
@@ -814,8 +820,8 @@
>>> from dateutil.relativedelta import *
>>> range1 = tzrange("EST", -18000, "EDT")
>>> range2 = tzrange("EST", -18000, "EDT", -14400,
-... relativedelta(hours=+2, month=4, day=1, weekday=(6, 1)),
-... relativedelta(hours=+1, month=10, day=31, weekday=(6, -1)))>>> tzstr('EST5EDT') == range1 == range2
+... relativedelta(hours=+2, month=4, day=1, weekday=SU(+1)),
+... relativedelta(hours=+1, month=10, day=31, weekday=SU(-1)))>>> tzstr('EST5EDT') == range1 == range2
>>> tzstr('EST5EDT') == range1 == range2
True
}}}
diff --git a/dateutil/parser.py b/dateutil/parser.py
index c465854..7b142ef 100644
--- a/dateutil/parser.py
+++ b/dateutil/parser.py
@@ -803,7 +803,7 @@
repl[attr] = value
ret = default.replace(**repl)
if res.weekday is not None and not res.day:
- ret = ret+relativedelta.relativedelta(weekday=(res.weekday, +1))
+ ret = ret+relativedelta.relativedelta(weekday=res.weekday)
if not ignoretz:
if callable(tzoffsets) or tzoffsets and res.tzname in tzoffsets:
if callable(tzoffsets):
diff --git a/dateutil/relativedelta.py b/dateutil/relativedelta.py
index e42f9d3..fe7ed25 100644
--- a/dateutil/relativedelta.py
+++ b/dateutil/relativedelta.py
@@ -10,7 +10,34 @@
import datetime
import calendar
-__all__ = ["relativedelta"]
+__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"]
+
+class weekday(object):
+ __slots__ = ["weekday", "n"]
+
+ def __init__(self, weekday, n=0):
+ self.weekday = weekday
+ self.n = n
+
+ def __call__(self, n):
+ 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:
"""
@@ -33,7 +60,11 @@
Relative information, may be negative.
weekday:
- Tuple with (wday, nth), specifying the nth relative 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
@@ -133,12 +164,16 @@
self.year = year
self.month = month
self.day = day
- self.weekday = weekday
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
@@ -236,8 +271,8 @@
minutes=self.minutes,
seconds=self.seconds,
microseconds=self.microseconds))
- if self.weekday and self.weekday[1]:
- weekday, nth = self.weekday
+ if self.weekday:
+ weekday, nth = self.weekday.weekday, self.weekday.n or 1
jumpdays = (abs(nth)-1)*7
ret_weekday = ret.weekday()
if nth > 0:
@@ -267,6 +302,7 @@
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,
@@ -286,6 +322,7 @@
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,
@@ -303,6 +340,7 @@
minutes=-self.minutes,
seconds=-self.seconds,
microseconds=-self.microseconds,
+ leapdays=self.leapdays,
year=self.year,
month=self.month,
day=self.day,
@@ -320,6 +358,7 @@
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
@@ -338,6 +377,7 @@
minutes=self.minutes*f,
seconds=self.seconds*f,
microseconds=self.microseconds*f,
+ leapdays=self.leapdays,
year=self.year,
month=self.month,
day=self.day,
@@ -350,10 +390,28 @@
def __eq__(self, other):
if not isinstance(other, relativedelta):
return False
- for attr in self.__dict__:
- if getattr(self, attr) != getattr(other, attr):
+ if self.weekday or other.weekday:
+ if not self.weekday or not other.weekday:
return False
- return True
+ if self.weekday.weekday != other.weekday.weekday:
+ return False
+ n1, n2 = self.weekday.n, other.weekday.n
+ if n1 != n2 and not (n1 in (0, 1) and n2 in (0, 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)
diff --git a/dateutil/tz.py b/dateutil/tz.py
index 45296ef..8f389dd 100644
--- a/dateutil/tz.py
+++ b/dateutil/tz.py
@@ -456,17 +456,13 @@
else:
self._dst_offset = ZERO
if start is None:
- self._start_delta = relativedelta.relativedelta(hours=+2,
- month=4,
- day=1,
- weekday=(6, +1))
+ self._start_delta = relativedelta.relativedelta(
+ hours=+2, month=4, day=1, weekday=relativedelta.SU(+1))
else:
self._start_delta = start
if end is None:
- self._end_delta = relativedelta.relativedelta(hours=+1,
- month=10,
- day=31,
- weekday=(6, -1))
+ self._end_delta = relativedelta.relativedelta(
+ hours=+1, month=10, day=31, weekday=relativedelta.SU(-1))
else:
self._end_delta = end
@@ -542,7 +538,7 @@
if x.month is not None:
kwargs["month"] = x.month
if x.weekday is not None:
- kwargs["weekday"] = (x.weekday, x.week)
+ kwargs["weekday"] = relativedelta.weekday(x.weekday, x.week)
if x.week > 0:
kwargs["day"] = 1
else:
@@ -559,11 +555,11 @@
if not isend:
kwargs["month"] = 4
kwargs["day"] = 1
- kwargs["weekday"] = (6, +1)
+ kwargs["weekday"] = relativedelta.SU(+1)
else:
kwargs["month"] = 10
kwargs["day"] = 31
- kwargs["weekday"] = (6, -1)
+ kwargs["weekday"] = relativedelta.SU(-1)
if x.time is not None:
kwargs["seconds"] = x.time
else:
diff --git a/test.py b/test.py
index a3db6df..4f1e66c 100644
--- a/test.py
+++ b/test.py
@@ -74,30 +74,29 @@
date(2000, 3, 1))
def testNextFriday(self):
- self.assertEqual(self.today +
- relativedelta(weekday=(calendar.FRIDAY, +1)),
+ self.assertEqual(self.today+relativedelta(weekday=FR),
+ date(2003, 9, 19))
+
+ def testNextFridayInt(self):
+ self.assertEqual(self.today+relativedelta(weekday=calendar.FRIDAY),
date(2003, 9, 19))
def testLastFridayInThisMonth(self):
- self.assertEqual(self.today +
- relativedelta(day=31, weekday=(calendar.FRIDAY, -1)),
+ self.assertEqual(self.today+relativedelta(day=31, weekday=FR(-1)),
date(2003, 9, 26))
def testNextWednesdayIsToday(self):
- self.assertEqual(self.today +
- relativedelta(weekday=(calendar.WEDNESDAY, +1)),
+ self.assertEqual(self.today+relativedelta(weekday=WE),
date(2003, 9, 17))
def testNextWenesdayNotToday(self):
- self.assertEqual(self.today +
- relativedelta(days=+1,
- weekday=(calendar.WEDNESDAY, +1)),
+ self.assertEqual(self.today+relativedelta(days=+1, weekday=WE),
date(2003, 9, 24))
def test15thISOYearWeek(self):
self.assertEqual(date(2003, 1, 1) +
- relativedelta(day=4, weekday=(0, -1), weeks=+14),
+ relativedelta(day=4, weeks=+14, weekday=MO(-1)),
date(2003, 4, 7))
def testMillenniumAge(self):
@@ -898,10 +897,10 @@
tzrange("EST", -18000, "EDT", -14400,
relativedelta(hours=+2,
month=4, day=1,
- weekday=(6, 1)),
+ weekday=SU(+1)),
relativedelta(hours=+1,
month=10, day=31,
- weekday=(6, -1))))
+ weekday=SU(-1))))
def testRangeCmp2(self):
self.assertEqual(tzstr("EST5EDT"),