<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -168,12 +168,29 @@ To add a parser to a parser type:
     t = Time.now
     {:civil=&gt;[t.year, t.mon, t.day]}
   end
+
   DateTime.add_parser(:mine, /\Anow\z/i) do |m|
     t = Time.now
     {:civil=&gt;[t.year, t.mon, t.day], :parts=&gt;[t.hour, t.min, t.sec, t.usec] \
       :offset=&gt;t.utc_offset}
   end
 
+If you add a DateTime parser that may guess at certain values instead of
+parsing them out of the string, you should include a :not_parsed entry which
+is an array of symbols indicating items that were not parsed directly out
+of the string.  This is only necessary if you are using the compatibility
+mode and want better compatibility for Date._parse (which ruby's Time.parse
+method uses internally):
+
+  DateTime.add_parser(:mine, /\A(\d\d)_(\d\d)_(\d{4})\z/i) do |m|
+    {:civil=&gt;[m[3].to_i, m[2].to_i, m[1].to_i], :parts=&gt;[0,0,0,0], :offset=&gt;0, \
+     :not_parsed=&gt;[:hour, :min, :sec, :sec_fraction, :offset, :zone]}
+  end
+
+The entries in :not_parsed should match keys that can be returned by
+Date._parse, so in addition to the ones listed above, you can also use
+:year, :mon, and :mday.
+
 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.</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}
