[Zope3-checkins] SVN: Zope3/trunk/src/zope/i18n/ Fix i18n datetime construction and improve tests

Stuart Bishop stuart at stuartbishop.net
Wed Sep 7 00:46:17 EDT 2005


Log message for revision 38336:
  Fix i18n datetime construction and improve tests

Changed:
  U   Zope3/trunk/src/zope/i18n/format.py
  U   Zope3/trunk/src/zope/i18n/tests/test_formats.py

-=-
Modified: Zope3/trunk/src/zope/i18n/format.py
===================================================================
--- Zope3/trunk/src/zope/i18n/format.py	2005-09-07 04:29:43 UTC (rev 38335)
+++ Zope3/trunk/src/zope/i18n/format.py	2005-09-07 04:46:17 UTC (rev 38336)
@@ -130,6 +130,7 @@
 
         # Handle timezones
         tzinfo = None
+        pytz_tzinfo = False # If True, we should use pytz specific syntax
         tz_entry = _findFormattingCharacterInPattern('z', bin_pattern)
         if ordered[3:] != [None, None, None, None] and tz_entry:
             length = tz_entry[0][1]
@@ -137,32 +138,54 @@
             if length == 1:
                 hours, mins = int(value[:-2]), int(value[-2:])
                 delta = datetime.timedelta(hours=hours, minutes=mins)
+                # XXX: I think this is making an unpickable tzinfo.
+                # Note that StaticTzInfo is not part of the exposed pytz API.
                 tzinfo = pytz.tzinfo.StaticTzInfo()
                 tzinfo._utcoffset = delta
+                pytz_tzinfo = True
             elif length == 2:
                 hours, mins = int(value[:-3]), int(value[-2:])
                 delta = datetime.timedelta(hours=hours, minutes=mins)
+                # XXX: I think this is making an unpickable tzinfo.
+                # Note that StaticTzInfo is not part of the exposed pytz API.
                 tzinfo = pytz.tzinfo.StaticTzInfo()
                 tzinfo._utcoffset = delta
+                pytz_tzinfo = True
             else:
-                if value in pytz.all_timezones:
+                try:
                     tzinfo = pytz.timezone(value)
-                else:
+                    pytz_tzinfo = True
+                except KeyError:
                     # TODO: Find timezones using locale information
                     pass
-                    
 
         # Create a date/time object from the data
+        # If we have a pytz tzinfo, we need to invoke localize() as per
+        # the pytz documentation on creating local times.
+        # NB. If we are in an end-of-DST transition period, we have a 50%
+        # chance of getting a time 1 hour out here, but that is the price
+        # paid for dealing with localtimes.
         if ordered[3:] == [None, None, None, None]:
             return datetime.date(*[e or 0 for e in ordered[:3]])
         elif ordered[:3] == [None, None, None]:
-            return datetime.time(*[e or 0 for e in ordered[3:]],
-                                 **{'tzinfo' :tzinfo})
+            if pytz_tzinfo:
+                return tzinfo.localize(
+                    datetime.time(*[e or 0 for e in ordered[3:]])
+                    )
+            else:
+                return datetime.time(
+                    *[e or 0 for e in ordered[3:]], **{'tzinfo' :tzinfo}
+                    )
         else:
-            return datetime.datetime(*[e or 0 for e in ordered],
-                                     **{'tzinfo' :tzinfo})
+            if pytz_tzinfo:
+                return tzinfo.localize(datetime.datetime(
+                    *[e or 0 for e in ordered]
+                    ))
+            else:
+                return datetime.datetime(
+                    *[e or 0 for e in ordered], **{'tzinfo' :tzinfo}
+                    )
 
-
     def format(self, obj, pattern=None):
         "See zope.i18n.interfaces.IFormat"
         # Make or get binary form of datetime pattern
@@ -599,7 +622,7 @@
     week_in_month = (dt.day + 6 - dt.weekday()) / 7 + 1
 
     # Getting the timezone right
-    tzinfo = dt.tzinfo or pytz.reference.utc
+    tzinfo = dt.tzinfo or pytz.utc
     tz_secs = tzinfo.utcoffset(dt).seconds
     tz_secs = (tz_secs > 12*3600) and tz_secs-24*3600 or tz_secs
     tz_mins = int(math.fabs(tz_secs % 3600 / 60))

Modified: Zope3/trunk/src/zope/i18n/tests/test_formats.py
===================================================================
--- Zope3/trunk/src/zope/i18n/tests/test_formats.py	2005-09-07 04:29:43 UTC (rev 38335)
+++ Zope3/trunk/src/zope/i18n/tests/test_formats.py	2005-09-07 04:46:17 UTC (rev 38336)
@@ -302,19 +302,41 @@
         self.assertEqual(dt.tzinfo.tzname(dt), None)
 
     def testParseTimeZoneNames(self):
+        # Note that EST is a deprecated timezone name since it is a US
+        # interpretation (other countries also use the EST timezone
+        # abbreviation)
         dt = self.format.parse('01.01.2003 09:48 EST', 'dd.MM.yyyy HH:mm zzz')
-        self.assertEqual(dt.tzinfo.utcoffset(dt), datetime.timedelta(hours=-6))
+        self.assertEqual(dt.tzinfo.utcoffset(dt), datetime.timedelta(hours=-5))
         self.assertEqual(dt.tzinfo.zone, 'EST')
-        # I think this is wrong due to a bug in pytz
-        self.assertEqual(dt.tzinfo.tzname(dt), 'CST')
+        self.assertEqual(dt.tzinfo.tzname(dt), 'EST')
 
         dt = self.format.parse('01.01.2003 09:48 US/Eastern',
                                'dd.MM.yyyy HH:mm zzzz')
         self.assertEqual(dt.tzinfo.utcoffset(dt), datetime.timedelta(hours=-5))
         self.assertEqual(dt.tzinfo.zone, 'US/Eastern')
-        # I think this is wrong due to a bug in pytz
         self.assertEqual(dt.tzinfo.tzname(dt), 'EST')
 
+        dt = self.format.parse('01.01.2003 09:48 Australia/Sydney',
+                               'dd.MM.yyyy HH:mm zzzz')
+        self.assertEqual(dt.tzinfo.utcoffset(dt), datetime.timedelta(hours=11))
+        self.assertEqual(dt.tzinfo.zone, 'Australia/Sydney')
+        self.assertEqual(dt.tzinfo.tzname(dt), 'EST')
+
+        # Note that historical and future (as far as known)
+        # timezones are handled happily using the pytz timezone database
+        # US DST transition points are changing in 2007
+        dt = self.format.parse('01.04.2006 09:48 US/Eastern',
+                               'dd.MM.yyyy HH:mm zzzz')
+        self.assertEqual(dt.tzinfo.zone, 'US/Eastern')
+        self.assertEqual(dt.tzinfo.tzname(dt), 'EST')
+        self.assertEqual(dt.tzinfo.utcoffset(dt), datetime.timedelta(hours=-5))
+        dt = self.format.parse('01.04.2007 09:48 US/Eastern',
+                               'dd.MM.yyyy HH:mm zzzz')
+        self.assertEqual(dt.tzinfo.zone, 'US/Eastern')
+        self.assertEqual(dt.tzinfo.tzname(dt), 'EDT')
+        self.assertEqual(dt.tzinfo.utcoffset(dt), datetime.timedelta(hours=-4))
+
+
     def testDateTimeParseError(self):
         self.assertRaises(DateTimeParseError,
             self.format.parse, '02.01.03 21:48', 'dd.MM.yyyy HH:mm')



More information about the Zope3-Checkins mailing list