bug in interval2DateTimeDelta() method of TypeCast

Karsten Hilbert <[email protected]> Wed, 12 May 2004 13:15:47 +0200
Newsgroups gmane.comp.python.db.pypgsql.user,gmane.comp.gnu.medical.devel
Message-ID <[email protected]>
Dear pyPgSQL developers,

pyPgSQL assumes that PostgreSQL will not issue "mons" parts in
interval output. It does, however, if age() is used in
queries. The result of age() is, of course, not safe for
post-processing and thus shouldn't really be used. However,
pyPgSQL also works around the unsafe practice of returning
"years" parts in intervals (yes, they are 365.2425 days in
most cases but not always, think leap years).

So, to at least make pyPgSQL *work* with intervals including
"mons" I fixed interval2DateTimeDelta(). Patch attached. I
also added a comment explaining why date-date should be used
instead of age() if one intends to post-process the interval.

Please consider for inclusion.

Regards,
Karsten Hilbert, MD
GnuMed i18n coordinator
-- 
GPG key ID E4071346 @ wwwkeys.pgp.net
E167 67FD A291 2BEA 73BD  4537 78B9 A9F9 E407 1346
ZZ-pyPgSQL-interval2mxDateTimeDelta-bugfix.py (text/plain, 1.7 KB)
def interval2DateTimeDelta(self, s):
	"""Parses PostgreSQL INTERVALs.
	The expected format is [[[-]YY years] [-]DD days] [-]HH:MM:SS.ss"""
	parser = DateTime.Parser.DateTimeDeltaFromString

	ydh = s.split()
	ago = 1

	result = DateTimeDelta(0) 

	# Convert any years using 365.2425 days per year, which is PostgreSQL's
	# assumption about the number of days in a year.
	if len(ydh) > 1:
		if ydh[1].lower().startswith('year'):
			result += parser('%s days' % ((int(ydh[0]) * 365.2425),))
			ydh = ydh[2:]

	# Convert any months using 30 days per month, which is PostgreSQL's
	# assumption about the number of days in a months IF it doesn't
	# know the end or start date of the interval. If PG DOES know either
	# date it will use the correct length of the month, eg 28-31 days.
	# However, at this stage we have no way of telling which one it
	# was. If you want to work with accurate intervals (eg. post-processing
	# them) you need to use date1-date2 syntax rather than age(date1, date2)
	# in your queries.
	#
	# This is per discussion on pgsql-general:
	#  http://www.spinics.net/lists/pgsql/msg09668.html
	# Google for: >>>"interval output format" available that removes ambiguity<<<
	#
	# Note: Should a notice be provided to the user that post-processing
	#       year/month intervals is unsafe practice ?
	if len(ydh) > 1:
		if ydh[1].lower().startswith('mon'):
			result += parser('%s days' % ((int(ydh[0]) * 30),))
			ydh = ydh[2:]

	# Converts any days and adds it to the years (as an interval)
	if len(ydh) > 1:
		if ydh[1].lower().startswith('day'):
			result += parser('%s days' % (ydh[0],))
			ydh = ydh[2:]

	# Adds in the hours, minutes, seconds (as an interval)
	if len(ydh) > 0:
		result += parser(ydh[0])

	return result
signature.asc (application/pgp-signature, 248 B)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: Weitere Infos: siehe http://www.gnupg.org

iEYEAREDAAYFAkCiB2IACgkQeLmp+eQHE0ZZbgCg68qShiIb2L66L1KKIM6X75AD
sJEAn3cngP472R3yf9zTXYVksLqVV0e4
=uAn5
-----END PGP SIGNATURE-----