chronic-davispuh 0.10.2.v0.1da32066b3f46f2506b3471e39557497e34afa27

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +10 -0
  4. data/Gemfile +3 -0
  5. data/HISTORY.md +243 -0
  6. data/LICENSE +21 -0
  7. data/README.md +185 -0
  8. data/Rakefile +68 -0
  9. data/chronic.gemspec +27 -0
  10. data/lib/chronic.rb +122 -0
  11. data/lib/chronic/arrow.rb +270 -0
  12. data/lib/chronic/date.rb +272 -0
  13. data/lib/chronic/definition.rb +208 -0
  14. data/lib/chronic/dictionary.rb +36 -0
  15. data/lib/chronic/handler.rb +44 -0
  16. data/lib/chronic/handlers/anchor.rb +65 -0
  17. data/lib/chronic/handlers/arrow.rb +84 -0
  18. data/lib/chronic/handlers/date.rb +270 -0
  19. data/lib/chronic/handlers/date_time.rb +72 -0
  20. data/lib/chronic/handlers/general.rb +130 -0
  21. data/lib/chronic/handlers/narrow.rb +54 -0
  22. data/lib/chronic/handlers/time.rb +167 -0
  23. data/lib/chronic/handlers/time_zone.rb +50 -0
  24. data/lib/chronic/objects/anchor_object.rb +263 -0
  25. data/lib/chronic/objects/arrow_object.rb +27 -0
  26. data/lib/chronic/objects/date_object.rb +164 -0
  27. data/lib/chronic/objects/date_time_object.rb +64 -0
  28. data/lib/chronic/objects/handler_object.rb +81 -0
  29. data/lib/chronic/objects/narrow_object.rb +85 -0
  30. data/lib/chronic/objects/time_object.rb +96 -0
  31. data/lib/chronic/objects/time_zone_object.rb +27 -0
  32. data/lib/chronic/parser.rb +154 -0
  33. data/lib/chronic/span.rb +32 -0
  34. data/lib/chronic/tag.rb +84 -0
  35. data/lib/chronic/tags/day_name.rb +34 -0
  36. data/lib/chronic/tags/day_portion.rb +33 -0
  37. data/lib/chronic/tags/day_special.rb +30 -0
  38. data/lib/chronic/tags/grabber.rb +29 -0
  39. data/lib/chronic/tags/keyword.rb +63 -0
  40. data/lib/chronic/tags/month_name.rb +39 -0
  41. data/lib/chronic/tags/ordinal.rb +52 -0
  42. data/lib/chronic/tags/pointer.rb +28 -0
  43. data/lib/chronic/tags/rational.rb +35 -0
  44. data/lib/chronic/tags/scalar.rb +101 -0
  45. data/lib/chronic/tags/season_name.rb +31 -0
  46. data/lib/chronic/tags/separator.rb +130 -0
  47. data/lib/chronic/tags/sign.rb +35 -0
  48. data/lib/chronic/tags/time_special.rb +34 -0
  49. data/lib/chronic/tags/time_zone.rb +56 -0
  50. data/lib/chronic/tags/unit.rb +174 -0
  51. data/lib/chronic/time.rb +141 -0
  52. data/lib/chronic/time_zone.rb +80 -0
  53. data/lib/chronic/token.rb +61 -0
  54. data/lib/chronic/token_group.rb +271 -0
  55. data/lib/chronic/tokenizer.rb +42 -0
  56. data/lib/chronic/version.rb +3 -0
  57. data/test/helper.rb +12 -0
  58. data/test/test_chronic.rb +190 -0
  59. data/test/test_daylight_savings.rb +98 -0
  60. data/test/test_handler.rb +113 -0
  61. data/test/test_parsing.rb +1520 -0
  62. data/test/test_span.rb +23 -0
  63. data/test/test_token.rb +31 -0
  64. metadata +218 -0
