SF patch 670012:  Compatibility changes for _strptime.py.
Patch from Brett Cannon:

    First, the 'y' directive now handles [00, 68] as a suffix for the
    21st century while [69, 99] is treated as the suffix for the 20th
    century (this is for Open Group compatibility).

    strptime now returns default values that make it a valid date ...

    the ability to pass in a regex object to use instead of a format
    string (and the inverse ability to have strptime return a regex object)
    has been removed. This is in preparation for a future patch that will
    add some caching internally to get a speed boost.
diff --git a/Lib/_strptime.py b/Lib/_strptime.py
index 90665f3..1694456 100644
--- a/Lib/_strptime.py
+++ b/Lib/_strptime.py
@@ -399,101 +399,99 @@
 
 
 def strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
-    """Return a time struct based on the input data and the format string.
-
-    The format argument may either be a regular expression object compiled by
-    strptime(), or a format string.  If False is passed in for data_string
-    then the re object calculated for format will be returned.  The re object
-    must be used with the same locale as was used to compile the re object.
-    """
+    """Return a time struct based on the input data and the format string."""
     locale_time = LocaleTime()
-    if isinstance(format, RegexpType):
-        if format.pattern.find(locale_time.lang) == -1:
-            raise TypeError("re object not created with same language as "
-                            "LocaleTime instance")
-        else:
-            compiled_re = format
-    else:
-        compiled_re = TimeRE(locale_time).compile(format)
-    if data_string is False:
-        return compiled_re
-    else:
-        found = compiled_re.match(data_string)
-        if not found:
-            raise ValueError("time data did not match format")
-        year = month = day = hour = minute = second = weekday = julian = tz =-1
-        found_dict = found.groupdict()
-        for group_key in found_dict.iterkeys():
-            if group_key == 'y':
-                year = int("%s%s" %
-                           (time.strftime("%Y")[:-2], found_dict['y']))
-            elif group_key == 'Y':
-                year = int(found_dict['Y'])
-            elif group_key == 'm':
-                month = int(found_dict['m'])
-            elif group_key == 'B':
-                month = _insensitiveindex(locale_time.f_month, found_dict['B'])
-            elif group_key == 'b':
-                month = _insensitiveindex(locale_time.a_month, found_dict['b'])
-            elif group_key == 'd':
-                day = int(found_dict['d'])
-            elif group_key is 'H':
-                hour = int(found_dict['H'])
-            elif group_key == 'I':
-                hour = int(found_dict['I'])
-                ampm = found_dict.get('p', '').lower()
-                # If there was no AM/PM indicator, we'll treat this like AM
-                if ampm in ('', locale_time.am_pm[0].lower()):
-                    # We're in AM so the hour is correct unless we're
-                    # looking at 12 midnight.
-                    # 12 midnight == 12 AM == hour 0
-                    if hour == 12:
-                        hour = 0
-                elif ampm == locale_time.am_pm[1].lower():
-                    # We're in PM so we need to add 12 to the hour unless
-                    # we're looking at 12 noon.
-                    # 12 noon == 12 PM == hour 12
-                    if hour != 12:
-                        hour += 12
-            elif group_key == 'M':
-                minute = int(found_dict['M'])
-            elif group_key == 'S':
-                second = int(found_dict['S'])
-            elif group_key == 'A':
-                weekday = _insensitiveindex(locale_time.f_weekday,
-                                            found_dict['A'])
-            elif group_key == 'a':
-                weekday = _insensitiveindex(locale_time.a_weekday,
-                                            found_dict['a'])
-            elif group_key == 'w':
-                weekday = int(found_dict['w'])
-                if weekday == 0:
-                    weekday = 6
-                else:
-                    weekday -= 1
-            elif group_key == 'j':
-                julian = int(found_dict['j'])
-            elif group_key == 'Z':
-                found_zone = found_dict['Z'].lower()
-                if locale_time.timezone[0] == locale_time.timezone[1]:
-                    pass #Deals with bad locale setup where timezone info is
-                         # the same; first found on FreeBSD 4.4.
-                elif locale_time.timezone[0].lower() == found_zone:
-                    tz = 0
-                elif locale_time.timezone[1].lower() == found_zone:
-                    tz = 1
-                elif locale_time.timezone[2].lower() == found_zone:
-                    tz = 0
-        #XXX <bc>: If calculating fxns are never exposed to the general
-        #          populous then just inline calculations.
-        if julian == -1 and year != -1 and month != -1 and day != -1:
+    compiled_re = TimeRE(locale_time).compile(format)
+    found = compiled_re.match(data_string)
+    if not found:
+        raise ValueError("time data did not match format")
+    year = 1900
+    month = day = 1
+    hour = minute = second = 0
+    tz = -1
+    # Defaulted to -1 so as to signal using functions to calc values
+    weekday = julian = -1
+    found_dict = found.groupdict()
+    for group_key in found_dict.iterkeys():
+        if group_key == 'y':
+            year = int(found_dict['y'])
+            # Open Group specification for strptime() states that a %y
+            #value in the range of [00, 68] is in the century 2000, while
+            #[69,99] is in the century 1900
+            if year <= 68:
+                year += 2000
+            else:
+                year += 1900
+        elif group_key == 'Y':
+            year = int(found_dict['Y'])
+        elif group_key == 'm':
+            month = int(found_dict['m'])
+        elif group_key == 'B':
+            month = _insensitiveindex(locale_time.f_month, found_dict['B'])
+        elif group_key == 'b':
+            month = _insensitiveindex(locale_time.a_month, found_dict['b'])
+        elif group_key == 'd':
+            day = int(found_dict['d'])
+        elif group_key is 'H':
+            hour = int(found_dict['H'])
+        elif group_key == 'I':
+            hour = int(found_dict['I'])
+            ampm = found_dict.get('p', '').lower()
+            # If there was no AM/PM indicator, we'll treat this like AM
+            if ampm in ('', locale_time.am_pm[0].lower()):
+                # We're in AM so the hour is correct unless we're
+                # looking at 12 midnight.
+                # 12 midnight == 12 AM == hour 0
+                if hour == 12:
+                    hour = 0
+            elif ampm == locale_time.am_pm[1].lower():
+                # We're in PM so we need to add 12 to the hour unless
+                # we're looking at 12 noon.
+                # 12 noon == 12 PM == hour 12
+                if hour != 12:
+                    hour += 12
+        elif group_key == 'M':
+            minute = int(found_dict['M'])
+        elif group_key == 'S':
+            second = int(found_dict['S'])
+        elif group_key == 'A':
+            weekday = _insensitiveindex(locale_time.f_weekday,
+                                        found_dict['A'])
+        elif group_key == 'a':
+            weekday = _insensitiveindex(locale_time.a_weekday,
+                                        found_dict['a'])
+        elif group_key == 'w':
+            weekday = int(found_dict['w'])
+            if weekday == 0:
+                weekday = 6
+            else:
+                weekday -= 1
+        elif group_key == 'j':
+            julian = int(found_dict['j'])
+        elif group_key == 'Z':
+            found_zone = found_dict['Z'].lower()
+            if locale_time.timezone[0] == locale_time.timezone[1]:
+                pass #Deals with bad locale setup where timezone info is
+                     # the same; first found on FreeBSD 4.4.
+            elif locale_time.timezone[0].lower() == found_zone:
+                tz = 0
+            elif locale_time.timezone[1].lower() == found_zone:
+                tz = 1
+            elif locale_time.timezone[2].lower() == found_zone:
+                tz = -1
+    #XXX <bc>: If calculating fxns are never exposed to the general
+    #populous then just inline calculations.  Also might be able to use
+    #``datetime`` and the methods it provides.
+    if julian == -1:
             julian = julianday(year, month, day)
