diff --unified -r roundup.patched/backends/back_anydbm.py /usr/local/lib/python2.3/site-packages/roundup/backends/back_anydbm.py
--- roundup.patched/backends/back_anydbm.py	Thu Mar  3 23:09:51 2005
+++ /usr/local/lib/python2.3/site-packages/roundup/backends/back_anydbm.py	Mon Jul 11 14:57:33 2005
@@ -1588,7 +1588,6 @@
         INTERVAL = 'spec:interval'
         OTHER = 'spec:other'
 
-        timezone = self.db.getUserTimezone()
         for k, v in filterspec.items():
             propclass = props[k]
             if isinstance(propclass, hyperdb.Link):
@@ -1619,7 +1618,7 @@
                     l.append((STRING, k, re.compile(v, re.I)))
             elif isinstance(propclass, hyperdb.Date):
                 try:
-                    date_rng = date.Range(v, date.Date, offset=timezone)
+                    date_rng = propclass.range_from_raw (v, self.db)
                     l.append((DATE, k, date_rng))
                 except ValueError:
                     # If range creation fails - ignore that search parameter
diff --unified -r roundup.patched/backends/back_metakit.py /usr/local/lib/python2.3/site-packages/roundup/backends/back_metakit.py
--- roundup.patched/backends/back_metakit.py	Thu Mar  3 23:09:36 2005
+++ /usr/local/lib/python2.3/site-packages/roundup/backends/back_metakit.py	Mon Jul 11 14:59:10 2005
@@ -1209,8 +1209,6 @@
         if __debug__:
             start_t = time.time()
 
-        timezone = self.db.getUserTimezone()
-
         where = {'_isdel':0}
         wherehigh = {}
         mlcriteria = {}
@@ -1277,7 +1275,7 @@
             elif isinstance(prop, hyperdb.Date):
                 try:
                     # Try to filter on range of dates
-                    date_rng = Range(value, date.Date, offset=timezone)
+                    date_rng = prop.range_from_raw (value, self.db)
                     if date_rng.from_value:
                         t = date_rng.from_value.get_tuple()
                         where[propname] = int(calendar.timegm(t))
diff --unified -r roundup.patched/backends/back_mysql.py /usr/local/lib/python2.3/site-packages/roundup/backends/back_mysql.py
--- roundup.patched/backends/back_mysql.py	Mon May  2 07:46:27 2005
+++ /usr/local/lib/python2.3/site-packages/roundup/backends/back_mysql.py	Mon Jul 11 14:53:55 2005
@@ -520,8 +520,6 @@
 
         cn = self.classname
 
-        timezone = self.db.getUserTimezone()
-
         # vars to hold the components of the SQL statement
         frum = ['_'+cn] # FROM clauses
         loj = []        # LEFT OUTER JOIN clauses
@@ -616,7 +614,7 @@
                 else:
                     try:
                         # Try to filter on range of dates
-                        date_rng = Range(v, date.Date, offset=timezone)
+                        date_rng = propclass.range_from_raw (v, self.db)
                         if date_rng.from_value:
                             where.append('_%s._%s >= %s'%(cn, k, a))
                             args.append(dc(date_rng.from_value))
diff --unified -r roundup.patched/backends/rdbms_common.py /usr/local/lib/python2.3/site-packages/roundup/backends/rdbms_common.py
--- roundup.patched/backends/rdbms_common.py	Mon May  2 07:47:13 2005
+++ /usr/local/lib/python2.3/site-packages/roundup/backends/rdbms_common.py	Mon Jul 11 14:53:24 2005
@@ -2046,8 +2046,6 @@
 
         cn = self.classname
 
-        timezone = self.db.getUserTimezone()
-
         # vars to hold the components of the SQL statement
         frum = []       # FROM clauses
         loj = []        # LEFT OUTER JOIN clauses
@@ -2136,7 +2134,7 @@
                 else:
                     try:
                         # Try to filter on range of dates
