diff -r 000000000000 -r b97547f5f1fa embedded/mx/DateTime/mxDateTime_python.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/embedded/mx/DateTime/mxDateTime_python.py Wed Nov 05 15:52:50 2008 +0100 @@ -0,0 +1,614 @@ +""" + 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]' + +import time,types,exceptions,math + +### Errors + +class Error(exceptions.StandardError): + pass + +class RangeError(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), + ) + +### Helpers + +def _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: + pass + +def createEmptyObject(Class, + _EmptyClass=_EmptyClass): + + o = _EmptyClass() + o.__class__ = Class + return o + +### DateTime class + +class DateTime: + + def __init__(self, year, month=1, day=1, hour=0, minute=0, second=0.0): + + second=1.0 * second + if month <= 0: + raise RangeError, "year out of range (>0)" + + #calculate absolute date + leap = (year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0)) + + #Negative values indicate days relative to the years end + if month < 0: + month = month + 13 + + if not (month >= 1 and month <= 12): + raise RangeError, "month out of range (1-12)" + + #Negative values indicate days relative to the months end + if (day < 0): + day = day + days_in_month[leap][month - 1] + 1; + + if not (day >= 1 and day <= days_in_month[leap][month - 1]): + raise RangeError, "day out of range" + + year = year - 1 + yearoffset = year * 365 + year / 4 - year / 100 + year / 400 + year = year + 1 + absdate = day + month_offset[leap][month - 1] + yearoffset; + + self.absdate = absdate + self.year = year + self.month = month + self.day = day + self.day_of_week = (absdate - 1) % 7 + self.day_of_year = absdate - yearoffset + self.days_in_month = days_in_month[leap][month - 1] + comdate = absdate - 693594 + + if not (hour >=0 and hour <= 23): + raise RangeError, "hour out of range (0-23)" + if not (minute >= 0 and minute <= 59): + raise RangeError, "minute out of range (0-59)" + if not (second >= 0.0 and + (second < 60.0 or + (hour == 23 and minute == 59 and second < 61.0))): + raise RangeError, "second out of range (0.0 - <60.0; <61.0 for 23:59)" + + self.abstime = (hour * 3600 + minute * 60) + second + self.hour = hour + self.minute = minute + self.second = second + self.dst = -1 + self.tz = "???" + self.is_leapyear = leap + self.yearoffset = yearoffset + self.iso_week = (self.year, self.day, self.day_of_week) + + if comdate < 0.0: + comdate = comdate - self.abstime / 86400.0 + else: + comdate = comdate + self.abstime / 86400.0 + + self.comdate = comdate + + def COMDate(self): + return self.comdate + + def __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): + if attr == 'mjd': + return (self - mjd0).days + elif attr == 'jdn': + return (self - jdn0).days + elif attr == 'tjd': + return (self - jdn0).days % 10000 + elif attr == 'tjd_myriad': + return int((self - jdn0).days) / 10000 + 240 + elif attr == 'absdays': + return self.absdate - 1 + self.abstime / 86400.0 + else: + try: + return self.__dict__[attr] + except: + raise AttributeError, attr + + def __mul__(self, other): + raise TypeError, "bad operand type(s) for *" + + def __div__(self, other): + raise TypeError, "bad operand type(s) for /" + + def strftime(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 float + items = [int(item) for item in self.tuple()] + return time.strftime(format_string, items) + + # Alias + Format = strftime + + def tuple(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()) + + def absvalues(self): + return self.absdate, self.abstime + + def __float__(self): + return self.ticks() + + def __int__(self): + return int(self.ticks) + + def ticks(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) + if tticks == -1: + raise OverflowError, "cannot convert value to a time value" + ticks = (1.0*tticks) + (self.abstime - int(self.abstime)) - offset + return ticks + + def gmticks(self, offset=0.0): + from mx.DateTime import tz_offset + return (self-tz_offset(self)).ticks() + + def gmtoffset(self): + gmtime = DateTime(*time.gmtime()[:6]) + return - (now() - gmtime) + + def __repr__(self): + return ""% ( + self.year, self.month, self.day, self.hour, self.minute, + self.second, id(self)) + + def __cmp__(self, other, + cmp=cmp): + + if isinstance(other,DateTime): + cmpdate = cmp(self.absdate,other.absdate) + if cmpdate == 0: + return cmp(self.abstime,other.abstime) + else: + return cmpdate + elif type(other) == types.NoneType: + return -1 + elif type(other) == types.StringType: + return -1 + elif type(other) in (types.FloatType, types.LongType, types.IntType): + return 1 + return -1 + + def __hash__(self): + return hash(self.tuple()) + + def __add__(self, other): + abstime=self.abstime + absdate=self.absdate + + didadd=0 + + if type(other) == types.InstanceType: + if other.__class__ == DateTimeDelta: + abstime = abstime + other.seconds + didadd=1 + elif other.__class__ == DateTime: + raise TypeError, "DateTime + DateTime is not supported" + else: + return other.__class__.__radd__(other, self) + + elif type(other) == types.IntType or type(other) == types.FloatType: + abstime = abstime + other * 86400.0 + didadd=1 + + if not didadd: + raise TypeError, "cannot add these two types" + + if abstime >= 86400.0: + days = abstime / 86400.0 + absdate = absdate + days + abstime = abstime - (86400.0 * int(days)) + #print "absdate, abstime = ", absdate, abstime + elif abstime < 0.0: + days = int(((-abstime - 1) / 86400.0)) + 1 + #days = int(-abstime / 86400.0) + absdate = absdate - days + abstime = abstime + 86400.0 * int(days) + + if absdate < 1: + raise RangeError, "underflow while adding" + + return DateTimeFromAbsDateTime(absdate, abstime) + + def __radd__(self, other): + return DateTime.__add__(other, self) + + def __sub__(self, other): + abstime=self.abstime + absdate=self.absdate + + didsub=0 + if type(other) == types.InstanceType: + if other.__class__ == DateTimeDelta: + abstime = abstime - other.seconds + didsub = 1 + elif other.__class__ == DateTime: + absdate = absdate - other.absdate + abstime = abstime - other.abstime + return DateTimeDelta(absdate,0.0,0.0,abstime) + else: + return other.__rsub__(self) + + elif type(other) == types.IntType or type(other) == types.FloatType: + abstime = abstime - other * 86400.0; + didsub=1 + + if not didsub: + raise TypeError, "cannot subtract these two types" + + if abstime >= 86400.0: + days = abstime / 86400.0 + absdate = absdate + days + abstime = abstime - (86400.0 * days) + #print "absdate, abstime = ", absdate, abstime + elif abstime < 0.0: + #print "abstime < 0" + days = int( ((-abstime - 1) / 86400.0) + 1) + #days = -abstime / 86400.0 + absdate = absdate - int(days) + abstime = (1.0*abstime) + (86400.0 * days) + #print "absdate, abstime", absdate, abstime + if absdate < 1: + raise RangeError, "underflow while adding" + + return DateTimeFromAbsDateTime(absdate, abstime) + +# Constants +mjd0 = DateTime(1858, 11, 17) +jdn0 = DateTime(-4713, 1, 1, 12, 0, 0.0) + +# Other DateTime constructors + +def DateTimeFromCOMDate(comdate): + + absdate = int(comdate) + abstime = (comdate - float(absdate)) * 86400.0 + if abstime < 0.0: + abstime = -abstime + absdate = absdate + 693594; + dt = DateTimeFromAbsDateTime(absdate, abstime) + dt.comdate = comdate + return dt + +def DateTimeFromAbsDateTime(absdate, abstime): + + # Create the object without calling its default constructor + dt = createEmptyObject(DateTime) + + # Init. the object + abstime=1.0 * abstime + if abstime < 0 and abstime > -0.001: abstime = 0.0 + if not (absdate > 0): + raise RangeError, "absdate out of range (>0)" + if not (abstime >= 0.0 and abstime <= 86400.0): + raise RangeError, "abstime out of range (0.0 - 86400.0) <%s>" % abstime + + dt.absdate=absdate + dt.abstime=abstime + + #calculate com date + comdate = 1.0 * (dt.absdate - 693594) + if comdate < 0.0: + comdate = comdate - dt.abstime / 86400.0 + else: + comdate = comdate + dt.abstime / 86400.0 + dt.comdate = comdate + + #calculate the date + #print "absdate=", absdate + year = int((1.0 * absdate) / 365.2425) + + #newApproximation: + while 1: + #print "year=", year + yearoffset = year * 365 + year / 4 - year / 100 + year / 400 + #print "yearoffset=", yearoffset + #print "absdate=", absdate + if yearoffset >= absdate: + year = year - 1 + #print "year = ", year + continue #goto newApproximation + + year = year + 1 + leap = (year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0)) + dayoffset = absdate - yearoffset + #print "dayoffset=", dayoffset + if dayoffset > 365 and leap == 0: + #print "dayoffset=", dayoffset + continue #goto newApproximation + + monthoffset = month_offset[leap] + for month in range(1, 13): + if monthoffset[month] >= dayoffset: + break + dt.year = year + dt.month = month + dt.day = dayoffset - month_offset[leap][month-1] + dt.day_of_week = (dt.absdate - 1) % 7 + dt.day_of_year = dayoffset + break + + #calculate the time + inttime = int(abstime) + hour = inttime / 3600 + minute = (inttime % 3600) / 60 + second = 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 = -1 + dt.tz = "???" + dt.is_leapyear = leap + dt.yearoffset = yearoffset + return dt + +def now( + 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)) + return DateTime(Y,M,D,h,m,s) + +def utc( + 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)) + return DateTime(Y,M,D,h,m,s) + +# Aliases +Date = Timestamp = DateTime + +# XXX Calendars are not supported: +def notSupported(*args,**kws): + raise Error,'calendars are not supported by the Python version of mxDateTime' +JulianDateTime = notSupported + +### DateTimeDelta class + +class DateTimeDelta: + + def __init__(self, days=0, hours=0, minutes=0, seconds=0): + + seconds = seconds + (days * 86400.0 + hours * 3600.0 + minutes * 60.0) + self.seconds = seconds + if seconds < 0.0: + seconds = -seconds + day = long(seconds / 86400.0) + seconds = seconds - (86400.0 * day) + wholeseconds = int(seconds) + hour = wholeseconds / 3600 + minute = (wholeseconds % 3600) / 60 + second = seconds - (hour * 3600.0 + minute * 60.0) + self.day = day + self.hour = hour + self.minute = minute + self.second = second + seconds=self.seconds + self.minutes = seconds / 60.0 + self.hours = seconds / 3600.0 + self.days = seconds / 86400.0 + + def __str__(self): + if self.day != 0: + if self.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: + if self.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) + return r + + def absvalues(self): + days=self.seconds / 86400 + seconds=self.seconds - (days * 86400.0) + return days, seconds + + def tuple(self): + return (self.day, self.hour, self.minute, self.second) + + def strftime(self, format_string): + raise NotImplementedError + + def __int__(self): + return int(self.seconds) + + def __float__(self): + return self.seconds + + def __cmp__(self, other, accuracy=0.0): + if (type(other) == types.InstanceType + and other.__class__ == DateTimeDelta): + + diff=self.seconds - other.seconds + if abs(diff) > accuracy: + if diff > 0: return 1 + return -1 + + elif type(other) == types.FloatType: + diff=self.seconds - other + if abs(diff) > accuracy: + if diff > 0: return 1 + return -1 + + elif type(other) == types.IntType: + diff=self.seconds - other + if abs(diff) > accuracy: + if diff > 0: return 1 + return -1 + + return 0 + + def __getattr__(self, attr): + seconds=self.__dict__['seconds'] + if attr in ('hour', 'minute', 'second', 'day'): + if seconds >= 0.0: + return self.__dict__[attr] + else: + return -self.__dict__[attr] + else: + try: + return self.__dict__[attr] + except: + raise AttributeError, attr + + def __div__(self, other): + if type(other) in (types.IntType, types.FloatType): + return DateTimeDelta(0.0,0.0,0.0,self.seconds / other) + elif (type(other) == types.InstanceType + and isinstance(other,DateTimeDelta)): + return DateTimeDelta(0.0,0.0,0.0,self.seconds / other.seconds) + raise TypeError, "bad operand types for /" + + def __mul__(self, other): + if type(other) == types.IntType or type(other) == types.FloatType: + return DateTimeDelta(0.0,0.0,0.0,self.seconds * other) + else: + #print "type", type(other) + raise TypeError, "cannot multiply these two types" + + def __rmul__(self, other): + return self.__mul__(other) + + def __neg__(self): + return DateTimeDelta(0.0,0.0,0.0,-self.seconds) + + def __repr__(self): + if self.day != 0: + if self.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: + if self.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 "" % (strval, id(self)) + + def __abs__(self): + if self.seconds < 0: + return -self + return self + + def __nonzero__(self): + return self.seconds != 0.0 + + def __add__(self, other): + if type(other) == types.InstanceType: + if isinstance(other,DateTime): + return other + self + elif isinstance(other,DateTimeDelta): + return DateTimeDelta(0.0,0.0,0.0,self.seconds + other.seconds) + + # What about __radd__ ? + +# Other DateTimeDelta constructors + +def TimeDelta(hour=0.0, minute=0.0, second=0.0): + return DateTimeDelta(0.0, hours, minutes, seconds) + +Time=TimeDelta + +def DateTimeDeltaFromSeconds(seconds): + return DateTimeDelta(0.0,0.0,0.0,seconds) + +def DateTimeDeltaFromDays(days): + return DateTimeDelta(days) + +### Types + +DateTimeType = DateTime +DateTimeDeltaType = DateTimeDelta + +### Functions + +def cmp(a,b,acc): + + if isinstance(a,DateTime) and isinstance(b,DateTime): + diff = a.absdays - b.absdays + if (diff >= 0 and diff <= acc) or (diff < 0 and -diff <= acc): + return 0 + elif diff < 0: + return 1 + else: + return -1 + + elif isinstance(a,DateTimeDelta) and isinstance(b,DateTimeDelta): + diff = a.days - b.days + if (diff >= 0 and diff <= acc) or (diff < 0 and -diff <= acc): + return 0 + elif diff < 0: + return 1 + else: + return -1 + + else: + raise TypeError,"objects must be DateTime[Delta] instances"