<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -3,7 +3,7 @@
 ThirdBase differs from Ruby's standard Date/DateTime class in the following
 ways:
 
-- ThirdBase is roughly 2-12 times faster depending on usage
+- ThirdBase is roughly 2-10 times faster depending on usage
 - ThirdBase has a lower memory footprint
 - ThirdBase supports pluggable parsers
 - ThirdBase doesn't depend on Ruby's Rational class
@@ -150,17 +150,17 @@ To add a parser type:
   Date.add_parser_type(:mine)
   DateTime.add_parser_type(:mine)
 
-=== Adding Parsers to Parser Types
+=== Adding Regexp Parsers to Parser Types
 
-A ThirdBase Date/Datetime parser consists of two parts, a regular
-expression, and a proc that takes a MatchData object and returns a hash
-passed to Date/DateTime.new!.  The proc is only called if the regular
-expression matches the string to be parsed, and it can return nil if it
-is not able to successfully parse the string (even if the string matches
-the regular expression).  To add a parser, you use the add_parser class
-method, which takes an argument specifying which parser family to
-use, the regular expression, and a block that is used as a proc for the
-parser:
+A ThirdBase Date/Datetime regexp parser consists of two parts, a regular
+expression, and a block that takes a MatchData object and returns a 
+Date/DateTime instance or a hash to be passed to Date/DateTime.new!.  The
+block is only called if the regular expression matches the string to be
+parsed, and it can return nil if it is not able to successfully parse the
+string (even if the string matches the regular expression).  To add a
+parser, you use the add_parser class method, which takes an argument
+specifying which parser family to use, the regular expression, and a block
+that is used as a proc for the parser:
 
 To add a parser to a parser type:
 
@@ -195,6 +195,15 @@ Adding a parser to a parser type adds it to the front of the array of parsers
 for that type, so it will be tried before other parsers for that type.  It is
 an error to add a parser to a parser type that doesn't exist.
 
+=== Adding strptime Parsers to Parser Types (New in 1.2.0)
+
+ThirdBase 1.2.0 added the ability to more easily create common parsers
+using the strptime format string syntax.  These are created similar to regexp
+parsers, but use a format string, and the block is then optional (and should
+be omitted unless you know what you are doing):
+
+  DateTime.add_parser(:mine, '%Z %m~%Y~%d %S`%M`%H')
+
 === Modifying the Order of Parsers Types
 
 You can change the order in which parsers types are tried by using the</diff>
      <filename>README</filename>
    </modified>
    <modified>
      <diff>@@ -42,7 +42,7 @@ module ThirdBase
     # * :zone : time zone offset as string
     def _parse(str, comp=false)
       d = DateTime.parse(str)
