chronic 0.1.5 → 0.2.1
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.txt +17 -1
- data/Manifest.txt +3 -1
- data/Rakefile +5 -25
- data/lib/chronic/chronic.rb +3 -5
- data/lib/chronic/handlers.rb +84 -27
- data/lib/chronic/pointer.rb +3 -3
- data/lib/chronic/repeater.rb +3 -2
- data/lib/chronic/repeaters/repeater_day.rb +6 -6
- data/lib/chronic/repeaters/repeater_day_name.rb +2 -2
- data/lib/chronic/repeaters/repeater_day_portion.rb +8 -8
- data/lib/chronic/repeaters/repeater_fortnight.rb +2 -2
- data/lib/chronic/repeaters/repeater_hour.rb +7 -7
- data/lib/chronic/repeaters/repeater_minute.rb +16 -6
- data/lib/chronic/repeaters/repeater_month.rb +14 -10
- data/lib/chronic/repeaters/repeater_month_name.rb +10 -10
- data/lib/chronic/repeaters/repeater_weekend.rb +49 -0
- data/lib/chronic/repeaters/repeater_year.rb +12 -12
- data/lib/chronic.rb +79 -1
- data/lib/numerizer/numerizer.rb +103 -0
- data/test/{parse_numbers.rb → test_Numerizer.rb} +6 -8
- data/test/test_RepeaterWeekend.rb +75 -0
- data/test/test_Time.rb +50 -0
- data/test/test_parsing.rb +232 -147
- metadata +13 -7
|
@@ -1,6 +1,55 @@
|
|
|
1
1
|
class Chronic::RepeaterWeekend < Chronic::Repeater #:nodoc:
|
|
2
2
|
WEEKEND_SECONDS = 172_800 # (2 * 24 * 60 * 60)
|
|
3
3
|
|
|
4
|
+
def next(pointer)
|
|
5
|
+
super
|
|
6
|
+
|
|
7
|
+
if !@current_week_start
|
|
8
|
+
case pointer
|
|
9
|
+
when :future
|
|
10
|
+
saturday_repeater = Chronic::RepeaterDayName.new(:saturday)
|
|
11
|
+
saturday_repeater.start = @now
|
|
12
|
+
next_saturday_span = saturday_repeater.next(:future)
|
|
13
|
+
@current_week_start = next_saturday_span.begin
|
|
14
|
+
when :past
|
|
15
|
+
saturday_repeater = Chronic::RepeaterDayName.new(:saturday)
|
|
16
|
+
saturday_repeater.start = (@now + Chronic::RepeaterDay::DAY_SECONDS)
|
|
17
|
+
last_saturday_span = saturday_repeater.next(:past)
|
|
18
|
+
@current_week_start = last_saturday_span.begin
|
|
19
|
+
end
|
|
20
|
+
else
|
|
21
|
+
direction = pointer == :future ? 1 : -1
|
|
22
|
+
@current_week_start += direction * Chronic::RepeaterWeek::WEEK_SECONDS
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
Chronic::Span.new(@current_week_start, @current_week_start + WEEKEND_SECONDS)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def this(pointer = :future)
|
|
29
|
+
super
|
|
30
|
+
|
|
31
|
+
case pointer
|
|
32
|
+
when :future, :none
|
|
33
|
+
saturday_repeater = Chronic::RepeaterDayName.new(:saturday)
|
|
34
|
+
saturday_repeater.start = @now
|
|
35
|
+
this_saturday_span = saturday_repeater.this(:future)
|
|
36
|
+
Chronic::Span.new(this_saturday_span.begin, this_saturday_span.begin + WEEKEND_SECONDS)
|
|
37
|
+
when :past
|
|
38
|
+
saturday_repeater = Chronic::RepeaterDayName.new(:saturday)
|
|
39
|
+
saturday_repeater.start = @now
|
|
40
|
+
last_saturday_span = saturday_repeater.this(:past)
|
|
41
|
+
Chronic::Span.new(last_saturday_span.begin, last_saturday_span.begin + WEEKEND_SECONDS)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def offset(span, amount, pointer)
|
|
46
|
+
direction = pointer == :future ? 1 : -1
|
|
47
|
+
weekend = Chronic::RepeaterWeekend.new(:weekend)
|
|
48
|
+
weekend.start = span.begin
|
|
49
|
+
start = weekend.next(pointer).begin + (amount - 1) * direction * Chronic::RepeaterWeek::WEEK_SECONDS
|
|
50
|
+
Chronic::Span.new(start, start + (span.end - span.begin))
|
|
51
|
+
end
|
|
52
|
+
|
|
4
53
|
def width
|
|
5
54
|
WEEKEND_SECONDS
|
|
6
55
|
end
|
|
@@ -6,16 +6,16 @@ class Chronic::RepeaterYear < Chronic::Repeater #:nodoc:
|
|
|
6
6
|
if !@current_year_start
|
|
7
7
|
case pointer
|
|
8
8
|
when :future
|
|
9
|
-
@current_year_start = Time.
|
|
9
|
+
@current_year_start = Time.construct(@now.year + 1)
|
|
10
10
|
when :past
|
|
11
|
-
@current_year_start = Time.
|
|
11
|
+
@current_year_start = Time.construct(@now.year - 1)
|
|
12
12
|
end
|
|
13
13
|
else
|
|
14
14
|
diff = pointer == :future ? 1 : -1
|
|
15
|
-
@current_year_start = Time.
|
|
15
|
+
@current_year_start = Time.construct(@current_year_start.year + diff)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
Chronic::Span.new(@current_year_start, Time.
|
|
18
|
+
Chronic::Span.new(@current_year_start, Time.construct(@current_year_start.year + 1))
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def this(pointer = :future)
|
|
@@ -23,14 +23,14 @@ class Chronic::RepeaterYear < Chronic::Repeater #:nodoc:
|
|
|
23
23
|
|
|
24
24
|
case pointer
|
|
25
25
|
when :future
|
|
26
|
-
this_year_start = Time.
|
|
27
|
-
this_year_end = Time.
|
|
26
|
+
this_year_start = Time.construct(@now.year, @now.month, @now.day) + Chronic::RepeaterDay::DAY_SECONDS
|
|
27
|
+
this_year_end = Time.construct(@now.year + 1, 1, 1)
|
|
28
28
|
when :past
|
|
29
|
-
this_year_start = Time.
|
|
30
|
-
this_year_end = Time.
|
|
29
|
+
this_year_start = Time.construct(@now.year, 1, 1)
|
|
30
|
+
this_year_end = Time.construct(@now.year, @now.month, @now.day)
|
|
31
31
|
when :none
|
|
32
|
-
this_year_start = Time.
|
|
33
|
-
this_year_end = Time.
|
|
32
|
+
this_year_start = Time.construct(@now.year, 1, 1)
|
|
33
|
+
this_year_end = Time.construct(@now.year + 1, 1, 1)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
Chronic::Span.new(this_year_start, this_year_end)
|
|
@@ -40,10 +40,10 @@ class Chronic::RepeaterYear < Chronic::Repeater #:nodoc:
|
|
|
40
40
|
direction = pointer == :future ? 1 : -1
|
|
41
41
|
|
|
42
42
|
sb = span.begin
|
|
43
|
-
new_begin = Time.
|
|
43
|
+
new_begin = Time.construct(sb.year + (amount * direction), sb.month, sb.day, sb.hour, sb.min, sb.sec)
|
|
44
44
|
|
|
45
45
|
se = span.end
|
|
46
|
-
new_end = Time.
|
|
46
|
+
new_end = Time.construct(se.year + (amount * direction), se.month, se.day, se.hour, se.min, se.sec)
|
|
47
47
|
|
|
48
48
|
Chronic::Span.new(new_begin, new_end)
|
|
49
49
|
end
|
data/lib/chronic.rb
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
#
|
|
8
8
|
#=============================================================================
|
|
9
9
|
|
|
10
|
+
$:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
|
|
11
|
+
|
|
10
12
|
require 'chronic/chronic'
|
|
11
13
|
require 'chronic/handlers'
|
|
12
14
|
|
|
@@ -32,9 +34,12 @@ require 'chronic/pointer'
|
|
|
32
34
|
require 'chronic/scalar'
|
|
33
35
|
require 'chronic/ordinal'
|
|
34
36
|
require 'chronic/separator'
|
|
37
|
+
require 'chronic/time_zone'
|
|
38
|
+
|
|
39
|
+
require 'numerizer/numerizer'
|
|
35
40
|
|
|
36
41
|
module Chronic
|
|
37
|
-
VERSION = "0.1
|
|
42
|
+
VERSION = "0.2.1"
|
|
38
43
|
|
|
39
44
|
def self.debug; false; end
|
|
40
45
|
end
|
|
@@ -44,4 +49,77 @@ alias p_orig p
|
|
|
44
49
|
def p(val)
|
|
45
50
|
p_orig val
|
|
46
51
|
puts
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# class Time
|
|
55
|
+
# def self.construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0)
|
|
56
|
+
# # extra_seconds = second > 60 ? second - 60 : 0
|
|
57
|
+
# # extra_minutes = minute > 59 ? minute - 59 : 0
|
|
58
|
+
# # extra_hours = hour > 23 ? hour - 23 : 0
|
|
59
|
+
# # extra_days = day >
|
|
60
|
+
#
|
|
61
|
+
# if month > 12
|
|
62
|
+
# if month % 12 == 0
|
|
63
|
+
# year += (month - 12) / 12
|
|
64
|
+
# month = 12
|
|
65
|
+
# else
|
|
66
|
+
# year += month / 12
|
|
67
|
+
# month = month % 12
|
|
68
|
+
# end
|
|
69
|
+
# end
|
|
70
|
+
#
|
|
71
|
+
# base = Time.local(year, month)
|
|
72
|
+
# puts base
|
|
73
|
+
# offset = ((day - 1) * 24 * 60 * 60) + (hour * 60 * 60) + (minute * 60) + second
|
|
74
|
+
# puts offset.to_s
|
|
75
|
+
# date = base + offset
|
|
76
|
+
# puts date
|
|
77
|
+
# date
|
|
78
|
+
# end
|
|
79
|
+
# end
|
|
80
|
+
|
|
81
|
+
class Time
|
|
82
|
+
def self.construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0)
|
|
83
|
+
if second >= 60
|
|
84
|
+
minute += second / 60
|
|
85
|
+
second = second % 60
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
if minute >= 60
|
|
89
|
+
hour += minute / 60
|
|
90
|
+
minute = minute % 60
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
if hour >= 24
|
|
94
|
+
day += hour / 24
|
|
95
|
+
hour = hour % 24
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# determine if there is a day overflow. this is complicated by our crappy calendar
|
|
99
|
+
# system (non-constant number of days per month)
|
|
100
|
+
day <= 56 || raise("day must be no more than 56 (makes month resolution easier)")
|
|
101
|
+
if day > 28
|
|
102
|
+
# no month ever has fewer than 28 days, so only do this if necessary
|
|
103
|
+
leap_year = (year % 4 == 0) && !(year % 100 == 0)
|
|
104
|
+
leap_year_month_days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
|
105
|
+
common_year_month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
|
106
|
+
days_this_month = leap_year ? leap_year_month_days[month - 1] : common_year_month_days[month - 1]
|
|
107
|
+
if day > days_this_month
|
|
108
|
+
month += day / days_this_month
|
|
109
|
+
day = day % days_this_month
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
if month > 12
|
|
114
|
+
if month % 12 == 0
|
|
115
|
+
year += (month - 12) / 12
|
|
116
|
+
month = 12
|
|
117
|
+
else
|
|
118
|
+
year += month / 12
|
|
119
|
+
month = month % 12
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
Time.local(year, month, day, hour, minute, second)
|
|
124
|
+
end
|
|
47
125
|
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require 'strscan'
|
|
2
|
+
|
|
3
|
+
class Numerizer
|
|
4
|
+
|
|
5
|
+
DIRECT_NUMS = [
|
|
6
|
+
['eleven', '11'],
|
|
7
|
+
['twelve', '12'],
|
|
8
|
+
['thirteen', '13'],
|
|
9
|
+
['fourteen', '14'],
|
|
10
|
+
['fifteen', '15'],
|
|
11
|
+
['sixteen', '16'],
|
|
12
|
+
['seventeen', '17'],
|
|
13
|
+
['eighteen', '18'],
|
|
14
|
+
['nineteen', '19'],
|
|
15
|
+
['ninteen', '19'], # Common mis-spelling
|
|
16
|
+
['zero', '0'],
|
|
17
|
+
['one', '1'],
|
|
18
|
+
['two', '2'],
|
|
19
|
+
['three', '3'],
|
|
20
|
+
['four(\W|$)', '4\1'], # The weird regex is so that it matches four but not fourty
|
|
21
|
+
['five', '5'],
|
|
22
|
+
['six(\W|$)', '6\1'],
|
|
23
|
+
['seven(\W|$)', '7\1'],
|
|
24
|
+
['eight(\W|$)', '8\1'],
|
|
25
|
+
['nine(\W|$)', '9\1'],
|
|
26
|
+
['ten', '10'],
|
|
27
|
+
['\ba[\b^$]', '1'] # doesn't make sense for an 'a' at the end to be a 1
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
TEN_PREFIXES = [ ['twenty', 20],
|
|
31
|
+
['thirty', 30],
|
|
32
|
+
['fourty', 40],
|
|
33
|
+
['fifty', 50],
|
|
34
|
+
['sixty', 60],
|
|
35
|
+
['seventy', 70],
|
|
36
|
+
['eighty', 80],
|
|
37
|
+
['ninety', 90]
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
BIG_PREFIXES = [ ['hundred', 100],
|
|
41
|
+
['thousand', 1000],
|
|
42
|
+
['million', 1_000_000],
|
|
43
|
+
['billion', 1_000_000_000],
|
|
44
|
+
['trillion', 1_000_000_000_000],
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
class << self
|
|
48
|
+
def numerize(string)
|
|
49
|
+
string = string.dup
|
|
50
|
+
|
|
51
|
+
# preprocess
|
|
52
|
+
string.gsub!(/ +|([^\d])-([^d])/, '\1 \2') # will mutilate hyphenated-words but shouldn't matter for date extraction
|
|
53
|
+
string.gsub!(/a half/, 'haAlf') # take the 'a' out so it doesn't turn into a 1, save the half for the end
|
|
54
|
+
|
|
55
|
+
# easy/direct replacements
|
|
56
|
+
|
|
57
|
+
DIRECT_NUMS.each do |dn|
|
|
58
|
+
string.gsub!(/#{dn[0]}/i, dn[1])
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# ten, twenty, etc.
|
|
62
|
+
|
|
63
|
+
TEN_PREFIXES.each do |tp|
|
|
64
|
+
string.gsub!(/(?:#{tp[0]})( *\d(?=[^\d]|$))*/i) { (tp[1] + $1.to_i).to_s }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# hundreds, thousands, millions, etc.
|
|
68
|
+
|
|
69
|
+
BIG_PREFIXES.each do |bp|
|
|
70
|
+
string.gsub!(/(\d*) *#{bp[0]}/i) { (bp[1] * $1.to_i).to_s}
|
|
71
|
+
andition(string)
|
|
72
|
+
#combine_numbers(string) # Should to be more efficient way to do this
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# fractional addition
|
|
76
|
+
# I'm not combining this with the previous block as using float addition complicates the strings
|
|
77
|
+
# (with extraneous .0's and such )
|
|
78
|
+
string.gsub!(/(\d+)(?: | and |-)*haAlf/i) { ($1.to_f + 0.5).to_s }
|
|
79
|
+
|
|
80
|
+
string
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
def andition(string)
|
|
85
|
+
sc = StringScanner.new(string)
|
|
86
|
+
while(sc.scan_until(/(\d+)( | and )(\d+)(?=[^\w]|$)/i))
|
|
87
|
+
if sc[2] =~ /and/ || sc[1].size > sc[3].size
|
|
88
|
+
string[(sc.pos - sc.matched_size)..(sc.pos-1)] = (sc[1].to_i + sc[3].to_i).to_s
|
|
89
|
+
sc.reset
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# def combine_numbers(string)
|
|
95
|
+
# sc = StringScanner.new(string)
|
|
96
|
+
# while(sc.scan_until(/(\d+)(?: | and |-)(\d+)(?=[^\w]|$)/i))
|
|
97
|
+
# string[(sc.pos - sc.matched_size)..(sc.pos-1)] = (sc[1].to_i + sc[2].to_i).to_s
|
|
98
|
+
# sc.reset
|
|
99
|
+
# end
|
|
100
|
+
# end
|
|
101
|
+
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
__END__
|
|
2
|
-
|
|
3
1
|
require 'test/unit'
|
|
2
|
+
require 'chronic'
|
|
4
3
|
|
|
5
4
|
class ParseNumbersTest < Test::Unit::TestCase
|
|
6
5
|
|
|
7
|
-
def
|
|
8
|
-
strings = {1 => 'one',
|
|
6
|
+
def test_straight_parsing
|
|
7
|
+
strings = { 1 => 'one',
|
|
9
8
|
5 => 'five',
|
|
10
9
|
10 => 'ten',
|
|
11
10
|
11 => 'eleven',
|
|
@@ -24,7 +23,7 @@ class ParseNumbersTest < Test::Unit::TestCase
|
|
|
24
23
|
100 => 'a hundred',
|
|
25
24
|
100 => 'one hundred',
|
|
26
25
|
150 => 'one hundred and fifty',
|
|
27
|
-
|
|
26
|
+
# 150 => 'one fifty',
|
|
28
27
|
200 => 'two-hundred',
|
|
29
28
|
500 => '5 hundred',
|
|
30
29
|
999 => 'nine hundred and ninety nine',
|
|
@@ -40,11 +39,10 @@ class ParseNumbersTest < Test::Unit::TestCase
|
|
|
40
39
|
1_000_000 => 'one million',
|
|
41
40
|
1_250_007 => 'one million two hundred fifty thousand and seven',
|
|
42
41
|
1_000_000_000 => 'one billion',
|
|
43
|
-
1_000_000_001 => 'one billion and one'}
|
|
42
|
+
1_000_000_001 => 'one billion and one' }
|
|
44
43
|
|
|
45
44
|
strings.keys.sort.each do |key|
|
|
46
|
-
assert_equal key,
|
|
45
|
+
assert_equal key, Numerizer.numerize(strings[key]).to_i
|
|
47
46
|
end
|
|
48
47
|
end
|
|
49
|
-
|
|
50
48
|
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require 'chronic'
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
|
|
4
|
+
class TestRepeaterWeekend < Test::Unit::TestCase
|
|
5
|
+
|
|
6
|
+
def setup
|
|
7
|
+
# Wed Aug 16 14:00:00 2006
|
|
8
|
+
@now = Time.local(2006, 8, 16, 14, 0, 0, 0)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def test_next_future
|
|
12
|
+
weekend = Chronic::RepeaterWeekend.new(:weekend)
|
|
13
|
+
weekend.start = @now
|
|
14
|
+
|
|
15
|
+
next_weekend = weekend.next(:future)
|
|
16
|
+
assert_equal Time.local(2006, 8, 19), next_weekend.begin
|
|
17
|
+
assert_equal Time.local(2006, 8, 21), next_weekend.end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_next_past
|
|
21
|
+
weekend = Chronic::RepeaterWeekend.new(:weekend)
|
|
22
|
+
weekend.start = @now
|
|
23
|
+
|
|
24
|
+
next_weekend = weekend.next(:past)
|
|
25
|
+
assert_equal Time.local(2006, 8, 12), next_weekend.begin
|
|
26
|
+
assert_equal Time.local(2006, 8, 14), next_weekend.end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_this_future
|
|
30
|
+
weekend = Chronic::RepeaterWeekend.new(:weekend)
|
|
31
|
+
weekend.start = @now
|
|
32
|
+
|
|
33
|
+
next_weekend = weekend.this(:future)
|
|
34
|
+
assert_equal Time.local(2006, 8, 19), next_weekend.begin
|
|
35
|
+
assert_equal Time.local(2006, 8, 21), next_weekend.end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_this_past
|
|
39
|
+
weekend = Chronic::RepeaterWeekend.new(:weekend)
|
|
40
|
+
weekend.start = @now
|
|
41
|
+
|
|
42
|
+
next_weekend = weekend.this(:past)
|
|
43
|
+
assert_equal Time.local(2006, 8, 12), next_weekend.begin
|
|
44
|
+
assert_equal Time.local(2006, 8, 14), next_weekend.end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_this_none
|
|
48
|
+
weekend = Chronic::RepeaterWeekend.new(:weekend)
|
|
49
|
+
weekend.start = @now
|
|
50
|
+
|
|
51
|
+
next_weekend = weekend.this(:future)
|
|
52
|
+
assert_equal Time.local(2006, 8, 19), next_weekend.begin
|
|
53
|
+
assert_equal Time.local(2006, 8, 21), next_weekend.end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_offset
|
|
57
|
+
span = Chronic::Span.new(@now, @now + 1)
|
|
58
|
+
|
|
59
|
+
offset_span = Chronic::RepeaterWeekend.new(:weekend).offset(span, 3, :future)
|
|
60
|
+
|
|
61
|
+
assert_equal Time.local(2006, 9, 2), offset_span.begin
|
|
62
|
+
assert_equal Time.local(2006, 9, 2, 0, 0, 1), offset_span.end
|
|
63
|
+
|
|
64
|
+
offset_span = Chronic::RepeaterWeekend.new(:weekend).offset(span, 1, :past)
|
|
65
|
+
|
|
66
|
+
assert_equal Time.local(2006, 8, 12), offset_span.begin
|
|
67
|
+
assert_equal Time.local(2006, 8, 12, 0, 0, 1), offset_span.end
|
|
68
|
+
|
|
69
|
+
offset_span = Chronic::RepeaterWeekend.new(:weekend).offset(span, 0, :future)
|
|
70
|
+
|
|
71
|
+
assert_equal Time.local(2006, 8, 12), offset_span.begin
|
|
72
|
+
assert_equal Time.local(2006, 8, 12, 0, 0, 1), offset_span.end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
data/test/test_Time.rb
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'chronic'
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
|
|
4
|
+
class TestTime < Test::Unit::TestCase
|
|
5
|
+
|
|
6
|
+
def setup
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_normal
|
|
10
|
+
assert_equal Time.local(2006, 1, 2, 0, 0, 0), Time.construct(2006, 1, 2, 0, 0, 0)
|
|
11
|
+
assert_equal Time.local(2006, 1, 2, 3, 0, 0), Time.construct(2006, 1, 2, 3, 0, 0)
|
|
12
|
+
assert_equal Time.local(2006, 1, 2, 3, 4, 0), Time.construct(2006, 1, 2, 3, 4, 0)
|
|
13
|
+
assert_equal Time.local(2006, 1, 2, 3, 4, 5), Time.construct(2006, 1, 2, 3, 4, 5)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_second_overflow
|
|
17
|
+
assert_equal Time.local(2006, 1, 1, 0, 1, 30), Time.construct(2006, 1, 1, 0, 0, 90)
|
|
18
|
+
assert_equal Time.local(2006, 1, 1, 0, 5, 0), Time.construct(2006, 1, 1, 0, 0, 300)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_minute_overflow
|
|
22
|
+
assert_equal Time.local(2006, 1, 1, 1, 30), Time.construct(2006, 1, 1, 0, 90)
|
|
23
|
+
assert_equal Time.local(2006, 1, 1, 5), Time.construct(2006, 1, 1, 0, 300)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_hour_overflow
|
|
27
|
+
assert_equal Time.local(2006, 1, 2, 12), Time.construct(2006, 1, 1, 36)
|
|
28
|
+
assert_equal Time.local(2006, 1, 7), Time.construct(2006, 1, 1, 144)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_day_overflow
|
|
32
|
+
assert_equal Time.local(2006, 2, 1), Time.construct(2006, 1, 32)
|
|
33
|
+
assert_equal Time.local(2006, 3, 5), Time.construct(2006, 2, 33)
|
|
34
|
+
assert_equal Time.local(2004, 3, 4), Time.construct(2004, 2, 33)
|
|
35
|
+
assert_equal Time.local(2000, 3, 5), Time.construct(2000, 2, 33)
|
|
36
|
+
|
|
37
|
+
assert_nothing_raised do
|
|
38
|
+
Time.construct(2006, 1, 56)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
assert_raise(RuntimeError) do
|
|
42
|
+
Time.construct(2006, 1, 57)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_month_overflow
|
|
47
|
+
assert_equal Time.local(2006, 1), Time.construct(2005, 13)
|
|
48
|
+
assert_equal Time.local(2005, 12), Time.construct(2000, 72)
|
|
49
|
+
end
|
|
50
|
+
end
|