-        if (month == -1 or day == -1) and julian != -1 and year != -1:
+    else:  # Assuming that if they bothered to include Julian day it will
+           #be accurate
             year, month, day = gregorian(julian, year)
-        if weekday == -1 and year != -1 and month != -1 and day != -1:
+    if weekday == -1:
             weekday = dayofweek(year, month, day)
-        return time.struct_time(
-            (year,month,day,hour,minute,second,weekday, julian,tz))
+    return time.struct_time((year, month, day,
+                             hour, minute, second,
+                             weekday, julian, tz))
 
 def _insensitiveindex(lst, findme):
     # Perform a case-insensitive index search.
diff --git a/Lib/test/test_strptime.py b/Lib/test/test_strptime.py
index 83c03b4..2510a90 100644
--- a/Lib/test/test_strptime.py
+++ b/Lib/test/test_strptime.py
@@ -124,6 +124,14 @@
         self.assertRaises(TypeError, _strptime.LocaleTime, timezone=range(1))
         self.assertRaises(TypeError, _strptime.LocaleTime, timezone=range(3))
 
+    def test_unknowntimezone(self):
+        # Handle timezone set to ('','') properly.
+        # Fixes bug #661354
+        locale_time = _strptime.LocaleTime(timezone=('',''))
+        self.failUnless("%Z" not in locale_time.LC_date,
+                        "when timezone == ('',''), string.replace('','%Z') is "
+                         "occuring")
+
 class TimeRETests(unittest.TestCase):
     """Tests for TimeRE."""
 
