""" Python implementation courtesy of Drew Csillag (StarMedia Network, Inc.) This version has been somewhat modified by MAL. It is still fairly rough though and not necessarily high performance... XXX Still needs testing and checkup !!! WARNING: Using this file is only recommended if you really must use it for some reason. It is not being actively maintained !"""__version__='1.2.0 [Python]'importtime,types,exceptions,math### ErrorsclassError(exceptions.StandardError):passclassRangeError(Error):pass### Constants (internal use only)month_offset=((0,31,59,90,120,151,181,212,243,273,304,334,365),(0,31,60,91,121,152,182,213,244,274,305,335,366),)days_in_month=((31,28,31,30,31,30,31,31,30,31,30,31),(31,29,31,30,31,30,31,31,30,31,30,31),)### Helpersdef_IS_LEAPYEAR(d):return((d.year%4==0)and((d.year%100!=0)or(d.year%400==0)))def_YEAROFFSET(d):return((d.year-1)*365+(d.year-1)/4-(d.year-1)/100+(d.year-1)/400)class_EmptyClass:passdefcreateEmptyObject(Class,_EmptyClass=_EmptyClass):o=_EmptyClass()o.__class__=Classreturno### DateTime classclassDateTime:def__init__(self,year,month=1,day=1,hour=0,minute=0,second=0.0):second=1.0*secondifmonth<=0:raiseRangeError,"year out of range (>0)"#calculate absolute dateleap=(year%4==0)and((year%100!=0)or(year%400==0))#Negative values indicate days relative to the years endifmonth<0:month=month+13ifnot(month>=1andmonth<=12):raiseRangeError,"month out of range (1-12)"#Negative values indicate days relative to the months endif(day<0):day=day+days_in_month[leap][month-1]+1;ifnot(day>=1andday<=days_in_month[leap][month-1]):raiseRangeError,"day out of range"year=year-1yearoffset=year*365+year/4-year/100+year/400year=year+1absdate=day+month_offset[leap][month-1]+yearoffset;self.absdate=absdateself.year=yearself.month=monthself.day=dayself.day_of_week=(absdate-1)%7self.day_of_year=absdate-yearoffsetself.days_in_month=days_in_month[leap][month-1]comdate=absdate-693594ifnot(hour>=0andhour<=23):raiseRangeError,"hour out of range (0-23)"ifnot(minute>=0andminute<=59):raiseRangeError,"minute out of range (0-59)"ifnot(second>=0.0and(second<60.0or(hour==23andminute==59andsecond<61.0))):raiseRangeError,"second out of range (0.0 - <60.0; <61.0 for 23:59)"self.abstime=(hour*3600+minute*60)+secondself.hour=hourself.minute=minuteself.second=secondself.dst=-1self.tz="???"self.is_leapyear=leapself.yearoffset=yearoffsetself.iso_week=(self.year,self.day,self.day_of_week)ifcomdate<0.0:comdate=comdate-self.abstime/86400.0else:comdate=comdate+self.abstime/86400.0self.comdate=comdatedefCOMDate(self):returnself.comdatedef__str__(self):return"%04d-%02d-%02d%02d:%02d:%05.2f"%(self.year,self.month,self.day,self.hour,self.minute,self.second)def__getattr__(self,attr):ifattr=='mjd':return(self-mjd0).dayselifattr=='jdn':return(self-jdn0).dayselifattr=='tjd':return(self-jdn0).days%10000elifattr=='tjd_myriad':returnint((self-jdn0).days)/10000+240elifattr=='absdays':returnself.absdate-1+self.abstime/86400.0else:try:returnself.__dict__[attr]except:raiseAttributeError,attrdef__mul__(self,other):raiseTypeError,"bad operand type(s) for *"def__div__(self,other):raiseTypeError,"bad operand type(s) for /"defstrftime(self,format_string="%c"):"localtime([seconds]) -> (tm_year,tm_mon,tm_day,tm_hour,tm_min,tm_sec,tm_wday,tm_yday,tm_isdst)"# The map prevents a deprecation warning on Python 2.5.1 (Mac)# DeprecationWarning: integer argument expected, got floatitems=[int(item)foriteminself.tuple()]returntime.strftime(format_string,items)# AliasFormat=strftimedeftuple(self):return(self.year,self.month,self.day,self.hour,self.minute,self.second,self.day_of_week,self.day_of_year,-1)#return time.localtime(self.ticks())defabsvalues(self):returnself.absdate,self.abstimedef__float__(self):returnself.ticks()def__int__(self):returnint(self.ticks)defticks(self,offset=0.0,dst=-1):tticks=time.mktime(self.year,self.month,self.day,self.hour,self.minute,self.second,self.day_of_week,0,dst)iftticks==-1:raiseOverflowError,"cannot convert value to a time value"ticks=(1.0*tticks)+(self.abstime-int(self.abstime))-offsetreturnticksdefgmticks(self,offset=0.0):frommx.DateTimeimporttz_offsetreturn(self-tz_offset(self)).ticks()defgmtoffset(self):gmtime=DateTime(*time.gmtime()[:6])return-(now()-gmtime)def__repr__(self):return"<DateTime object for '%d-%02d-%02d%02d:%02d:%05.2f' at %x>"%(self.year,self.month,self.day,self.hour,self.minute,self.second,id(self))def__cmp__(self,other,cmp=cmp):ifisinstance(other,DateTime):cmpdate=cmp(self.absdate,other.absdate)ifcmpdate==0:returncmp(self.abstime,other.abstime)else:returncmpdateeliftype(other)==types.NoneType:return-1eliftype(other)==types.StringType:return-1eliftype(other)in(types.FloatType,types.LongType,types.IntType):return1return-1def__hash__(self):returnhash(self.tuple())def__add__(self,other):abstime=self.abstimeabsdate=self.absdatedidadd=0iftype(other)==types.InstanceType:ifother.__class__==DateTimeDelta:abstime=abstime+other.secondsdidadd=1elifother.__class__==DateTime:raiseTypeError,"DateTime + DateTime is not supported"else:returnother.__class__.__radd__(other,self)eliftype(other)==types.IntTypeortype(other)==types.FloatType:abstime=abstime+other*86400.0didadd=1ifnotdidadd:raiseTypeError,"cannot add these two types"ifabstime>=86400.0:days=abstime/86400.0absdate=absdate+daysabstime=abstime-(86400.0*int(days))#print "absdate, abstime = ", absdate, abstimeelifabstime<0.0:days=int(((-abstime-1)/86400.0))+1#days = int(-abstime / 86400.0)absdate=absdate-daysabstime=abstime+86400.0*int(days)ifabsdate<1:raiseRangeError,"underflow while adding"returnDateTimeFromAbsDateTime(absdate,abstime)def__radd__(self,other):returnDateTime.__add__(other,self)def__sub__(self,other):abstime=self.abstimeabsdate=self.absdatedidsub=0iftype(other)==types.InstanceType:ifother.__class__==DateTimeDelta:abstime=abstime-other.secondsdidsub=1elifother.__class__==DateTime:absdate=absdate-other.absdateabstime=abstime-other.abstimereturnDateTimeDelta(absdate,0.0,0.0,abstime)else:returnother.__rsub__(self)eliftype(other)==types.IntTypeortype(other)==types.FloatType:abstime=abstime-other*86400.0;didsub=1ifnotdidsub:raiseTypeError,"cannot subtract these two types"ifabstime>=86400.0:days=abstime/86400.0absdate=absdate+daysabstime=abstime-(86400.0*days)#print "absdate, abstime = ", absdate, abstimeelifabstime<0.0:#print "abstime < 0"days=int(((-abstime-1)/86400.0)+1)#days = -abstime / 86400.0absdate=absdate-int(days)abstime=(1.0*abstime)+(86400.0*days)#print "absdate, abstime", absdate, abstimeifabsdate<1:raiseRangeError,"underflow while adding"returnDateTimeFromAbsDateTime(absdate,abstime)# Constantsmjd0=DateTime(1858,11,17)jdn0=DateTime(-4713,1,1,12,0,0.0)# Other DateTime constructorsdefDateTimeFromCOMDate(comdate):absdate=int(comdate)abstime=(comdate-float(absdate))*86400.0ifabstime<0.0:abstime=-abstimeabsdate=absdate+693594;dt=DateTimeFromAbsDateTime(absdate,abstime)dt.comdate=comdatereturndtdefDateTimeFromAbsDateTime(absdate,abstime):# Create the object without calling its default constructordt=createEmptyObject(DateTime)# Init. the objectabstime=1.0*abstimeifabstime<0andabstime>-0.001:abstime=0.0ifnot(absdate>0):raiseRangeError,"absdate out of range (>0)"ifnot(abstime>=0.0andabstime<=86400.0):raiseRangeError,"abstime out of range (0.0 - 86400.0) <%s>"%abstimedt.absdate=absdatedt.abstime=abstime#calculate com datecomdate=1.0*(dt.absdate-693594)ifcomdate<0.0:comdate=comdate-dt.abstime/86400.0else:comdate=comdate+dt.abstime/86400.0dt.comdate=comdate#calculate the date#print "absdate=", absdateyear=int((1.0*absdate)/365.2425)#newApproximation:while1:#print "year=", yearyearoffset=year*365+year/4-year/100+year/400#print "yearoffset=", yearoffset#print "absdate=", absdateifyearoffset>=absdate:year=year-1#print "year = ", yearcontinue#goto newApproximationyear=year+1leap=(year%4==0)and((year%100!=0)or(year%400==0))dayoffset=absdate-yearoffset#print "dayoffset=", dayoffsetifdayoffset>365andleap==0:#print "dayoffset=", dayoffsetcontinue#goto newApproximationmonthoffset=month_offset[leap]formonthinrange(1,13):ifmonthoffset[month]>=dayoffset:breakdt.year=yeardt.month=monthdt.day=dayoffset-month_offset[leap][month-1]dt.day_of_week=(dt.absdate-1)%7dt.day_of_year=dayoffsetbreak#calculate the timeinttime=int(abstime)hour=inttime/3600minute=(inttime%3600)/60second=abstime-1.0*(hour*3600+minute*60)dt.hour=hour;dt.minute=minute;dt.second=second;dt.days_in_month=days_in_month[leap][month-1]dt.dst=-1dt.tz="???"dt.is_leapyear=leapdt.yearoffset=yearoffsetreturndtdefnow(time=time.time,float=float,localtime=time.localtime,round=round,int=int,DateTime=DateTime,floor=math.floor):ticks=time()Y,M,D,h,m,s=localtime(ticks)[:6]s=s+(ticks-floor(ticks))returnDateTime(Y,M,D,h,m,s)defutc(time=time.time,float=float,gmtime=time.gmtime,round=round,int=int,DateTime=DateTime,floor=math.floor):ticks=time()Y,M,D,h,m,s=gmtime(ticks)[:6]s=s+(ticks-floor(ticks))returnDateTime(Y,M,D,h,m,s)# AliasesDate=Timestamp=DateTime# XXX Calendars are not supported:defnotSupported(*args,**kws):raiseError,'calendars are not supported by the Python version of mxDateTime'JulianDateTime=notSupported### DateTimeDelta classclassDateTimeDelta:def__init__(self,days=0,hours=0,minutes=0,seconds=0):seconds=seconds+(days*86400.0+hours*3600.0+minutes*60.0)self.seconds=secondsifseconds<0.0:seconds=-secondsday=long(seconds/86400.0)seconds=seconds-(86400.0*day)wholeseconds=int(seconds)hour=wholeseconds/3600minute=(wholeseconds%3600)/60second=seconds-(hour*3600.0+minute*60.0)self.day=dayself.hour=hourself.minute=minuteself.second=secondseconds=self.secondsself.minutes=seconds/60.0self.hours=seconds/3600.0self.days=seconds/86400.0def__str__(self):ifself.day!=0:ifself.seconds>=0.0:r="%s:%02d:%02d:%05.2f"%(self.day,self.hour,self.minute,self.second)else:r="-%s:%02d:%02d:%05.2f"%(self.day,self.hour,self.minute,self.second)else:ifself.seconds>=0.0:r="%02d:%02d:%05.2f"%(self.hour,self.minute,self.second)else:r="-%02d:%02d:%05.2f"%(self.hour,self.minute,self.second)returnrdefabsvalues(self):days=self.seconds/86400seconds=self.seconds-(days*86400.0)returndays,secondsdeftuple(self):return(self.day,self.hour,self.minute,self.second)defstrftime(self,format_string):raiseNotImplementedErrordef__int__(self):returnint(self.seconds)def__float__(self):returnself.secondsdef__cmp__(self,other,accuracy=0.0):if(type(other)==types.InstanceTypeandother.__class__==DateTimeDelta):diff=self.seconds-other.secondsifabs(diff)>accuracy:ifdiff>0:return1return-1eliftype(other)==types.FloatType:diff=self.seconds-otherifabs(diff)>accuracy:ifdiff>0:return1return-1eliftype(other)==types.IntType:diff=self.seconds-otherifabs(diff)>accuracy:ifdiff>0:return1return-1return0def__getattr__(self,attr):seconds=self.__dict__['seconds']ifattrin('hour','minute','second','day'):ifseconds>=0.0:returnself.__dict__[attr]else:return-self.__dict__[attr]else:try:returnself.__dict__[attr]except:raiseAttributeError,attrdef__div__(self,other):iftype(other)in(types.IntType,types.FloatType):returnDateTimeDelta(0.0,0.0,0.0,self.seconds/other)elif(type(other)==types.InstanceTypeandisinstance(other,DateTimeDelta)):returnDateTimeDelta(0.0,0.0,0.0,self.seconds/other.seconds)raiseTypeError,"bad operand types for /"def__mul__(self,other):iftype(other)==types.IntTypeortype(other)==types.FloatType:returnDateTimeDelta(0.0,0.0,0.0,self.seconds*other)else:#print "type", type(other)raiseTypeError,"cannot multiply these two types"def__rmul__(self,other):returnself.__mul__(other)def__neg__(self):returnDateTimeDelta(0.0,0.0,0.0,-self.seconds)def__repr__(self):ifself.day!=0:ifself.seconds>=0.0:strval="%s:%02d:%02d:%05.2f"%(self.day,self.hour,self.minute,self.second)else:strval="-%s:%02d:%02d:%05.2f"%(self.day,self.hour,self.minute,self.second)else:ifself.seconds>=0.0:strval="%02d:%02d:%05.2f"%(self.hour,self.minute,self.second)else:strval="-%02d:%02d:%05.2f"%(self.hour,self.minute,self.second)return"<DateTimeDelta object for '%s' at %x>"%(strval,id(self))def__abs__(self):ifself.seconds<0:return-selfreturnselfdef__nonzero__(self):returnself.seconds!=0.0def__add__(self,other):iftype(other)==types.InstanceType:ifisinstance(other,DateTime):returnother+selfelifisinstance(other,DateTimeDelta):returnDateTimeDelta(0.0,0.0,0.0,self.seconds+other.seconds)# What about __radd__ ?# Other DateTimeDelta constructorsdefTimeDelta(hour=0.0,minute=0.0,second=0.0):returnDateTimeDelta(0.0,hours,minutes,seconds)Time=TimeDeltadefDateTimeDeltaFromSeconds(seconds):returnDateTimeDelta(0.0,0.0,0.0,seconds)defDateTimeDeltaFromDays(days):returnDateTimeDelta(days)### TypesDateTimeType=DateTimeDateTimeDeltaType=DateTimeDelta### Functionsdefcmp(a,b,acc):ifisinstance(a,DateTime)andisinstance(b,DateTime):diff=a.absdays-b.absdaysif(diff>=0anddiff<=acc)or(diff<0and-diff<=acc):return0elifdiff<0:return1else:return-1elifisinstance(a,DateTimeDelta)andisinstance(b,DateTimeDelta):diff=a.days-b.daysif(diff>=0anddiff<=acc)or(diff<0and-diff<=acc):return0elifdiff<0:return1else:return-1else:raiseTypeError,"objects must be DateTime[Delta] instances"