-      {:mon=&gt;d.mon, :zone=&gt;d.zone, :sec=&gt;d.sec, :year=&gt;d.year, :hour=&gt;d.hour, :offset=&gt;d.offset, :mday=&gt;d.day, :min=&gt;d.min, :sec_fraction=&gt;d.usec/1000000.0}.reject{|k, v| d.not_parsed.include?(k)}
+      {:mon=&gt;d.mon, :zone=&gt;d.zone, :sec=&gt;d.sec, :year=&gt;d.year, :hour=&gt;d.hour, :offset=&gt;d.utc_offset, :mday=&gt;d.day, :min=&gt;d.min, :sec_fraction=&gt;d.usec/1000000.0}.reject{|k, v| d.not_parsed.include?(k)}
     end
     
     # Converts an Astronomical Julian Date to an Astronomical Modified Julian Date (substracts an integer from ajd)</diff>
      <filename>lib/third_base/compat.rb</filename>
    </modified>
    <modified>
      <diff>@@ -43,7 +43,8 @@ module ThirdBase
       [%r{\A#{MONTHNAME_RE_PATTERN}[-./ ](\d\d?)(?:st|nd|rd|th)?,?(?:[-./ ](-?(?:\d\d(?:\d\d)?)))?\z}io, proc{|m| {:civil=&gt;[m[3] ? two_digit_year(m[3]) : Time.now.year, MONTH_NUM_MAP[m[1].downcase], m[2].to_i]}}],
       [%r{\A(\d\d?)(?:st|nd|rd|th)?[-./ ]#{MONTHNAME_RE_PATTERN}[-./ ](-?\d{4})\z}io, proc{|m| {:civil=&gt;[m[3].to_i, MONTH_NUM_MAP[m[2].downcase], m[1].to_i]}}],
       [%r{\A(-?\d{4})[-./ ]#{MONTHNAME_RE_PATTERN}[-./ ](\d\d?)(?:st|nd|rd|th)?\z}io, proc{|m| {:civil=&gt;[m[1].to_i, MONTH_NUM_MAP[m[2].downcase], m[3].to_i]}}],
-      [%r{\A#{MONTHNAME_RE_PATTERN}[-./ ](-?\d{4})\z}io, proc{|m| {:civil=&gt;[m[2].to_i, MONTH_NUM_MAP[m[1].downcase], 1]}}]]
+      [%r{\A#{MONTHNAME_RE_PATTERN}[-./ ](-?\d{4})\z}io, proc{|m| {:civil=&gt;[m[2].to_i, MONTH_NUM_MAP[m[1].downcase], 1]}}],
+      [%r{\A#{ABBR_DAYNAME_RE_PATTERN} #{ABBR_MONTHNAME_RE_PATTERN} (\d\d?) (-?\d{4})\z}io, proc{|m| {:civil=&gt;[m[4].to_i, MONTH_NUM_MAP[m[2].downcase], m[3].to_i]}}]]
     DEFAULT_PARSERS[:eu] = [[%r{\A(\d\d?)[-./ ](\d\d?)[-./ ](\d\d\d\d)\z}o, proc{|m| {:civil=&gt;[m[3].to_i, m[2].to_i, m[1].to_i]}}],
       [%r{\A(\d\d?)[-./ ](\d?\d)[-./ ](\d?\d)\z}o, proc{|m| {:civil=&gt;[two_digit_year(m[1]), m[2].to_i, m[3].to_i]}}]]
     DEFAULT_PARSERS[:num] = [[%r{\A\d{2,8}\z}o, proc do |m|
@@ -91,13 +92,26 @@ module ThirdBase
       alias new! new
     end
     
-    # Add a parser to the parser type.  re should be
-    # a Regexp, and a block must be provided.  The block
-    # should take a single MatchData argument, a return
-    # either nil specifying it could not parse the string,
-    # or a hash of values to be passed to new!.
-    def self.add_parser(type, re, &amp;block)
-      parser_hash[type].unshift([re, block])
+    # Add a parser to the parser type. Arguments:
+    # * type - The parser type to which to add the parser, should be a Symbol.
+    # * pattern - Can be either a Regexp or String:
+    #   * String - A strptime parser regular expression is created using pattern as the format string.
+    #     If a block is given, it is used.  If no block is given, the parser will
+    #     operate identically to strptime.
+    #   * Regexp - The regular expression is used directly.  In this case, a block must be provided,
+    #     or an error is raised.
+    # 
+    # The block, if provided, should take a single MatchData argument.  It should return
+    # nil if it cannot successfully parse the string, an instance of this class,  or a hash of
+    # values to be passed to new!.
+    def self.add_parser(type, pattern, &amp;block)
+      if pattern.is_a?(String)
+        pattern, blk = strptime_pattern_and_block(pattern)
+        block ||= blk
+      else
+        raise(ArgumentError, 'must provide block for Regexp parser') unless block_given?
+      end
+      parser_hash[type].unshift([pattern, block])
     end
     
     # Add a parser type to the list of parser types.
@@ -144,7 +158,7 @@ module ThirdBase
       parsers(opts[:parser_types]) do |pattern, block|
         if m = pattern.match(s)
           if res = block.call(m)
-            return new!(res)
+            return res.is_a?(Hash) ? new!(res) : res
           end
         end
       end
@@ -166,24 +180,15 @@ module ThirdBase
     # Parse the string using the provided format (or the default format).
     # Raises an ArgumentError if the format does not match the string.
     def self.strptime(str, fmt=strptime_default)
-      blocks = []
+      pattern, block = strptime_pattern_and_block(fmt)
       s = str.strip
-      date_hash = {}
-      pattern = Regexp.escape(expand_strptime_format(fmt)).gsub(STRFTIME_RE) do |x|
-        pat, *blks = _strptime_part(x[1..1])
-        blocks += blks
-        pat
-      end
-      if m = /#{pattern}/i.match(s)
-        m.to_a[1..-1].zip(blocks) do |x, blk|
-          blk.call(date_hash, x)
-        end
-        new_from_parts(date_hash)
+      if m = pattern.match(s)
+        block.call(m)
       else
         raise ArgumentError, 'invalid date'
       end
     end
-    
+
     # Returns a date with the current year, month, and date.
     def self.today
       t = Time.now
@@ -283,6 +288,23 @@ module ThirdBase
       '%Y-%m-%d'
     end
     
+    def self.strptime_pattern_and_block(fmt)
+      blocks = []
+      pattern = Regexp.escape(expand_strptime_format(fmt)).gsub(STRFTIME_RE) do |x|
+        pat, *blks = _strptime_part(x[1..1])
+        blocks += blks
+        pat
+      end
+      block = proc do |m|
+        h = {}
+        m.to_a[1..-1].zip(blocks) do |x, blk|
+          blk.call(h, x)
+        end
+        new_from_parts(h)
+      end
+      [/\A#{pattern}\z/i, block]
+    end
+    
     def self.two_digit_year(y)
       y = if y.length == 2
         y = y.to_i
@@ -292,7 +314,7 @@ module ThirdBase
       end
     end
     
-    private_class_method :_expand_strptime_format, :_strptime_part, :default_parser_hash, :default_parser_list, :expand_strptime_format, :new_from_parts, :parser_hash, :parser_list, :parsers, :parsers_for_family, :strptime_default, :two_digit_year
+    private_class_method :_expand_strptime_format, :_strptime_part, :default_parser_hash, :default_parser_list, :expand_strptime_format, :new_from_parts, :parser_hash, :parser_list, :parsers, :parsers_for_family, :strptime_default, :strptime_pattern_and_block, :two_digit_year
     
     reset_parsers!
     </diff>
      <filename>lib/third_base/date.rb</filename>
    </modified>
    <modified>
      <diff>@@ -4,11 +4,16 @@ module ThirdBase
   # ThirdBase's DateTime class, which builds on the Date class and adds a time component of
   # hours, minutes, seconds, microseconds, and an offset from UTC.
   class DateTime &lt; Date
-    
+    TIME_ZONE_SECOND_OFFSETS = {
+      'UTC'=&gt;0, 'Z'=&gt;0, 'UT'=&gt;0, 'GMT'=&gt;0,
+      'EST'=&gt;-18000, 'EDT'=&gt;-14400, 'CST'=&gt;-21600, 'CDT'=&gt;-18000, 'MST'=&gt;-25200, 'MDT'=&gt;-21600, 'PST'=&gt;-28800, 'PDT'=&gt;-25200,
+      'A'=&gt;3600, 'B'=&gt;7200, 'C'=&gt;10800, 'D'=&gt;14400, 'E'=&gt;18000, 'F'=&gt;21600, 'G'=&gt;25200, 'H'=&gt;28800, 'I'=&gt;32400, 'K'=&gt;36000, 'L'=&gt;39600, 'M'=&gt;43200,
+      'N'=&gt;-3600, 'O'=&gt;-7200, 'P'=&gt;-10800, 'Q'=&gt;-14400, 'R'=&gt;-18000, 'S'=&gt;-21600, 'T'=&gt;-25200, 'U'=&gt;-28800, 'V'=&gt;-32400, 'W'=&gt;-36000, 'X'=&gt;-39600, 'Y'=&gt;-43200}
     PARSER_LIST = []
     DEFAULT_PARSER_LIST = [:time, :iso, :us, :num]
     DEFAULT_PARSERS = {}
-    TIME_RE_STRING = '(?:[T ]?([\d ]?\d):(\d\d)(?::(\d\d(\.\d+)?))?([ap]m?)? ?(Z|[+-](?:\d\d:?(?:\d\d)?))?)?'
+    TIME_ZONE_RE_STRING = &quot;(#{TIME_ZONE_SECOND_OFFSETS.keys.sort.join('|')}|[+-](?:\\d\\d:?(?:\\d\\d)?))&quot;
+    TIME_RE_STRING = &quot;(?:[T ]?([\\d ]?\\d):(\\d\\d)(?::(\\d\\d(\\.\\d+)?))?([ap]m?)? ?#{TIME_ZONE_RE_STRING}?)?&quot;
     DEFAULT_PARSERS[:time] = [[%r{\A#{TIME_RE_STRING}\z}io, proc do |m|
         unless m[0] == ''
           t = Time.now
@@ -21,7 +26,8 @@ module ThirdBase
       [%r{\A#{MONTHNAME_RE_PATTERN}[-./ ](\d\d?)(?:st|nd|rd|th)?,?(?:[-./ ](-?(?:\d\d(?:\d\d)?)))?#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, :civil=&gt;[m[3] ? two_digit_year(m[3]) : Time.now.year, MONTH_NUM_MAP[m[1].downcase], m[2].to_i], :not_parsed=&gt;m[3] ? [] : [:year])}],
       [%r{\A(\d\d?)(?:st|nd|rd|th)?[-./ ]#{MONTHNAME_RE_PATTERN}[-./ ](-?\d{4})#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, :civil=&gt;[m[3].to_i, MONTH_NUM_MAP[m[2].downcase], m[1].to_i])}],
       [%r{\A(-?\d{4})[-./ ]#{MONTHNAME_RE_PATTERN}[-./ ](\d\d?)(?:st|nd|rd|th)?#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, :civil=&gt;[m[1].to_i, MONTH_NUM_MAP[m[2].downcase], m[3].to_i])}],
-      [%r{\A#{MONTHNAME_RE_PATTERN}[-./ ](-?\d{4})#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, {:civil=&gt;[m[2].to_i, MONTH_NUM_MAP[m[1].downcase], 1]}, 3)}]]
+      [%r{\A#{MONTHNAME_RE_PATTERN}[-./ ](-?\d{4})#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, {:civil=&gt;[m[2].to_i, MONTH_NUM_MAP[m[1].downcase], 1]}, 3)}],
+      [%r{\A#{ABBR_DAYNAME_RE_PATTERN} #{ABBR_MONTHNAME_RE_PATTERN} (\d\d?) #{TIME_RE_STRING} (-?\d{4})\z}io, proc{|m| add_parsed_time_parts(m, {:civil=&gt;[m[10].to_i, MONTH_NUM_MAP[m[2].downcase], m[3].to_i]})}]]
     DEFAULT_PARSERS[:eu] = [[%r{\A(\d\d?)[-./ ](\d\d?)[-./ ](\d{4})#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, :civil=&gt;[m[3].to_i, m[2].to_i, m[1].to_i])}],
       [%r{\A(\d\d?)[-./ ](\d?\d)[-./ ](\d?\d)#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, :civil=&gt;[two_digit_year(m[1]), m[2].to_i, m[3].to_i])}]]
     DEFAULT_PARSERS[:num] = [[%r{\A(\d{2,8})#{TIME_RE_STRING}\z}io, proc do |n|
@@ -58,7 +64,7 @@ module ThirdBase
       minutes, seconds = i.divmod(60)
       h.merge!(:jd=&gt;j+UNIXEPOCH, :hour=&gt;hours, :min=&gt;minutes, :sec=&gt;seconds)
     end
-    STRPTIME_PROC_z = proc{|h,x| x=x.gsub(':',''); h[:offset] = (x == 'Z' ? 0 : x[0..2].to_i*3600 + x[3..4].to_i*60)}
+    STRPTIME_PROC_z = proc{|h,x| h[:offset] = convert_parsed_offset(x)}
     
     # Public Class Methods
     
@@ -102,7 +108,7 @@ module ThirdBase
       when '%T', '%X' then '%H:%M:%S'
       when '%R' then '%H:%M'
       when '%r' then '%I:%M:%S %p'
-      when '%+' then '%a %b %e %H:%M:%S %z %Y'
+      when '%+' then '%a %b %e %H:%M:%S %Z %Y'
       else super(v)
       end
     end
@@ -115,7 +121,7 @@ module ThirdBase
       when 'P', 'p' then ['([ap]m)', STRPTIME_PROC_P]
       when 'S' then ['(\d\d)', STRPTIME_PROC_S]
       when 's' then ['(\d+)', STRPTIME_PROC_s]
-      when 'z', 'Z' then ['(Z|[+-](?:\d{4}|\d\d:\d\d))', STRPTIME_PROC_z]
+      when 'z', 'Z' then [TIME_ZONE_RE_STRING, STRPTIME_PROC_z]
       else super(v)
       end
     end
@@ -133,8 +139,7 @@ module ThirdBase
       meridian = m[i+4]
       hour = hour_with_meridian(hour, /a/io.match(meridian) ? :am : :pm) if meridian
       offset = if of = m[i+5]
-        x = of.gsub(':','')
-        offset = x == 'Z' ? 0 : x[0..2].to_i*3600 + x[3..4].to_i*60
+        convert_parsed_offset(of)
       else
         not_parsed.concat([:zone, :offset])
         Time.now.utc_offset
@@ -168,11 +173,18 @@ module ThirdBase
     end
     
     def self.new_from_parts(date_hash)
+      not_parsed = [:hour, :min, :sec].reject{|x| date_hash.has_key?(x)}
+      not_parsed.concat([:zone, :offset]) unless date_hash.has_key?(:offset)
+      not_parsed &lt;&lt; :year unless date_hash.has_key?(:year) || date_hash.has_key?(:cwyear)
+      not_parsed &lt;&lt; :mon unless date_hash.has_key?(:month) || date_hash.has_key?(:cweek)
+      not_parsed &lt;&lt; :mday unless date_hash.has_key?(:day) || date_hash.has_key?(:cwday)
+      not_parsed &lt;&lt; :sec_fraction
+
       date_hash[:hour] = hour_with_meridian(date_hash[:hour], date_hash[:meridian]) if date_hash[:meridian]
       d = now
-      weights = {:cwyear=&gt;1, :year=&gt;1, :cweek=&gt;2, :cwday=&gt;3, :yday=&gt;3, :month=&gt;2, :day=&gt;3, :hour=&gt;4, :min=&gt;5, :sec=&gt;6}
+      weights = {:cwyear=&gt;1, :year=&gt;1, :cweek=&gt;2, :cwday=&gt;3, :yday=&gt;3, :month=&gt;2, :day=&gt;3, :hour=&gt;4, :min=&gt;5, :sec=&gt;6, :offset=&gt;7}
       columns = {}
-      min = 7
+      min = 8
       max = 0
       date_hash.each do |k,v|
         if w = weights[k]
@@ -183,21 +195,31 @@ module ThirdBase
       offset = date_hash[:offset] || d.offset
       hour = date_hash[:hour] || (min &gt; 4 ? d.hour : 0)
       minute = date_hash[:min] || (min &gt; 5 ? d.min : 0)
-      sec = date_hash[:sec] || 0
+      sec = date_hash[:sec] || (min &gt; 6 ? d.sec : 0)
+      hash = {:parts=&gt;[hour, minute, sec, 0], :offset=&gt;offset.to_i, :not_parsed=&gt;not_parsed}
       if date_hash[:jd]
-        jd(date_hash[:jd], hour, minute, sec, 0, offset)
+        new!(hash.merge!(:jd=&gt;date_hash[:jd]))
       elsif date_hash[:year] || date_hash[:yday] || date_hash[:month] || date_hash[:day] || !(date_hash[:cwyear] || date_hash[:cweek])
         if date_hash[:yday]
-          ordinal(date_hash[:year]||d.year, date_hash[:yday], hour, minute, sec, 0, offset)
+          new!(hash.merge!(:ordinal=&gt;[date_hash[:year]||d.year, date_hash[:yday]]))
         else
-          civil(date_hash[:year]||d.year, date_hash[:month]||(min &gt; 2 ? d.mon : 1), date_hash[:day]||(min &gt; 3 ? d.day : 1), hour, minute, sec, 0, offset)
+          new!(hash.merge!(:civil=&gt;[date_hash[:year]||d.year, date_hash[:month]||(min &gt; 2 ? d.mon : 1), date_hash[:day]||(min &gt; 3 ? d.day : 1)]))
         end
       elsif date_hash[:cwyear] || date_hash[:cweek] || date_hash[:cwday]
-        commercial(date_hash[:cwyear]||d.cwyear, date_hash[:cweek]||(min &gt; 2 ? d.cweek : 1), date_hash[:cwday]||(min &gt; 3 ? d.cwday : 1), hour, minute, sec, 0, offset)
+        new!(hash.merge!(:commercial=&gt;[date_hash[:cwyear]||d.cwyear, date_hash[:cweek]||(min &gt; 2 ? d.cweek : 1), date_hash[:cwday]||(min &gt; 3 ? d.cwday : 1)]))
       else
         raise ArgumentError, 'invalid date'
       end
     end
+
+    def self.convert_parsed_offset(of)
+      if offset = TIME_ZONE_SECOND_OFFSETS[of.upcase]
+        offset
+      else
+        x = of.gsub(':','')
+        x[0..2].to_i*3600 + x[3..4].to_i*60
+      end
+    end
     
     def self.parser_hash
       PARSERS
@@ -211,7 +233,7 @@ module ThirdBase
       '%Y-%m-%dT%H:%M:%S'
     end
     
-    private_class_method :_expand_strptime_format, :_strptime_part, :add_parsed_time_parts, :default_parser_hash, :default_parser_list, :new_from_parts, :parser_hash, :parser_list, :strptime_default
+    private_class_method :_expand_strptime_format, :_strptime_part, :add_parsed_time_parts, :convert_parsed_offset, :default_parser_hash, :default_parser_list, :new_from_parts, :parser_hash, :parser_list, :strptime_default
     
     reset_parsers!
     
@@ -342,7 +364,7 @@ module ThirdBase
     
     # Return the offset as a time zone string (+/-HHMM).
     def zone
-      strftime('%z')
+      strftime('%Z')
     end
     
     private
@@ -362,9 +384,9 @@ module ThirdBase
       when 'S' then '%02d' % sec
       when 's' then '%d' % ((jd - UNIXEPOCH)*86400 + hour*3600 + min*60 + sec - @offset)
       when 'T', 'X' then strftime('%H:%M:%S')
-      when '+' then strftime('%a %b %e %H:%M:%S %z %Y')
-      when 'Z' then @offset == 0 ? 'Z' : _strftime('z')
-      when 'z' then &quot;%+03d:%02d&quot; % (@offset/60).divmod(60)
+      when '+' then strftime('%a %b %e %H:%M:%S %Z %Y')
+      when 'Z' then &quot;%+03d:%02d&quot; % (@offset/60).divmod(60)
+      when 'z' then &quot;%+03d%02d&quot; % (@offset/60).divmod(60)
       else super(v)
       end
     end
@@ -385,7 +407,7 @@ module ThirdBase
     end
 
     def strftime_default
-      '%Y-%m-%dT%H:%M:%S%z'
+      '%Y-%m-%dT%H:%M:%S%Z'
     end
     
     def time_parts</diff>
      <filename>lib/third_base/datetime.rb</filename>
    </modified>
    <modified>
      <diff>@@ -30,6 +30,35 @@ describe ThirdBase::CompatClassMethods do
     Date._parse('2008-10-20').should == {:year=&gt;2008, :mday=&gt;20, :mon=&gt;10}
     Date._parse('11:12:13').should == {:sec=&gt;13, :hour=&gt;11, :min=&gt;12}
   end
+  
+  it &quot;#_parse should not contain fields in the hash that were guessed when a strptime-parser is used&quot; do
+    DateTime.add_parser(:us, &quot;%m-%d&lt;&gt;%H/%M&quot;)
+    Date._parse('10-11&lt;&gt;12/13').should == {:mon=&gt;10, :mday=&gt;11, :hour=&gt;12, :min=&gt;13}
+
+    DateTime.add_parser(:us, &quot;%d&quot;)
+    Date._parse('11').should == {:mday=&gt;11}
+
+    DateTime.add_parser(:us, &quot;%m&quot;)
+    Date._parse('11').should == {:mon=&gt;11}
+
+    DateTime.add_parser(:us, &quot;%Y&quot;)
+    Date._parse('2009').should == {:year=&gt;2009}
+
+    DateTime.add_parser(:us, &quot;%H&quot;)
+    Date._parse('11').should == {:hour=&gt;11}
+
+    DateTime.add_parser(:us, &quot;%M&quot;)
+    Date._parse('11').should == {:min=&gt;11}
+
+    DateTime.add_parser(:us, &quot;%S&quot;)
+    Date._parse('20').should == {:sec=&gt;20}
+
+    DateTime.add_parser(:us, &quot;%Z&quot;)
+    Date._parse('UTC').should == {:zone=&gt;'+00:00', :offset=&gt;0}
+    Date._parse('CDT').should == {:zone=&gt;'-05:00', :offset=&gt;-18000}
+
+    DateTime.reset_parsers!
+  end
 
   it &quot;#ajd_to_amjd should convert a astronomical julian date to a astronomical modified julian date&quot; do
     Date.ajd_to_amjd(2400002).should == 1</diff>
      <filename>spec/compat/compat_class_methods_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -82,6 +82,10 @@ describe :date_parse, :shared =&gt; true do
     Date.parse(&quot;november#{@sep}5th&quot;).should == Date.civil(Date.today.year, 11, 5)
   end
 
+  it &quot;can parse a weekday, month, day, and year into a Date object&quot; do
+    Date.parse(&quot;Mon Aug 10 2009&quot;).should == Date.civil(2009, 8, 10)
+  end
+
   it &quot;can parse a month name, day and year into a Date object&quot; do
     Date.parse(&quot;november#{@sep}5th#{@sep}2005&quot;).should == Date.civil(2005, 11, 5)
   end
@@ -209,12 +213,25 @@ describe &quot;Date parser modifications&quot; do
     Date.reset_parsers!
   end
   
-  it &quot;should be able to add a parser to an existing parser type that takes precedence&quot; do
+  it &quot;should raise an ArgumentError if it can't parse a date&quot; do
     proc{Date.parse(&quot;today&quot;)}.should raise_error(ArgumentError)
+  end
+
+  it &quot;should be able to add a parser to an existing parser type that takes precedence&quot; do
     Date.add_parser(:iso, /today/){t = Time.now; {:civil=&gt;[t.year, t.mon, t.day]}}
     Date.parse(&quot;today&quot;).should == Date.today
   end
   
+  it &quot;should be able to handle parsers that return Date instances&quot; do
+    Date.add_parser(:iso, /today/){t = Time.now; Date.new(t.year, t.mon, t.day)}
+    Date.parse(&quot;today&quot;).should == Date.today
+  end
+  
+  it &quot;should be able to specify a strptime format string for a parser&quot; do
+    Date.add_parser(:iso, &quot;%d&lt;&lt;%m&lt;&lt;%Y&quot;)
+    Date.parse(&quot;03&lt;&lt;02&lt;&lt;2001&quot;).should == Date.new(2001, 2, 3)
+  end
+  
   it &quot;should be able to add new parser types&quot; do
     proc{Date.parse(&quot;today&quot;)}.should raise_error(ArgumentError)
     Date.add_parser_type(:mine)</diff>
      <filename>spec/date/parse_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -22,7 +22,7 @@ describe &quot;DateTime#parse&quot; do
     DateTime.parse(&quot;12:02:03p&quot;).should == DateTime.civil(DateTime.today.year, DateTime.today.month, DateTime.today.day, 12, 2, 3)
     proc{DateTime.parse(&quot;13:02:03p&quot;)}.should raise_error(ArgumentError)
     proc{DateTime.parse(&quot;00:02:03p&quot;)}.should raise_error(ArgumentError)
-    proc{DateTime.parse(&quot;00:02:03r&quot;)}.should raise_error(ArgumentError)
+    proc{DateTime.parse(&quot;00:02:03rsdf&quot;)}.should raise_error(ArgumentError)
   end
 
   it &quot;should use the current time offset if no time offset is specified&quot; do
@@ -34,6 +34,50 @@ describe &quot;DateTime#parse&quot; do
     DateTime.parse(&quot;01:02:03-01&quot;).should == DateTime.civil(DateTime.today.year, DateTime.today.month, DateTime.today.day, 1, 2, 3, 0, -3600)
   end
 
+  it &quot;should parse the time zone abbreviations supported by ruby's Time class&quot; do
+    DateTime.parse(&quot;01:02:03 UTC&quot;).offset.should == 0
+    DateTime.parse(&quot;01:02:03 UT&quot;).offset.should == 0
+    DateTime.parse(&quot;01:02:03 GMT&quot;).offset.should == 0
+    DateTime.parse(&quot;01:02:03 EST&quot;).offset.should == -5*3600
+    DateTime.parse(&quot;01:02:03 EDT&quot;).offset.should == -4*3600
+    DateTime.parse(&quot;01:02:03 CST&quot;).offset.should == -6*3600
+    DateTime.parse(&quot;01:02:03 CDT&quot;).offset.should == -5*3600
+    DateTime.parse(&quot;01:02:03 MST&quot;).offset.should == -7*3600
+    DateTime.parse(&quot;01:02:03 MDT&quot;).offset.should == -6*3600
+    DateTime.parse(&quot;01:02:03 PST&quot;).offset.should == -8*3600
+    DateTime.parse(&quot;01:02:03 PDT&quot;).offset.should == -7*3600
+    DateTime.parse(&quot;01:02:03 A&quot;).offset.should == 1*3600
+    DateTime.parse(&quot;01:02:03 B&quot;).offset.should == 2*3600
+    DateTime.parse(&quot;01:02:03 C&quot;).offset.should == 3*3600
+    DateTime.parse(&quot;01:02:03 D&quot;).offset.should == 4*3600
+    DateTime.parse(&quot;01:02:03 E&quot;).offset.should == 5*3600
+    DateTime.parse(&quot;01:02:03 F&quot;).offset.should == 6*3600
+    DateTime.parse(&quot;01:02:03 G&quot;).offset.should == 7*3600
+    DateTime.parse(&quot;01:02:03 H&quot;).offset.should == 8*3600
+    DateTime.parse(&quot;01:02:03 I&quot;).offset.should == 9*3600
+    DateTime.parse(&quot;01:02:03 K&quot;).offset.should == 10*3600
+    DateTime.parse(&quot;01:02:03 L&quot;).offset.should == 11*3600
+    DateTime.parse(&quot;01:02:03 M&quot;).offset.should == 12*3600
+    DateTime.parse(&quot;01:02:03 N&quot;).offset.should == -1*3600
+    DateTime.parse(&quot;01:02:03 O&quot;).offset.should == -2*3600
+    DateTime.parse(&quot;01:02:03 P&quot;).offset.should == -3*3600
+    DateTime.parse(&quot;01:02:03 Q&quot;).offset.should == -4*3600
+    DateTime.parse(&quot;01:02:03 R&quot;).offset.should == -5*3600
+    DateTime.parse(&quot;01:02:03 S&quot;).offset.should == -6*3600
+    DateTime.parse(&quot;01:02:03 T&quot;).offset.should == -7*3600
+    DateTime.parse(&quot;01:02:03 U&quot;).offset.should == -8*3600
+    DateTime.parse(&quot;01:02:03 V&quot;).offset.should == -9*3600
+    DateTime.parse(&quot;01:02:03 W&quot;).offset.should == -10*3600
+    DateTime.parse(&quot;01:02:03 X&quot;).offset.should == -11*3600
+    DateTime.parse(&quot;01:02:03 Y&quot;).offset.should == -12*3600
+    DateTime.parse(&quot;01:02:03 Z&quot;).offset.should == 0
+  end
+
+  it &quot;should parse the time strings output by ruby's Time class&quot; do
+    proc{DateTime.parse(Time.now.to_s)}.should_not raise_error
+    proc{DateTime.parse(Time.now.strftime('%+'))}.should_not raise_error
+  end
+
   it &quot;can handle DD as month day number&quot; do
     DateTime.parse(&quot;10&quot;).should == DateTime.civil(DateTime.today.year, DateTime.today.month, 10)
     DateTime.parse(&quot;10 01:02:03&quot;).should == DateTime.civil(DateTime.today.year, DateTime.today.month, 10, 1, 2, 3)
@@ -318,15 +362,35 @@ describe &quot;DateTime parser modifications&quot; do
     DateTime.reset_parsers!
   end
   
+  it &quot;should raise an ArgumentError if it can't parse a date&quot; do
+    proc{DateTime.parse(&quot;today&quot;)}.should raise_error(ArgumentError)
+  end
+
   it &quot;should be able to add a parser to an existing parser type that takes precedence&quot; do
     d = DateTime.now
-    proc{DateTime.parse(&quot;today&quot;)}.should raise_error(ArgumentError)
     DateTime.add_parser(:iso, /\Anow\z/){{:civil=&gt;[d.year, d.mon, d.day], :parts=&gt;[d.hour, d.min, d.sec, d.usec], :offset=&gt;d.offset}}
     DateTime.parse(&quot;now&quot;).should == d
   end
   
+  it &quot;should be able to handle parsers that return Date instances&quot; do
+    d = DateTime.now
+    DateTime.add_parser(:iso, /\Anow\z/){d}
+    DateTime.parse(&quot;now&quot;).should == d
+  end
+  
+  it &quot;should be able to specify a strptime format string for a parser&quot; do
+    DateTime.add_parser(:iso, &quot;%Z||%S&gt;&gt;%M&gt;&gt;%H||%d&lt;&lt;%m&lt;&lt;%Y&quot;)
+    DateTime.parse(&quot;UTC||06&gt;&gt;05&gt;&gt;04||03&lt;&lt;02&lt;&lt;2001&quot;).should == DateTime.new(2001,2,3,4,5,6)
+  end
+
+  it &quot;should assume current seconds if just offset is given&quot; do
+    DateTime.add_parser_type(:mine)
+    DateTime.use_parsers(:mine)
+    DateTime.add_parser(:mine, &quot;%Z&quot;)
+    DateTime.parse(&quot;UTC&quot;).sec.should == DateTime.now.sec
+  end
+
   it &quot;should be able to add new parser types&quot; do
-    proc{DateTime.parse(&quot;today&quot;)}.should raise_error(ArgumentError)
     DateTime.add_parser_type(:mine)
     d = DateTime.now
     DateTime.add_parser(:mine, /\Anow\z/){{:civil=&gt;[d.year, d.mon, d.day], :parts=&gt;[d.hour, d.min, d.sec, d.usec], :offset=&gt;d.offset}}</diff>
      <filename>spec/datetime/parse_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -52,17 +52,18 @@ describe &quot;DateTime#strftime&quot; do
     DateTime.civil(2008, 11, 12, 14, 3, 31, 0, -28800).strftime('%s').should == &quot;1226527411&quot;
   end
   
-  it &quot;should be able to print the time zone offset as a Z if the offset is zero&quot; do
-    DateTime.civil(2000, 4, 6, 10, 11, 12).strftime('%Z').should == &quot;Z&quot;
-    DateTime.civil(2000, 4, 6, 10, 11, 12, 0, -43200).strftime('%Z').should == &quot;-12:00&quot;
-  end
-  
   it &quot;should be able to print the time zone offset as a string of hours and minutes&quot; do
-    DateTime.civil(2000, 4, 6, 10, 11, 12).strftime('%z').should == &quot;+00:00&quot;
-    DateTime.civil(2000, 4, 6, 10, 11, 12, 0, -43200).strftime('%z').should == &quot;-12:00&quot;
-    DateTime.civil(2000, 4, 6, 10, 11, 12, 0, 43200).strftime('%z').should == &quot;+12:00&quot;
-    DateTime.civil(2000, 4, 6, 10, 11, 12, 0, -3600).strftime('%z').should == &quot;-01:00&quot;
-    DateTime.civil(2000, 4, 6, 10, 11, 12, 0, 3600).strftime('%z').should == &quot;+01:00&quot;
+    DateTime.civil(2000, 4, 6, 10, 11, 12).strftime('%z').should == &quot;+0000&quot;
+    DateTime.civil(2000, 4, 6, 10, 11, 12, 0, -43200).strftime('%z').should == &quot;-1200&quot;
+    DateTime.civil(2000, 4, 6, 10, 11, 12, 0, 43200).strftime('%z').should == &quot;+1200&quot;
+    DateTime.civil(2000, 4, 6, 10, 11, 12, 0, -3600).strftime('%z').should == &quot;-0100&quot;
+    DateTime.civil(2000, 4, 6, 10, 11, 12, 0, 3600).strftime('%z').should == &quot;+0100&quot;
+    
+    DateTime.civil(2000, 4, 6, 10, 11, 12).strftime('%Z').should == &quot;+00:00&quot;
+    DateTime.civil(2000, 4, 6, 10, 11, 12, 0, -43200).strftime('%Z').should == &quot;-12:00&quot;
+    DateTime.civil(2000, 4, 6, 10, 11, 12, 0, 43200).strftime('%Z').should == &quot;+12:00&quot;
+    DateTime.civil(2000, 4, 6, 10, 11, 12, 0, -3600).strftime('%Z').should == &quot;-01:00&quot;
+    DateTime.civil(2000, 4, 6, 10, 11, 12, 0, 3600).strftime('%Z').should == &quot;+01:00&quot;
   end
   
   ############################
@@ -97,6 +98,6 @@ describe &quot;DateTime#strftime&quot; do
   it &quot;should be able to print the common date and timezone&quot; do
     DateTime.civil(2000, 4, 6, 10, 11, 12).strftime(&quot;%+&quot;).should == &quot;Thu Apr  6 10:11:12 +00:00 2000&quot;
     DateTime.civil(2000, 4, 6, 10, 11, 12, 0, 43200).strftime(&quot;%+&quot;).should == &quot;Thu Apr  6 10:11:12 +12:00 2000&quot;
-    DateTime.civil(2000, 4, 6, 10, 11, 12).strftime(&quot;%+&quot;).should == DateTime.civil(2000, 4, 6, 10, 11, 12).strftime('%a %b %e %H:%M:%S %z %Y')  
+    DateTime.civil(2000, 4, 6, 10, 11, 12).strftime(&quot;%+&quot;).should == DateTime.civil(2000, 4, 6, 10, 11, 12).strftime('%a %b %e %H:%M:%S %Z %Y')  
   end
 end</diff>
      <filename>spec/datetime/strftime_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,6 @@
 spec = Gem::Specification.new do |s|
   s.name = &quot;third_base&quot;
-  s.version = &quot;1.1.1&quot;
+  s.version = &quot;1.2.0&quot;
   s.author = &quot;Jeremy Evans&quot;
   s.email = &quot;code@jeremyevans.net&quot;
   s.homepage = &quot;http://third-base.rubyforge.org&quot;</diff>
      <filename>third_base.gemspec</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>5ffc2f28dd5ee94462f0ff3a2d1426cdab689d12</id>
    </parent>
  </parents>
  <author>
    <name>Jeremy Evans</name>
    <email>code@jeremyevans.net</email>
  </author>
  <url>http://github.com/jeremyevans/third_base/commit/9b9e13b456b63ce67ad837f3978269251b5463c4</url>
  <id>9b9e13b456b63ce67ad837f3978269251b5463c4</id>
  <committed-date>2009-08-17T13:21:03-07:00</committed-date>
  <authored-date>2009-08-17T13:21:03-07:00</authored-date>
  <message>Add strptime based parsers, many bugfixes, bump version to 1.2.0

This is a major update that fixes many bugs and allows the user
to more easily create custom parsers using the strptime format
string syntax.  Example:

  DateTime.add_parser(:mine, '%Z %m~%Y~%d %S`%M`%H')

With a strptime-based parser, you don't need to provide a block,
and you probably shouldn't.

The following minor improvements are included in this commit:

* An additional parser has been added by default, so that the
  following code will work:

    DateTime.parse(Time.now.to_s)
    DateTime.parse(Time.now.strftime('%+'))

* You can now have a custom parser return a Date/DateTime object
  that you create.  If you provide a hash, it still creates a
  Date/DateTime object for you using the hash as parameters.  Any
  object other than a hash that is returned by a parser block is
  returned directly.

* The default parsers all understand the timezones that are
  used by Time.now.strftime('%+'), so you can use PST, EDT, UTC,
  A-Z, etc..

* The %z strptime/strftime format string modifier now operates more
  closely to standard ruby.

* A parser where only the offset is parsed will now assume the
  current seconds instead of 0 seconds.</message>
  <tree>80b354c92cbacb100bc4e8168de8494bd3b2b67e</tree>
  <committer>
    <name>Jeremy Evans</name>
    <email>code@jeremyevans.net</email>
  </committer>
</commit>
