Re: Interval Type Mapping

Francois Girault <francois.girault-ZQ1FT/[email protected]> Thu, 8 Jan 2004 11:16:15 +0100
Newsgroups gmane.comp.python.db.pypgsql.user
Organization Clarisys Informatique
Message-ID <[email protected]>
Well... I did it ! See attached patch.


On Thu, 18 Dec 2003 18:29:10 +0100
Francois Girault wrote:

> Hi all,
> 
> I'm using interval data type in postgres.
> 
> pypgsql returns a DateTimeDelta instance when retrieving such values.
> 
> Is there any plan to use RelativeDateTime, cause interval <->
> DateTimeDelta is destructive on client side.
> 
> With DateTimeDelta, years can't be specified and all years haven't 365
> days. Even saying a year is  365.2425 days, working with months is worse
> :(
> 
> Any turn-around ? 
> 
> Or, if I want to do it myself, is interval2DateTimeDelta the only place
> to look at for returning RelativeDateTime instead of DateTimeDelta ?
> 
> Thanks for any help.
> 
> François 
> 
> 
> -------------------------------------------------------
> This SF.net email is sponsored by: IBM Linux Tutorials.
> Become an expert in LINUX or just sharpen your skills.  Sign up for IBM's
> Free Linux Tutorials.  Learn everything from the bash shell to sys admin.
> Click now! http://ads.osdn.com/?ad_id78&alloc_id371&op=click
> _______________________________________________
> Pypgsql-users mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/pypgsql-users
>
pypgsql-rdt.diff (application/octet-stream, 5.8 KB)
diff -r -d -u ../pypgsql/pyPgSQL/PgSQL.py pypgsql/pyPgSQL/PgSQL.py
--- ../pypgsql/pyPgSQL/PgSQL.py	2003-07-14 23:19:20.000000000 +0200
+++ pypgsql/pyPgSQL/PgSQL.py	2004-01-08 10:37:26.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 = (
+       ( 'day', 'days'),
+        ( 'month', 'mon', 'mons' ),
+        ( 'year', 'years'),
+        )
+        
     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						|