--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/embedded/mx/DateTime/ISO.py Wed Nov 05 15:52:50 2008 +0100
@@ -0,0 +1,366 @@
+""" This module provides a set of constructors and routines to convert
+ between DateTime[Delta] instances and ISO representations of date
+ and time.
+
+ Note: Timezones are only interpreted by ParseDateTimeGMT(). All
+ other constructors silently ignore the time zone information.
+
+ Copyright (c) 1998-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
+ Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
+ See the documentation for further information on copyrights,
+ or contact the author.
+
+"""
+import DateTime,Timezone
+import re,string
+
+# Grammar: ISO 8601 (not all, but what we need from it)
+_year = '(?P<year>\d?\d\d\d)'
+_month = '(?P<month>\d?\d)'
+_day = '(?P<day>\d?\d)'
+_hour = '(?P<hour>\d?\d)'
+_minute = '(?P<minute>\d?\d)'
+_second = '(?P<second>\d?\d(?:\.\d+)?)'
+_sign = '(?P<sign>[-+])'
+_week = 'W(?P<week>\d?\d)'
+_zone = Timezone.isozone
+
+_weekdate = _year + '-?(?:' + _week + '-?' + _day + '?)?'
+_date = _year + '-?' + '(?:' + _month + '-?' + _day + '?)?'
+_time = _hour + ':?' + _minute + ':?' + _second + '?(?:' + _zone + ')?'
+
+isodatetimeRE = re.compile(_date + '(?:[ T]' + _time + ')?$')
+isodateRE = re.compile(_date + '$')
+isotimeRE = re.compile(_time + '$')
+isodeltaRE = re.compile(_sign + '?' + _time + '$')
+isoweekRE = re.compile(_weekdate + '$')
+isoweektimeRE = re.compile(_weekdate + '(?:[ T]' + _time + ')?$')
+
+def WeekTime(year,isoweek=1,isoday=1,hour=0,minute=0,second=0.0):
+
+ """Week(year,isoweek=1,isoday=1,hour=0,minute=0,second=0.0)
+
+ Returns a DateTime instance pointing to the given ISO week and
+ day. isoday defaults to 1, which corresponds to Monday in the
+ ISO numbering. The time part is set as given.
+
+ """
+ d = DateTime.DateTime(year,1,1,hour,minute,second)
+ if d.iso_week[0] == year:
+ # 1.1. belongs to year (backup to Monday)
+ return d + (-d.day_of_week + 7 * (isoweek-1) + isoday-1)
+ else:
+ # 1.1. belongs to year-1 (advance to next Monday)
+ return d + (7-d.day_of_week + 7 * (isoweek-1) + isoday-1)
+
+# Alias
+Week = WeekTime
+
+# Aliases for the other constructors (they all happen to already use
+# ISO format)
+Date = DateTime.Date
+Time = DateTime.Time
+TimeDelta = DateTime.TimeDelta
+
+def ParseDateTime(isostring,parse_isodatetime=isodatetimeRE.match,
+
+ strip=string.strip,atoi=string.atoi,atof=string.atof):
+
+ """ParseDateTime(isostring)
+
+ Returns a DateTime instance reflecting the given ISO date. A
+ time part is optional and must be delimited from the date by a
+ space or 'T'.
+
+ Time zone information is parsed, but not evaluated.
+
+ """
+ s = strip(isostring)
+ date = parse_isodatetime(s)
+ if not date:
+ raise ValueError,'wrong format, use YYYY-MM-DD HH:MM:SS'
+ year,month,day,hour,minute,second,zone = date.groups()
+ year = atoi(year)
+ if month is None:
+ month = 1
+ else:
+ month = atoi(month)
+ if day is None:
+ day = 1
+ else:
+ day = atoi(day)
+ if hour is None:
+ hour = 0
+ else:
+ hour = atoi(hour)
+ if minute is None:
+ minute = 0
+ else:
+ minute = atoi(minute)
+ if second is None:
+ second = 0.0
+ else:
+ second = atof(second)
+ return DateTime.DateTime(year,month,day,hour,minute,second)
+
+def ParseDateTimeGMT(isostring,parse_isodatetime=isodatetimeRE.match,
+
+ strip=string.strip,atoi=string.atoi,atof=string.atof):
+
+ """ParseDateTimeGMT(isostring)
+
+ Returns a DateTime instance in UTC reflecting the given ISO
+ date. A time part is optional and must be delimited from the
+ date by a space or 'T'. Timezones are honored.
+
+ """
+ s = strip(isostring)
+ date = parse_isodatetime(s)
+ if not date:
+ raise ValueError,'wrong format, use YYYY-MM-DD HH:MM:SS'
+ year,month,day,hour,minute,second,zone = date.groups()
+ year = atoi(year)
+ if month is None:
+ month = 1
+ else:
+ month = atoi(month)
+ if day is None:
+ day = 1
+ else:
+ day = atoi(day)
+ if hour is None:
+ hour = 0
+ else:
+ hour = atoi(hour)
+ if minute is None:
+ minute = 0
+ else:
+ minute = atoi(minute)
+ if second is None:
+ second = 0.0
+ else:
+ second = atof(second)
+ offset = Timezone.utc_offset(zone)
+ return DateTime.DateTime(year,month,day,hour,minute,second) - offset
+
+# Alias
+ParseDateTimeUTC = ParseDateTimeGMT
+
+def ParseDate(isostring,parse_isodate=isodateRE.match,
+
+ strip=string.strip,atoi=string.atoi,atof=string.atof):
+
+ """ParseDate(isostring)
+
+ Returns a DateTime instance reflecting the given ISO date. A
+ time part may not be included.
+
+ """
+ s = strip(isostring)
+ date = parse_isodate(s)
+ if not date:
+ raise ValueError,'wrong format, use YYYY-MM-DD'
+ year,month,day = date.groups()
+ year = atoi(year)
+ if month is None:
+ month = 1
+ else:
+ month = atoi(month)
+ if day is None:
+ day = 1
+ else:
+ day = atoi(day)
+ return DateTime.DateTime(year,month,day)
+
+def ParseWeek(isostring,parse_isoweek=isoweekRE.match,
+
+ strip=string.strip,atoi=string.atoi,atof=string.atof):
+
+ """ParseWeek(isostring)
+
+ Returns a DateTime instance reflecting the given ISO date. A
+ time part may not be included.
+
+ """
+ s = strip(isostring)
+ date = parse_isoweek(s)
+ if not date:
+ raise ValueError,'wrong format, use yyyy-Www-d, e.g. 1998-W01-1'
+ year,week,day = date.groups()
+ year = atoi(year)
+ if week is None:
+ week = 1
+ else:
+ week = atoi(week)
+ if day is None:
+ day = 1
+ else:
+ day = atoi(day)
+ return Week(year,week,day)
+
+def ParseWeekTime(isostring,parse_isoweektime=isoweektimeRE.match,
+
+ strip=string.strip,atoi=string.atoi,atof=string.atof):
+
+ """ParseWeekTime(isostring)
+
+ Returns a DateTime instance reflecting the given ISO date. A
+ time part is optional and must be delimited from the date by a
+ space or 'T'.
+
+ """
+ s = strip(isostring)
+ date = parse_isoweektime(s)
+ if not date:
+ raise ValueError,'wrong format, use e.g. "1998-W01-1 12:00:30"'
+ year,week,day,hour,minute,second,zone = date.groups()
+ year = atoi(year)
+ if week is None:
+ week = 1
+ else:
+ week = atoi(week)
+ if day is None:
+ day = 1
+ else:
+ day = atoi(day)
+ if hour is None:
+ hour = 0
+ else:
+ hour = atoi(hour)
+ if minute is None:
+ minute = 0
+ else:
+ minute = atoi(minute)
+ if second is None:
+ second = 0.0
+ else:
+ second = atof(second)
+ return WeekTime(year,week,day,hour,minute,second)
+
+def ParseTime(isostring,parse_isotime=isotimeRE.match,
+
+ strip=string.strip,atoi=string.atoi,atof=string.atof):
+
+ """ParseTime(isostring)
+
+ Returns a DateTimeDelta instance reflecting the given ISO time.
+ Hours and minutes must be given, seconds are
+ optional. Fractions of a second may also be used,
+ e.g. 12:23:12.34.
+
+ """
+ s = strip(isostring)
+ time = parse_isotime(s)
+ if not time:
+ raise ValueError,'wrong format, use HH:MM:SS'
+ hour,minute,second,zone = time.groups()
+ hour = atoi(hour)
+ minute = atoi(minute)
+ if second is not None:
+ second = atof(second)
+ else:
+ second = 0.0
+ return DateTime.TimeDelta(hour,minute,second)
+
+def ParseTimeDelta(isostring,parse_isodelta=isodeltaRE.match,
+
+ strip=string.strip,atoi=string.atoi,atof=string.atof):
+
+ """ParseTimeDelta(isostring)
+
+ Returns a DateTimeDelta instance reflecting the given ISO time
+ as delta. Hours and minutes must be given, seconds are
+ optional. Fractions of a second may also be used,
+ e.g. 12:23:12.34. In addition to the ISO standard a sign may be
+ prepended to the time, e.g. -12:34.
+
+ """
+ s = strip(isostring)
+ time = parse_isodelta(s)
+ if not time:
+ raise ValueError,'wrong format, use [-]HH:MM:SS'
+ sign,hour,minute,second,zone = time.groups()
+ hour = atoi(hour)
+ minute = atoi(minute)
+ if second is not None:
+ second = atof(second)
+ else:
+ second = 0.0
+ if sign and sign == '-':
+ return -DateTime.TimeDelta(hour,minute,second)
+ else:
+ return DateTime.TimeDelta(hour,minute,second)
+
+def ParseAny(isostring):
+
+ """ParseAny(isostring)
+
+ Parses the given string and tries to convert it to a
+ DateTime[Delta] instance.
+
+ """
+ try:
+ return ParseDateTime(isostring)
+ except ValueError:
+ pass
+ try:
+ return ParseWeekTime(isostring)
+ except ValueError:
+ pass
+ try:
+ return ParseTimeDelta(isostring)
+ except ValueError:
+ raise ValueError,'unsupported format: "%s"' % isostring
+
+def str(datetime,tz=None):
+
+ """str(datetime,tz=DateTime.tz_offset(datetime))
+
+ Returns the datetime instance as ISO date string. tz can be
+ given as DateTimeDelta instance providing the time zone
+ difference from datetime's zone to UTC. It defaults to
+ DateTime.tz_offset(datetime) which assumes local time.
+
+ """
+ if tz is None:
+ tz = datetime.gmtoffset()
+ return '%04i-%02i-%02i %02i:%02i:%02i%+03i%02i' % (
+ datetime.year, datetime.month, datetime.day,
+ datetime.hour, datetime.minute, datetime.second,
+ tz.hour,tz.minute)
+
+def strGMT(datetime):
+
+ """strGMT(datetime)
+
+ Returns the datetime instance as ISO date string assuming it is
+ given in GMT.
+
+ """
+ return '%04i-%02i-%02i %02i:%02i:%02i+0000' % (
+ datetime.year, datetime.month, datetime.day,
+ datetime.hour, datetime.minute, datetime.second)
+
+def strUTC(datetime):
+
+ """strUTC(datetime)
+
+ Returns the datetime instance as ISO date string assuming it is
+ given in UTC.
+
+ """
+ return '%04i-%02i-%02i %02i:%02i:%02i+0000' % (
+ datetime.year, datetime.month, datetime.day,
+ datetime.hour, datetime.minute, datetime.second)
+
+# Testing
+if __name__ == '__main__':
+ e = DateTime.Date(1900,1,1)
+ for i in range(100000):
+ d = e + i
+ year,week,day = d.iso_week
+ c = WeekTime(year,week,day)
+ if d != c:
+ print ' Check %s (given; %i) != %s (parsed)' % (d,d.day_of_week,c)
+ elif i % 1000 == 0:
+ print d,'ok'