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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0feffe90d4bd2fdd8c478624bc78b67e3a7ab1c5905e236767c7734ba8c6b098
4
- data.tar.gz: 4e924fa6b145f2b7cb06836d408b05e8bb34e8133797a3b7702ba29033af4400
3
+ metadata.gz: 9f12b99565a7b2bdc24a8e9c6e3d2b38a439d3b273f73df6af514f1bee2c7905
4
+ data.tar.gz: e2680119ef10f30ea98803e89e9dd2e6f0b9d0b9291939100896ce3c192d0b86
5
5
  SHA512:
6
- metadata.gz: 52773368aa3a11f6ac7e6e2e71b56e8ebb84f78b2c6807ac509f77a8342566cae41fb4b93a1c0c03f4fd1fbed07ae698144fb208f433b5a663a08cbf80ff83cb
7
- data.tar.gz: 61d67459512fa64a4e7b8967b7300af0c9719b61c2bf4f66c478b5c08a064c38d889f0d2830bb7399d81ba02c516b194ccaab85406855a688204c06347cd6117
6
+ metadata.gz: ffca26ce458c6867518d4804e50fa85e673c972e32941299697b19a49b20baba1731a9d512d566bffa4532870a4e0f229e154c61d20e8b3ad1ec94e95d3ba2fc
7
+ data.tar.gz: a1b3f59a940a30d3e7634cdbbb748fa39f45558ce0ac65412b8630c2a847293f708dc8fbe85760eb13f4462d82067e2c677dac84ba0b6cfafed48622b10cea90
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --no-private
File without changes
data/NEWS.md ADDED
@@ -0,0 +1,8 @@
1
+ NEWS
2
+ ====
3
+
4
+ 0.9.8 -> 0.9.9
5
+ --------------
6
+
7
+ * [Mod] TimeStep::Range.new was modified to accept `start` and `last` argument of mixed type (Integer, DateTime, DateTimeLike, String).
8
+
data/Note.ja.md CHANGED
@@ -1,4 +1,13 @@
1
1
  # メモ
2
+
3
+ masterブランチ -> gem リリース最新版
4
+ developブランチ -> 開発統合版
5
+ topicブランチ -> Feature開発版
6
+
7
+
8
+
9
+ "XX since YYY" と since: time を同時に指定下場合は、前者が採用される (sinceオプションは無視される)。
10
+
2
11
  ### 時間の単位 (udunits)
3
12
  * years, year
4
13
  * months,month
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 of this library is to describe the time axis
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 an unit time interval.
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.days_at(0) ### => 0 [Integer]
62
- ts.days_at(1) ### => (1/8) [Rational]
63
- ts.days_at(8) ### => 1 [Integer]
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. To parse date-time string of UDUNITS type, `bc` option for `Date.parse_timestamp` method.
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("-0001-01-01", bc: true)
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", bc: false, format: nil)
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
- hash = { year: $1.to_i, mon: $3 ? $3.to_i : 1, mday: 1 }
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, offset =
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
- offset ||= 0
59
- if hour == 24 && minute == 0 && second == 0.0
60
- klass.new(year, month, day, 23, minute, second + sec_fraction, offset.quo(86400), start) + 1.quo(24)
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
- klass.new(year, month, day, hour, minute, second + sec_fraction, offset.quo(86400), start)
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
- extra = 0
402
- if self.year > other.year && self.compare_md(other) < 0
403
- extra = -1
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
- extra = 0
416
- if self.month > other.month && self.compare_d(other) < 0
417
- extra = -1
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
 
@@ -1,6 +1,24 @@
1
- require_relative "../timesteps"
1
+ require "timesteps"
2
2
 
3
- class TimeStep
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
- def self.parse_grads_tdef (tdef_string)
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
- if time =~ /(((\d{2})?(:(\d{2}))?Z)?(\d{2}))?(\w{3})(\d{4})/i
26
- hour = $3 || "00"
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
- spec = format("%s since %s", increment, origin.strftime("%F %T"))
39
-
40
- return TimeStep.new(spec, count: count)
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
@@ -1,16 +1,17 @@
1
1
 
2
+
2
3
  class TimePeriod < TimeStep
3
-
4
- def initialize (spec, since: nil, format: nil, calendar: "standard", bc: false, boundary: "[)" )
5
- super(spec, since: since, format: format, count: 1, calendar: calendar, bc: bc)
6
- raise "invalid boundary specification" unless boundary =~ /\A[\[\(][\]\)]\z/
7
- @boundary = boundary
8
- @include_start = ( boundary[0] == "[" ) ? true : false
9
- @include_last = ( boundary[1] == "]" ) ? true : false
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} calendar='#{calendar.name}'>"
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? ) && other.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? ) && other.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? && other.include_last? )
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? && other.include_start? )
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
- left_boundary = other.include_start? ? "[" : "("
120
+ left_end = other.include_start? ? "[" : "("
120
121
  else
121
122
  left = @origin
122
- left_boundary = include_start? ? "[" : "("
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
- right_boundary = other.include_last? ? "]" : ")"
128
+ right_end = other.include_last? ? "]" : ")"
128
129
  else
129
130
  right = @last
130
- right_boundary = include_last? ? ")" : "]"
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
- boundary = left_boundary + right_boundary
138
- return TimePeriod.new(interval_spec, since: origin, calendar: @calendar.name, bc: @bc, boundary: boundary)
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
- left_boundary = other.include_start? ? "[" : "("
147
+ left_end = other.include_start? ? "[" : "("
147
148
  else
148
149
  left = @origin
149
- left_boundary = include_start? ? "[" : "("
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
- right_boundary = other.include_last? ? "]" : ")"
155
+ right_end = other.include_last? ? "]" : ")"
155
156
  else
156
157
  right = @last
157
- right_boundary = include_last? ? ")" : "]"
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
- bndry = left_boundary + right_boundary
165
- return TimePeriod.new(interval_spec, since: origin, calendar: @calendar.name, bc: @bc, boundary: bndry)
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, boundary: ")[")
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
- bndry = (@include_start ? "[" : "(") + boundary[0]
174
- left_period = TimePeriod.new(interval_spec, since: @origin, calendar: @calendar.name, bc: @bc, boundary: bndry)
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
- bndry = boundary[1] + (@include_last ? "]" : ")")
179
- right_period = TimePeriod.new(interval_spec, since: @origin, calendar: @calendar.name, bc: @bc, boundary: bndry)
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.name, bc: @bc, boundary: boundary)
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.name, bc: @bc, boundary: boundary)
190
+ return TimePeriod.new(interval_spec, since: origin, calendar: @calendar, ends: ends)
190
191
  end
191
192
 
192
- def shift (index)
193
- return TimePeriod.new(interval_spec, since: time_at(index), calendar: @calendar.name, bc: @bc, boundary: boundary)
194
- end
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