@@ -0,0 +1,263 @@
1
+ require 'chronic/handlers/anchor'
2
+
3
+ module Chronic
4
+ class AnchorObject < HandlerObject
5
+ attr_reader :grabber
6
+ attr_reader :unit
7
+ attr_reader :season
8
+ attr_reader :month
9
+ attr_reader :wday
10
+ attr_reader :day_special
11
+ attr_reader :time_special
12
+ attr_reader :count
13
+ def initialize(tokens, token_index, definitions, local_date, options)
14
+ super
15
+ match(tokens, @index, definitions)
16
+ end
17
+
18
+ def is_valid?
19
+ true
20
+ end
21
+
22
+ def to_s
23
+ "grabber #{@grabber.inspect}, unit #{@unit.inspect}, season #{@season.inspect}, quarter #{@quarter.inspect}, month #{@month.inspect}, wday #{@wday.inspect}, day special #{@day_special.inspect}, time special #{@time_special.inspect}, count #{@count.inspect}"
24
+ end
25
+
26
+ def to_span(span = nil, time = nil, timezone = nil)
27
+ modifier = get_modifier
28
+ if span
29
+ year, month, day = Date::split(span.begin)
30
+ else
31
+ year, month, day = local_day
32
+ end
33
+ time = TimeInfo.new(@local_date) unless time
34
+ hour, minute, second = time.to_a
35
+ time_precision = false
36
+ if time.is_a?(TimeObject)
37
+ @precision = time.precision
38
+ time_precision = true
39
+ end
40
+ date = Chronic.time_class.new(year, month, day)
41
+ end_year, end_month, end_day = year, month, day
42
+ end_hour, end_minute, end_second = time.get_end
43
+ if @count
44
+ modifier = @count - 1
45
+ @context == :future
46
+ end
47
+ sign = get_sign
48
+ if @season
49
+ season = Date::SEASON_DATES[@season]
50
+ diff = Date::month_diff(month, season.first, modifier, sign)
51
+ year, month = Date::add_month(year, month, diff)
52
+ day = season.last
53
+ end_year, next_season = Date::add_season(year, @season)
54
+ end_month, end_day = Date::SEASON_DATES[next_season]
55
+ hour = minute = second = end_hour = end_minute = end_second = 0
56
+ elsif @quarter
57
+ quarter = Date::get_quarter_index(month)
58
+ diff = Date::quarter_diff(quarter, @quarter, modifier, sign)
59
+ year, quarter = Date::add_quarter(year, quarter, diff)
60
+ month = Date::QUARTERS[@quarter]
61
+ end_year, next_quarter = Date::add_quarter(year, @quarter)
62
+ end_month = Date::QUARTERS[next_quarter]
63
+ day = end_day = 1
64
+ hour = minute = second = end_hour = end_minute = end_second = 0
65
+ elsif @month
66
+ diff = Date::month_diff(month, @month, modifier, sign)
67
+ year, month = Date::add_month(year, month, diff)
68
+ end_year, end_month = Date::add_month(year, month)
69
+ day = end_day = 1
70
+ hour = minute = second = end_hour = end_minute = end_second = 0
71
+ elsif @wday
72
+ diff = Date::wday_diff(date, @wday, modifier.zero? ? 1 : modifier, 0)
73
+ year, month, day = Date::add_day(year, month, day, diff) unless diff.zero?
74
+ end_year, end_month, end_day = year, month, day
75
+ unless time_precision
76
+ end_year, end_month, end_day = Date::add_day(year, month, day)
77
+ hour = minute = second = 0 if [year, month, day] != local_date
78
+ end_hour = end_minute = end_second = 0
79
+ end
80
+ elsif @day_special
81
+ case @day_special
82
+ when :yesterday
83
+ year, month, day = Date::add_day(year, month, day, -1)
84
+ if time_precision
85
+ end_year, end_month, end_day = year, month, day
86
+ else
87
+ end_year, end_month, end_day = Date::add_day(year, month, day)
88
+ hour = minute = second = end_hour = end_minute = end_second = 0
89
+ end
90
+ when :today
91
+ unless time_precision
92
+ end_year, end_month, end_day = Date::add_day(year, month, day)
93
+ end_hour = end_minute = end_second = 0
94
+ end
95
+ when :tomorrow
96
+ year, month, day = Date::add_day(year, month, day)
97
+ if time_precision
98
+ end_year, end_month, end_day = year, month, day
99
+ else
100
+ end_year, end_month, end_day = Date::add_day(year, month, day)
101
+ hour = minute = second = end_hour = end_minute = end_second = 0
102
+ end
103
+ else
104
+ raise "Uknown day special #{@day_special.inspect}"
105
+ end
106
+ elsif @time_special
107
+ year, month, day = Date::add_day(year, month, day, modifier)
108
+ end_year, end_month, end_day = year, month, day
109
+ hour = Time::SPECIAL[@time_special].begin
110
+ end_hour = Time::SPECIAL[@time_special].end
111
+ minute = second = end_minute = end_second = 0
112
+ else
113
+ case @unit
114
+ when :year
115
+ year += modifier
116
+ unless modifier.zero? and @context == :future
117
+ month = 1
118
+ day = 1
119
+ hour = minute = second = 0
120
+ end
121
+ unless modifier.zero? and @context == :past
122
+ end_year = year + 1
123
+ end_month = 1
124
+ end_day = 1
125
+ end_hour = end_minute = end_second = 0
126
+ end
127
+ when :quarter
128
+ year, quarter = Date::add_quarter(year, Date::get_quarter_index(month), modifier)
129
+ month = Date::QUARTERS[quarter]
130
+ unless modifier.zero? and @context == :future
131
+ day = 1
132
+ hour = minute = second = 0
133
+ end
134
+ unless modifier.zero? and @context == :past
135
+ end_year, next_quarter = Date::add_quarter(year, quarter)
136
+ end_month = Date::QUARTERS[next_quarter]
137
+ end_day = 1
138
+ end_hour = end_minute = end_second = 0
139
+ end
140
+ when :month
141
+ year, month = Date::add_month(year, month, modifier)
142
+ unless modifier.zero? and @context == :future
143
+ day = 1
144
+ hour = minute = second = 0
145
+ end
146
+ unless modifier.zero? and @context == :past
147
+ end_year, end_month = Date::add_month(year, month)
148
+ end_day = 1
149
+ end_hour = end_minute = end_second = 0
150
+ end
151
+ when :fortnight
152
+ unless modifier.zero? and @context == :future
153
+ diff = Date::wday_diff(date, Date::DAYS[@options[:week_start]], modifier, sign)
154
+ diff -= Date::WEEK_DAYS
155
+ year, month, day = Date::add_day(year, month, day, diff)
156
+ date = Chronic.time_class.new(year, month, day)
157
+ hour = minute = second = 0
158
+ end
159
+ unless modifier.zero? and @context == :past
160
+ end_date = Chronic.time_class.new(year, month, day)
161
+ diff = Date::wday_diff(end_date, Date::DAYS[@options[:week_start]], modifier, sign)
162
+ end_year, end_month, end_day = Date::add_day(year, month, day, diff + Date::WEEK_DAYS)
163
+ end_hour = end_minute = end_second = 0
164
+ end
165
+ when :week
166
+ unless modifier.zero? and @context == :future
167
+ diff = Date::wday_diff(date, Date::DAYS[@options[:week_start]], 0, 0)
168
+ diff += Date::WEEK_DAYS * modifier
169
+ year, month, day = Date::add_day(year, month, day, diff)
170
+ hour = minute = second = 0
171
+ end
172
+ unless modifier.zero? and @context == :past
173
+ end_date = Chronic.time_class.new(year, month, day)
174
+ diff = Date::wday_diff(end_date, Date::DAYS[@options[:week_start]], 1, 0)
175
+ end_year, end_month, end_day = Date::add_day(year, month, day, diff)
176
+ end_hour = end_minute = end_second = 0
177
+ end
178
+ when :weekend
179
+ diff = Date::wday_diff(date, Date::DAYS[:saturday], modifier, sign)
180
+ year, month, day = Date::add_day(year, month, day, diff)
181
+ if [year, month, day] != local_date or @context == :past
182
+ hour = minute = second = 0
183
+ end
184
+ if [year, month, day] != local_date or @context == :future
185
+ end_date = Chronic.time_class.new(year, month, day)
186
+ diff = Date::wday_diff(end_date, Date::DAYS[:monday], 1, 1)
187
+ end_year, end_month, end_day = Date::add_day(year, month, day, diff)
188
+ end_hour = end_minute = end_second = 0
189
+ end
190
+ when :weekday
191
+ diff = Date::wd_diff(date, modifier)
192
+ year, month, day = Date::add_day(year, month, day, diff)
193
+ if [year, month, day] != local_date or @context == :past
194
+ hour = minute = second = 0
195
+ end
196
+ if [year, month, day] != local_date or @context == :future
197
+ end_year, end_month, end_day = Date::add_day(year, month, day)
198
+ end_hour = end_minute = end_second = 0
199
+ end
200
+ when :day
201
+ unless modifier.zero? and @context == :future
202
+ year, month, day = Date::add_day(year, month, day, modifier)
203
+ hour = minute = second = 0
204
+ end
205
+ unless modifier.zero? and @context == :past or time_precision
206
+ end_year, end_month, end_day = Date::add_day(year, month, day)
207
+ end_hour = end_minute = end_second = 0
208
+ end
209
+ when :morning, :noon, :afternoon, :evening, :night, :midnight
210
+ unless modifier.zero? and @context == :future
211
+ year, month, day = Date::add_day(year, month, day, modifier)
212
+ hour = Time::SPECIAL[@unit].begin
213
+ minute = second = 0
214
+ end
215
+ unless modifier.zero? and @context == :past
216
+ end_year, end_month, end_day = Date::add_day(year, month, day)
217
+ end_hour = Time::SPECIAL[@unit].end
218
+ end_minute = end_second = 0
219
+ end
220
+ when :hour
221
+ unless modifier.zero? and @context == :future
222
+ day, hour = Time::add_hour(day, hour, modifier)
223
+ minute = second = 0
224
+ end
225
+ unless modifier.zero? and @context == :past
226
+ end_day, end_hour = Time::add_hour(day, hour)
227
+ end_minute = end_second = 0
228
+ end
229
+ when :minute
230
+ unless modifier.zero? and @context == :future
231
+ hour, minute = Time::add_minute(hour, minute, modifier)
232
+ second = 0
233
+ end
234
+ unless modifier.zero? and @context == :past
235
+ end_hour, end_minute = Time::add_minute(hour, minute)
236
+ end_second = 0
237
+ end
238
+ when :second
239
+ unless modifier.zero? and @context == :future
240
+ minute, second = Time::add_second(minute, second, modifier)
241
+ hour, minute = Time::add_minute(hour, minute, 0)
242
+ end
243
+ unless modifier.zero? and @context == :past
244
+ end_hour = hour
245
+ end_minute, end_second = Time::add_second(minute, second)
246
+ end
247
+ else
248
+ raise "Uknown unit #{unit.inspect}"
249
+ end
250
+ end
251
+ span_start = Chronic.construct(year, month, day, hour, minute, second, timezone)
252
+ span_end = Chronic.construct(end_year, end_month, end_day, end_hour, end_minute, end_second, timezone)
253
+ span = Span.new(span_start, span_end, true)
254
+ span.precision = @precision
255
+ span
256
+ end
257
+
258
+ protected
259
+
260
+ include AnchorHandlers
261
+
262
+ end
263
+ end
@@ -0,0 +1,27 @@
1
+ require 'chronic/handlers/arrow'
2
+
3
+ module Chronic
4
+ class ArrowObject < HandlerObject
5
+ attr_reader :count
6
+ attr_reader :unit
7
+ attr_reader :special
8
+ attr_reader :pointer
9
+ def initialize(tokens, token_index, definitions, local_date, options)
10
+ super
11
+ match(tokens, @index, definitions)
12
+ end
13
+
14
+ def is_valid?
15
+ true
16
+ end
17
+
18
+ def to_s
19
+ "count #{@count.inspect}, unit #{@unit.inspect}, pointer #{@pointer.inspect}, special #{@special.inspect}"
20
+ end
21
+
22
+ protected
23
+
24
+ include ArrowHandlers
25
+
26
+ end
27
+ end
@@ -0,0 +1,164 @@
1
+ require 'chronic/handlers/date'
2
+
3
+ module Chronic
4
+ class DateObject < HandlerObject
5
+ include DateStructure
6
+ attr_reader :wday
7
+ attr_reader :day_special
8
+ def initialize(tokens, token_index, definitions, local_date, options)
9
+ super
10
+ handle_possible(KeywordOn)
11
+ unless handle_possible(KeywordIn)
12
+ handle_possible(SeparatorSpace)
13
+ end
14
+ @normalized = false
15
+ match(tokens, @index, definitions)
16
+ end
17
+
18
+ def normalize!
19
+ return if @normalized
20
+ adjust!
21
+ @normalized = true
22
+ end
23
+
24
+ def force_normalize!
25
+ @year = @local_date.year unless @have_year
26
+ @month = @local_date.month unless @have_month
27
+ @day = @local_date.day unless @have_day
28
+ adjust!
29
+ @normalized = true
30
+ end
31
+
32
+ def is_valid?
33
+ normalize!
34
+ return false if @year.nil? or @month.nil? or @day.nil?
35
+ ::Date.valid_date?(@year, @month, @day)
36
+ end
37
+
38
+ def get_end
39
+ year = @year
40
+ month = @month
41
+ day = @day
42
+ case @precision
43
+ when :year
44
+ year += 1
45
+ month = 1
46
+ day = 1
47
+ when :month
48
+ year, month = Date::add_month(year, month)
49
+ day = 1
50
+ when :day
51
+ year, month, day = Date::add_day(year, month, day)
52
+ else
53
+ # BUG! Should never happen
54
+ raise "Uknown precision #{@precision}"
55
+ end
56
+ [year, month, day]
57
+ end
58
+
59
+ def to_s
60
+ "year #{@year.inspect}, month #{@month.inspect}, day #{@day.inspect}, wday #{@wday.inspect}, day special #{@day_special.inspect}, precision #{@precision.inspect}"
61
+ end
62
+
63
+ protected
64
+
65
+ def get_date_compare(sign)
66
+ sign.zero? ? false : ((sign == -1) ? (@day > @local_date.day) : (@day < @local_date.day))
67
+ end
68
+
69
+ def adjust!
70
+ sign = get_sign
71
+ if @day_special
72
+ set_date
73
+ case @day_special
74
+ when :yesterday
75
+ @year, @month, @day = Date::add_day(@year, @month, @day, -1)
76
+ when :today
77
+ # do nothing
78
+ when :tomorrow
79
+ @year, @month, @day = Date::add_day(@year, @month, @day, 1)
80
+ else
81
+ raise "Uknown special day #{@day_special.inspect}"
82
+ end
83
+ @precision = :day
84
+ elsif @wday
85
+ year, month, day = local_day
86
+ year = @year if @year
87
+ month = @month if @month
88
+ day = @day if @day
89
+ date = ::Date.new(year, month, day)
90
+ s = 0
91
+ s = sign if not @have_year and not @have_month and not @have_day
92
+ diff = Date::wday_diff(date, @wday, s, 0)
93
+ actual_year, actual_month, actual_day = Date::add_day(year, month, day, diff)
94
+ if @have_day and @day != actual_day
95
+ actual_day = @day
96
+ n = 0
97
+ s = sign
98
+ if not @month
99
+ begin
100
+ n += s
101
+ actual_year, actual_month = Date::add_month(year, month, n)
102
+ date = ::Date.new(actual_year, actual_month, actual_day)
103
+ actual_year = nil if date.wday != @wday or (@year and @year != actual_year)
104
+ end while actual_year.nil? and n*s < 20
105
+ elsif not @year
106
+ actual_month = @month
107
+ begin
108
+ actual_year = year + n*s
109
+ date = ::Date.new(actual_year, actual_month, actual_day)
110
+ actual_year = nil if date.wday != @wday
111
+ n += 1 if s == sign
112
+ s *= -1
113
+ end while actual_year.nil? and n < 200
114
+ else
115
+ actual_year = nil
116
+ end
117
+ elsif @have_month and @month != actual_month
118
+ if not @year
119
+ n = 0
120
+ begin
121
+ n += 1
122
+ year += sign
123
+ date = ::Date.new(year, month, day)
124
+ diff = Date::wday_diff(date, @wday, sign)
125
+ actual_year, actual_month, actual_day = Date::add_day(year, month, day, diff)
126
+ actual_year = nil if @month != actual_month
127
+ end while actual_year.nil? and n < 50
128
+ else
129
+ actual_year = nil
130
+ end
131
+ elsif @have_year and @year != actual_year
132
+ actual_year = nil
133
+ end
134
+ @year, @month, @day = [actual_year, actual_month, actual_day]
135
+ @precision = :day
136
+ else
137
+ @month = 1 if not @month and not @day
138
+ @day ||= 1
139
+ date_compare = get_date_compare(sign)
140
+ if @year.nil?
141
+ @year = @local_date.year
142
+ if @month.nil?
143
+ @month = @local_date.month
144
+ @year, @month = Date::add_month(@year, @month, sign) if date_compare
145
+ elsif not sign.zero?
146
+ month_compare = (sign == -1) ? (@month > @local_date.month) : (@month < @local_date.month)
147
+ @year += sign if month_compare or (@month == @local_date.month and date_compare)
148
+ end
149
+ elsif @month.nil? and date_compare
150
+ @year, @month = Date::add_month(@year, @local_date.month, sign)
151
+ elsif @month.nil?
152
+ @month = @local_date.month
153
+ end
154
+ end
155
+ end
156
+
157
+ def set_date
158
+ @year, @month, @day = local_day
159
+ end
160
+
161
+ include DateHandlers
162
+
163
+ end
164
+ end