Commit 6bfff663 authored by Evan Simpson's avatar Evan Simpson

Mostly fixed Collector #1129. Badly formed ISO8601 dates are rejected,

except that 'Z' is still allowed in front of a '+/-HH:MM' timezone.  I
left that in since it was used elsewhere in the code, and was probably
harmless, whereas the other parse problems caused dates like "2003-2-5"
to be accepted as valid and silently converted into "2003-01-01".

Also re-exposed the DateTime-specific exceptions as attributes of the
DateTime class.  During their recent converted from strings to classes,
they were removed.
parent 608c08b1
...@@ -34,6 +34,8 @@ Zope Changes ...@@ -34,6 +34,8 @@ Zope Changes
Bugs fixed Bugs fixed
- Collector #1129: Improper parsing of ISO8601 in DateTime.
- Removed pervasive use of string exceptions (some may still be - Removed pervasive use of string exceptions (some may still be
hiding in the woodwork, but all raise's with string literals are hiding in the woodwork, but all raise's with string literals are
gone). gone).
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
############################################################################## ##############################################################################
"""Encapsulation of date/time values""" """Encapsulation of date/time values"""
__version__='$Revision: 1.91 $'[11:-2] __version__='$Revision: 1.92 $'[11:-2]
import os, re, math, DateTimeZone import os, re, math, DateTimeZone
...@@ -497,6 +497,12 @@ class DateTime: ...@@ -497,6 +497,12 @@ class DateTime:
then the current date/time is returned, represented in the then the current date/time is returned, represented in the
timezone of the local machine. timezone of the local machine.
# Make class-specific exceptions available as attributes.
DateError = DateError
TimeError = TimeError
DateTimeError = DateTimeError
SyntaxError = SyntaxError
- If the function is invoked with a single string argument - If the function is invoked with a single string argument
which is a recognized timezone name, an object representing which is a recognized timezone name, an object representing
the current time is returned, represented in the specified the current time is returned, represented in the specified
...@@ -1657,7 +1663,8 @@ class DateTime: ...@@ -1657,7 +1663,8 @@ class DateTime:
hour=minute=seconds=hour_off=min_off=0 hour=minute=seconds=hour_off=min_off=0
datereg = re.compile('([0-9]{4})(-([0-9][0-9]))?(-([0-9][0-9]))?') datereg = re.compile('([0-9]{4})(-([0-9][0-9]))?(-([0-9][0-9]))?')
timereg = re.compile('([0-9]{2})(:([0-9][0-9]))?(:([0-9][0-9]))?(\.[0-9]{1,20})?') timereg = re.compile('T([0-9]{2})(:([0-9][0-9]))?(:([0-9][0-9]))?(\.[0-9]{1,20})?')
zonereg = re.compile('([+-][0-9][0-9])(:([0-9][0-9]))')
# Date part # Date part
...@@ -1666,21 +1673,33 @@ class DateTime: ...@@ -1666,21 +1673,33 @@ class DateTime:
if fields[1]: year = int(fields[1]) if fields[1]: year = int(fields[1])
if fields[3]: month = int(fields[3]) if fields[3]: month = int(fields[3])
if fields[5]: day = int(fields[5]) if fields[5]: day = int(fields[5])
t = fields[6]
if t:
if not fields[5]:
# Specifying time requires specifying a day.
raise IndexError
if s.find('T')>-1: fields = timereg.split(t)
fields = timereg.split(s[s.find('T')+1:])
if fields[1]: hour = int(fields[1]) if fields[1]: hour = int(fields[1])
if fields[3]: minute = int(fields[3]) if fields[3]: minute = int(fields[3])
if fields[5]: seconds = int(fields[5]) if fields[5]: seconds = int(fields[5])
if fields[6]: seconds = seconds+float(fields[6]) if fields[6]: seconds = seconds+float(fields[6])
z = fields[7]
if s.find('Z')>-1:
pass if z and z.startswith('Z'):
# Waaaa! This is wrong, since 'Z' and '+HH:MM'
if s[-3]==':' and s[-6] in ['+','-']: # are supposed to be mutually exclusive.
hour_off = int(s[-6:-3]) # It's only here to prevent breaking 2.7 beta.
min_off = int(s[-2:]) z = z[1:]
if z:
fields = zonereg.split(z)
hour_off = int(fields[1])
min_off = int(fields[3])
if fields[4]:
# Garbage after time zone
raise IndexError
return year,month,day,hour,minute,seconds,'GMT%+03d%02d' % (hour_off,min_off) return year,month,day,hour,minute,seconds,'GMT%+03d%02d' % (hour_off,min_off)
......
...@@ -257,9 +257,17 @@ class DateTimeTests(unittest.TestCase): ...@@ -257,9 +257,17 @@ class DateTimeTests(unittest.TestCase):
isoDt = DateTime('2002-05-02T08:00:00Z') isoDt = DateTime('2002-05-02T08:00:00Z')
self.assertEqual( ref0, isoDt) self.assertEqual( ref0, isoDt)
isoDt = DateTime('2002-05-02T08:00:00Z-04:00') isoDt = DateTime('2002-05-02T08:00:00-04:00')
self.assertEqual( ref1, isoDt) self.assertEqual( ref1, isoDt)
dgood = '2002-05-02'
tgood = 'T08:00:00-04:00'
for dbad in '2002-5-2', '2002-10-2', '2002-2-10', '02-2-10':
self.assertRaises(DateTime.SyntaxError, DateTime, dbad)
self.assertRaises(DateTime.SyntaxError, DateTime, dbad + tgood)
for tbad in '08:00', 'T8:00': #, 'T08:00Z-04:00':
self.assertRaises(DateTime.SyntaxError, DateTime, dgood + tbad)
def testJulianWeek(self): def testJulianWeek(self):
""" check JulianDayWeek function """ """ check JulianDayWeek function """
...@@ -279,13 +287,13 @@ class DateTimeTests(unittest.TestCase): ...@@ -279,13 +287,13 @@ class DateTimeTests(unittest.TestCase):
def testRFC822(self): def testRFC822(self):
'''rfc822 conversion''' '''rfc822 conversion'''
dt = DateTime('2002-05-02T08:00:00Z+00:00') dt = DateTime('2002-05-02T08:00:00+00:00')
self.assertEqual(dt.rfc822(), 'Thu, 02 May 2002 08:00:00 +0000') self.assertEqual(dt.rfc822(), 'Thu, 02 May 2002 08:00:00 +0000')
dt = DateTime('2002-05-02T08:00:00Z+02:00') dt = DateTime('2002-05-02T08:00:00+02:00')
self.assertEqual(dt.rfc822(), 'Thu, 02 May 2002 08:00:00 +0200') self.assertEqual(dt.rfc822(), 'Thu, 02 May 2002 08:00:00 +0200')
dt = DateTime('2002-05-02T08:00:00Z-02:00') dt = DateTime('2002-05-02T08:00:00-02:00')
self.assertEqual(dt.rfc822(), 'Thu, 02 May 2002 08:00:00 -0200') self.assertEqual(dt.rfc822(), 'Thu, 02 May 2002 08:00:00 -0200')
# Checking that conversion from local time is working. # Checking that conversion from local time is working.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment