""" 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 modulefrommxDateTime_pythonimport*frommxDateTime_pythonimport__version__# SingletonsoneSecond=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):returnDateTimeFromAbsDateTime(absdate,abstime)def_DTD(seconds):returnDateTimeDeltaFromSeconds(seconds)# Module initclassmodinit:global_time,_string,_math,_typesimporttime,string,math,types_time=time_string=string_math=math_types=typesdelmodinit### Helpersdef_isstring(arg,isinstance=isinstance,types=_types):ifisinstance(arg,types.StringType):return1try:ifisinstance(arg,types.UnicodeType):return1exceptAttributeError:passreturn0### Compatibility APIs# Aliases and functions to make 'from mx.DateTime import *' work much# like 'from time import *'deflocaltime(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. """ifticksisNone: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)returnDateTime(Y,M,D,h,m,s)defgmtime(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. """ifticksisNone: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)returnDateTime(Y,M,D,h,m,s)defmktime((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. """returnDateTime(year,month,day,hour,minute,second)defctime(datetime):"""ctime(datetime) Returns a string representation of the given DateTime instance using the current locale's default settings. """returndatetime.strftime('%c')deftoday(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]returnDateTime(Y,M,D,hour,minute,second)defTimeDelta(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. """returnDateTimeDelta(0,hours,minutes,seconds)defgm2local(datetime):""" gm2local(datetime) Convert a DateTime instance holding UTC time to a DateTime instance using local time. """returnlocaltime(datetime.gmticks())deflocal2gm(datetime):""" local2gm(datetime) Convert a DateTime instance holding local time to a DateTime instance using UTC time. """returngmtime(datetime.ticks())# Aliasgmt=utc# Default value for DateTimeFromTJD's tjd_myriad parametercurrent_myriad=localtime().tjd_myriaddefDateTimeFromTJD(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. """returnDateTimeFromAbsDays(tjd+tjd_myriad*10000.0-1721425.0)defDateTimeFromJDN(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. """returnDateTimeFromAbsDays(jdn-1721425.5)defDateTimeFromMJD(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. """returnDateTimeFromAbsDays(mjd+678575.0)defDateTimeFrom(*args,**kws):""" DateTimeFrom(*args, **kws) Generic DateTime instance constructor. Can handle parsing strings, numbers and keywords. XXX Add support for Unicode. """iflen(args)==1:# Single argumentarg=args[0]argtype=type(arg)if_isstring(arg):importParserreturnapply(Parser.DateTimeFromString,args,kws)elifargtypeisDateTimeType:returnargelifargtypeisDateTimeDeltaType:raiseTypeError,'cannot convert DateTimeDelta to DateTime'else:try:value=float(arg)except(TypeError,ValueError):value=int(arg)assertnotkwsreturnDateTimeFromTicks(value)eliflen(args)>1:# More than one argumentiflen(args)==2and_isstring(args[0])and_isstring(args[1]):# interpret as date and time stringimportParserreturnapply(Parser.DateTimeFromString,(args[0]+' '+args[1],),kws)# Assume the arguments are the same as for DateTime()returnapply(DateTime,args,kws)eliflen(kws)>0:# Keyword arguments; add defaults... today at 0:00:00hour=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)returnDateTime(year,month,day,hour,minute,second)else:raiseTypeError,'cannot convert arguments to DateTime'defDateTimeDeltaFrom(*args,**kws):""" DateTimeDeltaFrom(*args, **kws) Generic DateTimeDelta instance constructor. Can handle parsing strings, numbers and keywords. XXX Add support for Unicode. """iflen(args)==1:# Single argumentarg=args[0]if_isstring(arg):importParserreturnapply(Parser.DateTimeDeltaFromString,args,kws)eliftype(arg)isDateTimeDeltaType:returnargeliftype(arg)isDateTimeType:raiseTypeError,'cannot convert DateTime to DateTimeDelta'else:try:value=float(arg)exceptTypeError:value=int(arg)assertnotkwsreturnDateTimeDeltaFromSeconds(value)eliflen(args)>1:# Assume the arguments are the same as for DateTimeDelta()returnapply(DateTimeDelta,args,kws)eliflen(kws)>0:# Keyword arguments; default: 00:00:00:00.00hours=kws.get('hours',0)minutes=kws.get('minutes',0)seconds=kws.get('seconds',0.0)days=kws.get('days',0)returnDateTimeDelta(days,hours,minutes,seconds)else:raiseTypeError,'cannot convert arguments to DateTimeDelta'defTimeDeltaFrom(*args,**kws):""" TimeDeltaFrom(*args, **kws) Generic TimeDelta instance constructor. Can handle parsing strings, numbers and keywords. XXX Add support for Unicode. """iflen(args)>1:# Assume the arguments are the same as for TimeDelta(): without# days part !returnapply(DateTimeDelta,(0,)+args,kws)else:# Otherwise treat the arguments just like for DateTimeDelta# instances.returnapply(DateTimeDeltaFrom,args,kws)defDateFromTicks(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. """returnapply(DateTime,localtime(ticks)[:3])defTimestampFromTicks(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. """returnapply(DateTime,localtime(ticks)[:6])defTimeFromTicks(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. """returnapply(DateTimeDelta,(0,)+localtime(ticks)[3:6])# Aliasesutctime=gmtimeutc2local=gm2locallocal2utc=local2gmDateTimeFromTicks=localtimeDate=DateTimeTime=TimeDeltaTimestamp=DateTimeDateFrom=DateTimeFrom# XXX should only parse the date part !TimeFrom=TimeDeltaFromTimestampFrom=DateTimeFromGregorianDateTime=DateTimeGregorianDate=DateJulianDate=JulianDateTime### For backward compatibility (these are depreciated):defgmticks(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. """returndatetime.gmticks()# Aliasutcticks=gmticksdeftz_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. """returndatetime.gmtoffset()### Constants (only English; see Locale.py for other languages)# WeekdaysMonday=0Tuesday=1Wednesday=2Thursday=3Friday=4Saturday=5Sunday=6# as mappingWeekday={'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'}# MonthsJanuary=1February=2March=3April=4May=5June=6July=7August=8September=9October=10November=11December=12# as mappingMonth={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###classRelativeDateTime:"""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=0months=0days=0year=Nonemonth=0day=0hours=0minutes=0seconds=0hour=Noneminute=Nonesecond=Noneweekday=None# cached hash value_hash=None# For Zope security:__roles__=None__allow_access_to_unprotected_subobjects__=1def__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=yearsself.months=monthsself.days=days+weeks*7self.year=yearself.month=monthself.day=dayself.hours=hoursself.minutes=minutesself.seconds=secondsself.hour=hourself.minute=minuteself.second=secondifweekdayisnotNone:# Make sure we've got a 2-tupleassertlen(weekday)==2self.weekday=weekdaydef__add__(self,other,# Locals:isinstance=isinstance):ifisinstance(other,RelativeDateTime):# RelativeDateTime (self) + RelativeDateTime (other)r=RelativeDateTime()# date deltasr.years=self.years+other.yearsr.months=self.months+other.monthsr.days=self.days+other.days# absolute entries of other override those in self, if givenr.year=other.yearorself.yearr.month=other.monthorself.monthr.day=other.dayorself.dayr.weekday=other.weekdayorself.weekday# time deltasr.hours=self.hours+other.hoursr.minutes=self.minutes+other.minutesr.seconds=self.seconds+other.seconds# absolute entries of other override those in self, if givenr.hour=other.hourorself.hourr.minute=other.minuteorself.minuter.second=other.secondorself.secondreturnrelse:raiseTypeError,"can't add the two types"def__radd__(self,other,# Locals:isinstance=isinstance,DateTimeType=DateTimeType,DateTime=DateTime,DateTimeDelta=DateTimeDelta):ifisinstance(other,DateTimeType):# DateTime (other) + RelativeDateTime (self)# dateifself.yearisNone:year=other.year+self.yearselse:year=self.year+self.yearsifself.monthisNone:month=other.month+self.monthselse:month=self.month+self.monthsifself.dayisNone:day=other.dayelse:day=self.dayifday<0:# fix negative day valuesmonth=month+1day=day+1day=day+self.days# timeifself.hourisNone:hour=other.hour+self.hourselse:hour=self.hour+self.hoursifself.minuteisNone:minute=other.minute+self.minuteselse:minute=self.minute+self.minutesifself.secondisNone:second=other.second+self.secondselse:second=self.second+self.seconds# Refit into proper ranges:ifmonth<1ormonth>12:month=month-1yeardelta,monthdelta=divmod(month,12)year=year+yeardeltamonth=monthdelta+1# Make sure we have integersyear=int(year)month=int(month)day=int(day)ifself.weekdayisNone:returnDateTime(year,month,1)+ \DateTimeDelta(day-1,hour,minute,second)# Adjust to the correct weekdayday_of_week,index=self.weekdayd=DateTime(year,month,1)+ \DateTimeDelta(day-1,hour,minute,second)ifindex==0:# 0 index: next weekday if no matchreturnd+(day_of_week-d.day_of_week)elifindex>0:# positive index (1 == first weekday of month)first=d-(d.day-1)diff=day_of_week-first.day_of_weekifdiff>=0:returnfirst+(diff+(index-1)*7)else:returnfirst+(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_weekifdiff<=0:returnlast+(diff+(index+1)*7)else:returnlast+(diff+index*7)else:raiseTypeError,"can't add the two types"def__sub__(self,other):ifisinstance(other,RelativeDateTime):# RelativeDateTime (self) - RelativeDateTime (other)r=RelativeDateTime()# date deltasr.years=self.years-other.yearsr.months=self.months-other.monthsr.days=self.days-other.days# absolute entries of other override those in self, if givenr.year=other.yearorself.yearr.month=other.monthorself.monthr.day=other.dayorself.dayr.weekday=other.weekdayorself.weekday# time deltasr.hours=self.hours-other.hoursr.minutes=self.minutes-other.minutesr.seconds=self.seconds-other.seconds# absolute entries of other override those in self, if givenr.hour=other.hourorself.hourr.minute=other.minuteorself.minuter.second=other.secondorself.secondreturnrelse:raiseTypeError,"can't subtract the two types"def__rsub__(self,other,# Locals:isinstance=isinstance,DateTimeType=DateTimeType):ifisinstance(other,DateTimeType):# DateTime (other) - RelativeDateTime (self)returnother+self.__neg__()else:raiseTypeError,"can't subtract the two types"def__neg__(self):# - RelativeDateTime(self)r=RelativeDateTime()# negate date deltasr.years=-self.yearsr.months=-self.monthsr.days=-self.days# absolute entries don't changer.year=self.yearr.month=self.monthr.day=self.dayr.weekday=self.weekday# negate time deltasr.hours=-self.hoursr.minutes=-self.minutesr.seconds=-self.seconds# absolute entries don't changer.hour=self.hourr.minute=self.minuter.second=self.secondreturnrdef__nonzero__(self):# RelativeDateTime instances are considered false in case# they do not define any alterationsif(self.yearisNoneandself.years==0andself.monthisNoneandself.months==0andself.dayisNoneandself.weekdayisNoneandself.days==0andself.hourisNoneandself.hours==0andself.minuteisNoneandself.minutes==0andself.secondisNoneandself.seconds==0):return0else:return1def__mul__(self,other):# RelativeDateTime (self) * Number (other)factor=float(other)r=RelativeDateTime()# date deltasr.years=factor*self.yearsr.months=factor*self.monthsr.days=factor*self.days# time deltasr.hours=factor*self.hoursr.minutes=factor*self.minutesr.seconds=factor*self.secondsreturnr__rmul__=__mul__def__div__(self,other):# RelativeDateTime (self) / Number (other)returnself.__mul__(1/float(other))def__eq__(self,other):ifisinstance(self,RelativeDateTime)and \isinstance(other,RelativeDateTime):# RelativeDateTime (self) == RelativeDateTime (other)if(self.years==other.yearsandself.months==other.monthsandself.days==other.daysandself.year==other.yearandself.day==other.dayandself.hours==other.hoursandself.minutes==other.minutesandself.seconds==other.secondsandself.hour==other.hourandself.minute==other.minuteandself.second==other.secondandself.weekday==other.weekday):return1else:return0else:raiseTypeError,"can't compare the two types"def__hash__(self):ifself._hashisnotNone:returnself._hashx=1234forvaluein(self.years,self.months,self.days,self.year,self.day,self.hours,self.minutes,self.seconds,self.hour,self.minute,self.second,self.weekday):ifvalueisNone:x=135051820^xelse:x=hash(value)^xself._hash=xreturnxdef__str__(self,join=_string.join):l=[]append=l.append# Format date partifself.yearisnotNone:append('%04i-'%self.year)elifself.years:append('(%0+5i)-'%self.years)else:append('YYYY-')ifself.monthisnotNone:append('%02i-'%self.month)elifself.months:append('(%0+3i)-'%self.months)else:append('MM-')ifself.dayisnotNone:append('%02i'%self.day)elifself.days:append('(%0+3i)'%self.days)else:append('DD')ifself.weekday:append(' %s:%i'%(Weekday[self.weekday[0]][:3],self.weekday[1]))append(' ')# Normalize relative time values to avoid fractionshours=self.hoursminutes=self.minutesseconds=self.secondshours_fraction=hours-int(hours)minutes=minutes+hours_fraction*60.0minutes_fraction=minutes-int(minutes)seconds=seconds+minutes_fraction*6.0seconds_fraction=seconds-int(seconds)if0:# Normalize to standard time rangesifseconds>60.0:extra_minutes,seconds=divmod(seconds,60.0)minutes=minutes+extra_minuteselifseconds<-60.0:extra_minutes,seconds=divmod(seconds,-60.0)minutes=minutes-extra_minutesifminutes>=60.0:extra_hours,minutes=divmod(minutes,60.0)hours=hours+extra_hourselifminutes<=-60.0:extra_hours,minutes=divmod(minutes,-60.0)hours=hours-extra_hours# Format time partifself.hourisnotNone:append('%02i:'%self.hour)elifhours:append('(%0+3i):'%hours)else:append('HH:')ifself.minuteisnotNone:append('%02i:'%self.minute)elifminutes:append('(%0+3i):'%minutes)else:append('MM:')ifself.secondisnotNone:append('%02i'%self.second)elifseconds:append('(%0+3i)'%seconds)else:append('SS')returnjoin(l,'')def__repr__(self):return"<%s instance for '%s' at 0x%x>"%(self.__class__.__name__,self.__str__(),id(self))# AliasRelativeDate=RelativeDateTimedefRelativeDateTimeFrom(*args,**kws):""" RelativeDateTimeFrom(*args, **kws) Generic RelativeDateTime instance constructor. Can handle parsing strings and keywords. """iflen(args)==1:# Single argumentarg=args[0]if_isstring(arg):importParserreturnapply(Parser.RelativeDateTimeFromString,args,kws)elifisinstance(arg,RelativeDateTime):returnargelse:raiseTypeError,\'cannot convert argument to RelativeDateTime'else:returnapply(RelativeDateTime,args,kws)defRelativeDateTimeDiff(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-date2ifdiff.days==0:returnRelativeDateTime()date1months=date1.year*12+(date1.month-1)date2months=date2.year*12+(date2.month-1)#print 'months',date1months,date2months# Calculate the months differencediffmonths=date1months-date2months#print 'diffmonths',diffmonthsifdiff.days>0:years,months=divmod(diffmonths,12)else:years,months=divmod(diffmonths,-12)years=-yearsdate3=date2+RelativeDateTime(years=years,months=months)diff3=date1-date3days=date1.absdays-date3.absdays#print 'date3',date3,'diff3',diff3,'days',days# Correction to ensure that all relative parts have the same signwhiledays*diff.days<0:ifdiff.days>0:diffmonths=diffmonths-1years,months=divmod(diffmonths,12)else:diffmonths=diffmonths+1years,months=divmod(diffmonths,-12)years=-years#print 'diffmonths',diffmonthsdate3=date2+RelativeDateTime(years=years,months=months)diff3=date1-date3days=date1.absdays-date3.absdays#print 'date3',date3,'diff3',diff3,'days',days# Drop the fraction part of daysifdays>0:days=int(floor(days))else:days=int(-floor(-days))returnRelativeDateTime(years=years,months=months,days=days,hours=diff3.hour,minutes=diff3.minute,seconds=diff3.second)# AliasesRelativeDateDiff=RelativeDateTimeDiffAge=RelativeDateTimeDiff###_current_year=now().year_current_century,_current_year_in_century=divmod(_current_year,100)_current_century=_current_century*100defadd_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. """ifyear>99:# Take it as-isreturnyearyear=year+current_centurydiff=year-current_yearifdiff>=-70anddiff<=30:returnyearelifdiff<-70:returnyear+100else:returnyear-100# Reference formulas for JDN taken from the Calendar FAQ:defgregorian_jdn(year,month,day):# XXX These require proper integer division.a=(14-month)/12y=year+4800-am=month+12*a-3returnday+(306*m+5)/10+y*365+y/4-y/100+y/400-32045defjulian_jdn(year,month,day):# XXX These require proper integer division.a=(14-month)/12y=year+4800-am=month+12*a-3returnday+(306*m+5)/10+y*365+y/4-32083