[Python-checkins] python/nondist/sandbox/datetime datetime.py,1.95,1.96 test_datetime.py,1.65,1.66

tim_one@users.sourceforge.net tim_one@users.sourceforge.net
Wed, 11 Dec 2002 20:03:49 -0800


Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory sc8-pr-cvs1:/tmp/cvs-serv23554

Modified Files:
	datetime.py test_datetime.py 
Log Message:
Implement tzinfo.strftime() correctly.  This includes:
- Don't call utcoffset or tzname unless they're actually needed by
  the format string.
- Handle % escapes in the format string correctly.  For example,
  %%Z is the string %Z, not a % followed by a reference to the
  format code %Z.
- If %Z is used and the tzname has any % characters, escape them.

All this was a minor PITA in Python, and will be a major PITA when
rewritten in C.


Index: datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.py,v
retrieving revision 1.95
retrieving revision 1.96
diff -C2 -d -r1.95 -r1.96
*** datetime.py	12 Dec 2002 03:24:55 -0000	1.95
--- datetime.py	12 Dec 2002 04:03:47 -0000	1.96
***************
*** 161,164 ****
--- 161,193 ----
      return result
  
+ # Correctly substitute for %z and %Z escapes in strftime formats.
+ def _handle_z_escapes(format, Zreplace, zreplace):
+     result = []
+     push = result.append
+     i, n = 0, len(format)
+     while i < n:
+         ch = format[i]
+         i += 1
+         if ch == '%':
+             if i < n:
+                 ch = format[i]
+                 i += 1
+                 if ch == 'z':
+                     s = zreplace()
+                     assert '%' not in s
+                     result.append(s)
+                 elif ch == 'Z':
+                     # strftime is going to have at this, so escape %
+                     s = Zreplace().replace('%', '%%')
+                     result.append(s)
+                 else:
+                     push('%')
+                     push(ch)
+             else:
+                 push('%')
+         else:
+             push(ch)
+     return "".join(result)
+ 
  # This is a start at a struct tm workalike.  Goals:
  #
***************
*** 961,976 ****
      def _tzstr(self, sep=":"):
          """Return formatted timezone offset (+xx:xx) or None."""
!         if self.__tzinfo is not None:
!             off = self.__tzinfo.utcoffset(self)
!             if off is not None:
!                 if off < 0:
!                     sign = "-"
!                     off = -off
!                 else:
!                     sign = "+"
!                 hh, mm = divmod(off, 60)
!                 if hh >= 24:
!                     raise ValueError("utcoffset must be in -1439 .. 1439")
!                 return "%s%02d%s%02d" % (sign, hh, sep, mm)
  
      def __repr__(self):
--- 990,1005 ----
      def _tzstr(self, sep=":"):
          """Return formatted timezone offset (+xx:xx) or None."""
!         off = self.utcoffset()
!         if off is not None:
!             if off < 0:
!                 sign = "-"
!                 off = -off
!             else:
!                 sign = "+"
!             hh, mm = divmod(off, 60)
!             if hh >= 24:
!                 raise ValueError("utcoffset must be in -1439 .. 1439")
!             off = "%s%02d%s%02d" % (sign, hh, sep, mm)
!         return off
  
      def __repr__(self):
***************
*** 1002,1010 ****
          UTC offset (+zzzz).
          """
!         tz = self._tzstr(sep="")
!         if tz:
!             fmt = fmt.replace("%z", tz).replace("%Z", self.tzinfo.tzname(None))
!         else:
!             fmt = fmt.replace("%z", "").replace("%Z", "")
          return super(timetz, self).strftime(fmt)
  
--- 1031,1045 ----
          UTC offset (+zzzz).
          """
! 
!         # Don't call utcoffset or tzname unless the format string really
!         # needs them -- there's no requirement in the docs that a tzinfo
!         # object implement every method.
!         def getz():
!            return self._tzstr('') or ""
! 
!         def getZ():
!             return self.tzname() or ""
! 
!         fmt = _handle_z_escapes(fmt, getZ, getz)
          return super(timetz, self).strftime(fmt)
  

Index: test_datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_datetime.py,v
retrieving revision 1.65
retrieving revision 1.66
diff -C2 -d -r1.65 -r1.66
*** test_datetime.py	12 Dec 2002 02:55:16 -0000	1.65
--- test_datetime.py	12 Dec 2002 04:03:47 -0000	1.66
***************
*** 42,49 ****
          t3 = timetz(13, 47, tzinfo=met)
          # XXX Most of the tests here have moved into test_both.py.
!         self.assertEqual(t1.strftime("%H:%M:%S %Z %z"), "07:47:00 EST -0500")
          self.assertEqual(t2.strftime("%H:%M:%S %Z %z"), "12:47:00 UTC +0000")
          self.assertEqual(t3.strftime("%H:%M:%S %Z %z"), "13:47:00 MET +0100")
  
  
  class TestDateTime(unittest.TestCase):
--- 42,54 ----
          t3 = timetz(13, 47, tzinfo=met)
          # XXX Most of the tests here have moved into test_both.py.
!         self.assertEqual(t1.strftime("%H:%M:%S %%Z=%Z %%z=%z"),
!                                      "07:47:00 %Z=EST %z=-0500")
          self.assertEqual(t2.strftime("%H:%M:%S %Z %z"), "12:47:00 UTC +0000")
          self.assertEqual(t3.strftime("%H:%M:%S %Z %z"), "13:47:00 MET +0100")
  
+         yuck = FixedOffset(-1439, "%z %Z %%z%%Z")
+         t1 = timetz(23, 59, tzinfo=yuck)
+         self.assertEqual(t1.strftime("%H:%M %%Z='%Z' %%z='%z'"),
+                                      "23:59 %Z='%z %Z %%z%%Z' %z='-2359'")
  
  class TestDateTime(unittest.TestCase):