#!/usr/bin/env python """ isodate.py Copyright 2002 Mark Nottingham, THIS SOFTWARE IS SUPPLIED WITHOUT WARRANTY OF ANY KIND, AND MAY BE COPIED, MODIFIED OR DISTRIBUTED IN ANY WAY, AS LONG AS THIS NOTICE AND ACKNOWLEDGEMENT OF AUTHORSHIP REMAIN. Functions for manipulating a subset of ISO8601 date, as specified by Exposes: - parse(s) s being a conforming (regular or unicode) string. Raises ValueError for invalid strings. Returns a float (representing seconds from the epoch; see the time module). - asString(i) i being an integer or float. Returns a conforming string. TODO: - Precision? it would be nice to have an interface that tells us how precise a datestring is, so that we don't make assumptions about it; e.g., 2001 != 2001-01-01T00:00:00Z. 2002-06-22 added bad string to error message -- timbl@w3.org """ import sys, time, re, operator import calendar # timegm - from python from types import StringType, UnicodeType, IntType, LongType, FloatType __version__ = "0.6" date_parser = re.compile(r"""^ (?P\d{4,4}) (?: - (?P\d{1,2}) (?: - (?P\d{1,2}) (?: T (?P\d{1,2}) : (?P\d{1,2}) (?: : (?P\d{1,2}) (?: \. (?P\d+)? )? )? (?: Z | (?: (?P[+-]) (?P\d{1,2}) : (?P\d{2,2}) ) ) )? )? )? $""", re.VERBOSE) def parse(s): """ parse a string and return seconds since the epoch. """ assert type(s) in [StringType, UnicodeType] r = date_parser.search(s) try: a = r.groupdict('0') except: raise ValueError, 'invalid date string format:'+s y = int(a['year']) if y < 1970: raise ValueError, 'Sorry, date must be in Unix era (1970 or after):'+s d = calendar.timegm(( int(a['year']), int(a['month']) or 1, int(a['day']) or 1, int(a['hour']), int(a['minute']), int(a['second']), 0, 0, 0 )) return d - int("%s%s" % ( a.get('tz_sign', '+'), ( int(a.get('tz_hour', 0)) * 60 * 60 ) - \ ( int(a.get('tz_min', 0)) * 60 )) ) def fullString(i): """ given seconds since the epoch, return a full dateTime string in Z timezone. """ assert type(i) in [IntType, FloatType, LongType], "Wrong type: "+ `type(i)` +`i` year, month, day, hour, minute, second, wday, jday, dst = time.gmtime(i) return str(year) + '-%2.2d-%2.2dT%2.2d:%2.2d:%2.2dZ' % (month, day, hour, minute, second) def asString(i): """ given seconds since the epoch, return a dateTime string. """ assert type(i) in [IntType, FloatType] year, month, day, hour, minute, second, wday, jday, dst = time.gmtime(i) o = str(year) if (month, day, hour, minute, second) == (1, 1, 0, 0, 0): return o o = o + '-%2.2d' % month if (day, hour, minute, second) == (1, 0, 0, 0): return o o = o + '-%2.2d' % day if (hour, minute, second) == (0, 0, 0): return o o = o + 'T%2.2d:%2.2d' % (hour, minute) if second != 0: o = o + ':%2.2d' % second o = o + 'Z' return o