""" 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."""importDateTime,Timezoneimportre,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+')?$')defWeekTime(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)ifd.iso_week[0]==year:# 1.1. belongs to year (backup to Monday)returnd+(-d.day_of_week+7*(isoweek-1)+isoday-1)else:# 1.1. belongs to year-1 (advance to next Monday)returnd+(7-d.day_of_week+7*(isoweek-1)+isoday-1)# AliasWeek=WeekTime# Aliases for the other constructors (they all happen to already use# ISO format)Date=DateTime.DateTime=DateTime.TimeTimeDelta=DateTime.TimeDeltadefParseDateTime(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)ifnotdate:raiseValueError,'wrong format, use YYYY-MM-DD HH:MM:SS'year,month,day,hour,minute,second,zone=date.groups()year=atoi(year)ifmonthisNone:month=1else:month=atoi(month)ifdayisNone:day=1else:day=atoi(day)ifhourisNone:hour=0else:hour=atoi(hour)ifminuteisNone:minute=0else:minute=atoi(minute)ifsecondisNone:second=0.0else:second=atof(second)returnDateTime.DateTime(year,month,day,hour,minute,second)defParseDateTimeGMT(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)ifnotdate:raiseValueError,'wrong format, use YYYY-MM-DD HH:MM:SS'year,month,day,hour,minute,second,zone=date.groups()year=atoi(year)ifmonthisNone:month=1else:month=atoi(month)ifdayisNone:day=1else:day=atoi(day)ifhourisNone:hour=0else:hour=atoi(hour)ifminuteisNone:minute=0else:minute=atoi(minute)ifsecondisNone:second=0.0else:second=atof(second)offset=Timezone.utc_offset(zone)returnDateTime.DateTime(year,month,day,hour,minute,second)-offset# AliasParseDateTimeUTC=ParseDateTimeGMTdefParseDate(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)ifnotdate:raiseValueError,'wrong format, use YYYY-MM-DD'year,month,day=date.groups()year=atoi(year)ifmonthisNone:month=1else:month=atoi(month)ifdayisNone:day=1else:day=atoi(day)returnDateTime.DateTime(year,month,day)defParseWeek(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)ifnotdate:raiseValueError,'wrong format, use yyyy-Www-d, e.g. 1998-W01-1'year,week,day=date.groups()year=atoi(year)ifweekisNone:week=1else:week=atoi(week)ifdayisNone:day=1else:day=atoi(day)returnWeek(year,week,day)defParseWeekTime(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)ifnotdate:raiseValueError,'wrong format, use e.g. "1998-W01-1 12:00:30"'year,week,day,hour,minute,second,zone=date.groups()year=atoi(year)ifweekisNone:week=1else:week=atoi(week)ifdayisNone:day=1else:day=atoi(day)ifhourisNone:hour=0else:hour=atoi(hour)ifminuteisNone:minute=0else:minute=atoi(minute)ifsecondisNone:second=0.0else:second=atof(second)returnWeekTime(year,week,day,hour,minute,second)defParseTime(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)ifnottime:raiseValueError,'wrong format, use HH:MM:SS'hour,minute,second,zone=time.groups()hour=atoi(hour)minute=atoi(minute)ifsecondisnotNone:second=atof(second)else:second=0.0returnDateTime.TimeDelta(hour,minute,second)defParseTimeDelta(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)ifnottime:raiseValueError,'wrong format, use [-]HH:MM:SS'sign,hour,minute,second,zone=time.groups()hour=atoi(hour)minute=atoi(minute)ifsecondisnotNone:second=atof(second)else:second=0.0ifsignandsign=='-':return-DateTime.TimeDelta(hour,minute,second)else:returnDateTime.TimeDelta(hour,minute,second)defParseAny(isostring):"""ParseAny(isostring) Parses the given string and tries to convert it to a DateTime[Delta] instance. """try:returnParseDateTime(isostring)exceptValueError:passtry:returnParseWeekTime(isostring)exceptValueError:passtry:returnParseTimeDelta(isostring)exceptValueError:raiseValueError,'unsupported format: "%s"'%isostringdefstr(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. """iftzisNone: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)defstrGMT(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)defstrUTC(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)# Testingif__name__=='__main__':e=DateTime.Date(1900,1,1)foriinrange(100000):d=e+iyear,week,day=d.iso_weekc=WeekTime(year,week,day)ifd!=c:print' Check %s (given; %i) != %s (parsed)'%(d,d.day_of_week,c)elifi%1000==0:printd,'ok'