Re: Interval Type Mapping

Francois Girault <francois.girault-ZQ1FT/[email protected]> Fri, 9 Jan 2004 10:46:56 +0100
Newsgroups gmane.comp.python.db.pypgsql.user
Organization Clarisys Informatique
Message-ID <[email protected]>
Ooops, I've sent a buggy version of my patch :/

here is the correct one. (sorry for flooding)

On Fri, 9 Jan 2004 00:25:11 +0100
Karsten Hilbert wrote:

> > Well... I did it ! See attached patch.
> I support inclusion of the patch. Had the same problem when
> calculating due/overdue vaccinations for GnuMed.
> 
> Karsten
> -- 
> GPG key ID E4071346 @ wwwkeys.pgp.net
> E167 67FD A291 2BEA 73BD  4537 78B9 A9F9 E407 1346
> 
> 
> -------------------------------------------------------
> This SF.net email is sponsored by: Perforce Software.
> Perforce is the Fast Software Configuration Management System offering
> advanced branching capabilities and atomic changes on 50+ platforms.
> Free Eval! http://www.perforce.com/perforce/loadprog.html
> _______________________________________________
> Pypgsql-users mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/pypgsql-users
>
pypg-relativedatetime.diff (application/octet-stream, 5.9 KB)
diff -u -r pypgsql/pyPgSQL/PgSQL.py pypgsql-clarisys/pyPgSQL/PgSQL.py
--- pypgsql/pyPgSQL/PgSQL.py	2003-07-14 23:19:20.000000000 +0200
+++ pypgsql-clarisys/pyPgSQL/PgSQL.py	2004-01-09 10:40:03.000000000 +0100
@@ -427,18 +427,16 @@
 TimestampFromTicks = DateTime.TimestampFromTicks
 
 #-----------------------------------------------+
-# The DateTimeDelta type for PgInterval support |
+# The RelativeDateTime type for PgInterval support |
 #-----------------------------------------------+
 
-DateTimeDelta = DateTime.DateTimeDelta
+RelativeDateTime = DateTime.RelativeDateTime
 
 #-------------------------------+
 # Also the DateTime types	|
 #-------------------------------+
 
 DateTimeType = DateTime.DateTimeType
-DateTimeDeltaType = DateTime.DateTimeDeltaType
-DateTimeDelta = DateTime.DateTimeDelta
 
 #-----------------------------------------------------------------------+
 # Name:		DBAPITypeObject						|
@@ -548,7 +546,13 @@
 
 class TypeCache:
     """Type cache -- used to cache postgreSQL data type information."""
-
+    
+    _time_units = (
+       ( 'days', 'day'),
+        ( 'months', 'month', 'mon', 'mons' ),
+        ( 'years', 'year'),
+        )
+        
     def __init__(self, conn):
 	if noWeakRef:
 	    self.__conn = conn
@@ -560,34 +564,35 @@
     def __callback(self, o):
 	self.__conn = None
 
-    def interval2DateTimeDelta(self, s):
-	"""Parses PostgreSQL INTERVALs.
+    def interval2RelativeDateTime(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:]
-	
-	# 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
+        tokens = s.split()
+        quantity = None
+        result = RelativeDateTime()
+        for token in tokens: 
+            # looking for quantity
+            if token.isdigit() or token[0] == '-' and token[1:].isdigit():
+                quantity = int(token)
+                continue
+            # looking for unit
+            elif token.isalpha() and not quantity is None:
+                unitAttr = None
+                for unit in self._time_units:
+                    if token in unit:
+                        unitAttr = unit[0]
+                if unitAttr and not quantity is None:
+                    setattr(result, unitAttr, quantity)
+                    quantity = None
+                    continue
+            # looking for time
+            elif token.find(':') != -1:
+                hms = [ int(value) for value in token.split(':') ]
+                result.hour = hms[0]
+                result.minute= hms[1]
+                if len(hms) == 3:
+                    result.second = hms[2]
+        return result
 
     def parseArray(self, s):
 	"""Parse a PostgreSQL array strings representation.
@@ -795,11 +800,11 @@
 	    else:
 		return PgMoney(value).value
 	elif _ftv == DATETIME:
-	    if type(value) in [DateTimeType, DateTimeDeltaType]:
+	    if type(value) is DateTimeType:
 		return value
 	    else:
 		if _ftv == PG_INTERVAL:
-		    return self.interval2DateTimeDelta(value)
+                    return self.interval2RelativeDateTime(value)
 		else:
 		    return DateTime.ISO.ParseAny(value)
 	elif _ftv == BINARY:
@@ -2230,8 +2235,9 @@
 	    _j = '%s%s,' % (_j, _i._quote(1))
 	elif type(_i) is DateTimeType:
 	    _j = '%s"%s",' % (_j, _i)
-	elif type(_i) is DateTime.DateTimeDeltaType:
-	    _j = '%s"%s",' % (_j, dateTimeDelta2Interval(_i))
+        elif isinstance(value, RelativeDateTime):
+	    _j = '%s"%s",' % (_j, relativeDateTime2Interval(_i))
+
 	elif type(_i) is PgInt2Type or isinstance(_i, PgInt8Type):
 	    _j = '%s%s,' % (_j, str(_i))
 	else:
@@ -2255,8 +2261,8 @@
 	return value._quote()
     elif type(value) is DateTimeType:
 	return "'%s'" % value
-    elif type(value) is DateTimeDeltaType:
-	return "'%s'" % dateTimeDelta2Interval(value)
+    elif isinstance(value, RelativeDateTime):
+        return "'%s'" % relativeDateTime2Interval(value)
     elif isinstance(value, StringType):
 	return PgQuoteString(value)
     elif isinstance(value, LongType):
@@ -2286,28 +2292,19 @@
 
     return t
 
-def dateTimeDelta2Interval(interval):
+def relativeDateTime2Interval(interval):
     """
-DateTimeDelta2Interval - Converts a DateTimeDelta to an interval string\n
-    The input format is [+-]DD:HH:MM:SS.ss\n
-    The output format is DD days HH:MM:SS.ss [ago]\n
+relativeDateTime2Interval - Converts a RelativeDateTime to an interval string\n
+    The output format is YYYY years M mons DD days HH:MM:SS\n
     """
-
-    if type(interval) is DateTimeDeltaType:
-	s = str(interval)
-	ago = ''
-	if s[0] == '-':
-	    ago = ' ago'
-	    s = s[1:]
-	else:
-	    ago = ''
-	s = s.split(':')
-	if len(s) < 4:
-	    return '%s:%s:%s %s' % (s[0], s[1], s[2], ago)
-
-	return '%s days %s:%s:%s %s' % (s[0], s[1], s[2], s[3], ago)
-    else:
-	raise TypeException, "DateTimeDelta2Interval requires a DataTimeDelta."
+    return "%s years %s mons %s days %02i:%02i:%02i" % (
+            interval.years,
+            interval.months,
+            interval.days,
+            interval.hours,
+            interval.minutes,
+            interval.seconds
+            )
 
 #-----------------------------------------------------------------------+
 # Name:		Connection						|