+      {: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)}
     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>@@ -12,13 +12,13 @@ module ThirdBase
     DEFAULT_PARSERS[:time] = [[%r{\A#{TIME_RE_STRING}\z}io, proc do |m|
         unless m[0] == ''
           t = Time.now
-          add_parsed_time_parts(m, {:civil=&gt;[t.year, t.mon, t.day]}, 1)
+          add_parsed_time_parts(m, {:civil=&gt;[t.year, t.mon, t.day], :not_parsed=&gt;[:year, :mon, :mday]}, 1)
         end
       end]]
     DEFAULT_PARSERS[:iso] = [[%r{\A(-?\d{4})[-./ ](\d\d)[-./ ](\d\d)#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, :civil=&gt;[m[1].to_i, m[2].to_i, m[3].to_i])}]]
     DEFAULT_PARSERS[:us] = [[%r{\A(\d\d?)[-./ ](\d\d?)[-./ ](\d\d(?:\d\d)?)#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, :civil=&gt;[two_digit_year(m[3]), m[1].to_i, m[2].to_i])}],
-      [%r{\A(\d\d?)/(\d?\d)#{TIME_RE_STRING}\z}o, proc{|m| add_parsed_time_parts(m, {:civil=&gt;[Time.now.year, m[1].to_i, m[2].to_i]}, 3)}],
-      [%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])}],
+      [%r{\A(\d\d?)/(\d?\d)#{TIME_RE_STRING}\z}o, proc{|m| add_parsed_time_parts(m, {:civil=&gt;[Time.now.year, m[1].to_i, m[2].to_i], :not_parsed=&gt;:year}, 3)}],
+      [%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)}]]
@@ -30,11 +30,11 @@ module ThirdBase
         case m.length
         when 2
           t = Time.now
-          {:civil=&gt;[t.year, t.mon, m.to_i]}
+          {:civil=&gt;[t.year, t.mon, m.to_i], :not_parsed=&gt;[:year, :mon, :mday]}
         when 3
-          {:ordinal=&gt;[Time.now.year, m.to_i]}
+          {:ordinal=&gt;[Time.now.year, m.to_i], :not_parsed=&gt;[:year, :mon, :mday]}
         when 4
-          {:civil=&gt;[Time.now.year, m[0..1].to_i, m[2..3].to_i]}
+          {:civil=&gt;[Time.now.year, m[0..1].to_i, m[2..3].to_i], :not_parsed=&gt;[:year]}
         when 5
           {:ordinal=&gt;[two_digit_year(m[0..1]), m[2..4].to_i]}
         when 6
@@ -128,16 +128,25 @@ module ThirdBase
     # * i + 4 : meridian indicator
     # * i + 5 : time zone
     def self.add_parsed_time_parts(m, h, i=4)
+      not_parsed = h[:not_parsed] || []
       hour = m[i].to_i
       meridian = m[i+4]
       hour = hour_with_meridian(hour, /a/io.match(meridian) ? :am : :pm) if meridian
-      offset = if m[i+5]
-        x = m[i+5].gsub(':','')
-        x == 'Z' ? 0 : x[0..2].to_i*3600 + x[3..4].to_i*60
+      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
       else
+        not_parsed.concat([:zone, :offset])
         Time.now.utc_offset
       end
-      h.merge!(:parts=&gt;[hour, m[i+1].to_i, m[i+2].to_i, (m[i+3].to_f/0.000001).to_i], :offset=&gt;offset)
+      min = m[i+1].to_i
+      sec = m[i+2].to_i
+      sec_fraction = m[i+3].to_f 
+      not_parsed &lt;&lt; :hour unless m[i]
+      not_parsed &lt;&lt; :min unless m[i+1]
+      not_parsed &lt;&lt; :sec unless m[i+2]
+      not_parsed &lt;&lt; :sec_fraction unless m[i+3]
+      h.merge!(:parts=&gt;[hour, min, sec, (sec_fraction/0.000001).to_i], :offset=&gt;offset, :not_parsed=&gt;not_parsed)
       h
     end
     
@@ -212,6 +221,9 @@ module ThirdBase
     attr_reader :offset
     alias utc_offset offset
     
+    # Which parts of this datetime were guessed instead of being parsed from the input.
+    attr_reader :not_parsed
+
     # Called by DateTime.new!, should be a hash with the following possible keys:
     #
     # * :civil, :commericial, :jd, :ordinal : See ThirdBase::Date#initialize
@@ -221,6 +233,7 @@ module ThirdBase
     #
     # Raises an ArgumentError if an invalid date is used.  DateTime objects are immutable once created.
     def initialize(opts)
+      @not_parsed = opts[:not_parsed] || []
       @offset = opts[:offset]
       raise(ArgumentError, 'invalid datetime') unless @offset.is_a?(Integer) and @offset &lt;= 43200 and @offset &gt;= -43200
       if opts[:parts]</diff>
      <filename>lib/third_base/datetime.rb</filename>
    </modified>
    <modified>
      <diff>@@ -22,8 +22,13 @@ describe ThirdBase::CompatClassMethods do
   end
 
   it &quot;#_parse should parse the date string and return a hash&quot; do
-    Date._parse('2008-10-20 11:12:13-08:00').should == {:mon=&gt;10, :zone=&gt;'-08:00', :sec=&gt;13, :sec_fraction=&gt;0.0, :year=&gt;2008, :hour=&gt;11, :offset=&gt;-28800, :mday=&gt;20, :min=&gt;12}
-    Date._parse('2008-10-20 11:12:13-08:00', true).should == {:mon=&gt;10, :zone=&gt;'-08:00', :sec=&gt;13, :sec_fraction=&gt;0.0, :year=&gt;2008, :hour=&gt;11, :offset=&gt;-28800, :mday=&gt;20, :min=&gt;12}
+    Date._parse('2008-10-20 11:12:13.0-08:00').should == {:mon=&gt;10, :zone=&gt;'-08:00', :sec=&gt;13, :sec_fraction=&gt;0.0, :year=&gt;2008, :hour=&gt;11, :offset=&gt;-28800, :mday=&gt;20, :min=&gt;12}
+    Date._parse('2008-10-20 11:12:13.0-08:00', true).should == {:mon=&gt;10, :zone=&gt;'-08:00', :sec=&gt;13, :sec_fraction=&gt;0.0, :year=&gt;2008, :hour=&gt;11, :offset=&gt;-28800, :mday=&gt;20, :min=&gt;12}
+  end
+
+  it &quot;#_parse should not contain fields in the hash that were guessed&quot; 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;#ajd_to_amjd should convert a astronomical julian date to a astronomical modified julian date&quot; do</diff>
      <filename>spec/compat/compat_class_methods_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -33,4 +33,4 @@ describe &quot;DateTime#+&quot; do
     lambda { DateTime.civil(2007,2,27) + Object.new }.should raise_error(TypeError)
   end
   
-end
\ No newline at end of file
+end</diff>
      <filename>spec/datetime/add_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.0.1&quot;
+  s.version = &quot;1.1.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>b31b918a8ba7ef82aa5f5e0039c37996cc30e659</id>
    </parent>
  </parents>
  <author>
    <name>Jeremy Evans</name>
    <email>code@jeremyevans.net</email>
  </author>
  <url>http://github.com/jeremyevans/third_base/commit/32db77410ff0fa5b879db2770bed8a2d21f68b39</url>
  <id>32db77410ff0fa5b879db2770bed8a2d21f68b39</id>
  <committed-date>2009-06-01T10:15:23-07:00</committed-date>
  <authored-date>2009-06-01T10:15:23-07:00</authored-date>
  <message>Fix Time.parse/Date._parse when using third_base; bump version to 1.1.0

ruby's Time.parse relies on Date._parse, and before third_base's
Date._parse operated differently than the standard Date._parse.
ruby's Date._parse returns a hash that only has keys where the
values were parsed out of the string.  third_base's Date._parse
used to include all possible values, instead of just those that
were parsed out of the string.

For example, for a string like &quot;06/01/2009&quot;, the standard
Date._parse would return {:year=&gt;2009, :mday=&gt;1, :mon=&gt;6}.
third_base's Date._parse would return :hour, :min, :sec,
:sec_fraction, :zone, and :offset keys in the hash.  This caused
problems with Time.parse because it used those values to build
a time object, and it could yield the wrong time, due to issues
with the offset.  Time.parse when using third_base's Date._parse
could give a time like 09:00:00-07:00 instead of 08:00:00-08:00.

This commit fixes that issue by making the hash returned by
Date._parse only include the keys parsed out of the string, and not
include parts guessed by using the current time.

This change unfortunately requires changing the DateTime parsers to
include a :not_parsed entry for values that were not_parsed out of
the string.  Since third_base allows custom parsers, those custom
parsers should change as well, though this should be backwards
compatible.

Because this change requires changes to external parsers to be
fully compatible, the version is getting bumped to 1.1.0 instead
of 1.0.2.

If you aren't using third_base's compatibility mode, there should
be no change by this commit, since it only affects Date._parse.

See the README section added if you are using a custom external
DateTime parser and want to see how to support the new :not_parsed
setting.</message>
  <tree>24d408292ae125b82962da940621c7f0da8e2315</tree>
  <committer>
    <name>Jeremy Evans</name>
    <email>code@jeremyevans.net</email>
  </committer>
</commit>