@@ -180,12 +188,19 @@
                           found.group('b')))
         for directive in ('a','A','b','B','c','d','H','I','j','m','M','p','S',
                           'U','w','W','x','X','y','Y','Z','%'):
-            compiled = self.time_re.compile("%%%s"% directive)
-            found = compiled.match(time.strftime("%%%s" % directive))
+            compiled = self.time_re.compile("%" + directive)
+            found = compiled.match(time.strftime("%" + directive))
             self.failUnless(found, "Matching failed on '%s' using '%s' regex" %
-                                    (time.strftime("%%%s" % directive),
+                                    (time.strftime("%" + directive),
                                      compiled.pattern))
 
+    def test_blankpattern(self):
+        # Make sure when tuple or something has no values no regex is generated.
+        # Fixes bug #661354
+        test_locale = _strptime.LocaleTime(timezone=('',''))
+        self.failUnless(_strptime.TimeRE(test_locale).pattern("%Z") == '',
+                        "with timezone == ('',''), TimeRE().pattern('%Z') != ''")
+
 class StrptimeTests(unittest.TestCase):
     """Tests for _strptime.strptime."""
 
@@ -198,21 +213,10 @@
         self.assertRaises(ValueError, _strptime.strptime, data_string="%d",
                           format="%A")
 
-    def test_returning_RE(self):
-        # Make sure that an re can be returned
-        strp_output = _strptime.strptime(False, "%Y")
-        self.failUnless(isinstance(strp_output, type(re.compile(''))),
-                        "re object not returned correctly")
-        self.failUnless(_strptime.strptime("1999", strp_output),
-                        "Use of re object failed")
-        bad_locale_time = _strptime.LocaleTime(lang="gibberish")
-        self.assertRaises(TypeError, _strptime.strptime, data_string='1999',
-                          format=strp_output, locale_time=bad_locale_time)
-
     def helper(self, directive, position):
         """Helper fxn in testing."""
-        strf_output = time.strftime("%%%s" % directive, self.time_tuple)
-        strp_output = _strptime.strptime(strf_output, "%%%s" % directive)
+        strf_output = time.strftime("%" + directive, self.time_tuple)
+        strp_output = _strptime.strptime(strf_output, "%" + directive)
         self.failUnless(strp_output[position] == self.time_tuple[position],
                         "testing of '%s' directive failed; '%s' -> %s != %s" %
                          (directive, strf_output, strp_output[position],
@@ -222,6 +226,14 @@
         # Test that the year is handled properly
         for directive in ('y', 'Y'):
             self.helper(directive, 0)
+        # Must also make sure %y values are correct for bounds set by Open Group
+        for century, bounds in ((1900, ('69', '99')), (2000, ('00', '68'))):
+            for bound in bounds:
+                strp_output = _strptime.strptime(bound, '%y')
+                expected_result = century + int(bound)
+                self.failUnless(strp_output[0] == expected_result,
+                                "'y' test failed; passed in '%s' "
+                                "and returned '%s'" % (bound, strp_output[0]))
 
     def test_month(self):
         # Test for month directives
@@ -262,7 +274,7 @@
         # Test timezone directives.
         # When gmtime() is used with %Z, entire result of strftime() is empty.
         # Check for equal timezone names deals with bad locale info when this
-        # occurs; first found in FreeBSD 4.4 -current
+        # occurs; first found in FreeBSD 4.4.
         time_tuple = time.localtime()
         strf_output = time.strftime("%Z")  #UTC does not have a timezone
         strp_output = _strptime.strptime(strf_output, "%Z")
@@ -274,7 +286,7 @@
         else:
             self.failUnless(strp_output[8] == -1,
                             "LocaleTime().timezone has duplicate values but "
-                             "timzone value not set to -1")
+                             "timzone value not set to 0")
 
     def test_date_time(self):
         # Test %c directive
@@ -309,6 +321,14 @@
         self.failUnless(_strptime.strptime(strf_output.capitalize(), "%B"),
                         "strptime does not handle capword names properly")
 
+    def test_defaults(self):
+        # Default return value should be (1900, 1, 1, 0, 0, 0, 0, 1, 0)
+        defaults = (1900, 1, 1, 0, 0, 0, 0, 1, -1)
+        strp_output = _strptime.strptime('1', '%m')
+        self.failUnless(strp_output == defaults,
+                        "Default values for strptime() are incorrect;"
+                        " %s != %s" % (strp_output, defaults))
+
 class FxnTests(unittest.TestCase):
     """Test functions that fill in info by validating result and are triggered
     properly."""
@@ -325,14 +345,6 @@
                         "julianday failed; %s != %s" %
                          (result, self.time_tuple[7]))
 
-    def test_julianday_trigger(self):
-        # Make sure julianday is called
-        strf_output = time.strftime("%Y-%m-%d", self.time_tuple)
-        strp_output = _strptime.strptime(strf_output, "%Y-%m-%d")
-        self.failUnless(strp_output[7] == self.time_tuple[7],
-                        "strptime did not trigger julianday(); %s != %s" %
-                         (strp_output[7], self.time_tuple[7]))
-
     def test_gregorian_result(self):
         # Test gregorian
         result = _strptime.gregorian(self.time_tuple[7], self.time_tuple[0])
@@ -340,17 +352,6 @@
         self.failUnless(result == comparison,
                         "gregorian() failed; %s != %s" % (result, comparison))
 
-    def test_gregorian_trigger(self):
-        # Test that gregorian() is triggered
-        strf_output = time.strftime("%j %Y", self.time_tuple)
-        strp_output = _strptime.strptime(strf_output, "%j %Y")
-        self.failUnless(strp_output[1] == self.time_tuple[1] and
-                        strp_output[2] == self.time_tuple[2],
-                        "gregorian() not triggered; month -- %s != %s, "
-                         "day -- %s != %s" %
-                          (strp_output[1], self.time_tuple[1], strp_output[2],
-                           self.time_tuple[2]))
-
     def test_dayofweek_result(self):
         # Test dayofweek
         result = _strptime.dayofweek(self.time_tuple[0], self.time_tuple[1],
@@ -359,15 +360,6 @@
         self.failUnless(result == comparison,
                         "dayofweek() failed; %s != %s" % (result, comparison))
 
-    def test_dayofweek_trigger(self):
-        # Make sure dayofweek() gets triggered
-        strf_output = time.strftime("%Y-%m-%d", self.time_tuple)
-        strp_output = _strptime.strptime(strf_output, "%Y-%m-%d")
-        self.failUnless(strp_output[6] == self.time_tuple[6],
-                        "triggering of dayofweek() failed; %s != %s" %
-                         (strp_output[6], self.time_tuple[6]))
-
-
 class Strptime12AMPMTests(unittest.TestCase):
     """Test a _strptime regression in '%I %p' at 12 noon (12 PM)"""
 
@@ -384,7 +376,6 @@
 
     def test_all_julian_days(self):
         eq = self.assertEqual
-        # XXX: should 0 be accepted?
         for i in range(1, 367):
             # use 2004, since it is a leap year, we have 366 days
             eq(_strptime.strptime('%d 2004' % i, '%j %Y')[7], i)