chronic 0.1.6 → 0.2.3
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 +22 -2
- data/Manifest.txt +5 -1
- data/Rakefile +3 -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 +1 -0
- 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 +10 -10
- 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_time.rb +10 -7
- data/lib/chronic/repeaters/repeater_year.rb +12 -12
- data/lib/chronic/time_zone.rb +22 -0
- 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_Time.rb +50 -0
- data/test/test_parsing.rb +236 -153
- metadata +30 -12
data/History.txt
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
|
+
= 0.2.3
|
|
2
|
+
|
|
3
|
+
* fixed 12am/12pm (by Nicholas Schlueter)
|
|
4
|
+
|
|
5
|
+
= 0.2.2
|
|
6
|
+
|
|
7
|
+
* added missing files (damn you manifest)
|
|
8
|
+
|
|
9
|
+
= 0.2.1
|
|
10
|
+
|
|
11
|
+
* fixed time overflow issue
|
|
12
|
+
* implemented "next" for minute repeater
|
|
13
|
+
* generalized time dealiasing to dealias regardless of day portion and time position
|
|
14
|
+
* added additional token match for cases like "friday evening at 7" and "tomorrow evening at 7"
|
|
15
|
+
* added support for Time#to_s output format: "Mon Apr 02 17:00:00 PDT 2007"
|
|
16
|
+
|
|
17
|
+
= 0.2.0 2007-03-20
|
|
18
|
+
|
|
19
|
+
* implemented numerizer, allowing the use of number words (e.g. five weeks ago) (by shalev)
|
|
20
|
+
|
|
1
21
|
= 0.1.6 2006-01-15
|
|
2
22
|
|
|
3
|
-
* added 'weekend' support (eventualbuddha)
|
|
23
|
+
* added 'weekend' support (by eventualbuddha)
|
|
4
24
|
|
|
5
25
|
= 0.1.5 2006-12-20
|
|
6
26
|
|
|
@@ -15,7 +35,7 @@
|
|
|
15
35
|
|
|
16
36
|
= 0.1.3
|
|
17
37
|
|
|
18
|
-
* improved regexes for word variations (Josh Goebel)
|
|
38
|
+
* improved regexes for word variations (by Josh Goebel)
|
|
19
39
|
* fixed a bug that caused "today at 3am" to return nil if current time is after 3am
|
|
20
40
|
|
|
21
41
|
= 0.1.2
|
data/Manifest.txt
CHANGED
|
@@ -26,10 +26,12 @@ lib/chronic/repeaters/repeater_weekend.rb
|
|
|
26
26
|
lib/chronic/repeaters/repeater_year.rb
|
|
27
27
|
lib/chronic/scalar.rb
|
|
28
28
|
lib/chronic/separator.rb
|
|
29
|
-
|
|
29
|
+
lib/chronic/time_zone.rb
|
|
30
|
+
lib/numerizer/numerizer.rb
|
|
30
31
|
test/suite.rb
|
|
31
32
|
test/test_Chronic.rb
|
|
32
33
|
test/test_Handler.rb
|
|
34
|
+
test/test_Numerizer.rb
|
|
33
35
|
test/test_RepeaterDayName.rb
|
|
34
36
|
test/test_RepeaterFortnight.rb
|
|
35
37
|
test/test_RepeaterHour.rb
|
|
@@ -37,7 +39,9 @@ test/test_RepeaterMonth.rb
|
|
|
37
39
|
test/test_RepeaterMonthName.rb
|
|
38
40
|
test/test_RepeaterTime.rb
|
|
39
41
|
test/test_RepeaterWeek.rb
|
|
42
|
+
test/test_RepeaterWeekend.rb
|
|
40
43
|
test/test_RepeaterYear.rb
|
|
41
44
|
test/test_Span.rb
|
|
45
|
+
test/test_Time.rb
|
|
42
46
|
test/test_Token.rb
|
|
43
47
|
test/test_parsing.rb
|
data/Rakefile
CHANGED
|
@@ -7,6 +7,8 @@ require './lib/chronic.rb'
|
|
|
7
7
|
Hoe.new('chronic', Chronic::VERSION) do |p|
|
|
8
8
|
p.rubyforge_name = 'chronic'
|
|
9
9
|
p.summary = 'A natural language date parser'
|
|
10
|
+
p.author = 'Tom Preston-Werner'
|
|
11
|
+
p.email = 'tom@rubyisawesome.com'
|
|
10
12
|
p.description = p.paragraphs_of('README.txt', 2).join("\n\n")
|
|
11
13
|
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
|
|
12
14
|
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
|
@@ -14,28 +16,4 @@ Hoe.new('chronic', Chronic::VERSION) do |p|
|
|
|
14
16
|
p.extra_deps = []
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
# vim: syntax=Ruby
|
|
18
|
-
|
|
19
|
-
__END__
|
|
20
|
-
|
|
21
|
-
require 'rubygems'
|
|
22
|
-
|
|
23
|
-
SPEC = Gem::Specification.new do |s|
|
|
24
|
-
s.name = 'chronic'
|
|
25
|
-
s.version = '0.1.5'
|
|
26
|
-
s.author = 'Tom Preston-Werner'
|
|
27
|
-
s.email = 'tom@rubyisawesome.com'
|
|
28
|
-
s.homepage = 'http://chronic.rubyforge.org'
|
|
29
|
-
s.platform = Gem::Platform::RUBY
|
|
30
|
-
s.summary = "A natural language date parser"
|
|
31
|
-
candidates = Dir["{lib,test}/**/*"]
|
|
32
|
-
s.files = candidates.delete_if do |item|
|
|
33
|
-
item.include?('.svn')
|
|
34
|
-
end
|
|
35
|
-
s.require_path = "lib"
|
|
36
|
-
s.autorequire = "chronic"
|
|
37
|
-
s.test_file = "test/suite.rb"
|
|
38
|
-
s.has_rdoc = true
|
|
39
|
-
s.extra_rdoc_files = ['README']
|
|
40
|
-
s.rdoc_options << '--main' << 'README'
|
|
41
|
-
end
|
|
19
|
+
# vim: syntax=Ruby
|
data/lib/chronic/chronic.rb
CHANGED
|
@@ -66,7 +66,7 @@ module Chronic
|
|
|
66
66
|
@tokens = tokenizer.scan(@tokens, options)
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
[Grabber, Pointer, Scalar, Ordinal, Separator].each do |tokenizer|
|
|
69
|
+
[Grabber, Pointer, Scalar, Ordinal, Separator, TimeZone].each do |tokenizer|
|
|
70
70
|
@tokens = tokenizer.scan(@tokens)
|
|
71
71
|
end
|
|
72
72
|
|
|
@@ -101,6 +101,7 @@ module Chronic
|
|
|
101
101
|
# ordinals (third => 3rd)
|
|
102
102
|
def pre_normalize(text) #:nodoc:
|
|
103
103
|
normalized_text = text.to_s.downcase
|
|
104
|
+
normalized_text = numericize_numbers(normalized_text)
|
|
104
105
|
normalized_text.gsub!(/['"\.]/, '')
|
|
105
106
|
normalized_text.gsub!(/([\/\-\,\@])/) { ' ' + $1 + ' ' }
|
|
106
107
|
normalized_text.gsub!(/\btoday\b/, 'this day')
|
|
@@ -118,15 +119,12 @@ module Chronic
|
|
|
118
119
|
normalized_text.gsub!(/\btonight\b/, 'this night')
|
|
119
120
|
normalized_text.gsub!(/(?=\w)([ap]m|oclock)\b/, ' \1')
|
|
120
121
|
normalized_text.gsub!(/\b(hence|after|from)\b/, 'future')
|
|
121
|
-
normalized_text.gsub!(/\ba\b/, '1')
|
|
122
|
-
normalized_text.gsub!(/\s+/, ' ')
|
|
123
|
-
normalized_text = numericize_numbers(normalized_text)
|
|
124
122
|
normalized_text = numericize_ordinals(normalized_text)
|
|
125
123
|
end
|
|
126
124
|
|
|
127
125
|
# Convert number words to numbers (three => 3)
|
|
128
126
|
def numericize_numbers(text) #:nodoc:
|
|
129
|
-
text
|
|
127
|
+
Numerizer.numerize(text)
|
|
130
128
|
end
|
|
131
129
|
|
|
132
130
|
# Convert ordinal words to numeric ordinals (third => 3rd)
|
data/lib/chronic/handlers.rb
CHANGED
|
@@ -6,7 +6,8 @@ module Chronic
|
|
|
6
6
|
@definitions ||=
|
|
7
7
|
{:time => [Handler.new([:repeater_time, :repeater_day_portion?], nil)],
|
|
8
8
|
|
|
9
|
-
:date => [Handler.new([:repeater_month_name, :scalar_day, :scalar_year], :
|
|
9
|
+
:date => [Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day, :repeater_time, :time_zone, :scalar_year], :handle_rdn_rmn_sd_t_tz_sy),
|
|
10
|
+
Handler.new([:repeater_month_name, :scalar_day, :scalar_year], :handle_rmn_sd_sy),
|
|
10
11
|
Handler.new([:repeater_month_name, :scalar_day, :scalar_year, :separator_at?, 'time?'], :handle_rmn_sd_sy),
|
|
11
12
|
Handler.new([:repeater_month_name, :scalar_day, :separator_at?, 'time?'], :handle_rmn_sd),
|
|
12
13
|
Handler.new([:repeater_month_name, :ordinal_day, :separator_at?, 'time?'], :handle_rmn_od),
|
|
@@ -17,13 +18,17 @@ module Chronic
|
|
|
17
18
|
Handler.new([:scalar_year, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_day, :separator_at?, 'time?'], :handle_sy_sm_sd),
|
|
18
19
|
Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_year], :handle_sm_sy)],
|
|
19
20
|
|
|
21
|
+
# tonight at 7pm
|
|
20
22
|
:anchor => [Handler.new([:grabber?, :repeater, :separator_at?, :repeater?, :repeater?], :handle_r),
|
|
23
|
+
Handler.new([:grabber?, :repeater, :repeater, :separator_at?, :repeater?, :repeater?], :handle_r),
|
|
21
24
|
Handler.new([:repeater, :grabber, :repeater], :handle_r_g_r)],
|
|
22
25
|
|
|
26
|
+
# 3 weeks from now, in 2 months
|
|
23
27
|
:arrow => [Handler.new([:scalar, :repeater, :pointer], :handle_s_r_p),
|
|
24
28
|
Handler.new([:pointer, :scalar, :repeater], :handle_p_s_r),
|
|
25
29
|
Handler.new([:scalar, :repeater, :pointer, 'anchor'], :handle_s_r_p_a)],
|
|
26
30
|
|
|
31
|
+
# 3rd week in march
|
|
27
32
|
:narrow => [Handler.new([:ordinal, :repeater, :separator_in, :repeater], :handle_o_r_s_r),
|
|
28
33
|
Handler.new([:ordinal, :repeater, :grabber, :repeater], :handle_o_r_g_r)]
|
|
29
34
|
}
|
|
@@ -34,6 +39,7 @@ module Chronic
|
|
|
34
39
|
|
|
35
40
|
self.definitions[:date].each do |handler|
|
|
36
41
|
if handler.match(tokens, self.definitions)
|
|
42
|
+
puts "-date" if Chronic.debug
|
|
37
43
|
good_tokens = tokens.select { |o| !o.get_tag Separator }
|
|
38
44
|
return self.send(handler.handler_method, good_tokens, options)
|
|
39
45
|
end
|
|
@@ -43,6 +49,7 @@ module Chronic
|
|
|
43
49
|
|
|
44
50
|
self.definitions[:anchor].each do |handler|
|
|
45
51
|
if handler.match(tokens, self.definitions)
|
|
52
|
+
puts "-anchor" if Chronic.debug
|
|
46
53
|
good_tokens = tokens.select { |o| !o.get_tag Separator }
|
|
47
54
|
return self.send(handler.handler_method, good_tokens, options)
|
|
48
55
|
end
|
|
@@ -52,21 +59,24 @@ module Chronic
|
|
|
52
59
|
|
|
53
60
|
self.definitions[:arrow].each do |handler|
|
|
54
61
|
if handler.match(tokens, self.definitions)
|
|
62
|
+
puts "-arrow" if Chronic.debug
|
|
55
63
|
good_tokens = tokens.reject { |o| o.get_tag(SeparatorAt) || o.get_tag(SeparatorSlashOrDash) || o.get_tag(SeparatorComma) }
|
|
56
64
|
return self.send(handler.handler_method, good_tokens, options)
|
|
57
65
|
end
|
|
58
66
|
end
|
|
59
67
|
|
|
60
|
-
# not an arrow, let's hope it's
|
|
68
|
+
# not an arrow, let's hope it's a narrow
|
|
61
69
|
|
|
62
70
|
self.definitions[:narrow].each do |handler|
|
|
63
71
|
if handler.match(tokens, self.definitions)
|
|
72
|
+
puts "-narrow" if Chronic.debug
|
|
64
73
|
#good_tokens = tokens.select { |o| !o.get_tag Separator }
|
|
65
74
|
return self.send(handler.handler_method, tokens, options)
|
|
66
75
|
end
|
|
67
76
|
end
|
|
68
77
|
|
|
69
78
|
# I guess you're out of luck!
|
|
79
|
+
puts "-none" if Chronic.debug
|
|
70
80
|
return nil
|
|
71
81
|
end
|
|
72
82
|
|
|
@@ -122,6 +132,19 @@ module Chronic
|
|
|
122
132
|
end
|
|
123
133
|
end
|
|
124
134
|
|
|
135
|
+
def handle_rdn_rmn_sd_t_tz_sy(tokens, options) #:nodoc:
|
|
136
|
+
month = tokens[1].get_tag(RepeaterMonthName).index
|
|
137
|
+
day = tokens[2].get_tag(ScalarDay).type
|
|
138
|
+
year = tokens[5].get_tag(ScalarYear).type
|
|
139
|
+
|
|
140
|
+
begin
|
|
141
|
+
day_start = Time.local(year, month, day)
|
|
142
|
+
day_or_time(day_start, [tokens[3]], options)
|
|
143
|
+
rescue ArgumentError
|
|
144
|
+
nil
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
125
148
|
def handle_rmn_sd_sy(tokens, options) #:nodoc:
|
|
126
149
|
month = tokens[0].get_tag(RepeaterMonthName).index
|
|
127
150
|
day = tokens[1].get_tag(ScalarDay).type
|
|
@@ -214,17 +237,19 @@ module Chronic
|
|
|
214
237
|
def handle_s_r_p(tokens, options) #:nodoc:
|
|
215
238
|
repeater = tokens[1].get_tag(Repeater)
|
|
216
239
|
|
|
217
|
-
span =
|
|
218
|
-
case true
|
|
219
|
-
when [RepeaterYear, RepeaterSeason, RepeaterSeasonName, RepeaterMonth, RepeaterMonthName, RepeaterFortnight, RepeaterWeek].include?(repeater.class)
|
|
220
|
-
|
|
221
|
-
when [RepeaterWeekend, RepeaterDay, RepeaterDayName, RepeaterDayPortion, RepeaterHour].include?(repeater.class)
|
|
222
|
-
|
|
223
|
-
when [RepeaterMinute, RepeaterSecond].include?(repeater.class)
|
|
224
|
-
|
|
225
|
-
else
|
|
226
|
-
|
|
227
|
-
end
|
|
240
|
+
# span =
|
|
241
|
+
# case true
|
|
242
|
+
# when [RepeaterYear, RepeaterSeason, RepeaterSeasonName, RepeaterMonth, RepeaterMonthName, RepeaterFortnight, RepeaterWeek].include?(repeater.class)
|
|
243
|
+
# self.parse("this hour", :guess => false, :now => @now)
|
|
244
|
+
# when [RepeaterWeekend, RepeaterDay, RepeaterDayName, RepeaterDayPortion, RepeaterHour].include?(repeater.class)
|
|
245
|
+
# self.parse("this minute", :guess => false, :now => @now)
|
|
246
|
+
# when [RepeaterMinute, RepeaterSecond].include?(repeater.class)
|
|
247
|
+
# self.parse("this second", :guess => false, :now => @now)
|
|
248
|
+
# else
|
|
249
|
+
# raise(ChronicPain, "Invalid repeater: #{repeater.class}")
|
|
250
|
+
# end
|
|
251
|
+
|
|
252
|
+
span = self.parse("this second", :guess => false, :now => @now)
|
|
228
253
|
|
|
229
254
|
self.handle_srp(tokens, span, options)
|
|
230
255
|
end
|
|
@@ -331,22 +356,54 @@ module Chronic
|
|
|
331
356
|
|
|
332
357
|
def dealias_and_disambiguate_times(tokens, options) #:nodoc:
|
|
333
358
|
# handle aliases of am/pm
|
|
334
|
-
# 5:00 in the morning
|
|
335
|
-
# 7:00 in the evening
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
if
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
359
|
+
# 5:00 in the morning -> 5:00 am
|
|
360
|
+
# 7:00 in the evening -> 7:00 pm
|
|
361
|
+
|
|
362
|
+
day_portion_index = nil
|
|
363
|
+
tokens.each_with_index do |t, i|
|
|
364
|
+
if t.get_tag(RepeaterDayPortion)
|
|
365
|
+
day_portion_index = i
|
|
366
|
+
break
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
time_index = nil
|
|
371
|
+
tokens.each_with_index do |t, i|
|
|
372
|
+
if t.get_tag(RepeaterTime)
|
|
373
|
+
time_index = i
|
|
374
|
+
break
|
|
347
375
|
end
|
|
348
376
|
end
|
|
349
|
-
|
|
377
|
+
|
|
378
|
+
if (day_portion_index && time_index)
|
|
379
|
+
t1 = tokens[day_portion_index]
|
|
380
|
+
t1tag = t1.get_tag(RepeaterDayPortion)
|
|
381
|
+
|
|
382
|
+
if [:morning].include?(t1tag.type)
|
|
383
|
+
puts '--morning->am' if Chronic.debug
|
|
384
|
+
t1.untag(RepeaterDayPortion)
|
|
385
|
+
t1.tag(RepeaterDayPortion.new(:am))
|
|
386
|
+
elsif [:afternoon, :evening, :night].include?(t1tag.type)
|
|
387
|
+
puts "--#{t1tag.type}->pm" if Chronic.debug
|
|
388
|
+
t1.untag(RepeaterDayPortion)
|
|
389
|
+
t1.tag(RepeaterDayPortion.new(:pm))
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
# tokens.each_with_index do |t0, i|
|
|
394
|
+
# t1 = tokens[i + 1]
|
|
395
|
+
# if t1 && (t1tag = t1.get_tag(RepeaterDayPortion)) && t0.get_tag(RepeaterTime)
|
|
396
|
+
# if [:morning].include?(t1tag.type)
|
|
397
|
+
# puts '--morning->am' if Chronic.debug
|
|
398
|
+
# t1.untag(RepeaterDayPortion)
|
|
399
|
+
# t1.tag(RepeaterDayPortion.new(:am))
|
|
400
|
+
# elsif [:afternoon, :evening, :night].include?(t1tag.type)
|
|
401
|
+
# puts "--#{t1tag.type}->pm" if Chronic.debug
|
|
402
|
+
# t1.untag(RepeaterDayPortion)
|
|
403
|
+
# t1.tag(RepeaterDayPortion.new(:pm))
|
|
404
|
+
# end
|
|
405
|
+
# end
|
|
406
|
+
# end
|
|
350
407
|
|
|
351
408
|
# handle ambiguous times if :ambiguous_time_range is specified
|
|
352
409
|
if options[:ambiguous_time_range] != :none
|
data/lib/chronic/pointer.rb
CHANGED
|
@@ -10,9 +10,9 @@ module Chronic
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def self.scan_for_all(token)
|
|
13
|
-
scanner = {/
|
|
14
|
-
/
|
|
15
|
-
/
|
|
13
|
+
scanner = {/\bpast\b/ => :past,
|
|
14
|
+
/\bfuture\b/ => :future,
|
|
15
|
+
/\bin\b/ => :future}
|
|
16
16
|
scanner.keys.each do |scanner_item|
|
|
17
17
|
return self.new(scanner[scanner_item]) if scanner_item =~ token.word
|
|
18
18
|
end
|
data/lib/chronic/repeater.rb
CHANGED
|
@@ -33,6 +33,7 @@ class Chronic::Repeater < Chronic::Tag #:nodoc:
|
|
|
33
33
|
def self.scan_for_day_names(token)
|
|
34
34
|
scanner = {/^m[ou]n(day)?$/ => :monday,
|
|
35
35
|
/^t(ue|eu|oo|u|)s(day)?$/ => :tuesday,
|
|
36
|
+
/^tue$/ => :tuesday,
|
|
36
37
|
/^we(dnes|nds|nns)day$/ => :wednesday,
|
|
37
38
|
/^wed$/ => :wednesday,
|
|
38
39
|
/^th(urs|ers)day$/ => :thursday,
|
|
@@ -19,14 +19,14 @@ class Chronic::RepeaterDay < Chronic::Repeater #:nodoc:
|
|
|
19
19
|
|
|
20
20
|
case pointer
|
|
21
21
|
when :future
|
|
22
|
-
day_begin = Time.
|
|
23
|
-
day_end = Time.
|
|
22
|
+
day_begin = Time.construct(@now.year, @now.month, @now.day, @now.hour + 1)
|
|
23
|
+
day_end = Time.construct(@now.year, @now.month, @now.day) + DAY_SECONDS
|
|
24
24
|
when :past
|
|
25
|
-
day_begin = Time.
|
|
26
|
-
day_end = Time.
|
|
25
|
+
day_begin = Time.construct(@now.year, @now.month, @now.day)
|
|
26
|
+
day_end = Time.construct(@now.year, @now.month, @now.day, @now.hour)
|
|
27
27
|
when :none
|
|
28
|
-
day_begin = Time.
|
|
29
|
-
day_end = Time.
|
|
28
|
+
day_begin = Time.construct(@now.year, @now.month, @now.day)
|
|
29
|
+
day_end = Time.construct(@now.year, @now.month, @now.day) + DAY_SECONDS
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
Chronic::Span.new(day_begin, day_end)
|
|
@@ -7,7 +7,7 @@ class Chronic::RepeaterDayName < Chronic::Repeater #:nodoc:
|
|
|
7
7
|
direction = pointer == :future ? 1 : -1
|
|
8
8
|
|
|
9
9
|
if !@current_day_start
|
|
10
|
-
@current_day_start = Time.
|
|
10
|
+
@current_day_start = Time.construct(@now.year, @now.month, @now.day)
|
|
11
11
|
@current_day_start += direction * DAY_SECONDS
|
|
12
12
|
|
|
13
13
|
day_num = symbol_to_number(@type)
|
|
@@ -34,7 +34,7 @@ class Chronic::RepeaterDayName < Chronic::Repeater #:nodoc:
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def to_s
|
|
37
|
-
super << '-
|
|
37
|
+
super << '-dayname-' << @type.to_s
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
private
|
|
@@ -10,8 +10,8 @@ class Chronic::RepeaterDayPortion < Chronic::Repeater #:nodoc:
|
|
|
10
10
|
if type.kind_of? Integer
|
|
11
11
|
@range = (@type * 60 * 60)..((@type + 12) * 60 * 60)
|
|
12
12
|
else
|
|
13
|
-
lookup = {:am =>
|
|
14
|
-
:pm => (12 * 60 * 60)..(24 * 60 * 60),
|
|
13
|
+
lookup = {:am => 0..(12 * 60 * 60 - 1),
|
|
14
|
+
:pm => (12 * 60 * 60)..(24 * 60 * 60 - 1),
|
|
15
15
|
:morning => @@morning,
|
|
16
16
|
:afternoon => @@afternoon,
|
|
17
17
|
:evening => @@evening,
|
|
@@ -28,27 +28,27 @@ class Chronic::RepeaterDayPortion < Chronic::Repeater #:nodoc:
|
|
|
28
28
|
full_day = 60 * 60 * 24
|
|
29
29
|
|
|
30
30
|
if !@current_span
|
|
31
|
-
now_seconds = @now - Time.
|
|
31
|
+
now_seconds = @now - Time.construct(@now.year, @now.month, @now.day)
|
|
32
32
|
if now_seconds < @range.begin
|
|
33
33
|
case pointer
|
|
34
34
|
when :future
|
|
35
|
-
range_start = Time.
|
|
35
|
+
range_start = Time.construct(@now.year, @now.month, @now.day) + @range.begin
|
|
36
36
|
when :past
|
|
37
|
-
range_start = Time.
|
|
37
|
+
range_start = Time.construct(@now.year, @now.month, @now.day) - full_day + @range.begin
|
|
38
38
|
end
|
|
39
39
|
elsif now_seconds > @range.end
|
|
40
40
|
case pointer
|
|
41
41
|
when :future
|
|
42
|
-
range_start = Time.
|
|
42
|
+
range_start = Time.construct(@now.year, @now.month, @now.day) + full_day + @range.begin
|
|
43
43
|
when :past
|
|
44
|
-
range_start = Time.
|
|
44
|
+
range_start = Time.construct(@now.year, @now.month, @now.day) + @range.begin
|
|
45
45
|
end
|
|
46
46
|
else
|
|
47
47
|
case pointer
|
|
48
48
|
when :future
|
|
49
|
-
range_start = Time.
|
|
49
|
+
range_start = Time.construct(@now.year, @now.month, @now.day) + full_day + @range.begin
|
|
50
50
|
when :past
|
|
51
|
-
range_start = Time.
|
|
51
|
+
range_start = Time.construct(@now.year, @now.month, @now.day) - full_day + @range.begin
|
|
52
52
|
end
|
|
53
53
|
end
|
|
54
54
|
|
|
@@ -66,7 +66,7 @@ class Chronic::RepeaterDayPortion < Chronic::Repeater #:nodoc:
|
|
|
66
66
|
def this(context = :future)
|
|
67
67
|
super
|
|
68
68
|
|
|
69
|
-
range_start = Time.
|
|
69
|
+
range_start = Time.construct(@now.year, @now.month, @now.day) + @range.begin
|
|
70
70
|
@current_span = Chronic::Span.new(range_start, range_start + (@range.end - @range.begin))
|
|
71
71
|
end
|
|
72
72
|
|
|
@@ -33,7 +33,7 @@ class Chronic::RepeaterFortnight < Chronic::Repeater #:nodoc:
|
|
|
33
33
|
|
|
34
34
|
case pointer
|
|
35
35
|
when :future
|
|
36
|
-
this_fortnight_start = Time.
|
|
36
|
+
this_fortnight_start = Time.construct(@now.year, @now.month, @now.day, @now.hour) + Chronic::RepeaterHour::HOUR_SECONDS
|
|
37
37
|
sunday_repeater = Chronic::RepeaterDayName.new(:sunday)
|
|
38
38
|
sunday_repeater.start = @now
|
|
39
39
|
sunday_repeater.this(:future)
|
|
@@ -41,7 +41,7 @@ class Chronic::RepeaterFortnight < Chronic::Repeater #:nodoc:
|
|
|
41
41
|
this_fortnight_end = this_sunday_span.begin
|
|
42
42
|
Chronic::Span.new(this_fortnight_start, this_fortnight_end)
|
|
43
43
|
when :past
|
|
44
|
-
this_fortnight_end = Time.
|
|
44
|
+
this_fortnight_end = Time.construct(@now.year, @now.month, @now.day, @now.hour)
|
|
45
45
|
sunday_repeater = Chronic::RepeaterDayName.new(:sunday)
|
|
46
46
|
sunday_repeater.start = @now
|
|
47
47
|
last_sunday_span = sunday_repeater.next(:past)
|
|
@@ -7,9 +7,9 @@ class Chronic::RepeaterHour < Chronic::Repeater #:nodoc:
|
|
|
7
7
|
if !@current_hour_start
|
|
8
8
|
case pointer
|
|
9
9
|
when :future
|
|
10
|
-
@current_hour_start = Time.
|
|
10
|
+
@current_hour_start = Time.construct(@now.year, @now.month, @now.day, @now.hour + 1)
|
|
11
11
|
when :past
|
|
12
|
-
@current_hour_start = Time.
|
|
12
|
+
@current_hour_start = Time.construct(@now.year, @now.month, @now.day, @now.hour - 1)
|
|
13
13
|
end
|
|
14
14
|
else
|
|
15
15
|
direction = pointer == :future ? 1 : -1
|
|
@@ -24,13 +24,13 @@ class Chronic::RepeaterHour < Chronic::Repeater #:nodoc:
|
|
|
24
24
|
|
|
25
25
|
case pointer
|
|
26
26
|
when :future
|
|
27
|
-
hour_start = Time.
|
|
28
|
-
hour_end = Time.
|
|
27
|
+
hour_start = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min + 1)
|
|
28
|
+
hour_end = Time.construct(@now.year, @now.month, @now.day, @now.hour + 1)
|
|
29
29
|
when :past
|
|
30
|
-
hour_start = Time.
|
|
31
|
-
hour_end = Time.
|
|
30
|
+
hour_start = Time.construct(@now.year, @now.month, @now.day, @now.hour)
|
|
31
|
+
hour_end = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min)
|
|
32
32
|
when :none
|
|
33
|
-
hour_start = Time.
|
|
33
|
+
hour_start = Time.construct(@now.year, @now.month, @now.day, @now.hour)
|
|
34
34
|
hour_end = hour_begin + HOUR_SECONDS
|
|
35
35
|
end
|
|
36
36
|
|
|
@@ -4,9 +4,19 @@ class Chronic::RepeaterMinute < Chronic::Repeater #:nodoc:
|
|
|
4
4
|
def next(pointer = :future)
|
|
5
5
|
super
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
if !@current_minute_start
|
|
8
|
+
case pointer
|
|
9
|
+
when :future
|
|
10
|
+
@current_minute_start = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min + 1)
|
|
11
|
+
when :past
|
|
12
|
+
@current_minute_start = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min - 1)
|
|
13
|
+
end
|
|
14
|
+
else
|
|
15
|
+
direction = pointer == :future ? 1 : -1
|
|
16
|
+
@current_minute_start += direction * MINUTE_SECONDS
|
|
17
|
+
end
|
|
8
18
|
|
|
9
|
-
|
|
19
|
+
Chronic::Span.new(@current_minute_start, @current_minute_start + MINUTE_SECONDS)
|
|
10
20
|
end
|
|
11
21
|
|
|
12
22
|
def this(pointer = :future)
|
|
@@ -15,13 +25,13 @@ class Chronic::RepeaterMinute < Chronic::Repeater #:nodoc:
|
|
|
15
25
|
case pointer
|
|
16
26
|
when :future
|
|
17
27
|
minute_begin = @now
|
|
18
|
-
minute_end = Time.
|
|
28
|
+
minute_end = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min)
|
|
19
29
|
when :past
|
|
20
|
-
minute_begin = Time.
|
|
30
|
+
minute_begin = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min)
|
|
21
31
|
minute_end = @now
|
|
22
32
|
when :none
|
|
23
|
-
minute_begin = Time.
|
|
24
|
-
minute_end = Time.
|
|
33
|
+
minute_begin = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min)
|
|
34
|
+
minute_end = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min) + MINUTE_SECONDS
|
|
25
35
|
end
|
|
26
36
|
|
|
27
37
|
Chronic::Span.new(minute_begin, minute_end)
|
|
@@ -6,12 +6,12 @@ class Chronic::RepeaterMonth < Chronic::Repeater #:nodoc:
|
|
|
6
6
|
super
|
|
7
7
|
|
|
8
8
|
if !@current_month_start
|
|
9
|
-
@current_month_start = offset_by(Time.
|
|
9
|
+
@current_month_start = offset_by(Time.construct(@now.year, @now.month), 1, pointer)
|
|
10
10
|
else
|
|
11
|
-
@current_month_start = offset_by(Time.
|
|
11
|
+
@current_month_start = offset_by(Time.construct(@current_month_start.year, @current_month_start.month), 1, pointer)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
Chronic::Span.new(@current_month_start, Time.
|
|
14
|
+
Chronic::Span.new(@current_month_start, Time.construct(@current_month_start.year, @current_month_start.month + 1))
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def this(pointer = :future)
|
|
@@ -19,14 +19,14 @@ class Chronic::RepeaterMonth < Chronic::Repeater #:nodoc:
|
|
|
19
19
|
|
|
20
20
|
case pointer
|
|
21
21
|
when :future
|
|
22
|
-
month_start = Time.
|
|
23
|
-
month_end = self.offset_by(Time.
|
|
22
|
+
month_start = Time.construct(@now.year, @now.month, @now.day + 1)
|
|
23
|
+
month_end = self.offset_by(Time.construct(@now.year, @now.month), 1, :future)
|
|
24
24
|
when :past
|
|
25
|
-
month_start = Time.
|
|
26
|
-
month_end = Time.
|
|
25
|
+
month_start = Time.construct(@now.year, @now.month)
|
|
26
|
+
month_end = Time.construct(@now.year, @now.month, @now.day)
|
|
27
27
|
when :none
|
|
28
|
-
month_start = Time.
|
|
29
|
-
month_end = self.offset_by(Time.
|
|
28
|
+
month_start = Time.construct(@now.year, @now.month)
|
|
29
|
+
month_end = self.offset_by(Time.construct(@now.year, @now.month), 1, :future)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
Chronic::Span.new(month_start, month_end)
|
|
@@ -48,10 +48,14 @@ class Chronic::RepeaterMonth < Chronic::Repeater #:nodoc:
|
|
|
48
48
|
new_year += 1
|
|
49
49
|
new_month -= YEAR_MONTHS
|
|
50
50
|
end
|
|
51
|
-
Time.
|
|
51
|
+
Time.construct(new_year, new_month, time.day, time.hour, time.min, time.sec)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def width
|
|
55
55
|
MONTH_SECONDS
|
|
56
56
|
end
|
|
57
|
+
|
|
58
|
+
def to_s
|
|
59
|
+
super << '-month'
|
|
60
|
+
end
|
|
57
61
|
end
|
|
@@ -9,30 +9,30 @@ class Chronic::RepeaterMonthName < Chronic::Repeater #:nodoc:
|
|
|
9
9
|
case pointer
|
|
10
10
|
when :future
|
|
11
11
|
if @now.month < target_month
|
|
12
|
-
@current_month_begin = Time.
|
|
12
|
+
@current_month_begin = Time.construct(@now.year, target_month)
|
|
13
13
|
else @now.month > target_month
|
|
14
|
-
@current_month_begin = Time.
|
|
14
|
+
@current_month_begin = Time.construct(@now.year + 1, target_month)
|
|
15
15
|
end
|
|
16
16
|
when :none
|
|
17
17
|
if @now.month <= target_month
|
|
18
|
-
@current_month_begin = Time.
|
|
18
|
+
@current_month_begin = Time.construct(@now.year, target_month)
|
|
19
19
|
else @now.month > target_month
|
|
20
|
-
@current_month_begin = Time.
|
|
20
|
+
@current_month_begin = Time.construct(@now.year + 1, target_month)
|
|
21
21
|
end
|
|
22
22
|
when :past
|
|
23
23
|
if @now.month > target_month
|
|
24
|
-
@current_month_begin = Time.
|
|
24
|
+
@current_month_begin = Time.construct(@now.year, target_month)
|
|
25
25
|
else @now.month < target_month
|
|
26
|
-
@current_month_begin = Time.
|
|
26
|
+
@current_month_begin = Time.construct(@now.year - 1, target_month)
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
@current_month_begin || raise("Current month should be set by now")
|
|
30
30
|
else
|
|
31
31
|
case pointer
|
|
32
32
|
when :future
|
|
33
|
-
@current_month_begin = Time.
|
|
33
|
+
@current_month_begin = Time.construct(@current_month_begin.year + 1, @current_month_begin.month)
|
|
34
34
|
when :past
|
|
35
|
-
@current_month_begin = Time.
|
|
35
|
+
@current_month_begin = Time.construct(@current_month_begin.year - 1, @current_month_begin.month)
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
|
|
@@ -47,7 +47,7 @@ class Chronic::RepeaterMonthName < Chronic::Repeater #:nodoc:
|
|
|
47
47
|
next_month_month = cur_month_month + 1
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
Chronic::Span.new(@current_month_begin, Time.
|
|
50
|
+
Chronic::Span.new(@current_month_begin, Time.construct(next_month_year, next_month_month))
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def this(pointer = :future)
|
|
@@ -70,7 +70,7 @@ class Chronic::RepeaterMonthName < Chronic::Repeater #:nodoc:
|
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def to_s
|
|
73
|
-
super << '-
|
|
73
|
+
super << '-monthname-' << @type.to_s
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
private
|