-                        date_rng = Range(v, date.Date, offset=timezone)
+                        date_rng = propclass.range_from_raw (v, self.db)
                         if date_rng.from_value:
                             where.append('_%s._%s >= %s'%(cn, k, a))
                             args.append(dc(date_rng.from_value))
diff --unified -r roundup.patched/cgi/templating.py /usr/local/lib/python2.3/site-packages/roundup/cgi/templating.py
--- roundup.patched/cgi/templating.py	Mon Jul 11 15:25:46 2005
+++ /usr/local/lib/python2.3/site-packages/roundup/cgi/templating.py	Mon Jul 11 15:11:28 2005
@@ -1369,6 +1369,8 @@
                 isinstance(self._value, unicode)):
             self._value.setTranslator(self._client.translator)
         self._offset = offset
+        if self._offset is None :
+            self._offset = self._prop.offset (self._db)
 
     def plain(self):
         ''' Render a "plain" representation of the property
@@ -1453,8 +1455,11 @@
             else:
                 value = date.Date(raw_value).pretty(format)
         else:
-            tz = self._db.getUserTimezone()
-            value = raw_value.local(tz)
+            if self._offset is None :
+                offset = self._db.getUserTimezone()
+            else :
+                offset = self._offset
+            value = raw_value.local(offset)
             if format is not self._marker:
                 value = value.pretty(format)
 
diff --unified -r roundup.patched/hyperdb.py /usr/local/lib/python2.3/site-packages/roundup/hyperdb.py
--- roundup.patched/hyperdb.py	Thu Mar  3 23:09:17 2005
+++ /usr/local/lib/python2.3/site-packages/roundup/hyperdb.py	Mon Jul 11 15:02:30 2005
@@ -37,24 +37,71 @@
     def __repr__(self):
         ' more useful for dumps '
         return '<%s>'%self.__class__
+    def from_raw(self, value, **kw):
+        """fix the CRLF/CR -> LF stuff"""
+        return fixNewlines(value)
 
 class Password:
     """An object designating a Password property."""
+    def __init__(self, pwre=re.compile(r'{(\w+)}(.+)')):
+        self.pwre = pwre
     def __repr__(self):
         ' more useful for dumps '
         return '<%s>'%self.__class__
+    def from_raw(self, value, pwre = None, **kw):
+        if pwre is None :
+            pwre = self.pwre
+        m = pwre.match(value)
+        if m:
+            # password is being given to us encrypted
+            p = password.Password()
+            p.scheme = m.group(1)
+            if p.scheme not in 'SHA crypt plaintext'.split():
+                raise HyperdbValueError, 'property %s: unknown encryption '\
+                    'scheme %r'%(propname, p.scheme)
+            p.password = m.group(2)
+            value = p
+        else:
+            try:
+                value = password.Password(value)
+            except password.PasswordValueError, message:
+                raise HyperdbValueError, 'property %s: %s'%(propname, message)
+        return value
 
 class Date:
     """An object designating a Date property."""
+    def __init__(self, offset = None):
+        self._offset = offset
     def __repr__(self):
         ' more useful for dumps '
         return '<%s>'%self.__class__
+    def offset (self, db) :
+        if self._offset is not None :
+            return self._offset
+        return db.getUserTimezone ()
+    def from_raw(self, value, db, **kw):
+        try:
+            value = date.Date(value).local(-self.offset(db))
+        except ValueError, message:
+            raise HyperdbValueError, 'property %s: %r is an invalid '\
+                'date (%s)'%(propname, value, message)
+        return value
+    def range_from_raw (self, value, db):
+        """return Range value from given raw value with offset correction"""
+        return date.Range(value, date.Date, offset=self.offset (db))
 
 class Interval:
     """An object designating an Interval property."""
     def __repr__(self):
         ' more useful for dumps '
         return '<%s>'%self.__class__
+    def from_raw(self, value, **kw):
+        try:
+            value = date.Interval(value)
+        except ValueError, message:
+            raise HyperdbValueError, 'property %s: %r is an invalid '\
+                'date interval (%s)'%(propname, value, message)
+        return value
 
 class Link:
     """An object designating a Link property that links to a
@@ -67,6 +114,12 @@
     def __repr__(self):
         ' more useful for dumps '
         return '<%s to "%s">'%(self.__class__, self.classname)
+    def from_raw(self, value, db, propname, **kw):
+        if value == '-1' or not value:
+            value = None
+        else:
+            value = convertLinkValue(db, propname, self, value)
+        return value
 
 class Multilink:
     """An object designating a Multilink property that links
@@ -85,18 +138,93 @@
     def __repr__(self):
         ' more useful for dumps '
         return '<%s to "%s">'%(self.__class__, self.classname)
+    def from_raw(self, value, db, klass, propname, itemid, **kw):
+        # get the current item value if it's not a new item
+        if itemid and not itemid.startswith('-'):
+            curvalue = klass.get(itemid, propname)
+        else:
+            curvalue = []
+
+        # if the value is a comma-separated string then split it now
+        if isinstance(value, type('')):
+            value = value.split(',')
+
+        # handle each add/remove in turn
+        # keep an extra list for all items that are
+        # definitely in the new list (in case of e.g.
+        # <propname>=A,+B, which should replace the old
+        # list with A,B)
+        set = 1
+        newvalue = []
+        for item in value:
+            item = item.strip()
+
+            # skip blanks
+            if not item: continue
+
+            # handle +/-
+            remove = 0
+            if item.startswith('-'):
+                remove = 1
+                item = item[1:]
+                set = 0
+            elif item.startswith('+'):
+                item = item[1:]
+                set = 0
+
+            # look up the value
+            itemid = convertLinkValue(db, propname, proptype, item)
+
+            # perform the add/remove
+            if remove:
+                try:
+                    curvalue.remove(itemid)
+                except ValueError:
+                    raise HyperdbValueError, 'property %s: %r is not ' \
+                        'currently an element'%(propname, item)
+            else:
+                newvalue.append(itemid)
+                if itemid not in curvalue:
+                    curvalue.append(itemid)
+
+        # that's it, set the new Multilink property value,
+        # or overwrite it completely
+        if set:
+            value = newvalue
+        else:
+            value = curvalue
+
+        # TODO: one day, we'll switch to numeric ids and this will be
+        # unnecessary :(
+        value = [int(x) for x in value]
+        value.sort()
+        value = [str(x) for x in value]
+        return value
 
 class Boolean:
     """An object designating a boolean property"""
     def __repr__(self):
         'more useful for dumps'
         return '<%s>' % self.__class__
+    def from_raw(self, value, **kw):
+        value = value.strip()
+        # checked is a common HTML checkbox value
+        value = value.lower() in ('checked', 'yes', 'true', 'on', '1')
+        return value
 
 class Number:
     """An object designating a numeric property"""
     def __repr__(self):
         'more useful for dumps'
         return '<%s>' % self.__class__
+    def from_raw(self, value, **kw):
+        value = value.strip()
+        try:
+            value = float(value)
+        except ValueError:
+            raise HyperdbValueError, 'property %s: %r is not a number'%(
+                propname, value)
+        return value
 #
 # Support for splitting designators
 #
@@ -597,8 +725,7 @@
     text = text.replace('\r\n', '\n')
     return text.replace('\r', '\n')
 
-def rawToHyperdb(db, klass, itemid, propname, value,
-        pwre=re.compile(r'{(\w+)}(.+)')):
+def rawToHyperdb(db, klass, itemid, propname, value, **kw):
     ''' Convert the raw (user-input) value to a hyperdb-storable value. The
         value is for the "propname" property on itemid (may be None for a
         new item) of "klass" in "db".
