chronic 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/HISTORY.md +27 -0
- data/Manifest.txt +16 -5
- data/README.md +14 -8
- data/Rakefile +2 -8
- data/chronic.gemspec +8 -11
- data/lib/chronic.rb +21 -14
- data/lib/chronic/chronic.rb +38 -130
- data/lib/chronic/grabber.rb +11 -15
- data/lib/chronic/handlers.rb +63 -40
- data/lib/chronic/mini_date.rb +27 -0
- data/lib/chronic/numerizer.rb +120 -0
- data/lib/chronic/ordinal.rb +5 -10
- data/lib/chronic/pointer.rb +8 -10
- data/lib/chronic/repeater.rb +106 -109
- data/lib/chronic/repeaters/repeater_day.rb +43 -41
- data/lib/chronic/repeaters/repeater_day_name.rb +38 -36
- data/lib/chronic/repeaters/repeater_day_portion.rb +74 -73
- data/lib/chronic/repeaters/repeater_fortnight.rb +57 -55
- data/lib/chronic/repeaters/repeater_hour.rb +46 -44
- data/lib/chronic/repeaters/repeater_minute.rb +46 -44
- data/lib/chronic/repeaters/repeater_month.rb +52 -50
- data/lib/chronic/repeaters/repeater_month_name.rb +84 -80
- data/lib/chronic/repeaters/repeater_season.rb +97 -119
- data/lib/chronic/repeaters/repeater_season_name.rb +39 -39
- data/lib/chronic/repeaters/repeater_second.rb +32 -30
- data/lib/chronic/repeaters/repeater_time.rb +106 -101
- data/lib/chronic/repeaters/repeater_week.rb +60 -58
- data/lib/chronic/repeaters/repeater_weekday.rb +67 -58
- data/lib/chronic/repeaters/repeater_weekend.rb +54 -52
- data/lib/chronic/repeaters/repeater_year.rb +50 -48
- data/lib/chronic/scalar.rb +24 -16
- data/lib/chronic/separator.rb +15 -33
- data/lib/chronic/span.rb +31 -0
- data/lib/chronic/tag.rb +26 -0
- data/lib/chronic/time_zone.rb +7 -9
- data/lib/chronic/token.rb +35 -0
- data/test/helper.rb +5 -6
- data/test/test_Chronic.rb +5 -0
- data/test/test_Numerizer.rb +60 -39
- data/test/test_RepeaterHour.rb +4 -0
- data/test/test_parsing.rb +104 -13
- metadata +14 -20
- data/lib/chronic/numerizer/numerizer.rb +0 -97
data/lib/chronic/scalar.rb
CHANGED
@@ -1,53 +1,61 @@
|
|
1
1
|
module Chronic
|
2
2
|
|
3
3
|
class Scalar < Tag #:nodoc:
|
4
|
-
|
4
|
+
DAY_PORTIONS = %w( am pm morning afternoon evening night )
|
5
|
+
|
6
|
+
def self.scan(tokens, options)
|
5
7
|
# for each token
|
6
8
|
tokens.each_index do |i|
|
7
|
-
if t =
|
8
|
-
if t =
|
9
|
-
if t =
|
10
|
-
if t =
|
9
|
+
if t = scan_for_scalars(tokens[i], tokens[i + 1]) then tokens[i].tag(t) end
|
10
|
+
if t = scan_for_days(tokens[i], tokens[i + 1]) then tokens[i].tag(t) end
|
11
|
+
if t = scan_for_months(tokens[i], tokens[i + 1]) then tokens[i].tag(t) end
|
12
|
+
if t = scan_for_years(tokens[i], tokens[i + 1], options) then tokens[i].tag(t) end
|
11
13
|
end
|
12
|
-
tokens
|
13
14
|
end
|
14
15
|
|
15
16
|
def self.scan_for_scalars(token, post_token)
|
16
17
|
if token.word =~ /^\d*$/
|
17
|
-
unless post_token &&
|
18
|
+
unless post_token && DAY_PORTIONS.include?(post_token.word)
|
18
19
|
return Scalar.new(token.word.to_i)
|
19
20
|
end
|
20
21
|
end
|
21
|
-
return nil
|
22
22
|
end
|
23
23
|
|
24
24
|
def self.scan_for_days(token, post_token)
|
25
25
|
if token.word =~ /^\d\d?$/
|
26
26
|
toi = token.word.to_i
|
27
|
-
unless toi > 31 || toi < 1 || (post_token &&
|
27
|
+
unless toi > 31 || toi < 1 || (post_token && DAY_PORTIONS.include?(post_token.word))
|
28
28
|
return ScalarDay.new(toi)
|
29
29
|
end
|
30
30
|
end
|
31
|
-
return nil
|
32
31
|
end
|
33
32
|
|
34
33
|
def self.scan_for_months(token, post_token)
|
35
34
|
if token.word =~ /^\d\d?$/
|
36
35
|
toi = token.word.to_i
|
37
|
-
unless toi > 12 || toi < 1 || (post_token &&
|
36
|
+
unless toi > 12 || toi < 1 || (post_token && DAY_PORTIONS.include?(post_token.word))
|
38
37
|
return ScalarMonth.new(toi)
|
39
38
|
end
|
40
39
|
end
|
41
|
-
return nil
|
42
40
|
end
|
43
41
|
|
44
|
-
def self.scan_for_years(token, post_token)
|
42
|
+
def self.scan_for_years(token, post_token, options)
|
45
43
|
if token.word =~ /^([1-9]\d)?\d\d?$/
|
46
|
-
unless post_token &&
|
47
|
-
|
44
|
+
unless post_token && DAY_PORTIONS.include?(post_token.word)
|
45
|
+
year = make_year(token.word.to_i, options[:ambiguous_year_future_bias])
|
46
|
+
return ScalarYear.new(year.to_i)
|
48
47
|
end
|
49
48
|
end
|
50
|
-
|
49
|
+
end
|
50
|
+
|
51
|
+
# Build a year from a 2 digit suffix
|
52
|
+
def self.make_year(year, bias)
|
53
|
+
return year if year.to_s.size > 2
|
54
|
+
start_year = Chronic.time_class.now.year - bias
|
55
|
+
century = (start_year / 100) * 100
|
56
|
+
full_year = century + year
|
57
|
+
full_year += 100 if full_year < start_year
|
58
|
+
full_year
|
51
59
|
end
|
52
60
|
|
53
61
|
def to_s
|
data/lib/chronic/separator.rb
CHANGED
@@ -1,56 +1,38 @@
|
|
1
1
|
module Chronic
|
2
2
|
|
3
3
|
class Separator < Tag #:nodoc:
|
4
|
-
def self.scan(tokens)
|
4
|
+
def self.scan(tokens, options)
|
5
5
|
tokens.each_index do |i|
|
6
|
-
if t =
|
7
|
-
if t =
|
8
|
-
if t =
|
9
|
-
if t =
|
10
|
-
if t =
|
6
|
+
if t = scan_for_commas(tokens[i]) then tokens[i].tag(t); next end
|
7
|
+
if t = scan_for_slash_or_dash(tokens[i]) then tokens[i].tag(t); next end
|
8
|
+
if t = scan_for_at(tokens[i]) then tokens[i].tag(t); next end
|
9
|
+
if t = scan_for_in(tokens[i]) then tokens[i].tag(t); next end
|
10
|
+
if t = scan_for_on(tokens[i]) then tokens[i].tag(t); next end
|
11
11
|
end
|
12
|
-
tokens
|
13
12
|
end
|
14
13
|
|
15
14
|
def self.scan_for_commas(token)
|
16
|
-
|
17
|
-
scanner.keys.each do |scanner_item|
|
18
|
-
return SeparatorComma.new(scanner[scanner_item]) if scanner_item =~ token.word
|
19
|
-
end
|
20
|
-
return nil
|
15
|
+
scan_for token, SeparatorComma, { /^,$/ => :comma }
|
21
16
|
end
|
22
17
|
|
23
18
|
def self.scan_for_slash_or_dash(token)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
return nil
|
19
|
+
scan_for token, SeparatorSlashOrDash,
|
20
|
+
{
|
21
|
+
/^-$/ => :dash,
|
22
|
+
/^\/$/ => :slash
|
23
|
+
}
|
30
24
|
end
|
31
25
|
|
32
26
|
def self.scan_for_at(token)
|
33
|
-
|
34
|
-
scanner.keys.each do |scanner_item|
|
35
|
-
return SeparatorAt.new(scanner[scanner_item]) if scanner_item =~ token.word
|
36
|
-
end
|
37
|
-
return nil
|
27
|
+
scan_for token, SeparatorAt, { /^(at|@)$/ => :at }
|
38
28
|
end
|
39
29
|
|
40
30
|
def self.scan_for_in(token)
|
41
|
-
|
42
|
-
scanner.keys.each do |scanner_item|
|
43
|
-
return SeparatorIn.new(scanner[scanner_item]) if scanner_item =~ token.word
|
44
|
-
end
|
45
|
-
return nil
|
31
|
+
scan_for token, SeparatorIn, { /^in$/ => :in }
|
46
32
|
end
|
47
33
|
|
48
34
|
def self.scan_for_on(token)
|
49
|
-
|
50
|
-
scanner.keys.each do |scanner_item|
|
51
|
-
return SeparatorOn.new(scanner[scanner_item]) if scanner_item =~ token.word
|
52
|
-
end
|
53
|
-
return nil
|
35
|
+
scan_for token, SeparatorOn, { /^on$/ => :on }
|
54
36
|
end
|
55
37
|
|
56
38
|
def to_s
|
data/lib/chronic/span.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Chronic
|
2
|
+
# A Span represents a range of time. Since this class extends
|
3
|
+
# Range, you can use #begin and #end to get the beginning and
|
4
|
+
# ending times of the span (they will be of class Time)
|
5
|
+
class Span < Range
|
6
|
+
# Returns the width of this span in seconds
|
7
|
+
def width
|
8
|
+
(self.end - self.begin).to_i
|
9
|
+
end
|
10
|
+
|
11
|
+
# Add a number of seconds to this span, returning the
|
12
|
+
# resulting Span
|
13
|
+
def +(seconds)
|
14
|
+
Span.new(self.begin + seconds, self.end + seconds)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Subtract a number of seconds to this span, returning the
|
18
|
+
# resulting Span
|
19
|
+
def -(seconds)
|
20
|
+
self + -seconds
|
21
|
+
end
|
22
|
+
|
23
|
+
# Prints this span in a nice fashion
|
24
|
+
def to_s
|
25
|
+
'(' << self.begin.to_s << '..' << self.end.to_s << ')'
|
26
|
+
end
|
27
|
+
|
28
|
+
alias :cover? :include? unless RUBY_VERSION =~ /^1.9/
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
data/lib/chronic/tag.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Chronic
|
2
|
+
# Tokens are tagged with subclassed instances of this class when
|
3
|
+
# they match specific criteria
|
4
|
+
class Tag #:nodoc:
|
5
|
+
attr_accessor :type
|
6
|
+
|
7
|
+
def initialize(type)
|
8
|
+
@type = type
|
9
|
+
end
|
10
|
+
|
11
|
+
def start=(s)
|
12
|
+
@now = s
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
private
|
17
|
+
|
18
|
+
def scan_for(token, klass, items={})
|
19
|
+
items.each do |item, symbol|
|
20
|
+
return klass.new(symbol) if item =~ token.word
|
21
|
+
end
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/chronic/time_zone.rb
CHANGED
@@ -1,19 +1,17 @@
|
|
1
1
|
module Chronic
|
2
2
|
class TimeZone < Tag #:nodoc:
|
3
|
-
def self.scan(tokens)
|
3
|
+
def self.scan(tokens, options)
|
4
4
|
tokens.each_index do |i|
|
5
|
-
if t =
|
5
|
+
if t = scan_for_all(tokens[i]) then tokens[i].tag(t); next end
|
6
6
|
end
|
7
|
-
tokens
|
8
7
|
end
|
9
8
|
|
10
9
|
def self.scan_for_all(token)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
return nil
|
10
|
+
scan_for token, self,
|
11
|
+
{
|
12
|
+
/[PMCE][DS]T/i => :tz,
|
13
|
+
/(tzminus)?\d{4}/ => :tz
|
14
|
+
}
|
17
15
|
end
|
18
16
|
|
19
17
|
def to_s
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Chronic
|
2
|
+
class Token #:nodoc:
|
3
|
+
attr_accessor :word, :tags
|
4
|
+
|
5
|
+
def initialize(word)
|
6
|
+
@word = word
|
7
|
+
@tags = []
|
8
|
+
end
|
9
|
+
|
10
|
+
# Tag this token with the specified tag
|
11
|
+
def tag(new_tag)
|
12
|
+
@tags << new_tag
|
13
|
+
end
|
14
|
+
|
15
|
+
# Remove all tags of the given class
|
16
|
+
def untag(tag_class)
|
17
|
+
@tags.delete_if { |m| m.kind_of? tag_class }
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return true if this token has any tags
|
21
|
+
def tagged?
|
22
|
+
@tags.size > 0
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return the Tag that matches the given class
|
26
|
+
def get_tag(tag_class)
|
27
|
+
@tags.find { |m| m.kind_of? tag_class }
|
28
|
+
end
|
29
|
+
|
30
|
+
# Print this Token in a pretty way
|
31
|
+
def to_s
|
32
|
+
@word << '(' << @tags.join(', ') << ') '
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/test/helper.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
|
1
|
+
unless defined? Chronic
|
2
|
+
$:.unshift File.expand_path('../../lib')
|
3
|
+
require 'chronic'
|
4
|
+
end
|
2
5
|
|
3
|
-
|
4
|
-
$LOAD_PATH.unshift(File.join(dir, '..', 'lib'))
|
5
|
-
$LOAD_PATH.unshift(dir)
|
6
|
-
|
7
|
-
require 'chronic'
|
6
|
+
require 'test/unit'
|
data/test/test_Chronic.rb
CHANGED
@@ -7,6 +7,11 @@ class TestChronic < Test::Unit::TestCase
|
|
7
7
|
@now = Time.local(2006, 8, 16, 14, 0, 0, 0)
|
8
8
|
end
|
9
9
|
|
10
|
+
def test_pre_normalize_numerized_string
|
11
|
+
string = 'two and a half years'
|
12
|
+
assert_equal Chronic::Numerizer.numerize(string), Chronic.pre_normalize(string)
|
13
|
+
end
|
14
|
+
|
10
15
|
def test_post_normalize_am_pm_aliases
|
11
16
|
# affect wanted patterns
|
12
17
|
|
data/test/test_Numerizer.rb
CHANGED
@@ -3,49 +3,70 @@ require File.join(File.dirname(__FILE__), *%w[helper])
|
|
3
3
|
class ParseNumbersTest < Test::Unit::TestCase
|
4
4
|
|
5
5
|
def test_straight_parsing
|
6
|
-
strings = {
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
6
|
+
strings = {
|
7
|
+
'one' => 1,
|
8
|
+
'five' => 5,
|
9
|
+
'ten' => 10,
|
10
|
+
'eleven' => 11,
|
11
|
+
'twelve' => 12,
|
12
|
+
'thirteen' => 13,
|
13
|
+
'fourteen' => 14,
|
14
|
+
'fifteen' => 15,
|
15
|
+
'sixteen' => 16,
|
16
|
+
'seventeen' => 17,
|
17
|
+
'eighteen' => 18,
|
18
|
+
'nineteen' => 19,
|
19
|
+
'twenty' => 20,
|
20
|
+
'twenty seven' => 27,
|
21
|
+
'thirty-one' => 31,
|
22
|
+
'thirty-seven' => 37,
|
23
|
+
'thirty seven' => 37,
|
24
|
+
'fifty nine' => 59,
|
25
|
+
'forty two' => 42,
|
26
|
+
'fourty two' => 42,
|
27
|
+
# 'a hundred' => 100,
|
28
|
+
'one hundred' => 100,
|
29
|
+
'one hundred and fifty' => 150,
|
30
|
+
# 'one fifty' => 150,
|
31
|
+
'two-hundred' => 200,
|
32
|
+
'5 hundred' => 500,
|
33
|
+
'nine hundred and ninety nine' => 999,
|
34
|
+
'one thousand' => 1000,
|
35
|
+
'twelve hundred' => 1200,
|
36
|
+
'one thousand two hundred' => 1_200,
|
37
|
+
'seventeen thousand' => 17_000,
|
38
|
+
'twentyone-thousand-four-hundred-and-seventy-three' => 21_473,
|
39
|
+
'seventy four thousand and two' => 74_002,
|
40
|
+
'ninety nine thousand nine hundred ninety nine' => 99_999,
|
41
|
+
'100 thousand' => 100_000,
|
42
|
+
'two hundred fifty thousand' => 250_000,
|
43
|
+
'one million' => 1_000_000,
|
44
|
+
'one million two hundred fifty thousand and seven' => 1_250_007,
|
45
|
+
'one billion' => 1_000_000_000,
|
46
|
+
'one billion and one' => 1_000_000_001}
|
42
47
|
|
43
|
-
strings.
|
44
|
-
assert_equal
|
48
|
+
strings.each do |key, val|
|
49
|
+
assert_equal val, Chronic::Numerizer.numerize(key).to_i
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_ordinal_strings
|
54
|
+
{
|
55
|
+
'first' => '1st',
|
56
|
+
'second' => 'second',
|
57
|
+
'second day' => '2nd day',
|
58
|
+
'second of may' => '2nd of may',
|
59
|
+
'fifth' => '5th',
|
60
|
+
'twenty third' => '23rd',
|
61
|
+
'first day month two' => '1st day month 2'
|
62
|
+
}.each do |key, val|
|
63
|
+
# Use pre_normalize here instead of Numerizer directly because
|
64
|
+
# pre_normalize deals with parsing 'second' appropriately
|
65
|
+
assert_equal val, Chronic.pre_normalize(key)
|
45
66
|
end
|
46
67
|
end
|
47
68
|
|
48
69
|
def test_edges
|
49
|
-
assert_equal "27 Oct 2006 7:30am", Numerizer.numerize("27 Oct 2006 7:30am")
|
70
|
+
assert_equal "27 Oct 2006 7:30am", Chronic::Numerizer.numerize("27 Oct 2006 7:30am")
|
50
71
|
end
|
51
72
|
end
|
data/test/test_RepeaterHour.rb
CHANGED
@@ -45,6 +45,10 @@ class TestRepeaterHour < Test::Unit::TestCase
|
|
45
45
|
this_hour = hours.this(:past)
|
46
46
|
assert_equal Time.local(2006, 8, 16, 14), this_hour.begin
|
47
47
|
assert_equal Time.local(2006, 8, 16, 14, 30), this_hour.end
|
48
|
+
|
49
|
+
this_hour = hours.this(:none)
|
50
|
+
assert_equal Time.local(2006, 8, 16, 14), this_hour.begin
|
51
|
+
assert_equal Time.local(2006, 8, 16, 15), this_hour.end
|
48
52
|
end
|
49
53
|
|
50
54
|
def test_offset
|
data/test/test_parsing.rb
CHANGED
@@ -26,6 +26,20 @@ class TestParsing < Test::Unit::TestCase
|
|
26
26
|
time = parse_now("may 28 at 5:32.19pm", :context => :past)
|
27
27
|
assert_equal Time.local(2006, 5, 28, 17, 32, 19), time
|
28
28
|
|
29
|
+
# rm_sd for current month
|
30
|
+
|
31
|
+
time = parse_now("aug 3")
|
32
|
+
assert_equal Time.local(2006, 8, 3, 12), time
|
33
|
+
|
34
|
+
time = parse_now("aug 3", :context => :past)
|
35
|
+
assert_equal Time.local(2006, 8, 3, 12), time
|
36
|
+
|
37
|
+
time = parse_now("aug 20")
|
38
|
+
assert_equal Time.local(2006, 8, 20, 12), time
|
39
|
+
|
40
|
+
time = parse_now("aug 20", :context => :future)
|
41
|
+
assert_equal Time.local(2006, 8, 20, 12), time
|
42
|
+
|
29
43
|
# rm_sd_on
|
30
44
|
|
31
45
|
time = parse_now("5pm on may 28")
|
@@ -59,6 +73,9 @@ class TestParsing < Test::Unit::TestCase
|
|
59
73
|
time = parse_now("5:00 pm may 27th", :context => :past)
|
60
74
|
assert_equal Time.local(2006, 5, 27, 17), time
|
61
75
|
|
76
|
+
time = parse_now("05:00 pm may 27th", :context => :past)
|
77
|
+
assert_equal Time.local(2006, 5, 27, 17), time
|
78
|
+
|
62
79
|
time = parse_now("5pm on may 27th", :context => :past)
|
63
80
|
assert_equal Time.local(2006, 5, 27, 17), time
|
64
81
|
|
@@ -73,8 +90,46 @@ class TestParsing < Test::Unit::TestCase
|
|
73
90
|
time = parse_now("dec 79")
|
74
91
|
assert_equal Time.local(1979, 12, 16, 12), time
|
75
92
|
|
93
|
+
# rm_od_sy
|
94
|
+
|
95
|
+
time = parse_now("November 18th 2010")
|
96
|
+
assert_equal Time.local(2010, 11, 18, 12), time
|
97
|
+
|
98
|
+
time = parse_now("November 18th, 2010")
|
99
|
+
assert_equal Time.local(2010, 11, 18, 12), time
|
100
|
+
|
101
|
+
time = parse_now("November 18th 2010 midnight")
|
102
|
+
assert_equal Time.local(2010, 11, 19, 0), time
|
103
|
+
|
104
|
+
time = parse_now("November 18th 2010 at midnight")
|
105
|
+
assert_equal Time.local(2010, 11, 19, 0), time
|
106
|
+
|
107
|
+
time = parse_now("November 18th 2010 at 4")
|
108
|
+
assert_equal Time.local(2010, 11, 18, 16), time
|
109
|
+
|
110
|
+
time = parse_now("November 18th 2010 at 4", :ambiguous_time_range => :none)
|
111
|
+
assert_equal Time.local(2010, 11, 18, 4), time
|
112
|
+
|
113
|
+
time = parse_now("March 30th, 1979")
|
114
|
+
assert_equal Time.local(1979, 3, 30, 12), time
|
115
|
+
|
116
|
+
time = parse_now("March 30th 79")
|
117
|
+
assert_equal Time.local(1979, 3, 30, 12), time
|
118
|
+
|
119
|
+
time = parse_now("March 30th 79 4:30")
|
120
|
+
assert_equal Time.local(1979, 3, 30, 16, 30), time
|
121
|
+
|
122
|
+
time = parse_now("March 30th 79 at 4:30", :ambiguous_time_range => :none)
|
123
|
+
assert_equal Time.local(1979, 3, 30, 4, 30), time
|
124
|
+
|
76
125
|
# rm_sd_sy
|
77
126
|
|
127
|
+
time = parse_now("November 18, 2010")
|
128
|
+
assert_equal Time.local(2010, 11, 18, 12), time
|
129
|
+
|
130
|
+
time = parse_now("February 14, 2004")
|
131
|
+
assert_equal Time.local(2004, 2, 14, 12), time
|
132
|
+
|
78
133
|
time = parse_now("jan 3 2010")
|
79
134
|
assert_equal Time.local(2010, 1, 3, 12), time
|
80
135
|
|
@@ -170,7 +225,7 @@ class TestParsing < Test::Unit::TestCase
|
|
170
225
|
|
171
226
|
now = Time.now
|
172
227
|
time = parse_now(now.to_s)
|
173
|
-
assert_equal now.to_s, time.to_s
|
228
|
+
# assert_equal now.to_s, time.to_s
|
174
229
|
|
175
230
|
# rm_sd_rt
|
176
231
|
|
@@ -180,15 +235,26 @@ class TestParsing < Test::Unit::TestCase
|
|
180
235
|
# old dates
|
181
236
|
|
182
237
|
time = parse_now("may 40")
|
183
|
-
assert_equal Time.local(
|
238
|
+
assert_equal Time.local(2040, 5, 16, 12, 0, 0), time
|
184
239
|
|
185
240
|
time = parse_now("may 27 40")
|
186
|
-
assert_equal Time.local(
|
241
|
+
assert_equal Time.local(2040, 5, 27, 12, 0, 0), time
|
187
242
|
|
188
243
|
time = parse_now("1800-08-20")
|
189
244
|
assert_equal Time.local(1800, 8, 20, 12, 0, 0), time
|
190
245
|
end
|
191
246
|
|
247
|
+
def test_parse_two_digit_years
|
248
|
+
time = parse_now("may 97")
|
249
|
+
assert_equal Time.local(1997, 5, 16, 12), time
|
250
|
+
|
251
|
+
time = parse_now("may 1st 01")
|
252
|
+
assert_equal Time.local(2001, 5, 1, 12), time
|
253
|
+
|
254
|
+
time = parse_now("may 79", :ambiguous_year_future_bias => 10)
|
255
|
+
assert_equal Time.local(2079, 5, 16, 12), time
|
256
|
+
end
|
257
|
+
|
192
258
|
def test_parse_guess_r
|
193
259
|
time = parse_now("friday")
|
194
260
|
assert_equal Time.local(2006, 8, 18, 12), time
|
@@ -246,6 +312,9 @@ class TestParsing < Test::Unit::TestCase
|
|
246
312
|
time = parse_now("4:00 in the morning")
|
247
313
|
assert_equal Time.local(2006, 8, 16, 4), time
|
248
314
|
|
315
|
+
time = parse_now("0:10")
|
316
|
+
assert_equal Time.local(2006, 8, 17, 0, 10), time
|
317
|
+
|
249
318
|
time = parse_now("november 4")
|
250
319
|
assert_equal Time.local(2006, 11, 4, 12), time
|
251
320
|
|
@@ -325,17 +394,21 @@ class TestParsing < Test::Unit::TestCase
|
|
325
394
|
# day
|
326
395
|
|
327
396
|
time = parse_now("this day")
|
328
|
-
assert_equal Time.local(2006, 8, 16, 19
|
397
|
+
assert_equal Time.local(2006, 8, 16, 19), time
|
329
398
|
|
330
399
|
time = parse_now("this day", :context => :past)
|
331
400
|
assert_equal Time.local(2006, 8, 16, 7), time
|
332
401
|
|
333
402
|
time = parse_now("today")
|
334
|
-
assert_equal Time.local(2006, 8, 16, 19
|
403
|
+
assert_equal Time.local(2006, 8, 16, 19), time
|
335
404
|
|
336
405
|
time = parse_now("yesterday")
|
337
406
|
assert_equal Time.local(2006, 8, 15, 12), time
|
338
407
|
|
408
|
+
now = Time.parse("2011-05-27 23:10") # after 11pm
|
409
|
+
time = parse_now("yesterday", :now => now)
|
410
|
+
assert_equal Time.local(2011, 05, 26, 12), time
|
411
|
+
|
339
412
|
time = parse_now("tomorrow")
|
340
413
|
assert_equal Time.local(2006, 8, 17, 12), time
|
341
414
|
|
@@ -452,6 +525,10 @@ class TestParsing < Test::Unit::TestCase
|
|
452
525
|
|
453
526
|
time = parse_now("next monday at 12:01 pm")
|
454
527
|
assert_equal Time.local(2006, 8, 21, 12, 1), time
|
528
|
+
|
529
|
+
# with context
|
530
|
+
time = parse_now("sunday at 8:15pm", :context => :past)
|
531
|
+
assert_equal Time.local(2006, 8, 13, 20, 15), time
|
455
532
|
end
|
456
533
|
|
457
534
|
def test_parse_guess_rgr
|
@@ -578,12 +655,19 @@ class TestParsing < Test::Unit::TestCase
|
|
578
655
|
end
|
579
656
|
|
580
657
|
def test_parse_guess_o_r_g_r
|
581
|
-
time = parse_now("3rd month next year")
|
582
|
-
assert_equal Time.local(2007, 3
|
658
|
+
time = parse_now("3rd month next year", :guess => false)
|
659
|
+
assert_equal Time.local(2007, 3), time.begin
|
660
|
+
|
661
|
+
time = parse_now("3rd month next year", :guess => false)
|
662
|
+
assert_equal Time.local(2007, 3, 1), time.begin
|
583
663
|
|
584
664
|
time = parse_now("3rd thursday this september")
|
585
665
|
assert_equal Time.local(2006, 9, 21, 12), time
|
586
666
|
|
667
|
+
now = Time.parse("1/10/2010")
|
668
|
+
time = parse_now("3rd thursday this november", :now => now)
|
669
|
+
assert_equal Time.local(2010, 11, 18, 12), time
|
670
|
+
|
587
671
|
time = parse_now("4th day last week")
|
588
672
|
assert_equal Time.local(2006, 8, 9, 12), time
|
589
673
|
end
|
@@ -662,16 +746,16 @@ class TestParsing < Test::Unit::TestCase
|
|
662
746
|
assert_equal Time.local(2007, 6, 20), t.end
|
663
747
|
|
664
748
|
t = parse_now("this winter", :guess => false)
|
665
|
-
assert_equal Time.local(2006, 12, 22
|
749
|
+
assert_equal Time.local(2006, 12, 22), t.begin
|
666
750
|
assert_equal Time.local(2007, 3, 19), t.end
|
667
751
|
|
668
752
|
t = parse_now("last spring", :guess => false)
|
669
|
-
assert_equal Time.local(2006, 3, 20
|
753
|
+
assert_equal Time.local(2006, 3, 20), t.begin
|
670
754
|
assert_equal Time.local(2006, 6, 20), t.end
|
671
755
|
|
672
756
|
t = parse_now("last winter", :guess => false)
|
673
|
-
assert_equal Time.local(2005, 12, 22
|
674
|
-
assert_equal Time.local(2006, 3, 19
|
757
|
+
assert_equal Time.local(2005, 12, 22), t.begin
|
758
|
+
assert_equal Time.local(2006, 3, 19), t.end
|
675
759
|
|
676
760
|
t = parse_now("next spring", :guess => false)
|
677
761
|
assert_equal Time.local(2007, 3, 20), t.begin
|
@@ -694,8 +778,8 @@ class TestParsing < Test::Unit::TestCase
|
|
694
778
|
t1 = Chronic.parse('1st saturday in november', :now => Time.local(2007))
|
695
779
|
assert_equal Time.local(2007, 11, 3, 12), t1
|
696
780
|
|
697
|
-
t1 = Chronic.parse('1st sunday in november', :now => Time.local(2007))
|
698
|
-
assert_equal Time.local(2007, 11, 4,
|
781
|
+
# t1 = Chronic.parse('1st sunday in november', :now => Time.local(2007))
|
782
|
+
# assert_equal Time.local(2007, 11, 4, 12), t1
|
699
783
|
|
700
784
|
# Chronic.debug = true
|
701
785
|
#
|
@@ -703,6 +787,13 @@ class TestParsing < Test::Unit::TestCase
|
|
703
787
|
# assert_equal Time.local(2007, 11, 5, 11), t1
|
704
788
|
end
|
705
789
|
|
790
|
+
def test_now_changes
|
791
|
+
t1 = Chronic.parse("now")
|
792
|
+
sleep 0.1
|
793
|
+
t2 = Chronic.parse("now")
|
794
|
+
assert_not_equal t1, t2
|
795
|
+
end
|
796
|
+
|
706
797
|
private
|
707
798
|
def parse_now(string, options={})
|
708
799
|
Chronic.parse(string, {:now => TIME_2006_08_16_14_00_00 }.merge(options))
|