diff --git a/README.md b/README.md index b4e3b40f..d1c114bc 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,7 @@ Specific Times (many of the above with an added time) * January 5 at 7pm * 22nd of june at 8am * 1979-05-27 05:00:00 +* 03/01/2012 07:25:09.234567 * etc diff --git a/lib/chronic/repeater.rb b/lib/chronic/repeater.rb index d19f8214..8ac113a0 100644 --- a/lib/chronic/repeater.rb +++ b/lib/chronic/repeater.rb @@ -88,7 +88,7 @@ def self.scan_for_day_portions(token) # # Returns a new Repeater object. def self.scan_for_times(token) - scan_for token, RepeaterTime, /^\d{1,2}(:?\d{1,2})?([\.:]?\d{1,2})?$/ + scan_for token, RepeaterTime, /^\d{1,2}(:?\d{1,2})?([\.:]?\d{1,2}([\.:]\d{1,6})?)?$/ end # token - The Token object we want to scan. diff --git a/lib/chronic/repeaters/repeater_time.rb b/lib/chronic/repeaters/repeater_time.rb index e50caaa9..3ed83e9d 100644 --- a/lib/chronic/repeaters/repeater_time.rb +++ b/lib/chronic/repeaters/repeater_time.rb @@ -28,30 +28,33 @@ def to_s def initialize(time) @current_time = nil - t = time.gsub(/\:/, '') - - @type = - case t.size - when 1..2 - hours = t.to_i - Tick.new((hours == 12 ? 0 : hours) * 60 * 60, true) - when 3 - hours = t[0..0].to_i - ambiguous = hours > 0 - Tick.new((hours * 60 * 60) + (t[1..2].to_i * 60), ambiguous) - when 4 - ambiguous = time =~ /:/ && t[0..0].to_i != 0 && t[0..1].to_i <= 12 - hours = t[0..1].to_i - hours == 12 ? Tick.new(0 * 60 * 60 + t[2..3].to_i * 60, ambiguous) : Tick.new(hours * 60 * 60 + t[2..3].to_i * 60, ambiguous) - when 5 - Tick.new(t[0..0].to_i * 60 * 60 + t[1..2].to_i * 60 + t[3..4].to_i, true) - when 6 - ambiguous = time =~ /:/ && t[0..0].to_i != 0 && t[0..1].to_i <= 12 - hours = t[0..1].to_i - hours == 12 ? Tick.new(0 * 60 * 60 + t[2..3].to_i * 60 + t[4..5].to_i, ambiguous) : Tick.new(hours * 60 * 60 + t[2..3].to_i * 60 + t[4..5].to_i, ambiguous) - else - raise("Time cannot exceed six digits") + time_parts = time.split(':') + raise ArgumentError, "Time cannot have more than 4 groups of ':'" if time_parts.count > 4 + + if time_parts.first.length > 2 and time_parts.count == 1 + if time_parts.first.length > 4 + second_index = time_parts.first.length - 2 + time_parts.insert(1, time_parts.first[second_index..time_parts.first.length]) + time_parts[0] = time_parts.first[0..second_index - 1] + end + minute_index = time_parts.first.length - 2 + time_parts.insert(1, time_parts.first[minute_index..time_parts.first.length]) + time_parts[0] = time_parts.first[0..minute_index - 1] end + + ambiguous = false + hours = time_parts.first.to_i + ambiguous = true if (time_parts.first.length == 1 and hours > 0) or (hours >= 10 and hours <= 12) + hours = (hours == 12 ? 0 : hours) * 60 * 60 + minutes = 0 + seconds = 0 + subseconds = 0 + + minutes = time_parts[1].to_i * 60 if time_parts.count > 1 + seconds = time_parts[2].to_i if time_parts.count > 2 + subseconds = time_parts[3].to_f / (10 ** time_parts[3].length) if time_parts.count > 3 + + @type = Tick.new(hours + minutes + seconds + subseconds, ambiguous) end # Return the next past or future Span for the time that this Repeater represents diff --git a/test/test_parsing.rb b/test/test_parsing.rb index e844281c..66ba6084 100644 --- a/test/test_parsing.rb +++ b/test/test_parsing.rb @@ -23,7 +23,11 @@ def test_handle_generic time = Chronic.parse("2012-01-03 01:00:00.100") time2 = Time.parse("2012-01-03 01:00:00.100") - assert_equal time, time2 + assert_in_delta time, time2, 0.001 + + time = Chronic.parse("2012-01-03 01:00:00.234567") + time2 = Time.parse("2012-01-03 01:00:00.234567") + assert_in_delta time, time2, 0.000001 assert_nil Chronic.parse("1/1/32.1") @@ -64,6 +68,9 @@ def test_handle_rmn_sd time = parse_now("may 28 at 5:32.19pm", :context => :past) assert_equal Time.local(2006, 5, 28, 17, 32, 19), time + + time = parse_now("may 28 at 5:32:19.764") + assert_in_delta Time.local(2007, 5, 28, 17, 32, 19, 764000), time, 0.001 end def test_handle_rmn_sd_on @@ -171,6 +178,9 @@ def test_handle_sy_sm_sd_t_tz time = parse_now("2011-07-03 21:11:35 UTC") assert_equal 1309727495, time.to_i + + time = parse_now("2011-07-03 21:11:35.362 UTC") + assert_in_delta 1309727495.362, time.to_f, 0.001 end def test_handle_rmn_sd_sy @@ -325,6 +335,9 @@ def test_handle_sy_sm_sd time = parse_now("2006-08-20 15:30.30") assert_equal Time.local(2006, 8, 20, 15, 30, 30), time + time = parse_now("2006-08-20 15:30:30:000536") + assert_in_delta Time.local(2006, 8, 20, 15, 30, 30, 536), time, 0.000001 + time = parse_now("1902-08-20") assert_equal Time.local(1902, 8, 20, 12, 0, 0), time diff --git a/test/test_repeater_time.rb b/test/test_repeater_time.rb index b1a0be3f..26b2bcb3 100644 --- a/test/test_repeater_time.rb +++ b/test/test_repeater_time.rb @@ -7,6 +7,12 @@ def setup @now = Time.local(2006, 8, 16, 14, 0, 0, 0) end + def test_generic + assert_raises(ArgumentError) do + Chronic::RepeaterTime.new('00:01:02:03:004') + end + end + def test_next_future t = Chronic::RepeaterTime.new('4:00') t.start = @now @@ -25,6 +31,12 @@ def test_next_future assert_equal Time.local(2006, 8, 17, 4), t.next(:future).begin assert_equal Time.local(2006, 8, 18, 4), t.next(:future).begin + + t = Chronic::RepeaterTime.new('0000') + t.start = @now + + assert_equal Time.local(2006, 8, 17, 0), t.next(:future).begin + assert_equal Time.local(2006, 8, 18, 0), t.next(:future).begin end def test_next_past @@ -39,6 +51,12 @@ def test_next_past assert_equal Time.local(2006, 8, 16, 13), t.next(:past).begin assert_equal Time.local(2006, 8, 15, 13), t.next(:past).begin + + t = Chronic::RepeaterTime.new('0:00.000') + t.start = @now + + assert_equal Time.local(2006, 8, 16, 0), t.next(:past).begin + assert_equal Time.local(2006, 8, 15, 0), t.next(:past).begin end def test_type