diff -Naur roundup.orig/roundup/configuration.py roundup/roundup/configuration.py
--- roundup.orig/roundup/configuration.py	2006-02-08 04:47:28.000000000 +0100
+++ roundup/roundup/configuration.py	2006-04-04 20:17:41.000000000 +0200
@@ -12,6 +12,8 @@
 import logging, logging.config
 import sys
 
+import roundup.date
+
 # XXX i don't think this module needs string translation, does it?
 
 ### Exceptions
@@ -394,6 +396,15 @@
     class_description = FilePathOption.class_description
     # everything else taken from NullableOption (inheritance order)
 
+class TimezoneOption(Option):
+    def str2value(self, value):
+        try:
+            roundup.date.get_timezone(value)
+        except KeyError:
+            raise OptionValueError(self, value,
+                    "Timezone name or numeric hour offset required")
+        return value
+
 ### Main configuration layout.
 # Config is described as a sequence of sections,
 # where each section name is followed by a sequence
@@ -450,12 +461,9 @@
             "If you wish to make them xhtml, then you'll need to change this\n"
             "var to 'xhtml' too so all auto-generated HTML is compliant.\n"
             "Allowed values: html4, xhtml"),
-        # It seems to me that all timezone offsets in the modern world
-        # are integral hours.  However, there were fractional hour offsets
-        # in the past.  Use float number for sure.
-        (FloatNumberOption, "timezone", "0",
-            "Numeric timezone offset used when users do not choose their own\n"
-            "in their settings.",
+        (TimezoneOption, "timezone", "utc",
+            "Timezone name (UTC, Europe/Warsaw, etc.) or numeric timezone\n"
+            "offset used when users do not choose their own in their settings.",
             ["DEFAULT_TIMEZONE"]),
         (BooleanOption, "instant_registration", "no",
             "Register new users instantly, or require confirmation via\n"
diff -Naur roundup.orig/roundup/date.py roundup/roundup/date.py
--- roundup.orig/roundup/date.py	2006-04-03 18:39:37.000000000 +0200
+++ roundup/roundup/date.py	2006-04-04 17:30:13.000000000 +0200
@@ -23,6 +23,7 @@
 
 import time, re, calendar
 import i18n
+import pytz
 
 try:
     import datetime
@@ -52,6 +53,32 @@
     (\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d?(\.\d+)?)
 ''', re.VERBOSE)
 
+def get_timezone(tz):
+    # try integer offset first for backward compatibility
+    try:
+        utcoffset = int(tz)
+        
+        # Etc/GMT* zones follow POSIX-style signedness, so GMT+4 corresponds
+        # to 4 hours _behind_ UTC
+        return pytz.timezone('Etc/GMT%+d' % -utcoffset)
+    except ValueError:
+        pass
+    return pytz.timezone(tz)
+
+def _utc_to_local(y,m,d,H,M,S,tz):
+    TZ = get_timezone(tz)
+    frac = S - int(S)
+    dt = datetime.datetime(y, m, d, H, M, int(S), tzinfo=pytz.utc)
+    y,m,d,H,M,S = dt.astimezone(TZ).timetuple()[:6]
+    S = S + frac
+    return (y,m,d,H,M,S)
+
+def _local_to_utc(y,m,d,H,M,S,tz):
+    TZ = get_timezone(tz)
+    dt = datetime.datetime(y,m,d,H,M,int(S))
+    y,m,d,H,M,S = TZ.localize(dt).utctimetuple()[:6]
+    return (y,m,d,H,M,S)
+
 class Date:
     '''
     As strings, date-and-time stamps are specified with the date in
@@ -158,9 +185,8 @@
             y,m,d,H,M,S,x,x,x = spec
             if y < 1970: raise ValueError, 'year must be > 1970'
             frac = S - int(S)
-            ts = calendar.timegm((y,m,d,H+offset,M,S,0,0,0))
             self.year, self.month, self.day, self.hour, self.minute, \
-                self.second, x, x, x = time.gmtime(ts)
+                self.second = _local_to_utc(y, m, d, H, M, S, offset)
             # we lost the fractional part
             self.second = self.second + frac
         except:
@@ -199,6 +225,9 @@
         # gmtime loses the fractional seconds
         S = S + frac
 
+        # whether we need to convert to UTC
+        adjust = False
+
         if info['y'] is not None or info['a'] is not None:
             if info['y'] is not None:
                 y = int(info['y'])
@@ -211,16 +240,18 @@
             if info['a'] is not None:
                 m = int(info['a'])
                 d = int(info['b'])
-            H = -offset
+            H = 0
             M = S = 0
+            adjust = True
 
         # override hour, minute, second parts
         if info['H'] is not None and info['M'] is not None:
-            H = int(info['H']) - offset
+            H = int(info['H'])
             M = int(info['M'])
             S = 0
             if info['S'] is not None:
                 S = float(info['S'])
+            adjust = True
 
         if add_granularity:
             S = S - 1
@@ -228,8 +259,11 @@
         # now handle the adjustment of hour
         frac = S - int(S)
         ts = calendar.timegm((y,m,d,H,M,S,0,0,0))
+        y, m, d, H, M, S, x, x, x = time.gmtime(ts)
+        if adjust:
+            y, m, d, H, M, S = _local_to_utc(y, m, d, H, M, S, offset)
         self.year, self.month, self.day, self.hour, self.minute, \
-            self.second, x, x, x = time.gmtime(ts)
+            self.second = y, m, d, H, M, S
         # we lost the fractional part along the way
         self.second = self.second + frac
 
@@ -396,8 +430,9 @@
     def local(self, offset):
         """ Return this date as yyyy-mm-dd.hh:mm:ss in a local time zone.
         """
-        return Date((self.year, self.month, self.day, self.hour + offset,
-            self.minute, self.second, 0, 0, 0), translator=self.translator)
+        y, m, d, H, M, S = _utc_to_local(self.year, self.month, self.day,
+                self.hour, self.minute, self.second, offset)
+        return Date((y, m, d, H, M, S, 0, 0, 0), translator=self.translator)
 
     def __deepcopy__(self, memo):
         return Date((self.year, self.month, self.day, self.hour,
diff -Naur roundup.orig/roundup/hyperdb.py roundup/roundup/hyperdb.py
--- roundup.orig/roundup/hyperdb.py	2006-04-03 18:39:37.000000000 +0200
+++ roundup/roundup/hyperdb.py	2006-04-03 18:47:55.000000000 +0200
@@ -78,7 +78,7 @@
         return db.getUserTimezone ()
     def from_raw(self, value, db, **kw):
         try:
-            value = date.Date(value).local(-self.offset(db))
+            value = date.Date(value, self.offset(db))
         except ValueError, message:
             raise HyperdbValueError, 'property %s: %r is an invalid '\
                 'date (%s)'%(kw['propname'], value, message)
diff -Naur roundup.orig/roundup/roundupdb.py roundup/roundup/roundupdb.py
--- roundup.orig/roundup/roundupdb.py	2006-01-27 03:39:42.000000000 +0100
+++ roundup/roundup/roundupdb.py	2006-04-04 20:30:52.000000000 +0200
@@ -71,12 +71,17 @@
         If no such property exists return 0
         """
         userid = self.getuid()
+        timezone = None
         try:
-            timezone = int(self.user.get(userid, 'timezone'))
-        except (KeyError, ValueError, TypeError):
-            # If there is no class 'user' or current user doesn't have timezone
-            # property or that property is not numeric assume he/she lives in
-            # Greenwich :)
+            tz = self.user.get(userid, 'timezone')
+            date.get_timezone(tz)
+            timezone = tz
+        except KeyError:
+            pass
+        # If there is no class 'user' or current user doesn't have timezone
+        # property or that property is not set assume he/she lives in
+        # timezone specified by DEFAULT_TIMEZONE or Greenwich :)
+        if timezone is None:
             timezone = getattr(self.config, 'DEFAULT_TIMEZONE', 0)
         return timezone
 
diff -Naur roundup.orig/test/test_dates.py roundup/test/test_dates.py
--- roundup.orig/test/test_dates.py	2006-04-03 18:39:37.000000000 +0200
+++ roundup/test/test_dates.py	2006-04-04 17:30:13.000000000 +0200
@@ -20,7 +20,7 @@
 
 import unittest, time
 
-from roundup.date import Date, Interval, Range, fixTimeOverflow
+from roundup.date import Date, Interval, Range, fixTimeOverflow, get_timezone
 
 class DateTestCase(unittest.TestCase):
     def testDateInterval(self):
@@ -390,6 +390,35 @@
         d = datetime.datetime.now()
         Date(d)
 
+    def testTZ(self):
+        ae = self.assertEqual
+        tz = 'Europe/Warsaw'
+
+        # local to utc, DST
+        date = Date('2006-04-04.12:00:00', tz)
+        ae(str(date), '2006-04-04.10:00:00')
+
+        # local to utc, no DST
+        date = Date('2006-01-01.12:00:00', tz)
+        ae(str(date), '2006-01-01.11:00:00')
+
+        # utc to local, DST
+        date = Date('2006-04-04.10:00:00')
+        date = date.local(tz)
+        ae(str(date), '2006-04-04.12:00:00')
+
+        # utc to local, no DST
+        date = Date('2006-01-01.10:00:00')
+        date = date.local(tz)
+        ae(str(date), '2006-01-01.11:00:00')
+
+        date = Date('2006-04-04.12:00:00')
+        date = Date(date, tz)
+        ae(str(date), '2006-04-04.10:00:00')
+        date = Date('2006-01-01.12:00:00')
+        date = Date(date, tz)
+        ae(str(date), '2006-01-01.11:00:00')
+
 def test_suite():
     suite = unittest.TestSuite()
     suite.addTest(unittest.makeSuite(DateTestCase))

 	  	 
