chronic-davispuh 0.10.2.v0.1da32066b3f46f2506b3471e39557497e34afa27
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.
- 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
|