diff -r a721966779be -r cba9f175da2d embedded/mx/DateTime/DateTime.py --- a/embedded/mx/DateTime/DateTime.py Thu May 07 16:33:22 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1054 +0,0 @@ -""" Python part of the low-level DateTime[Delta] type implementation. - - Copyright (c) 1998-2001, 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. All Rights Reserved. -""" -# Import the python implementation module -from mxDateTime_python import * -from mxDateTime_python import __version__ - -# Singletons -oneSecond = DateTimeDelta(0,0,0,1) -oneMinute = DateTimeDelta(0,0,1) -oneHour = DateTimeDelta(0,1) -oneDay = DateTimeDelta(1) -oneWeek = DateTimeDelta(7) -Epoch = DateTimeFromAbsDateTime(1,0) - -# Shortcuts for pickle; for backward compatibility only (they are now -# defined in __init__.py to further reduce the pickles length) -def _DT(absdate,abstime): - return DateTimeFromAbsDateTime(absdate,abstime) -def _DTD(seconds): - return DateTimeDeltaFromSeconds(seconds) - -# Module init -class modinit: - - global _time,_string,_math,_types - import time,string,math,types - _time = time - _string = string - _math = math - _types = types - -del modinit - -### Helpers - -def _isstring(arg, - - isinstance=isinstance, types=_types): - - if isinstance(arg, types.StringType): - return 1 - try: - if isinstance(arg, types.UnicodeType): - return 1 - except AttributeError: - pass - return 0 - -### Compatibility APIs - -# Aliases and functions to make 'from mx.DateTime import *' work much -# like 'from time import *' - -def localtime(ticks=None, - # Locals: - time=_time.time,float=float,localtime=_time.localtime, - round=round,int=int,DateTime=DateTime,floor=_math.floor): - - """localtime(ticks=None) - - Construct a DateTime instance using local time from ticks. If - ticks are not given, it defaults to the current time. The - result is similar to time.localtime(). Fractions of a second - are rounded to the nearest micro-second. - - """ - if ticks is None: - ticks = time() - else: - ticks = float(ticks) - ticks = round(ticks, 6) - fticks = floor(ticks) - Y,M,D,h,m,s = localtime(fticks)[:6] - s = s + (ticks - fticks) - return DateTime(Y,M,D,h,m,s) - -def gmtime(ticks=None, - # Locals: - time=_time.time,float=float,gmtime=_time.gmtime, - round=round,int=int,DateTime=DateTime,floor=_math.floor): - - """gmtime(ticks=None) - - Construct a DateTime instance using UTC time from ticks. If - ticks are not given, it defaults to the current time. The - result is similar to time.gmtime(). Fractions of a second are - rounded to the nearest micro-second. - - """ - if ticks is None: - ticks = time() - else: - ticks = float(ticks) - ticks = round(ticks, 6) - fticks = floor(ticks) - Y,M,D,h,m,s = gmtime(ticks)[:6] - s = s + (ticks - fticks) - return DateTime(Y,M,D,h,m,s) - -def mktime((year,month,day,hour,minute,second,dow,doy,dst), - # Locals: - DateTime=DateTime): - - """mktime((year,month,day,hour,minute,second,dow,doy,dst)) - - Same as the DateTime() constructor accept that the interface - used is compatible to the similar time.mktime() API. - - Note that the tuple elements dow, doy and dst are not used in - any way. - - """ - return DateTime(year,month,day,hour,minute,second) - -def ctime(datetime): - - """ctime(datetime) - - Returns a string representation of the given DateTime instance - using the current locale's default settings. - - """ - return datetime.strftime('%c') - -def today(hour=0,minute=0,second=0.0, - # Locals: - localtime=_time.localtime,time=_time.time,DateTime=DateTime): - - """today(hour=0,minute=0,second=0.0) - - Returns a DateTime instance for today (in local time) at the - given time (defaults to midnight). - - """ - Y,M,D = localtime(time())[:3] - return DateTime(Y,M,D,hour,minute,second) - -def TimeDelta(hours=0.0,minutes=0.0,seconds=0.0, - # Locals: - DateTimeDelta=DateTimeDelta): - - """TimeDelta(hours=0.0,minutes=0.0,seconds=0.0) - - Returns a DateTimeDelta-object reflecting the given time - delta. Seconds can be given as float to indicate fractions. - - """ - return DateTimeDelta(0,hours,minutes,seconds) - -def gm2local(datetime): - - """ gm2local(datetime) - - Convert a DateTime instance holding UTC time to a DateTime - instance using local time. - - """ - return localtime(datetime.gmticks()) - -def local2gm(datetime): - - """ local2gm(datetime) - - Convert a DateTime instance holding local time to a DateTime - instance using UTC time. - - """ - return gmtime(datetime.ticks()) - -# Alias -gmt = utc - -# Default value for DateTimeFromTJD's tjd_myriad parameter -current_myriad = localtime().tjd_myriad - -def DateTimeFromTJD(tjd,tjd_myriad=current_myriad): - - """ DateTimeFromTJD(tjd[,myriad]) - - Return a DateTime instance for the given Truncated Julian Day. - myriad defaults to the TJD myriad current at package import - time. - - Note that this version of Truncated Julian Day number does - real truncation of important information. It's use is - discouraged and unsupported. - - """ - return DateTimeFromAbsDays(tjd + tjd_myriad * 10000.0 - 1721425.0) - -def DateTimeFromJDN(jdn): - - """ DateTimeFromJDN(jdn) - - Return a DateTime instance for the given Julian Day Number. - - References: - ----------- - Gregorian 2000-01-01 12:00:00 corresponds to JDN 2451545.0. - Gregorian 1858-11-17 00:00:00.00 corresponds to JDN 2400000.5; MJD 0.0. - Julian -4712-01-01 12:00:00.00 corresponds to JDN 0.0. - Gregorian -4713-11-24 12:00:00.00 corresponds to JDN 0.0. - - """ - return DateTimeFromAbsDays(jdn - 1721425.5) - -def DateTimeFromMJD(mjd): - - """ DateTimeFromMJD(mjd) - - Return a DateTime instance for the given Modified Julian Day - (MJD). The MJD is calculated the same way as the JDN except - that 1858-11-17 00:00:00.00 is taken as origin of the scale. - - """ - return DateTimeFromAbsDays(mjd + 678575.0) - -def DateTimeFrom(*args, **kws): - - """ DateTimeFrom(*args, **kws) - - Generic DateTime instance constructor. Can handle parsing - strings, numbers and keywords. - - XXX Add support for Unicode. - - """ - if len(args) == 1: - # Single argument - arg = args[0] - argtype = type(arg) - if _isstring(arg): - import Parser - return apply(Parser.DateTimeFromString, args, kws) - elif argtype is DateTimeType: - return arg - elif argtype is DateTimeDeltaType: - raise TypeError,'cannot convert DateTimeDelta to DateTime' - else: - try: - value = float(arg) - except (TypeError, ValueError): - value = int(arg) - assert not kws - return DateTimeFromTicks(value) - - elif len(args) > 1: - # More than one argument - if len(args) == 2 and _isstring(args[0]) and _isstring(args[1]): - # interpret as date and time string - import Parser - return apply(Parser.DateTimeFromString, - (args[0] + ' ' + args[1],), - kws) - - # Assume the arguments are the same as for DateTime() - return apply(DateTime, args, kws) - - elif len(kws) > 0: - # Keyword arguments; add defaults... today at 0:00:00 - hour = kws.get('hour',0) - minute = kws.get('minute',0) - second = kws.get('second',0) - today = now() - day = kws.get('day',today.day) - month = kws.get('month',today.month) - year = kws.get('year',today.year) - return DateTime(year,month,day,hour,minute,second) - - else: - raise TypeError,'cannot convert arguments to DateTime' - -def DateTimeDeltaFrom(*args, **kws): - - """ DateTimeDeltaFrom(*args, **kws) - - Generic DateTimeDelta instance constructor. Can handle parsing - strings, numbers and keywords. - - XXX Add support for Unicode. - - """ - if len(args) == 1: - # Single argument - arg = args[0] - if _isstring(arg): - import Parser - return apply(Parser.DateTimeDeltaFromString, args, kws) - elif type(arg) is DateTimeDeltaType: - return arg - elif type(arg) is DateTimeType: - raise TypeError,'cannot convert DateTime to DateTimeDelta' - else: - try: - value = float(arg) - except TypeError: - value = int(arg) - assert not kws - return DateTimeDeltaFromSeconds(value) - - elif len(args) > 1: - # Assume the arguments are the same as for DateTimeDelta() - return apply(DateTimeDelta, args, kws) - - elif len(kws) > 0: - # Keyword arguments; default: 00:00:00:00.00 - hours = kws.get('hours',0) - minutes = kws.get('minutes',0) - seconds = kws.get('seconds',0.0) - days = kws.get('days',0) - return DateTimeDelta(days,hours,minutes,seconds) - - else: - raise TypeError,'cannot convert arguments to DateTimeDelta' - -def TimeDeltaFrom(*args, **kws): - - """ TimeDeltaFrom(*args, **kws) - - Generic TimeDelta instance constructor. Can handle parsing - strings, numbers and keywords. - - XXX Add support for Unicode. - - """ - if len(args) > 1: - # Assume the arguments are the same as for TimeDelta(): without - # days part ! - return apply(DateTimeDelta, (0,)+args, kws) - else: - # Otherwise treat the arguments just like for DateTimeDelta - # instances. - return apply(DateTimeDeltaFrom, args, kws) - -def DateFromTicks(ticks, - # Locals: - DateTime=DateTime,localtime=_time.localtime): - - """ DateFromTicks(ticks) - - Constructs a DateTime instance pointing to the local time date - at 00:00:00.00 (midnight) indicated by the given ticks value. - The time part is ignored. - - """ - return apply(DateTime, localtime(ticks)[:3]) - -def TimestampFromTicks(ticks, - # Locals: - DateTime=DateTime,localtime=_time.localtime): - - """ TimestampFromTicks(ticks) - - Constructs a DateTime instance pointing to the local date and - time indicated by the given ticks value. - - """ - return apply(DateTime, localtime(ticks)[:6]) - -def TimeFromTicks(ticks, - # Locals: - DateTimeDelta=DateTimeDelta,localtime=_time.localtime): - - """ TimeFromTicks(ticks) - - Constructs a DateTimeDelta instance pointing to the local time - indicated by the given ticks value. The date part is ignored. - - """ - return apply(DateTimeDelta, (0,) + localtime(ticks)[3:6]) - -# Aliases -utctime = gmtime -utc2local = gm2local -local2utc = local2gm -DateTimeFromTicks = localtime -Date = DateTime -Time = TimeDelta -Timestamp = DateTime -DateFrom = DateTimeFrom # XXX should only parse the date part ! -TimeFrom = TimeDeltaFrom -TimestampFrom = DateTimeFrom -GregorianDateTime = DateTime -GregorianDate = Date -JulianDate = JulianDateTime - - -### For backward compatibility (these are depreciated): - -def gmticks(datetime): - - """gmticks(datetime) - - [DEPRECIATED: use the .gmticks() method] - - Returns a ticks value based on the values stored in - datetime under the assumption that they are given in UTC, - rather than local time. - - """ - return datetime.gmticks() - -# Alias -utcticks = gmticks - -def tz_offset(datetime, - # Locals: - oneSecond=oneSecond): - - """tz_offset(datetime) - - [DEPRECIATED: use the .gmtoffset() method] - - Returns a DateTimeDelta instance representing the UTC - offset for datetime assuming that the stored values refer - to local time. If you subtract this value from datetime, - you'll get UTC time. - - """ - return datetime.gmtoffset() - -### Constants (only English; see Locale.py for other languages) - -# Weekdays -Monday = 0 -Tuesday = 1 -Wednesday = 2 -Thursday = 3 -Friday = 4 -Saturday = 5 -Sunday = 6 -# as mapping -Weekday = {'Saturday': 5, 6: 'Sunday', 'Sunday': 6, 'Thursday': 3, - 'Wednesday': 2, 'Friday': 4, 'Tuesday': 1, 'Monday': 0, - 5: 'Saturday', 4: 'Friday', 3: 'Thursday', 2: 'Wednesday', - 1: 'Tuesday', 0: 'Monday'} - -# Months -January = 1 -February = 2 -March = 3 -April = 4 -May = 5 -June = 6 -July = 7 -August = 8 -September = 9 -October = 10 -November = 11 -December = 12 -# as mapping -Month = {2: 'February', 3: 'March', None: 0, 'July': 7, 11: 'November', - 'December': 12, 'June': 6, 'January': 1, 'September': 9, 'August': - 8, 'March': 3, 'November': 11, 'April': 4, 12: 'December', 'May': - 5, 10: 'October', 9: 'September', 8: 'August', 7: 'July', 6: - 'June', 5: 'May', 4: 'April', 'October': 10, 'February': 2, 1: - 'January', 0: None} - -# Limits (see also the range checks in mxDateTime.c) -MaxDateTime = DateTime(5867440,12,31) -MinDateTime = DateTime(-5851455,1,1) -MaxDateTimeDelta = DateTimeDeltaFromSeconds(2147483647 * 86400.0) -MinDateTimeDelta = -MaxDateTimeDelta - -### - -class RelativeDateTime: - - """RelativeDateTime(years=0,months=0,days=0, - hours=0,minutes=0,seconds=0, - year=0,month=0,day=0, - hour=None,minute=None,second=None, - weekday=None,weeks=None) - - Returns a RelativeDateTime instance for the specified relative - time. The constructor handles keywords, so you'll only have to - give those parameters which should be changed when you add the - relative to an absolute DateTime instance. - - Adding RelativeDateTime instances is supported with the - following rules: deltas will be added together, right side - absolute values override left side ones. - - Adding RelativeDateTime instances to DateTime instances will - return DateTime instances with the appropriate calculations - applied, e.g. to get a DateTime instance for the first of next - month, you'd call now() + RelativeDateTime(months=+1,day=1). - - """ - years = 0 - months = 0 - days = 0 - year = None - month = 0 - day = 0 - hours = 0 - minutes = 0 - seconds = 0 - hour = None - minute = None - second = None - weekday = None - - # cached hash value - _hash = None - - # For Zope security: - __roles__ = None - __allow_access_to_unprotected_subobjects__ = 1 - - def __init__(self, - years=0,months=0,days=0, - hours=0,minutes=0,seconds=0, - year=None,month=None,day=None, - hour=None,minute=None,second=None, - weekday=None,weeks=0): - - self.years = years - self.months = months - self.days = days + weeks*7 - self.year = year - self.month = month - self.day = day - self.hours = hours - self.minutes = minutes - self.seconds = seconds - self.hour = hour - self.minute = minute - self.second = second - if weekday is not None: - # Make sure we've got a 2-tuple - assert len(weekday) == 2 - self.weekday = weekday - - def __add__(self,other, - # Locals: - isinstance=isinstance): - - if isinstance(other,RelativeDateTime): - # RelativeDateTime (self) + RelativeDateTime (other) - - r = RelativeDateTime() - # date deltas - r.years = self.years + other.years - r.months = self.months + other.months - r.days = self.days + other.days - # absolute entries of other override those in self, if given - r.year = other.year or self.year - r.month = other.month or self.month - r.day = other.day or self.day - r.weekday = other.weekday or self.weekday - # time deltas - r.hours = self.hours + other.hours - r.minutes = self.minutes + other.minutes - r.seconds = self.seconds + other.seconds - # absolute entries of other override those in self, if given - r.hour = other.hour or self.hour - r.minute = other.minute or self.minute - r.second = other.second or self.second - return r - - else: - raise TypeError,"can't add the two types" - - def __radd__(self,other, - # Locals: - isinstance=isinstance,DateTimeType=DateTimeType, - DateTime=DateTime,DateTimeDelta=DateTimeDelta): - - if isinstance(other,DateTimeType): - # DateTime (other) + RelativeDateTime (self) - - # date - if self.year is None: - year = other.year + self.years - else: - year = self.year + self.years - if self.month is None: - month = other.month + self.months - else: - month = self.month + self.months - if self.day is None: - day = other.day - else: - day = self.day - if day < 0: - # fix negative day values - month = month + 1 - day = day + 1 - day = day + self.days - # time - if self.hour is None: - hour = other.hour + self.hours - else: - hour = self.hour + self.hours - if self.minute is None: - minute = other.minute + self.minutes - else: - minute = self.minute + self.minutes - if self.second is None: - second = other.second + self.seconds - else: - second = self.second + self.seconds - - # Refit into proper ranges: - if month < 1 or month > 12: - month = month - 1 - yeardelta, monthdelta = divmod(month, 12) - year = year + yeardelta - month = monthdelta + 1 - - # Make sure we have integers - year = int(year) - month = int(month) - day = int(day) - - if self.weekday is None: - return DateTime(year, month, 1) + \ - DateTimeDelta(day-1,hour,minute,second) - - # Adjust to the correct weekday - day_of_week,index = self.weekday - d = DateTime(year, month, 1) + \ - DateTimeDelta(day-1,hour,minute,second) - if index == 0: - # 0 index: next weekday if no match - return d + (day_of_week - d.day_of_week) - elif index > 0: - # positive index (1 == first weekday of month) - first = d - (d.day - 1) - diff = day_of_week - first.day_of_week - if diff >= 0: - return first + (diff + (index-1) * 7) - else: - return first + (diff + index * 7) - else: - # negative index (-1 == last weekday of month) - last = d + (d.days_in_month - d.day) - diff = day_of_week - last.day_of_week - if diff <= 0: - return last + (diff + (index+1) * 7) - else: - return last + (diff + index * 7) - - else: - raise TypeError,"can't add the two types" - - def __sub__(self,other): - - if isinstance(other,RelativeDateTime): - # RelativeDateTime (self) - RelativeDateTime (other) - - r = RelativeDateTime() - # date deltas - r.years = self.years - other.years - r.months = self.months - other.months - r.days = self.days - other.days - # absolute entries of other override those in self, if given - r.year = other.year or self.year - r.month = other.month or self.month - r.day = other.day or self.day - r.weekday = other.weekday or self.weekday - # time deltas - r.hours = self.hours - other.hours - r.minutes = self.minutes - other.minutes - r.seconds = self.seconds - other.seconds - # absolute entries of other override those in self, if given - r.hour = other.hour or self.hour - r.minute = other.minute or self.minute - r.second = other.second or self.second - - return r - - else: - raise TypeError,"can't subtract the two types" - - def __rsub__(self,other, - # Locals: - isinstance=isinstance,DateTimeType=DateTimeType): - - if isinstance(other,DateTimeType): - # DateTime (other) - RelativeDateTime (self) - return other + self.__neg__() - - else: - raise TypeError,"can't subtract the two types" - - def __neg__(self): - - # - RelativeDateTime(self) - - r = RelativeDateTime() - # negate date deltas - r.years = - self.years - r.months = - self.months - r.days = - self.days - # absolute entries don't change - r.year = self.year - r.month = self.month - r.day = self.day - r.weekday = self.weekday - # negate time deltas - r.hours = - self.hours - r.minutes = - self.minutes - r.seconds = - self.seconds - # absolute entries don't change - r.hour = self.hour - r.minute = self.minute - r.second = self.second - - return r - - def __nonzero__(self): - - # RelativeDateTime instances are considered false in case - # they do not define any alterations - if (self.year is None and - self.years == 0 and - self.month is None and - self.months == 0 and - self.day is None and - self.weekday is None and - self.days == 0 and - self.hour is None and - self.hours == 0 and - self.minute is None and - self.minutes == 0 and - self.second is None and - self.seconds == 0): - return 0 - else: - return 1 - - def __mul__(self,other): - - # RelativeDateTime (self) * Number (other) - factor = float(other) - - r = RelativeDateTime() - # date deltas - r.years = factor * self.years - r.months = factor * self.months - r.days = factor * self.days - # time deltas - r.hours = factor * self.hours - r.minutes = factor * self.minutes - r.seconds = factor * self.seconds - return r - - __rmul__ = __mul__ - - def __div__(self,other): - - # RelativeDateTime (self) / Number (other) - return self.__mul__(1/float(other)) - - def __eq__(self, other): - - if isinstance(self, RelativeDateTime) and \ - isinstance(other, RelativeDateTime): - # RelativeDateTime (self) == RelativeDateTime (other) - if (self.years == other.years and - self.months == other.months and - self.days == other.days and - self.year == other.year and - self.day == other.day and - self.hours == other.hours and - self.minutes == other.minutes and - self.seconds == other.seconds and - self.hour == other.hour and - self.minute == other.minute and - self.second == other.second and - self.weekday == other.weekday): - return 1 - else: - return 0 - else: - raise TypeError,"can't compare the two types" - - def __hash__(self): - - if self._hash is not None: - return self._hash - x = 1234 - for value in (self.years, self.months, self.days, - self.year, self.day, - self.hours, self.minutes, self.seconds, - self.hour, self.minute, self.second, - self.weekday): - if value is None: - x = 135051820 ^ x - else: - x = hash(value) ^ x - self._hash = x - return x - - def __str__(self, - - join=_string.join): - - l = [] - append = l.append - - # Format date part - if self.year is not None: - append('%04i-' % self.year) - elif self.years: - append('(%0+5i)-' % self.years) - else: - append('YYYY-') - if self.month is not None: - append('%02i-' % self.month) - elif self.months: - append('(%0+3i)-' % self.months) - else: - append('MM-') - if self.day is not None: - append('%02i' % self.day) - elif self.days: - append('(%0+3i)' % self.days) - else: - append('DD') - if self.weekday: - append(' %s:%i' % (Weekday[self.weekday[0]][:3],self.weekday[1])) - append(' ') - - # Normalize relative time values to avoid fractions - hours = self.hours - minutes = self.minutes - seconds = self.seconds - hours_fraction = hours - int(hours) - minutes = minutes + hours_fraction * 60.0 - minutes_fraction = minutes - int(minutes) - seconds = seconds + minutes_fraction * 6.0 - seconds_fraction = seconds - int(seconds) - - if 0: - # Normalize to standard time ranges - if seconds > 60.0: - extra_minutes, seconds = divmod(seconds, 60.0) - minutes = minutes + extra_minutes - elif seconds < -60.0: - extra_minutes, seconds = divmod(seconds, -60.0) - minutes = minutes - extra_minutes - if minutes >= 60.0: - extra_hours, minutes = divmod(minutes, 60.0) - hours = hours + extra_hours - elif minutes <= -60.0: - extra_hours, minutes = divmod(minutes, -60.0) - hours = hours - extra_hours - - # Format time part - if self.hour is not None: - append('%02i:' % self.hour) - elif hours: - append('(%0+3i):' % hours) - else: - append('HH:') - if self.minute is not None: - append('%02i:' % self.minute) - elif minutes: - append('(%0+3i):' % minutes) - else: - append('MM:') - if self.second is not None: - append('%02i' % self.second) - elif seconds: - append('(%0+3i)' % seconds) - else: - append('SS') - - return join(l,'') - - def __repr__(self): - - return "<%s instance for '%s' at 0x%x>" % ( - self.__class__.__name__, - self.__str__(), - id(self)) - -# Alias -RelativeDate = RelativeDateTime - -def RelativeDateTimeFrom(*args, **kws): - - """ RelativeDateTimeFrom(*args, **kws) - - Generic RelativeDateTime instance constructor. Can handle - parsing strings and keywords. - - """ - if len(args) == 1: - # Single argument - arg = args[0] - if _isstring(arg): - import Parser - return apply(Parser.RelativeDateTimeFromString, args, kws) - elif isinstance(arg, RelativeDateTime): - return arg - else: - raise TypeError,\ - 'cannot convert argument to RelativeDateTime' - - else: - return apply(RelativeDateTime,args,kws) - -def RelativeDateTimeDiff(date1,date2, - - floor=_math.floor,int=int,divmod=divmod, - RelativeDateTime=RelativeDateTime): - - """ RelativeDateTimeDiff(date1,date2) - - Returns a RelativeDateTime instance representing the difference - between date1 and date2 in relative terms. - - The following should hold: - - date2 + RelativeDateDiff(date1,date2) == date1 - - for all dates date1 and date2. - - Note that due to the algorithm used by this function, not the - whole range of DateTime instances is supported; there could - also be a loss of precision. - - XXX There are still some problems left (thanks to Carel - Fellinger for pointing these out): - - 29 1 1901 -> 1 3 1901 = 1 month - 29 1 1901 -> 1 3 1900 = -10 month and -28 days, but - 29 1 1901 -> 28 2 1900 = -11 month and -1 day - - and even worse: - - >>> print RelativeDateDiff(Date(1900,3,1),Date(1901,2,1)) - YYYY-(-11)-DD HH:MM:SS - - with: - - >>> print Date(1901,1,29) + RelativeDateTime(months=-11) - 1900-03-01 00:00:00.00 - >>> print Date(1901,2,1) + RelativeDateTime(months=-11) - 1900-03-01 00:00:00.00 - - """ - diff = date1 - date2 - if diff.days == 0: - return RelativeDateTime() - date1months = date1.year * 12 + (date1.month - 1) - date2months = date2.year * 12 + (date2.month - 1) - #print 'months',date1months,date2months - - # Calculate the months difference - diffmonths = date1months - date2months - #print 'diffmonths',diffmonths - if diff.days > 0: - years,months = divmod(diffmonths,12) - else: - years,months = divmod(diffmonths,-12) - years = -years - date3 = date2 + RelativeDateTime(years=years,months=months) - diff3 = date1 - date3 - days = date1.absdays - date3.absdays - #print 'date3',date3,'diff3',diff3,'days',days - - # Correction to ensure that all relative parts have the same sign - while days * diff.days < 0: - if diff.days > 0: - diffmonths = diffmonths - 1 - years,months = divmod(diffmonths,12) - else: - diffmonths = diffmonths + 1 - years,months = divmod(diffmonths,-12) - years = -years - #print 'diffmonths',diffmonths - date3 = date2 + RelativeDateTime(years=years,months=months) - diff3 = date1 - date3 - days = date1.absdays - date3.absdays - #print 'date3',date3,'diff3',diff3,'days',days - - # Drop the fraction part of days - if days > 0: - days = int(floor(days)) - else: - days = int(-floor(-days)) - - return RelativeDateTime(years=years, - months=months, - days=days, - hours=diff3.hour, - minutes=diff3.minute, - seconds=diff3.second) - -# Aliases -RelativeDateDiff = RelativeDateTimeDiff -Age = RelativeDateTimeDiff - -### - -_current_year = now().year -_current_century, _current_year_in_century = divmod(_current_year, 100) -_current_century = _current_century * 100 - -def add_century(year, - - current_year=_current_year, - current_century=_current_century): - - """ Sliding window approach to the Y2K problem: adds a suitable - century to the given year and returns it as integer. - - The window used depends on the current year (at import time). - If adding the current century to the given year gives a year - within the range current_year-70...current_year+30 [both - inclusive], then the current century is added. Otherwise the - century (current + 1 or - 1) producing the least difference is - chosen. - - """ - if year > 99: - # Take it as-is - return year - year = year + current_century - diff = year - current_year - if diff >= -70 and diff <= 30: - return year - elif diff < -70: - return year + 100 - else: - return year - 100 - -# Reference formulas for JDN taken from the Calendar FAQ: - -def gregorian_jdn(year,month,day): - - # XXX These require proper integer division. - a = (14-month)/12 - y = year+4800-a - m = month + 12*a - 3 - return day + (306*m+5)/10 + y*365 + y/4 - y/100 + y/400 - 32045 - -def julian_jdn(year,month,day): - - # XXX These require proper integer division. - a = (14-month)/12 - y = year+4800-a - m = month + 12*a - 3 - return day + (306*m+5)/10 + y*365 + y/4 - 32083