@@ -620,118 +747,15 @@
     # if we got a string, strip it now
     if isinstance(value, type('')):
         value = value.strip()
-
     # convert the input value to a real property value
-    if isinstance(proptype, String):
-        # fix the CRLF/CR -> LF stuff
-        value = fixNewlines(value)
-    if isinstance(proptype, Password):
-        m = pwre.match(value)
-        if m:
-            # password is being given to us encrypted
-            p = password.Password()
-            p.scheme = m.group(1)
-            if p.scheme not in 'SHA crypt plaintext'.split():
-                raise HyperdbValueError, 'property %s: unknown encryption '\
-                    'scheme %r'%(propname, p.scheme)
-            p.password = m.group(2)
-            value = p
-        else:
-            try:
-                value = password.Password(value)
-            except password.PasswordValueError, message:
-                raise HyperdbValueError, 'property %s: %s'%(propname, message)
-    elif isinstance(proptype, Date):
-        try:
-            tz = db.getUserTimezone()
-            value = date.Date(value).local(-tz)
-        except ValueError, message:
-            raise HyperdbValueError, 'property %s: %r is an invalid '\
-                'date (%s)'%(propname, value, message)
-    elif isinstance(proptype, Interval):
-        try:
-            value = date.Interval(value)
-        except ValueError, message:
-            raise HyperdbValueError, 'property %s: %r is an invalid '\
-                'date interval (%s)'%(propname, value, message)
-    elif isinstance(proptype, Link):
-        if value == '-1' or not value:
-            value = None
-        else:
-            value = convertLinkValue(db, propname, proptype, value)
-
-    elif isinstance(proptype, Multilink):
-        # get the current item value if it's not a new item
-        if itemid and not itemid.startswith('-'):
-            curvalue = klass.get(itemid, propname)
-        else:
-            curvalue = []
-
-        # if the value is a comma-separated string then split it now
-        if isinstance(value, type('')):
-            value = value.split(',')
-
-        # handle each add/remove in turn
-        # keep an extra list for all items that are
-        # definitely in the new list (in case of e.g.
-        # <propname>=A,+B, which should replace the old
-        # list with A,B)
-        set = 1
-        newvalue = []
-        for item in value:
-            item = item.strip()
-
-            # skip blanks
-            if not item: continue
-
-            # handle +/-
-            remove = 0
-            if item.startswith('-'):
-                remove = 1
-                item = item[1:]
-                set = 0
-            elif item.startswith('+'):
-                item = item[1:]
-                set = 0
-
-            # look up the value
-            itemid = convertLinkValue(db, propname, proptype, item)
-
-            # perform the add/remove
-            if remove:
-                try:
-                    curvalue.remove(itemid)
-                except ValueError:
-                    raise HyperdbValueError, 'property %s: %r is not ' \
-                        'currently an element'%(propname, item)
-            else:
-                newvalue.append(itemid)
-                if itemid not in curvalue:
-                    curvalue.append(itemid)
-
-        # that's it, set the new Multilink property value,
-        # or overwrite it completely
-        if set:
-            value = newvalue
-        else:
-            value = curvalue
-
-        # TODO: one day, we'll switch to numeric ids and this will be
-        # unnecessary :(
-        value = [int(x) for x in value]
-        value.sort()
-        value = [str(x) for x in value]
-    elif isinstance(proptype, Boolean):
-        value = value.strip()
-        # checked is a common HTML checkbox value
-        value = value.lower() in ('checked', 'yes', 'true', 'on', '1')
-    elif isinstance(proptype, Number):
-        value = value.strip()
-        try:
-            value = float(value)
-        except ValueError:
-            raise HyperdbValueError, 'property %s: %r is not a number'%(
-                propname, value)
+    value = proptype.from_raw \
+        ( value
+        , db = db
+        , klass = klass
+        , propname = propname
+        , itemid = itemid
+        , **kw
+        )
     return value
 
 class FileClass:

 	  	 
