aboutsummaryrefslogtreecommitdiff
path: root/dateutil
diff options
context:
space:
mode:
authorPaul Ganssle <paul@ganssle.io>2019-02-03 09:52:50 -0500
committerPaul Ganssle <paul@ganssle.io>2019-02-04 09:19:26 -0500
commit844f43ba2847999f32eb32818563fe225972d04d (patch)
tree848e6d4bba04c14a231f8482ee299d31bf9ad57c /dateutil
parent95743955dd521f1ff47ca3737e9372c9a3e15959 (diff)
downloaddateutil-844f43ba2847999f32eb32818563fe225972d04d.tar.gz
Add EXDATE parameter parsing to rrulestr
Per RFC 5545 Section 3.8.5.1, exception dates should support VALUE and TZID parameters. This commit adds support for the full grammar of EXDATE.
Diffstat (limited to 'dateutil')
-rw-r--r--dateutil/rrule.py51
-rw-r--r--dateutil/test/test_rrule.py3
2 files changed, 43 insertions, 11 deletions
diff --git a/dateutil/rrule.py b/dateutil/rrule.py
index ea450f2..3fe5e21 100644
--- a/dateutil/rrule.py
+++ b/dateutil/rrule.py
@@ -435,7 +435,7 @@ class rrule(rrulebase):
if not dtstart:
if until and until.tzinfo:
dtstart = datetime.datetime.now(tz=until.tzinfo).replace(microsecond=0)
- else:
+ else:
dtstart = datetime.datetime.now().replace(microsecond=0)
elif not isinstance(dtstart, datetime.datetime):
dtstart = datetime.datetime.fromordinal(dtstart.toordinal())
@@ -1629,10 +1629,48 @@ class _rrulestr(object):
raise ValueError("unsupported EXRULE parm: "+parm)
exrulevals.append(value)
elif name == "EXDATE":
+ value_found = False
+ TZID = None
for parm in parms:
- if parm != "VALUE=DATE-TIME":
- raise ValueError("unsupported EXDATE parm: "+parm)
- exdatevals.append(value)
+ if parm.startswith("TZID="):
+ try:
+ tzkey = TZID_NAMES[parm.split('TZID=')[-1]]
+ except KeyError:
+ continue
+ if tzids is None:
+ from . import tz
+ tzlookup = tz.gettz
+ elif callable(tzids):
+ tzlookup = tzids
+ else:
+ tzlookup = getattr(tzids, 'get', None)
+ if tzlookup is None:
+ msg = ('tzids must be a callable, ' +
+ 'mapping, or None, ' +
+ 'not %s' % tzids)
+ raise ValueError(msg)
+
+ TZID = tzlookup(tzkey)
+ continue
+ if parm not in {"VALUE=DATE-TIME", "VALUE=DATE"}:
+ raise ValueError("unsupported EXDATE parm: "
+ + parm)
+ else:
+ if value_found:
+ msg = ("Duplicate value parameter found in "
+ "EXDATE: " + parm)
+ raise ValueError(msg)
+ value_found = True
+ for datestr in value.split(','):
+ exdate = parser.parse(datestr, ignoretz=ignoretz,
+ tzinfos=tzinfos)
+ if TZID is not None:
+ if exdate.tzinfo is None:
+ exdate = exdate.replace(tzinfo=TZID)
+ else:
+ raise ValueError(
+ 'EXDATE specifies multiple timezone')
+ exdatevals.append(exdate)
elif name == "DTSTART":
# RFC 5445 3.8.2.4: The VALUE parameter is optional, but
# may be found only once.
@@ -1698,10 +1736,7 @@ class _rrulestr(object):
ignoretz=ignoretz,
tzinfos=tzinfos))
for value in exdatevals:
- for datestr in value.split(','):
- rset.exdate(parser.parse(datestr,
- ignoretz=ignoretz,
- tzinfos=tzinfos))
+ rset.exdate(value)
if compatible and dtstart:
rset.rdate(dtstart)
return rset
diff --git a/dateutil/test/test_rrule.py b/dateutil/test/test_rrule.py
index fbb943e..c43fea1 100644
--- a/dateutil/test/test_rrule.py
+++ b/dateutil/test/test_rrule.py
@@ -2853,7 +2853,6 @@ class RRuleTest(WarningTestMixin, unittest.TestCase):
datetime(1997, 9, 9, 9, 0),
datetime(1997, 9, 16, 9, 0)])
- @pytest.mark.xfail
def testStrSetExDateWithTZID(self):
BXL = tz.gettz('Europe/Brussels')
rr = rrulestr("DTSTART;TZID=Europe/Brussels:19970902T090000\n"
@@ -2888,7 +2887,6 @@ class RRuleTest(WarningTestMixin, unittest.TestCase):
rr = rrulestr(rrstr)
assert list(rr) == [datetime(1997, 9, 4, 9), datetime(1997, 9, 11, 9)]
- @pytest.mark.xfail
def testStrSetExDateValueDateTimeWithTZID(self):
BXL = tz.gettz('Europe/Brussels')
rrstr = '\n'.join([
@@ -2902,7 +2900,6 @@ class RRuleTest(WarningTestMixin, unittest.TestCase):
assert list(rr) == [datetime(1997, 9, 4, 9, tzinfo=BXL),
datetime(1997, 9, 11, 9, tzinfo=BXL)]
- @pytest.mark.xfail
def testStrSetExDateValueDate(self):
rrstr = '\n'.join([
"DTSTART;VALUE=DATE:19970902",