chronic-davispuh 0.10.2.v0.1da32066b3f46f2506b3471e39557497e34afa27
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +10 -0
- data/Gemfile +3 -0
- data/HISTORY.md +243 -0
- data/LICENSE +21 -0
- data/README.md +185 -0
- data/Rakefile +68 -0
- data/chronic.gemspec +27 -0
- data/lib/chronic.rb +122 -0
- data/lib/chronic/arrow.rb +270 -0
- data/lib/chronic/date.rb +272 -0
- data/lib/chronic/definition.rb +208 -0
- data/lib/chronic/dictionary.rb +36 -0
- data/lib/chronic/handler.rb +44 -0
- data/lib/chronic/handlers/anchor.rb +65 -0
- data/lib/chronic/handlers/arrow.rb +84 -0
- data/lib/chronic/handlers/date.rb +270 -0
- data/lib/chronic/handlers/date_time.rb +72 -0
- data/lib/chronic/handlers/general.rb +130 -0
- data/lib/chronic/handlers/narrow.rb +54 -0
- data/lib/chronic/handlers/time.rb +167 -0
- data/lib/chronic/handlers/time_zone.rb +50 -0
- data/lib/chronic/objects/anchor_object.rb +263 -0
- data/lib/chronic/objects/arrow_object.rb +27 -0
- data/lib/chronic/objects/date_object.rb +164 -0
- data/lib/chronic/objects/date_time_object.rb +64 -0
- data/lib/chronic/objects/handler_object.rb +81 -0
- data/lib/chronic/objects/narrow_object.rb +85 -0
- data/lib/chronic/objects/time_object.rb +96 -0
- data/lib/chronic/objects/time_zone_object.rb +27 -0
- data/lib/chronic/parser.rb +154 -0
- data/lib/chronic/span.rb +32 -0
- data/lib/chronic/tag.rb +84 -0
- data/lib/chronic/tags/day_name.rb +34 -0
- data/lib/chronic/tags/day_portion.rb +33 -0
- data/lib/chronic/tags/day_special.rb +30 -0
- data/lib/chronic/tags/grabber.rb +29 -0
- data/lib/chronic/tags/keyword.rb +63 -0
- data/lib/chronic/tags/month_name.rb +39 -0
- data/lib/chronic/tags/ordinal.rb +52 -0
- data/lib/chronic/tags/pointer.rb +28 -0
- data/lib/chronic/tags/rational.rb +35 -0
- data/lib/chronic/tags/scalar.rb +101 -0
- data/lib/chronic/tags/season_name.rb +31 -0
- data/lib/chronic/tags/separator.rb +130 -0
- data/lib/chronic/tags/sign.rb +35 -0
- data/lib/chronic/tags/time_special.rb +34 -0
- data/lib/chronic/tags/time_zone.rb +56 -0
- data/lib/chronic/tags/unit.rb +174 -0
- data/lib/chronic/time.rb +141 -0
- data/lib/chronic/time_zone.rb +80 -0
- data/lib/chronic/token.rb +61 -0
- data/lib/chronic/token_group.rb +271 -0
- data/lib/chronic/tokenizer.rb +42 -0
- data/lib/chronic/version.rb +3 -0
- data/test/helper.rb +12 -0
- data/test/test_chronic.rb +190 -0
- data/test/test_daylight_savings.rb +98 -0
- data/test/test_handler.rb +113 -0
- data/test/test_parsing.rb +1520 -0
- data/test/test_span.rb +23 -0
- data/test/test_token.rb +31 -0
- metadata +218 -0
data/Rakefile
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
require 'chronic/version'
|
3
|
+
|
4
|
+
def version
|
5
|
+
Chronic::VERSION
|
6
|
+
end
|
7
|
+
|
8
|
+
def do_test
|
9
|
+
require 'chronic'
|
10
|
+
$:.unshift './test'
|
11
|
+
Dir.glob('test/test_*.rb').each { |t| require File.basename(t) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def open_command
|
15
|
+
case RUBY_PLATFORM
|
16
|
+
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
17
|
+
'start'
|
18
|
+
when /darwin|mac os/
|
19
|
+
'open'
|
20
|
+
else
|
21
|
+
'xdg-open'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'Run tests'
|
26
|
+
task :test do
|
27
|
+
do_test
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'Generate SimpleCov test coverage and open in your browser'
|
31
|
+
task :coverage do
|
32
|
+
require 'simplecov'
|
33
|
+
FileUtils.rm_rf('./coverage')
|
34
|
+
SimpleCov.command_name 'Unit Tests'
|
35
|
+
SimpleCov.at_exit do
|
36
|
+
SimpleCov.result.format!
|
37
|
+
sh "#{open_command} #{SimpleCov.coverage_path}/index.html"
|
38
|
+
end
|
39
|
+
SimpleCov.start
|
40
|
+
do_test
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'Open an irb session preloaded with this library'
|
44
|
+
task :console do
|
45
|
+
sh 'irb -Ilib -rchronic'
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "Release Chronic version #{version}"
|
49
|
+
task :release => :build do
|
50
|
+
unless `git branch` =~ /^\* master$/
|
51
|
+
puts "You must be on the master branch to release!"
|
52
|
+
exit!
|
53
|
+
end
|
54
|
+
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
55
|
+
sh "git tag v#{version}"
|
56
|
+
sh "git push origin master"
|
57
|
+
sh "git push origin v#{version}"
|
58
|
+
sh "gem push pkg/chronic-#{version}.gem"
|
59
|
+
end
|
60
|
+
|
61
|
+
desc 'Build a gem from the gemspec'
|
62
|
+
task :build do
|
63
|
+
FileUtils.mkdir_p 'pkg'
|
64
|
+
sh 'gem build chronic.gemspec'
|
65
|
+
FileUtils.mv("./chronic-#{version}.gem", "pkg")
|
66
|
+
end
|
67
|
+
|
68
|
+
task :default => :test
|
data/chronic.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
require 'chronic/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'chronic-davispuh'
|
6
|
+
s.version = Chronic::VERSION
|
7
|
+
s.rubyforge_project = 'chronic'
|
8
|
+
s.summary = 'Natural language date/time parsing.'
|
9
|
+
s.description = 'Chronic is a natural language date/time parser written in pure Ruby.'
|
10
|
+
s.authors = ['Tom Preston-Werner', 'Lee Jarvis']
|
11
|
+
s.email = ['tom@mojombo.com', 'ljjarvis@gmail.com']
|
12
|
+
s.homepage = 'http://github.com/mojombo/chronic'
|
13
|
+
s.license = 'MIT'
|
14
|
+
s.rdoc_options = ['--charset=UTF-8']
|
15
|
+
s.extra_rdoc_files = %w[README.md HISTORY.md LICENSE]
|
16
|
+
s.files = `git ls-files`.split($/)
|
17
|
+
s.test_files = `git ls-files -- test`.split($/)
|
18
|
+
|
19
|
+
s.add_runtime_dependency 'numerizer', '~> 0.2'
|
20
|
+
s.add_runtime_dependency 'tzinfo'
|
21
|
+
s.add_runtime_dependency 'TimezoneParser'
|
22
|
+
|
23
|
+
s.add_development_dependency 'rake', '~> 10'
|
24
|
+
s.add_development_dependency 'simplecov', '~> 0'
|
25
|
+
s.add_development_dependency 'minitest', '~> 5.0'
|
26
|
+
s.add_development_dependency 'activesupport', '~> 4'
|
27
|
+
end
|
data/lib/chronic.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'date'
|
3
|
+
require 'numerizer'
|
4
|
+
|
5
|
+
require 'chronic/version'
|
6
|
+
|
7
|
+
require 'tzinfo'
|
8
|
+
require 'timezone_parser'
|
9
|
+
|
10
|
+
require 'chronic/parser'
|
11
|
+
require 'chronic/date'
|
12
|
+
require 'chronic/time'
|
13
|
+
require 'chronic/time_zone'
|
14
|
+
require 'chronic/arrow'
|
15
|
+
|
16
|
+
require 'chronic/handler'
|
17
|
+
require 'chronic/span'
|
18
|
+
require 'chronic/token'
|
19
|
+
require 'chronic/token_group'
|
20
|
+
require 'chronic/tokenizer'
|
21
|
+
|
22
|
+
require 'chronic/tag'
|
23
|
+
require 'chronic/tags/day_name'
|
24
|
+
require 'chronic/tags/day_portion'
|
25
|
+
require 'chronic/tags/day_special'
|
26
|
+
require 'chronic/tags/grabber'
|
27
|
+
require 'chronic/tags/keyword'
|
28
|
+
require 'chronic/tags/month_name'
|
29
|
+
require 'chronic/tags/ordinal'
|
30
|
+
require 'chronic/tags/pointer'
|
31
|
+
require 'chronic/tags/rational'
|
32
|
+
require 'chronic/tags/scalar'
|
33
|
+
require 'chronic/tags/season_name'
|
34
|
+
require 'chronic/tags/separator'
|
35
|
+
require 'chronic/tags/sign'
|
36
|
+
require 'chronic/tags/time_special'
|
37
|
+
require 'chronic/tags/time_zone'
|
38
|
+
require 'chronic/tags/unit'
|
39
|
+
|
40
|
+
# Parse natural language dates and times into Time or Chronic::Span objects.
|
41
|
+
#
|
42
|
+
# Examples:
|
43
|
+
#
|
44
|
+
# require 'chronic'
|
45
|
+
#
|
46
|
+
# Time.now #=> Sun Aug 27 23:18:25 PDT 2006
|
47
|
+
#
|
48
|
+
# Chronic.parse('tomorrow')
|
49
|
+
# #=> Mon Aug 28 12:00:00 PDT 2006
|
50
|
+
#
|
51
|
+
# Chronic.parse('monday', :context => :past)
|
52
|
+
# #=> Mon Aug 21 12:00:00 PDT 2006
|
53
|
+
module Chronic
|
54
|
+
|
55
|
+
class << self
|
56
|
+
|
57
|
+
# Returns true when debug mode is enabled.
|
58
|
+
attr_accessor :debug
|
59
|
+
|
60
|
+
# Examples:
|
61
|
+
#
|
62
|
+
# require 'chronic'
|
63
|
+
# require 'active_support/time'
|
64
|
+
#
|
65
|
+
# Time.zone = 'UTC'
|
66
|
+
# Chronic.time_class = Time.zone
|
67
|
+
# Chronic.parse('June 15 2006 at 5:54 AM')
|
68
|
+
# # => Thu, 15 Jun 2006 05:45:00 UTC +00:00
|
69
|
+
#
|
70
|
+
# Returns The Time class Chronic uses internally.
|
71
|
+
attr_accessor :time_class
|
72
|
+
end
|
73
|
+
|
74
|
+
self.debug = false
|
75
|
+
self.time_class = ::Time
|
76
|
+
|
77
|
+
|
78
|
+
# Parses a string containing a natural language date or time.
|
79
|
+
#
|
80
|
+
# If the parser can find a date or time, either a Time or Chronic::Span
|
81
|
+
# will be returned (depending on the value of `:guess`). If no
|
82
|
+
# date or time can be found, `nil` will be returned.
|
83
|
+
#
|
84
|
+
# text - The String text to parse.
|
85
|
+
# opts - An optional Hash of configuration options passed to Parser::new.
|
86
|
+
def self.parse(text, options = {})
|
87
|
+
Parser.new(options).parse(text)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Construct a new time object determining possible month overflows
|
91
|
+
# and leap years.
|
92
|
+
#
|
93
|
+
# year - Integer year.
|
94
|
+
# month - Integer month.
|
95
|
+
# day - Integer day.
|
96
|
+
# hour - Integer hour.
|
97
|
+
# minute - Integer minute.
|
98
|
+
# second - Integer second.
|
99
|
+
#
|
100
|
+
# Returns a new Time object constructed from these params.
|
101
|
+
def self.construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0, timezone = nil)
|
102
|
+
day, hour, minute, second = Time::normalize(day, hour, minute, second)
|
103
|
+
|
104
|
+
year, month, day = Date::add_day(year, month, day, 0) if day > 28
|
105
|
+
year, month = Date::add_month(year, month, 0) if month > 12
|
106
|
+
|
107
|
+
if Chronic.time_class.name == 'Date'
|
108
|
+
Chronic.time_class.new(year, month, day)
|
109
|
+
elsif not Chronic.time_class.respond_to?(:new) or (RUBY_VERSION.to_f < 1.9 and Chronic.time_class.name == 'Time')
|
110
|
+
Chronic.time_class.local(year, month, day, hour, minute, second)
|
111
|
+
else
|
112
|
+
if timezone and timezone.respond_to?(:to_offset)
|
113
|
+
offset = timezone.to_offset(year, month, day, hour, minute, second)
|
114
|
+
else
|
115
|
+
offset = timezone
|
116
|
+
end
|
117
|
+
offset = TimeZone::normalize_offset(offset) if Chronic.time_class.name == 'DateTime'
|
118
|
+
Chronic.time_class.new(year, month, day, hour, minute, second, offset)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,270 @@
|
|
1
|
+
module Chronic
|
2
|
+
class Arrow
|
3
|
+
BASE_UNITS = [
|
4
|
+
:years,
|
5
|
+
:months,
|
6
|
+
:days,
|
7
|
+
:hours,
|
8
|
+
:minutes,
|
9
|
+
:seconds
|
10
|
+
]
|
11
|
+
|
12
|
+
UNITS = BASE_UNITS + [
|
13
|
+
:miliseconds,
|
14
|
+
:mornings,
|
15
|
+
:noons,
|
16
|
+
:afternoons,
|
17
|
+
:evenings,
|
18
|
+
:nights,
|
19
|
+
:midnights,
|
20
|
+
:weeks,
|
21
|
+
:weekdays,
|
22
|
+
:wdays,
|
23
|
+
:weekends,
|
24
|
+
:fortnights,
|
25
|
+
:quarters,
|
26
|
+
:seasons
|
27
|
+
]
|
28
|
+
|
29
|
+
PRECISION = [
|
30
|
+
:miliseconds,
|
31
|
+
:seconds,
|
32
|
+
:minutes,
|
33
|
+
:noons,
|
34
|
+
:midnights,
|
35
|
+
:hours,
|
36
|
+
:mornings,
|
37
|
+
:afternoons,
|
38
|
+
:evenings,
|
39
|
+
:nights,
|
40
|
+
:days,
|
41
|
+
:weekdays,
|
42
|
+
:weekends,
|
43
|
+
:wdays,
|
44
|
+
:weeks,
|
45
|
+
:fortnights,
|
46
|
+
:months,
|
47
|
+
:quarters,
|
48
|
+
:seasons,
|
49
|
+
:years
|
50
|
+
]
|
51
|
+
|
52
|
+
attr_reader :begin
|
53
|
+
attr_reader :end
|
54
|
+
|
55
|
+
UNITS.each { |u| attr_reader u }
|
56
|
+
|
57
|
+
attr_reader :pointer
|
58
|
+
attr_reader :order
|
59
|
+
|
60
|
+
def initialize(arrows, options)
|
61
|
+
@options = options
|
62
|
+
@ordered = []
|
63
|
+
build(arrows)
|
64
|
+
end
|
65
|
+
|
66
|
+
def range
|
67
|
+
@begin..@end
|
68
|
+
end
|
69
|
+
|
70
|
+
def width
|
71
|
+
@end - @begin
|
72
|
+
end
|
73
|
+
|
74
|
+
def overlap?(r2)
|
75
|
+
r1 = range
|
76
|
+
(r1.begin <= r2.end) and (r2.begin <= r1.end)
|
77
|
+
end
|
78
|
+
|
79
|
+
def translate_unit(unit)
|
80
|
+
unit.to_s + 's'
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_span(span, timezone = nil)
|
84
|
+
precision = PRECISION.length - 1
|
85
|
+
ds = Date::split(span.begin)
|
86
|
+
ds += Time::split(span.begin)
|
87
|
+
case span.precision
|
88
|
+
when :year
|
89
|
+
precision = PRECISION.index(:years)
|
90
|
+
ds[3] = ds[4] = ds[5] = 0
|
91
|
+
when :month
|
92
|
+
precision = PRECISION.index(:months)
|
93
|
+
ds[3] = ds[4] = ds[5] = 0
|
94
|
+
when :day, :day_special
|
95
|
+
precision = PRECISION.index(:days)
|
96
|
+
ds[3] = ds[4] = ds[5] = 0
|
97
|
+
when :hour
|
98
|
+
precision = PRECISION.index(:hours)
|
99
|
+
when :minute
|
100
|
+
precision = PRECISION.index(:minutes)
|
101
|
+
when :second
|
102
|
+
precision = PRECISION.index(:seconds)
|
103
|
+
when :time_special
|
104
|
+
precision = 0
|
105
|
+
end
|
106
|
+
|
107
|
+
sign = (@pointer == :past) ? -1 : 1
|
108
|
+
@ordered.each do |data|
|
109
|
+
unit = data.first
|
110
|
+
count = data[1]
|
111
|
+
special = data.last
|
112
|
+
case unit
|
113
|
+
when *BASE_UNITS
|
114
|
+
ds[BASE_UNITS.index(unit)] += sign * count
|
115
|
+
ds[2], ds[3], ds[4], ds[5] = Time::normalize(ds[2], ds[3], ds[4], ds[5])
|
116
|
+
ds[0], ds[1], ds[2] = Date::normalize(ds[0], ds[1], ds[2])
|
117
|
+
precision = update_precision(precision, unit)
|
118
|
+
when :seasons
|
119
|
+
# TODO
|
120
|
+
raise "Not Implemented Arrow #{unit}"
|
121
|
+
when :quarters
|
122
|
+
ds[0], quarter = Date::add_quarter(ds[0], Date::get_quarter_index(ds[1]), sign * count)
|
123
|
+
ds[1] = Date::QUARTERS[quarter]
|
124
|
+
ds[2] = 1
|
125
|
+
ds[3], ds[4], ds[5] = 0, 0, 0
|
126
|
+
precision = PRECISION.index(unit)
|
127
|
+
when :fortnights
|
128
|
+
ds[0], ds[1], ds[2] = Date::add_day(ds[0], ds[1], ds[2], sign * count * Date::FORTNIGHT_DAYS)
|
129
|
+
precision = update_precision(precision, unit)
|
130
|
+
when :weeks
|
131
|
+
ds[0], ds[1], ds[2] = Date::add_day(ds[0], ds[1], ds[2], sign * count * Date::WEEK_DAYS)
|
132
|
+
precision = update_precision(precision, unit)
|
133
|
+
when :wdays
|
134
|
+
date = Chronic.time_class.new(ds[0], ds[1], ds[2])
|
135
|
+
diff = Date::wday_diff(date, special, sign)
|
136
|
+
ds[0], ds[1], ds[2] = Date::add_day(ds[0], ds[1], ds[2], diff + sign * (count - 1) * Date::WEEK_DAYS)
|
137
|
+
precision = update_precision(precision, unit)
|
138
|
+
when :weekends
|
139
|
+
date = Chronic.time_class.new(ds[0], ds[1], ds[2])
|
140
|
+
diff = Date::wday_diff(date, Date::DAYS[:saturday], sign)
|
141
|
+
ds[0], ds[1], ds[2] = Date::add_day(ds[0], ds[1], ds[2], diff + sign * (count - 1) * Date::WEEK_DAYS)
|
142
|
+
ds[3], ds[4], ds[5] = 0, 0, 0
|
143
|
+
precision = update_precision(precision, unit)
|
144
|
+
when :weekdays
|
145
|
+
# TODO
|
146
|
+
raise "Not Implemented Arrow #{unit}"
|
147
|
+
when :days
|
148
|
+
# TODO
|
149
|
+
raise "Not Implemented Arrow #{unit}"
|
150
|
+
when :mornings, :noons, :afternoons, :evenings, :nights, :midnights
|
151
|
+
name = n(unit)
|
152
|
+
count -= 1 if @pointer == :past and ds[3] > Time::SPECIAL[name].end
|
153
|
+
count += 1 if @pointer == :future and ds[3] < Time::SPECIAL[name].begin
|
154
|
+
ds[0], ds[1], ds[2] = Date::add_day(ds[0], ds[1], ds[2], sign * count)
|
155
|
+
ds[3], ds[4], ds[5] = Time::SPECIAL[name].begin, 0, 0
|
156
|
+
precision = PRECISION.index(unit)
|
157
|
+
when :miliseconds
|
158
|
+
# TODO
|
159
|
+
raise "Not Implemented Arrow #{unit}"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
de = ds.dup
|
164
|
+
case PRECISION[precision]
|
165
|
+
when :miliseconds
|
166
|
+
de[4], de[5] = Time::add_second(ds[4], ds[5], 0.001)
|
167
|
+
when :seconds
|
168
|
+
de[4], de[5] = Time::add_second(ds[4], ds[5])
|
169
|
+
when :minutes
|
170
|
+
de[3], de[4] = Time::add_minute(ds[3], ds[4])
|
171
|
+
de[5] = 0
|
172
|
+
when :mornings, :noons, :afternoons, :evenings, :nights, :midnights
|
173
|
+
name = n(PRECISION[precision])
|
174
|
+
de[3], de[4], de[5] = Time::SPECIAL[name].end, 0, 0
|
175
|
+
when :hours
|
176
|
+
de[2], de[3] = Time::add_hour(ds[2], ds[3])
|
177
|
+
de[4] = de[5] = 0
|
178
|
+
when :days, :weekdays, :wdays
|
179
|
+
de[0], de[1], de[2] = Date::add_day(ds[0], ds[1], ds[2])
|
180
|
+
de[3] = de[4] = de[5] = 0
|
181
|
+
when :weekends
|
182
|
+
end_date = Chronic.time_class.new(ds[0], ds[1], ds[2])
|
183
|
+
diff = Date::wday_diff(end_date, Date::DAYS[:monday])
|
184
|
+
de[0], de[1], de[2] = Date::add_day(ds[0], ds[1], ds[2], diff)
|
185
|
+
de[3] = de[4] = de[5] = 0
|
186
|
+
when :weeks
|
187
|
+
end_date = Chronic.time_class.new(ds[0], ds[1], ds[2])
|
188
|
+
diff = Date::wday_diff(end_date, Date::DAYS[@options[:week_start]])
|
189
|
+
de[0], de[1], de[2] = Date::add_day(ds[0], ds[1], ds[2], diff)
|
190
|
+
de[3] = de[4] = de[5] = 0
|
191
|
+
when :fortnights
|
192
|
+
end_date = Chronic.time_class.new(ds[0], ds[1], ds[2])
|
193
|
+
diff = Date::wday_diff(end_date, Date::DAYS[@options[:week_start]])
|
194
|
+
de[0], de[1], de[2] = Date::add_day(ds[0], ds[1], ds[2], diff + Date::WEEK_DAYS)
|
195
|
+
de[3] = de[4] = de[5] = 0
|
196
|
+
when :months
|
197
|
+
de[0], de[1] = Date::add_month(ds[0], ds[1])
|
198
|
+
de[2] = 1
|
199
|
+
de[3] = de[4] = de[5] = 0
|
200
|
+
when :quarters
|
201
|
+
de[0], quarter = Date::add_quarter(ds[0], Date::get_quarter_index(ds[1]))
|
202
|
+
de[1] = Date::QUARTERS[quarter]
|
203
|
+
de[2] = 1
|
204
|
+
de[3] = de[4] = de[5] = 0
|
205
|
+
when :seasons
|
206
|
+
# TODO
|
207
|
+
raise "Not Implemented Arrow #{PRECISION[precision]}"
|
208
|
+
when :years
|
209
|
+
de[0] += 1
|
210
|
+
de[1] = de[2] = 1
|
211
|
+
de[3] = de[4] = de[5] = 0
|
212
|
+
end
|
213
|
+
utc_offset = nil
|
214
|
+
end_utc_offset = nil
|
215
|
+
if timezone
|
216
|
+
utc_offset = timezone.to_offset(ds[0], ds[1], ds[2], ds[3], ds[4], ds[5])
|
217
|
+
end_utc_offset = timezone.to_offset(de[0], de[1], de[2], de[3], de[4], de[5])
|
218
|
+
end
|
219
|
+
span_start = Chronic.construct(ds[0], ds[1], ds[2], ds[3], ds[4], ds[5], utc_offset)
|
220
|
+
span_end = Chronic.construct(de[0], de[1], de[2], de[3], de[4], de[5], utc_offset)
|
221
|
+
Span.new(span_start, span_end)
|
222
|
+
end
|
223
|
+
|
224
|
+
def to_s
|
225
|
+
full = []
|
226
|
+
UNITS.each do |unit|
|
227
|
+
count = instance_variable_get('@'+unit.to_s)
|
228
|
+
full << [unit, count].join(' ') unless count.nil?
|
229
|
+
end
|
230
|
+
unless full.empty?
|
231
|
+
'Arrow => ' + @pointer.inspect + ' ' + full.join(', ')
|
232
|
+
else
|
233
|
+
'Arrow => empty'
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
protected
|
238
|
+
|
239
|
+
def n(unit)
|
240
|
+
s = unit.to_s
|
241
|
+
s.to_s[0, s.length - 1].to_sym
|
242
|
+
end
|
243
|
+
|
244
|
+
def v(v)
|
245
|
+
'@'+v.to_s
|
246
|
+
end
|
247
|
+
|
248
|
+
def update_precision(precision, unit)
|
249
|
+
new_precision = PRECISION.index(unit)
|
250
|
+
precision = new_precision if new_precision < precision
|
251
|
+
precision
|
252
|
+
end
|
253
|
+
|
254
|
+
def build(arrows)
|
255
|
+
arrows.each do |arrow|
|
256
|
+
@begin = arrow.begin if @begin.nil? or @begin > arrow.begin
|
257
|
+
@end = arrow.end if @end.nil? or @end < arrow.end
|
258
|
+
@pointer = arrow.pointer if @pointer.nil? and not arrow.pointer.nil?
|
259
|
+
next if arrow.unit.nil?
|
260
|
+
unit = translate_unit(arrow.unit)
|
261
|
+
raise "Uknown unit #{unit.to_sym.inspect}" unless UNITS.include?(unit.to_sym)
|
262
|
+
count = instance_variable_get(v(unit))
|
263
|
+
count ||= 0
|
264
|
+
@ordered << [unit.to_sym, arrow.count, arrow.special]
|
265
|
+
instance_variable_set(v(unit), count+arrow.count)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
end
|
270
|
+
end
|