Commits

Matthew Schinckel committed 269c670

Add preliminary support for durations.

Comments (0)

Files changed (3)

 Finally, only naive datetime objects are supported at this time. Timezones
 may not be included in the format string.
 
+Duration time formats of the following forms are also supported:
+
+  * P1W2DT3H4M5S
+
+Note that support for Year and Month data is not supported, as this does not
+make sense with python's timedelta object.
+
+You may, as per ISO8601, drop fields that have no value.
+
 Future (in no particular order):
 
 	* Support timezones
-	* Support durations
+	* Support durations fully
 	* Support time intervals
 	* Support repeating intervals
 	* Support week-dates
 
 Changelog:
     
-	0.1.6 - Allow for a date or datetime object to be passed to parse.
+    0.2a  - Initial support for duration data (excluding year/month).
+    
+    0.1.6 - Allow for a date or datetime object to be passed to parse.
 	
     0.1.5 - Added support for fractional times.
     
     0.1.1 - Helps if I spell my domain name right.
     
-    0.1 - Initial release.
+    0.1   - Initial release.

iso8601/parser.py

 import datetime
+import re
 
 def parse(data):
     """
         ...
     ValueError: fractional time may only apply to last component
     
+    >>> parse('P7D')
+    datetime.timedelta(7)
+    >>> parse('P14D')
+    datetime.timedelta(14)
+    >>> parse('P1DT')
+    Traceback (most recent call last):
+        ...
+    ValueError: 'P1DT' does not match ISO8601 format
+    >>> parse('P1D2H')
+    Traceback (most recent call last):
+        ...
+    ValueError: 'P1D2H' does not match ISO8601 format
+    >>> parse('P1DT2H')
+    datetime.timedelta(1, 7200)
+    >>> parse('P1Y')
+    Traceback (most recent call last):
+        ...
+    ValueError: Year and month values are not supported in python timedelta
     """
     
-    if isinstance(data, (datetime.datetime, datetime.date)):
+    if isinstance(data, (datetime.datetime, datetime.date, datetime.timedelta)):
         return data
     
+    if 'P' in data:
+        dt, duration = data.split('P')
+        if dt:
+            return parse(dt), parse_duration(duration)
+        return parse_duration(duration)
+        
     if 'T' not in data:
         data = data.replace(' ', 'T')
     
     
     return date + addition
 
+def parse_date(date):
+    pass
+
+def parse_time(time):
+    pass
+
+duration_regex = re.compile(
+    r'^((?P<years>\d+)Y)?'
+    r'((?P<months>\d+)M)?'
+    r'((?P<weeks>\d+)W)?'
+    r'((?P<days>\d+)D)?'
+    r'(T'
+    r'((?P<hours>\d+)H)?'
+    r'((?P<minutes>\d+)M)?'
+    r'((?P<seconds>\d+)S)?'
+    r')?$'
+)
+def parse_duration(duration):
+    data = duration_regex.match(duration)
+    if not data or duration[-1] == 'T':
+        raise ValueError("'P%s' does not match ISO8601 format" % duration)
+    data = {k:int(v) for k,v in data.groupdict().items() if v}
+    if 'years' in data or 'months' in data:
+        raise ValueError('Year and month values are not supported in python timedelta')
+    return datetime.timedelta(**data)
+
+def parse_interval(interval):
+    pass
+
 if __name__ == "__main__":
     import doctest
     doctest.testmod()
 
 setup(
     name = "iso-8601",
-    version = "0.1.6",
+    version = "0.2a",
     description = "Flexible ISO 8601 parser: pass in a valid ISO 8601 string, and a datetime object will be returned.",
     url = "http://hg.schinckel.net/iso-8601/",
     author = "Matthew Schinckel",