timesteps 0.9.6 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/{LICENSES → LICENSE} +0 -0
- data/NEWS.md +8 -0
- data/Note.ja.md +9 -0
- data/README.md +15 -7
- data/lib/timesteps/datetime_parse_timestamp.rb +21 -12
- data/lib/timesteps/datetime_timestep.rb +64 -0
- data/lib/timesteps/datetimelike.rb +6 -17
- data/lib/timesteps/grads.rb +39 -18
- data/lib/timesteps/time.rb +14 -0
- data/lib/timesteps/timeperiod.rb +50 -47
- data/lib/timesteps/timestep.rb +480 -248
- data/lib/timesteps/timestep_calendar.rb +49 -29
- data/lib/timesteps/timestep_converter.rb +19 -22
- data/lib/timesteps/timestep_datetime_ext.rb +6 -16
- data/lib/timesteps/timestep_pair.rb +37 -24
- data/lib/timesteps/timestep_query.rb +12 -4
- data/lib/timesteps/timestep_range.rb +155 -0
- data/lib/timesteps.rb +4 -0
- data/spec/allleap_spec.rb +4 -15
- data/spec/fixed360day_spec.rb +4 -15
- data/spec/noleap_spec.rb +2 -13
- data/spec/timestep_spec.rb +4 -27
- data/timesteps.gemspec +3 -3
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f12b99565a7b2bdc24a8e9c6e3d2b38a439d3b273f73df6af514f1bee2c7905
|
4
|
+
data.tar.gz: e2680119ef10f30ea98803e89e9dd2e6f0b9d0b9291939100896ce3c192d0b86
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ffca26ce458c6867518d4804e50fa85e673c972e32941299697b19a49b20baba1731a9d512d566bffa4532870a4e0f229e154c61d20e8b3ad1ec94e95d3ba2fc
|
7
|
+
data.tar.gz: a1b3f59a940a30d3e7634cdbbb748fa39f45558ce0ac65412b8630c2a847293f708dc8fbe85760eb13f4462d82067e2c677dac84ba0b6cfafed48622b10cea90
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--no-private
|
data/{LICENSES → LICENSE}
RENAMED
File without changes
|
data/NEWS.md
ADDED
data/Note.ja.md
CHANGED
data/README.md
CHANGED
@@ -2,13 +2,13 @@ timesteps
|
|
2
2
|
================
|
3
3
|
|
4
4
|
A library for handling discrete time series in constant increments.
|
5
|
-
The primary purpose
|
5
|
+
The primary purpose is to describe the time axis
|
6
6
|
when dealing with time series of observational data and climate data.
|
7
7
|
|
8
8
|
Features
|
9
9
|
--------
|
10
10
|
|
11
|
-
* TimeStep holds an origin time and
|
11
|
+
* TimeStep holds an origin time and a unit time interval.
|
12
12
|
* Parsing a time step expression like "hours since 2001-01-01 00:00:00" (originate from udunits library)
|
13
13
|
* Obtaining time value for the index value (0 for the origin time)
|
14
14
|
* Obtaining index value for the time value
|
@@ -58,9 +58,9 @@ ts.index_at("2001-01-02 00:00:00") ### => 8
|
|
58
58
|
ts.time_at(0) ### => #<DateTime 2001-01-01T00:00:00 ...>
|
59
59
|
ts.time_at(1) ### => #<DateTime 2001-01-01T03:00:00 ...>
|
60
60
|
ts.time_at(8) ### => #<DateTime 2001-01-02T00:00:00 ...>
|
61
|
-
ts.
|
62
|
-
ts.
|
63
|
-
ts.
|
61
|
+
ts.duration_at(0) ### => 0 [Integer]
|
62
|
+
ts.duration_at(1) ### => (1/8) [Rational]
|
63
|
+
ts.duration_at(8) ### => 1 [Integer]
|
64
64
|
```
|
65
65
|
|
66
66
|
#### Treatment of year and month units
|
@@ -137,14 +137,14 @@ ts = TimeStep.new("days since 2001-01-01", calendar: "allleap")
|
|
137
137
|
ts.parse("2001-02-29") ### => #<DateTime::AllLeap 2001-02-29T ...>
|
138
138
|
```
|
139
139
|
|
140
|
-
In the UDUNITS library, negative years are treated as BCs, and A.D. 0 is treated as non-existent. This is different from how it is handled in Ruby's DateTime class.
|
140
|
+
In the UDUNITS library, negative years are treated as BCs, and A.D. 0 is treated as non-existent. This is different from how it is handled in Ruby's DateTime class.
|
141
141
|
|
142
142
|
```ruby
|
143
143
|
DateTime.parse_timestamp("-0001-01-01")
|
144
144
|
# => #<DateTime: -0001-01-01T00:00:00+00:00 ...>
|
145
145
|
# B.C. 2
|
146
146
|
|
147
|
-
DateTime.parse_timestamp("-
|
147
|
+
DateTime.parse_timestamp("0000-01-01")
|
148
148
|
# => #<DateTime: 0000-01-01T00:00:00+00:00 ...>
|
149
149
|
# B.C. 1
|
150
150
|
|
@@ -195,6 +195,13 @@ ts = TimeStep.new("3 hours since 2001-01-01 09:00:00", calendar: "noleap")
|
|
195
195
|
|
196
196
|
# specify origin time with DateTime object
|
197
197
|
ts = TimeStep.new("3 hours", since: DateTime.parse("2001-01-01 09:00:00"))
|
198
|
+
|
199
|
+
# hourly increments whose origin is the most recent convenient time to the current time
|
200
|
+
ts = TimeStep.new("1 hour").new_origin(DateTime.now, truncate: true)
|
201
|
+
|
202
|
+
# hourly increments whose origin is the most recent convenient time to the current time
|
203
|
+
# with +0900 time offset
|
204
|
+
ts = TimeStep.new("1 hour", offset: "+0900").new_origin(DateTime.now, truncate: true)
|
198
205
|
```
|
199
206
|
|
200
207
|
### Attributes of TimeStep object
|
@@ -296,5 +303,6 @@ conv.forward(0, 56, 81, with_time: true)
|
|
296
303
|
# "ts2"=>[-48, 8, 33],
|
297
304
|
# "ts3"=>[-72, -16, 9]}
|
298
305
|
|
306
|
+
|
299
307
|
```
|
300
308
|
|
@@ -11,11 +11,10 @@ class DateTime
|
|
11
11
|
# `DateTime._parse()` is called internally.
|
12
12
|
#
|
13
13
|
# @param spec [String]
|
14
|
-
# @option bc [Boolean]
|
15
14
|
#
|
16
15
|
# @return [DateTimeFixedDPY]
|
17
16
|
|
18
|
-
def self.parse_timestamp (spec, calendar: "standard",
|
17
|
+
def self.parse_timestamp (spec, format: nil, offset: nil, calendar: "standard", tz: nil)
|
19
18
|
case calendar.downcase.intern
|
20
19
|
when :standard, :gregorian
|
21
20
|
klass = DateTime
|
@@ -40,27 +39,37 @@ class DateTime
|
|
40
39
|
hash = DateTime._strptime(spec, format)
|
41
40
|
raise "date-time string '#{spec}' doesn't match with the given format '#{format}'" unless hash
|
42
41
|
else
|
43
|
-
if spec =~ /\A([+\-]?\d{4})(\-(\d{1,2}))?\z/
|
44
|
-
|
42
|
+
if spec =~ /\A([+\-]?\d{1,4})(\-(\d{1,2}))?(\s+(\w{3}|[+\-]\d{1,2}(:?\d{1,2})))?\z/
|
43
|
+
year = $1.to_i
|
44
|
+
month = $3 ? $3.to_i : 1
|
45
|
+
mday = 1
|
46
|
+
rest = $4
|
47
|
+
hash = DateTime._parse("#{year}-#{month}-#{mday} 00:00:00 #{rest}")
|
45
48
|
else
|
46
49
|
hash = DateTime._parse(spec)
|
47
50
|
end
|
48
51
|
end
|
49
|
-
year, month, day, hour, minute, second, sec_fraction,
|
52
|
+
year, month, day, hour, minute, second, sec_fraction, offset_ =
|
50
53
|
hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset)
|
51
|
-
if bc and year < 0
|
52
|
-
year = year + 1
|
53
|
-
end
|
54
54
|
hour ||= 0
|
55
55
|
minute ||= 0
|
56
56
|
second ||= 0.0
|
57
57
|
sec_fraction ||= 0.0
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
if offset_
|
59
|
+
offset = offset_.quo(86400)
|
60
|
+
else
|
61
|
+
offset ||= 0
|
62
|
+
end
|
63
|
+
if tz
|
64
|
+
time = tz.local_datetime(year, month, day, hour, minute, second.to_i, sec_fraction.to_r)
|
61
65
|
else
|
62
|
-
|
66
|
+
if hour == 24 && minute == 0 && second == 0.0
|
67
|
+
time = klass.new(year, month, day, 23, minute, second + sec_fraction, offset, start) + 1.quo(24)
|
68
|
+
else
|
69
|
+
time = klass.new(year, month, day, hour, minute, second + sec_fraction, offset, start)
|
70
|
+
end
|
63
71
|
end
|
72
|
+
return time
|
64
73
|
end
|
65
74
|
|
66
75
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
class DateTime
|
3
|
+
|
4
|
+
def timestep (interval_spec, tz: nil)
|
5
|
+
case start
|
6
|
+
when Date::ITALY
|
7
|
+
calendar = "standard"
|
8
|
+
when Date::GREGORIAN
|
9
|
+
calendar = "proleptic_gregorian"
|
10
|
+
when Date::JULIAN
|
11
|
+
calendar = "proleptic_julian"
|
12
|
+
end
|
13
|
+
return TimeStep.new(interval_spec, since: self, calendar: calendar, tz: tz)
|
14
|
+
end
|
15
|
+
|
16
|
+
def timeperiod (interval_spec, tz: nil, ends: "[]")
|
17
|
+
case start
|
18
|
+
when Date::ITALY
|
19
|
+
calendar = "standard"
|
20
|
+
when Date::GREGORIAN
|
21
|
+
calendar = "proleptic_gregorian"
|
22
|
+
when Date::JULIAN
|
23
|
+
calendar = "proleptic_julian"
|
24
|
+
end
|
25
|
+
return TimePeriod.new(interval_spec, since: self, calendar: calendar, ends: ends, tz: tz)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
class DateTime::NoLeap
|
31
|
+
|
32
|
+
def timestep (interval_spec, tz: nil)
|
33
|
+
return TimeStep.new(interval_spec, since: self, clanedar: "noleap", tz: tz)
|
34
|
+
end
|
35
|
+
|
36
|
+
def timeperiod (interval_spec, tz: nil, ends: "[]")
|
37
|
+
return TimePeriod.new(interval_spec, since: self, calendar: "noleap", ends: ends, tz: tz)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
class DateTime::AllLeap
|
43
|
+
|
44
|
+
def timestep (interval_spec, tz: nil)
|
45
|
+
return TimeStep.new(interval_spec, since: self, clanedar: "allleap", tz: tz)
|
46
|
+
end
|
47
|
+
|
48
|
+
def timeperiod (interval_spec, tz: nil, ends: "[]")
|
49
|
+
return TimePeriod.new(interval_spec, since: self, calendar: "allleap", ends: ends, tz: tz)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
class DateTime::Fixed360Day
|
55
|
+
|
56
|
+
def timestep (interval_spec, tz: nil)
|
57
|
+
return TimeStep.new(interval_spec, since: self, clanedar: "360day", tz: tz)
|
58
|
+
end
|
59
|
+
|
60
|
+
def timeperiod (interval_spec, tz: nil, ends: "[]")
|
61
|
+
return TimePeriod.new(interval_spec, since: self, calendar: "360day", ends: ends, tz: tz)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -398,29 +398,18 @@ class DateTimeLike
|
|
398
398
|
#
|
399
399
|
# @return [Integer]
|
400
400
|
def difference_in_years (other)
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
end
|
405
|
-
if self.year < other.year && self.compare_md(other) > 0
|
406
|
-
extra = 1
|
407
|
-
end
|
408
|
-
return self.year - other.year + extra
|
401
|
+
my = self.new_offset(0)
|
402
|
+
other = other.new_offset(0)
|
403
|
+
return my.year - other.year + my.compare_md(other).quo(2)
|
409
404
|
end
|
410
405
|
|
411
406
|
# Calculate difference between the object and other object in months.
|
412
407
|
#
|
413
408
|
# @return [Integer]
|
414
409
|
def difference_in_months (other)
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
end
|
419
|
-
if self.month < other.month && self.compare_d(other) > 0
|
420
|
-
extra = 1
|
421
|
-
end
|
422
|
-
return 12*(self.year - other.year) + self.month - other.month + extra
|
410
|
+
my = self.new_offset(0)
|
411
|
+
other = other.new_offset(0)
|
412
|
+
return 12*(my.year - other.year) + my.month - other.month + my.compare_d(other).quo(2)
|
423
413
|
end
|
424
|
-
|
425
414
|
end
|
426
415
|
|
data/lib/timesteps/grads.rb
CHANGED
@@ -1,6 +1,24 @@
|
|
1
|
-
|
1
|
+
require "timesteps"
|
2
2
|
|
3
|
-
class
|
3
|
+
class DateTime
|
4
|
+
|
5
|
+
def self.parse_grads_time (time_string)
|
6
|
+
if time_string.strip =~ /\A(((\d{2})?(:(\d{2}))?Z)?(\d{2}))?(\w{3})(\d{4})\z/i
|
7
|
+
hour = $3 || "00"
|
8
|
+
min = $5 || "00"
|
9
|
+
day = $6 || "01"
|
10
|
+
mon = $7
|
11
|
+
year = $8
|
12
|
+
time = DateTime.parse("#{year}#{mon}#{day} #{hour}:#{min}:00")
|
13
|
+
else
|
14
|
+
raise "invalid time format"
|
15
|
+
end
|
16
|
+
return time
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
class TimeStep::Range
|
4
22
|
|
5
23
|
# @private
|
6
24
|
REGEXP_GRADS_TDEF = /\A(?:TDEF\s+)?(\d+)\s+LINEAR\s+([^\s]*?)\s+([^\s]*?)\s*\z/i
|
@@ -13,8 +31,17 @@ class TimeStep
|
|
13
31
|
"mo" => "months",
|
14
32
|
"yr" => "years",
|
15
33
|
}
|
16
|
-
|
17
|
-
|
34
|
+
|
35
|
+
module GrADSMixin
|
36
|
+
|
37
|
+
def parse_grads_time (time_string)
|
38
|
+
return DateTime.parse_grads_time(time_string)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.from_grads_tdef (tdef_string)
|
44
|
+
|
18
45
|
if tdef_string.strip =~ REGEXP_GRADS_TDEF
|
19
46
|
count = $1.to_i
|
20
47
|
time = $2
|
@@ -22,22 +49,16 @@ class TimeStep
|
|
22
49
|
else
|
23
50
|
raise "invalid grads tdef string"
|
24
51
|
end
|
25
|
-
|
26
|
-
|
27
|
-
min = $5 || "00"
|
28
|
-
day = $6 || "01"
|
29
|
-
mon = $7
|
30
|
-
year = $8
|
31
|
-
origin = DateTime.parse("#{year}#{mon}#{day} #{hour}:#{min}:00")
|
32
|
-
else
|
33
|
-
raise "invalid time format"
|
34
|
-
end
|
52
|
+
|
53
|
+
origin = DateTime.parse_grads_time(time)
|
35
54
|
|
36
55
|
increment = increment.sub(/(mn|hr|dy|mo|yr)/i) {|s| GRADS_INCREMENT[s.downcase]}
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
56
|
+
|
57
|
+
range = TimeStep.new(increment, since: origin).range(count)
|
58
|
+
range.extend GrADSMixin
|
59
|
+
|
60
|
+
return range
|
41
61
|
end
|
42
62
|
|
63
|
+
|
43
64
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
class Time
|
4
|
+
def to_datetime
|
5
|
+
# Convert seconds + microseconds into a fractional number of seconds
|
6
|
+
seconds = sec + Rational(usec, 10**6)
|
7
|
+
|
8
|
+
# Convert a UTC offset measured in minutes to one measured in a
|
9
|
+
# fraction of a day.
|
10
|
+
offset = Rational(utc_offset, 60 * 60 * 24)
|
11
|
+
|
12
|
+
DateTime.new(year, month, day, hour, min, seconds, offset)
|
13
|
+
end
|
14
|
+
end
|
data/lib/timesteps/timeperiod.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
|
2
|
+
|
2
3
|
class TimePeriod < TimeStep
|
3
|
-
|
4
|
-
def initialize (spec, since: nil, format: nil, calendar: "standard",
|
5
|
-
super(spec, since: since, format: format,
|
6
|
-
raise "invalid
|
7
|
-
@
|
8
|
-
@include_start = (
|
9
|
-
@include_last = (
|
4
|
+
|
5
|
+
def initialize (spec, since: nil, format: nil, offset: nil, calendar: "standard", tz: nil, ends: "[]" )
|
6
|
+
super(spec, since: since, format: format, offset: offset, calendar: calendar, tz: tz)
|
7
|
+
raise "invalid ends specification" unless ends =~ /\A[\[\(][\]\)]\z/
|
8
|
+
@ends = ends
|
9
|
+
@include_start = ( ends[0] == "[" ) ? true : false
|
10
|
+
@include_last = ( ends[1] == "]" ) ? true : false
|
10
11
|
@last = time_at(1)
|
11
12
|
end
|
12
13
|
|
13
|
-
attr_reader :last
|
14
|
+
attr_reader :last, :ends
|
14
15
|
|
15
16
|
def start
|
16
17
|
return @origin
|
@@ -27,40 +28,40 @@ class TimePeriod < TimeStep
|
|
27
28
|
# Returns the value as a string for inspection.
|
28
29
|
#
|
29
30
|
def inspect
|
31
|
+
options = ""
|
32
|
+
case @calendar.name
|
33
|
+
when "standard", "gregorian"
|
34
|
+
else
|
35
|
+
options << " calendar='#{calendar.name}'"
|
36
|
+
end
|
30
37
|
left_paren = @include_start ? "[" : "("
|
31
38
|
right_paren = @include_last ? "]" : ")"
|
32
|
-
"#<TimePeriod '#{interval_spec}' #{left_paren}#{start.to_s}, #{last.to_s}#{right_paren}
|
33
|
-
end
|
34
|
-
|
35
|
-
def boundary
|
36
|
-
left_paren = @include_start ? "[" : "("
|
37
|
-
right_paren = @include_last ? "]" : ")"
|
38
|
-
return left_paren + right_paren
|
39
|
+
"#<TimePeriod '#{interval_spec}' #{left_paren}#{start.to_s}, #{last.to_s}#{right_paren} #{options}>"
|
39
40
|
end
|
40
41
|
|
41
42
|
def include? (other)
|
42
43
|
case other
|
43
44
|
when TimePeriod
|
44
45
|
if ( other.origin < @origin ) ||
|
45
|
-
( other.origin == @origin && ( not include_start
|
46
|
+
( other.origin == @origin && ( not @include_start ) && other.include_start? )
|
46
47
|
left = false
|
47
48
|
else
|
48
49
|
left = true
|
49
50
|
end
|
50
51
|
if ( @last < other.last ) ||
|
51
|
-
( @last == other.last && ( not include_last
|
52
|
+
( @last == other.last && ( not @include_last ) && other.include_last? )
|
52
53
|
right = false
|
53
54
|
else
|
54
55
|
right = true
|
55
56
|
end
|
56
57
|
return left & right
|
57
58
|
else
|
58
|
-
if include_start
|
59
|
+
if @include_start
|
59
60
|
left = @origin <= other
|
60
61
|
else
|
61
62
|
left = @origin < other
|
62
63
|
end
|
63
|
-
if include_last
|
64
|
+
if @include_last
|
64
65
|
right = other <= @last
|
65
66
|
else
|
66
67
|
right = other < @last
|
@@ -73,13 +74,13 @@ class TimePeriod < TimeStep
|
|
73
74
|
case other
|
74
75
|
when TimePeriod
|
75
76
|
if ( @origin < other.last ) ||
|
76
|
-
( @origin == other.last && include_start
|
77
|
+
( @origin == other.last && @include_start && other.include_last? )
|
77
78
|
left = true
|
78
79
|
else
|
79
80
|
left = false
|
80
81
|
end
|
81
82
|
if ( other.origin < @last ) ||
|
82
|
-
( other.origin == @last && include_last
|
83
|
+
( other.origin == @last && @include_last && other.include_start? )
|
83
84
|
right = true
|
84
85
|
else
|
85
86
|
right = false
|
@@ -116,26 +117,26 @@ class TimePeriod < TimeStep
|
|
116
117
|
if ( other.origin < @origin ) ||
|
117
118
|
( other.origin == @origin && ( not include_start? ) && other.include_start? )
|
118
119
|
left = other.origin
|
119
|
-
|
120
|
+
left_end = other.include_start? ? "[" : "("
|
120
121
|
else
|
121
122
|
left = @origin
|
122
|
-
|
123
|
+
left_end = include_start? ? "[" : "("
|
123
124
|
end
|
124
125
|
if ( @last < other.last ) ||
|
125
126
|
( @last == other.last && ( not include_last? ) && other.include_last? )
|
126
127
|
right = other.last
|
127
|
-
|
128
|
+
right_end = other.include_last? ? "]" : ")"
|
128
129
|
else
|
129
130
|
right = @last
|
130
|
-
|
131
|
+
right_end = include_last? ? ")" : "]"
|
131
132
|
end
|
132
133
|
ridx = index_at(right)
|
133
134
|
lidx = index_at(left)
|
134
135
|
numeric = (ridx - lidx) * @numeric
|
135
136
|
origin = left
|
136
137
|
interval_spec = format("%g %s", numeric, @symbol)
|
137
|
-
|
138
|
-
return TimePeriod.new(interval_spec, since: origin, calendar: @calendar
|
138
|
+
ends = left_end + right_end
|
139
|
+
return TimePeriod.new(interval_spec, since: origin, calendar: @calendar, ends: ends)
|
139
140
|
end
|
140
141
|
|
141
142
|
def clip (other)
|
@@ -143,60 +144,62 @@ class TimePeriod < TimeStep
|
|
143
144
|
if ( @origin < other.origin ) ||
|
144
145
|
( @origin == other.origin && include_start? && ( not other.include_start? ) )
|
145
146
|
left = other.origin
|
146
|
-
|
147
|
+
left_end = other.include_start? ? "[" : "("
|
147
148
|
else
|
148
149
|
left = @origin
|
149
|
-
|
150
|
+
left_end = include_start? ? "[" : "("
|
150
151
|
end
|
151
152
|
if ( other.last < @last ) ||
|
152
153
|
( other.last == @last && include_last? && ( not other.include_last? ) )
|
153
154
|
right = other.last
|
154
|
-
|
155
|
+
right_end = other.include_last? ? "]" : ")"
|
155
156
|
else
|
156
157
|
right = @last
|
157
|
-
|
158
|
+
right_end = include_last? ? ")" : "]"
|
158
159
|
end
|
159
160
|
ridx = index_at(right)
|
160
161
|
lidx = index_at(left)
|
161
162
|
numeric = (ridx - lidx) * @numeric
|
162
163
|
origin = left
|
163
164
|
interval_spec = format("%g %s", numeric, @symbol)
|
164
|
-
|
165
|
-
return TimePeriod.new(interval_spec, since: origin, calendar: @calendar
|
165
|
+
ends = left_end + right_end
|
166
|
+
return TimePeriod.new(interval_spec, since: origin, calendar: @calendar, ends: ends)
|
166
167
|
end
|
167
168
|
|
168
|
-
def split (time,
|
169
|
+
def split (time, ends: ")[")
|
169
170
|
raise "can't split period without contacted time" unless contact?(time)
|
170
171
|
# left
|
171
172
|
numeric = index_at(time) * @numeric
|
172
173
|
interval_spec = format("%g %s", numeric, @symbol)
|
173
|
-
|
174
|
-
left_period = TimePeriod.new(interval_spec, since: @origin, calendar: @calendar
|
174
|
+
ends = (@include_start ? "[" : "(") + ends[0]
|
175
|
+
left_period = TimePeriod.new(interval_spec, since: @origin, calendar: @calendar, ends: ends)
|
175
176
|
# right
|
176
177
|
numeric = (1 - index_at(time)) * @numeric
|
177
178
|
interval_spec = format("%g %s", numeric, @symbol)
|
178
|
-
|
179
|
-
right_period = TimePeriod.new(interval_spec, since: @origin, calendar: @calendar
|
179
|
+
ends = ends[1] + (@include_last ? "]" : ")")
|
180
|
+
right_period = TimePeriod.new(interval_spec, since: @origin, calendar: @calendar, ends: ends)
|
180
181
|
return left_period, right_period
|
181
182
|
end
|
182
183
|
|
183
184
|
def next
|
184
|
-
return TimePeriod.new(interval_spec, since: @last, calendar: @calendar
|
185
|
+
return TimePeriod.new(interval_spec, since: @last, calendar: @calendar, ends: ends)
|
185
186
|
end
|
186
187
|
|
187
188
|
def prev
|
188
189
|
origin = index_at(-1)
|
189
|
-
return TimePeriod.new(interval_spec, since: origin, calendar: @calendar
|
190
|
+
return TimePeriod.new(interval_spec, since: origin, calendar: @calendar, ends: ends)
|
190
191
|
end
|
191
192
|
|
192
|
-
def
|
193
|
-
|
194
|
-
|
193
|
+
def shift_origin (index, with: "index")
|
194
|
+
case with
|
195
|
+
when :index, "index"
|
196
|
+
return TimePeriod.new(interval_spec, since: time_at(index), calendar: @calendar, ends: ends)
|
197
|
+
when :duration, "duration", :days, "days"
|
198
|
+
time = @origin + index
|
199
|
+
return TimePeriod.new(interval_spec, since: time, calendar: @calendar, ends: ends)
|
200
|
+
end
|
195
201
|
|
196
|
-
def shift_with_duration (duration)
|
197
|
-
time = @origin + duration
|
198
|
-
return TimePeriod.new(interval_spec, since: time, calendar: @calendar.name, bc: @calendar.bc?, boundary: boundary)
|
199
202
|
end
|
200
|
-
|
203
|
+
|
201
204
|
end
|
202
205
|
|