timesteps 0.9.3 → 0.9.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,7 +2,7 @@ require "timesteps"
2
2
 
3
3
  class TimeStep::Converter
4
4
 
5
- def initialize (reference, calendar: "standard", bc: false)
5
+ def initialize (reference, name: "reference", calendar: "standard", bc: false)
6
6
  @calendar = calendar
7
7
  @bc = bc
8
8
  case reference
@@ -15,16 +15,22 @@ class TimeStep::Converter
15
15
  end
16
16
  @pair = {}
17
17
  @target = {}
18
- self["reference"] = reference
18
+ self[name] = reference
19
19
  end
20
20
 
21
21
  # Append or reset new target time step for the given name.
22
22
  #
23
- def []= (name, spec)
23
+ def add_timestep (spec, name:)
24
24
  @pair[name] = TimeStep::Pair.new(@reference, spec, calendar: @calendar, bc: @bc)
25
25
  @target[name] = @pair[name].to
26
26
  return @target[name]
27
27
  end
28
+
29
+ # Append or reset new target time step for the given name.
30
+ #
31
+ def []= (name, spec)
32
+ return add_timestep(spec, name: name)
33
+ end
28
34
 
29
35
  # Return target time step of the given name.
30
36
  #
@@ -39,14 +45,41 @@ class TimeStep::Converter
39
45
  @target.delete(name)
40
46
  end
41
47
 
42
- def forward (*indices)
43
- hash = {}
48
+ # Returns the time represented by the given index as DateTime object
49
+ #
50
+ # @param indices [Numeric,Array<Numeric>]
51
+ #
52
+ # @return [DateTime]
53
+ def time_at (*indices)
54
+ return @reference.time_at(*indices)
55
+ end
56
+
57
+ # Converts index refering `from` timestep to index refering `to`timestep.
58
+ #
59
+ def forward (*indices, with_time: false)
60
+ if with_time
61
+ hash = {
62
+ "time" => time_at(*indices)
63
+ }
64
+ else
65
+ hash = {}
66
+ end
44
67
  @pair.each do |name, conv|
45
68
  hash[name] = conv.forward(*indices)
46
69
  end
47
70
  return hash
48
71
  end
49
72
 
73
+ def range (ge: nil, gt: nil, lt: nil, le: nil, with_time: false)
74
+ indices = @reference.range(ge: ge, gt: gt, lt: lt, le: le)
75
+ return forward(*indices, with_time: with_time)
76
+ end
77
+
78
+ def index_at (*times, format: nil, with_time: false)
79
+ indices = @reference.index_at(*times, format: format)
80
+ return forward(*indices, with_time: with_time)
81
+ end
82
+
50
83
  def valid? (*indices)
51
84
  hash = {}
52
85
  @pair.each do |name, conv|
@@ -55,9 +88,6 @@ class TimeStep::Converter
55
88
  return hash
56
89
  end
57
90
 
58
- def time_at (index)
59
- return @from.time_at(index)
60
- end
61
91
 
62
92
  end
63
93
 
@@ -73,7 +73,7 @@ class TimeStep
73
73
  end
74
74
 
75
75
  end
76
-
76
+
77
77
  end
78
78
 
79
79
 
@@ -18,7 +18,6 @@ class TimeStep::Pair
18
18
  # @option calendar [String, TimeStep::Calendar]
19
19
  # @option bc [Boolean]
20
20
  #
21
-
22
21
  def initialize (from, to, calendar: "standard", bc: false)
23
22
 
24
23
  case from
@@ -60,7 +59,9 @@ class TimeStep::Pair
60
59
  end
61
60
 
62
61
  attr_reader :from, :to, :difference
63
-
62
+
63
+ # Returns the value as a string for inspection.
64
+ #
64
65
  def inspect
65
66
  "#<TimeStep::Pair from='#{from.inspect}' to='#{to.inspect}'>"
66
67
  end
@@ -69,14 +70,20 @@ class TimeStep::Pair
69
70
  #
70
71
  # @return [Boolean]
71
72
  def == (other)
72
- return @from == other.from &&
73
- @to == other.to
73
+ return @from == other.from && @to == other.to
74
74
  end
75
75
 
76
+ # Returns the time represented by the given index as DateTime object
77
+ #
78
+ # @param indices [Numeric,Array<Numeric>]
79
+ #
80
+ # @return [DateTime]
76
81
  def time_at (*indices)
77
82
  @from.time_at(*indices)
78
83
  end
79
84
 
85
+ # Converts index refering `from` timestep to index refering `to`timestep.
86
+ #
80
87
  def forward (*indices, &block)
81
88
  if indices.size == 1
82
89
  index = indices.first.to_r
@@ -115,30 +122,17 @@ class TimeStep::Pair
115
122
 
116
123
  alias [] forward
117
124
 
118
- def forward_time (index)
119
- if @numeric_conversion
120
- return @to.time_at((index*@from_interval + @difference).quo(@to_interval))
121
- else
122
- case @from_symbol
123
- when :years, :months
124
- target = @from.time_at(index)
125
- else
126
- target = @from_origin + index*(@from_interval.quo(86400))
127
- end
128
- case @to_symbol
129
- when :years
130
- index = (target.year - @from_origin.year).quo(@to.numeric)
131
- when :months
132
- ms = 12*(target.year - @from_origin.year)
133
- ms += target.month - @from_origin.month
134
- index = ms.quo(@to.numeric)
135
- else
136
- index = (target.ajd - @from_origin.ajd).quo(@to_interval)
137
- end
138
- return @to.time_at(index)
139
- end
125
+ def forward_time (*indices)
126
+ return forward(*indices) {|index| @to.time_at(index) }
140
127
  end
141
128
 
129
+ def range (ge: nil, gt: nil, lt: nil, le: nil)
130
+ indices = @from.range(ge: ge, gt: gt, lt: lt, le: le)
131
+ return forward(*indices)
132
+ end
133
+
134
+ # Converts index refering `to` timestep to index refering `from` timestep.
135
+ #
142
136
  def inverse (*indices, &block)
143
137
  if indices.size == 1
144
138
  index = indices.first.to_r
@@ -159,11 +153,12 @@ class TimeStep::Pair
159
153
  else
160
154
  value = (target.ajd - @from_origin.ajd).quo(@from_interval)
161
155
  end
162
- if block
163
- return block[value]
164
- else
165
- return value
166
- end
156
+ end
157
+ value = value.to_i if value.denominator == 1
158
+ if block
159
+ return block[value]
160
+ else
161
+ return value
167
162
  end
168
163
  else
169
164
  if block
@@ -174,29 +169,8 @@ class TimeStep::Pair
174
169
  end
175
170
  end
176
171
 
177
- #
178
- def inverse_time (index)
179
- if @numeric_conversion
180
- return @from.time_at((index*@to_interval - @difference).quo(@from_interval))
181
- else
182
- case @to_symbol
183
- when :years, :months
184
- target = @to.time_at(index)
185
- else
186
- target = @to_origin + index*(@to_interval.quo(86400))
187
- end
188
- case @from_symbol
189
- when :years
190
- index = (target.year - @to_origin.year).quo(@from.numeric)
191
- when :months
192
- ms = 12*(target.year - @to_origin.year)
193
- ms += target.month - @to_origin.month
194
- index = ms.quo(@from.numeric)
195
- else
196
- index = (target.ajd - @to_origin.ajd).quo(@from_interval)
197
- end
198
- return @from.time_at(index)
199
- end
172
+ def inverse_time (*indices)
173
+ return inverse(*indices) {|index| @from.time_at(index) }
200
174
  end
201
175
 
202
176
  end
@@ -109,7 +109,7 @@ describe "AllLeap.parse_timestamp" do
109
109
  '05-Mar-2001 09:35:12.5 +09:00',
110
110
  ].each do |string|
111
111
 
112
- d2 = DateTime::AllLeap.parse_timestamp(string)
112
+ d2 = DateTime.parse_timestamp(string, calendar: "allleap")
113
113
 
114
114
  is_asserted_by { d2 == d1 }
115
115
  end
@@ -119,15 +119,15 @@ describe "AllLeap.parse_timestamp" do
119
119
  example 'raise for "2000-02-29"' do
120
120
 
121
121
  # leap day for noleap calendar
122
- is_asserted_by { DateTime::AllLeap.parse_timestamp("2000-2-29").is_a?(DateTime::AllLeap) }
122
+ is_asserted_by { DateTime.parse_timestamp("2000-2-29", calendar: "allleap").is_a?(DateTime::AllLeap) }
123
123
 
124
124
  end
125
125
 
126
126
  example "with bc option" do
127
127
 
128
128
  d1 = DateTime::AllLeap.new(0, 1, 1, 0, 0, 0, 0)
129
- d2 = DateTime::AllLeap.parse_timestamp('BC 0001-1-1 00:00:00')
130
- d3 = DateTime::AllLeap.parse_timestamp('-0001-1-1 00:00:00', bc: true)
129
+ d2 = DateTime.parse_timestamp('BC 0001-1-1 00:00:00', calendar: "allleap")
130
+ d3 = DateTime.parse_timestamp('-0001-1-1 00:00:00', calendar: "allleap", bc: true)
131
131
 
132
132
  is_asserted_by { d2 == d1 }
133
133
  is_asserted_by { d3 == d1 }
@@ -137,7 +137,7 @@ describe "AllLeap.parse_timestamp" do
137
137
  example '2000-12-31 24:00:00' do
138
138
 
139
139
  d1 = DateTime::AllLeap.new(2001, 1, 1, 0, 0, 0, 0)
140
- d2 = DateTime::AllLeap.parse_timestamp('2000-12-31 24:00:00')
140
+ d2 = DateTime.parse_timestamp('2000-12-31 24:00:00', calendar: "allleap")
141
141
 
142
142
  is_asserted_by { d2 == d1 }
143
143
 
@@ -118,7 +118,7 @@ describe "Fixed360Day.parse_timestamp" do
118
118
  '05-Mar-2001 09:35:12.5 +09:00',
119
119
  ].each do |string|
120
120
 
121
- d2 = DateTime::Fixed360Day.parse_timestamp(string)
121
+ d2 = DateTime.parse_timestamp(string, calendar: "360_day")
122
122
 
123
123
  is_asserted_by { d2 == d1 }
124
124
  end
@@ -128,7 +128,7 @@ describe "Fixed360Day.parse_timestamp" do
128
128
  example 'raise for "2000-02-29"' do
129
129
 
130
130
  # leap day for noleap calendar
131
- is_asserted_by { DateTime::Fixed360Day.parse_timestamp("2000-2-29").is_a?(DateTime::Fixed360Day) }
131
+ is_asserted_by { DateTime.parse_timestamp("2000-2-29", calendar: "360_day").is_a?(DateTime::Fixed360Day) }
132
132
 
133
133
 
134
134
  end
@@ -136,8 +136,8 @@ describe "Fixed360Day.parse_timestamp" do
136
136
  example "with bc option" do
137
137
 
138
138
  d1 = DateTime::Fixed360Day.new(0, 1, 1, 0, 0, 0, 0)
139
- d2 = DateTime::Fixed360Day.parse_timestamp('BC 0001-1-1 00:00:00')
140
- d3 = DateTime::Fixed360Day.parse_timestamp('-0001-1-1 00:00:00', bc: true)
139
+ d2 = DateTime.parse_timestamp('BC 0001-1-1 00:00:00', calendar: "360_day")
140
+ d3 = DateTime.parse_timestamp('-0001-1-1 00:00:00', calendar: "360_day", bc: true)
141
141
 
142
142
  is_asserted_by { d2 == d1 }
143
143
  is_asserted_by { d3 == d1 }
@@ -147,7 +147,7 @@ describe "Fixed360Day.parse_timestamp" do
147
147
  example '2000-12-31 24:00:00' do
148
148
 
149
149
  d1 = DateTime::Fixed360Day.new(2001, 1, 1, 0, 0, 0, 0)
150
- d2 = DateTime::Fixed360Day.parse_timestamp('2000-12-30 24:00:00')
150
+ d2 = DateTime.parse_timestamp('2000-12-30 24:00:00', calendar: "360_day")
151
151
 
152
152
  is_asserted_by { d2 == d1 }
153
153
 
@@ -107,7 +107,7 @@ describe "NoLeap.parse_timestamp" do
107
107
  '05-Mar-2001 09:35:12.5 +09:00',
108
108
  ].each do |string|
109
109
 
110
- d2 = DateTime::NoLeap.parse_timestamp(string)
110
+ d2 = DateTime.parse_timestamp(string, calendar: "noleap")
111
111
 
112
112
  is_asserted_by { d2 == d1 }
113
113
  end
@@ -117,15 +117,15 @@ describe "NoLeap.parse_timestamp" do
117
117
  example 'raise for "2000-02-29"' do
118
118
 
119
119
  # leap day for noleap calendar
120
- expect { DateTime::NoLeap.parse_timestamp("2000-2-29") }.to raise_error(RuntimeError)
120
+ expect { DateTime.parse_timestamp("2000-2-29", calendar: "noleap") }.to raise_error(RuntimeError)
121
121
 
122
122
  end
123
123
 
124
124
  example "with bc option" do
125
125
 
126
126
  d1 = DateTime::NoLeap.new(0, 1, 1, 0, 0, 0, 0)
127
- d2 = DateTime::NoLeap.parse_timestamp('BC 0001-1-1 00:00:00')
128
- d3 = DateTime::NoLeap.parse_timestamp('-0001-1-1 00:00:00', bc: true)
127
+ d2 = DateTime.parse_timestamp('BC 0001-1-1 00:00:00', calendar: "noleap")
128
+ d3 = DateTime.parse_timestamp('-0001-1-1 00:00:00', calendar: "noleap", bc: true)
129
129
 
130
130
  is_asserted_by { d2 == d1 }
131
131
  is_asserted_by { d3 == d1 }
@@ -135,7 +135,7 @@ describe "NoLeap.parse_timestamp" do
135
135
  example '2000-12-31 24:00:00' do
136
136
 
137
137
  d1 = DateTime::NoLeap.new(2001, 1, 1, 0, 0, 0, 0)
138
- d2 = DateTime::NoLeap.parse_timestamp('2000-12-31 24:00:00')
138
+ d2 = DateTime.parse_timestamp('2000-12-31 24:00:00', calendar: "noleap")
139
139
 
140
140
  is_asserted_by { d2 == d1 }
141
141
 
@@ -121,6 +121,53 @@ describe "TimeStep.new" do
121
121
  end
122
122
 
123
123
  end
124
+
125
+ example 'since option with format' do
126
+
127
+ time = "20010203_040506.dat"
128
+ template = "%Y%m%d_%H%M%S.dat"
129
+
130
+ ts = TimeStep.new("3 days", since: time, format: template)
131
+
132
+ is_asserted_by { ts.origin.strftime(template) == time }
133
+ is_asserted_by { ts.numeric == 3 }
134
+ is_asserted_by { ts.symbol == :days }
135
+
136
+ ts = TimeStep.new("3 days", since: time, format: template, calendar: "noleap")
137
+
138
+ is_asserted_by { ts.origin.strftime(template) == time }
139
+ is_asserted_by { ts.numeric == 3 }
140
+ is_asserted_by { ts.symbol == :days }
141
+
142
+ end
143
+
144
+ example 'since option' do
145
+
146
+ time = DateTime.new(2001,2,3,4,5,6,7.quo(24),Date::ITALY)
147
+ ts = TimeStep.new("3 days", since: time)
148
+
149
+ is_asserted_by { ts.origin == time }
150
+ is_asserted_by { ts.numeric == 3 }
151
+ is_asserted_by { ts.symbol == :days }
152
+
153
+ time = DateTime::NoLeap.new(2001,2,3,4,5,6,7.quo(24))
154
+ ts = TimeStep.new("3 days", since: time, calendar: "noleap")
155
+
156
+ is_asserted_by { ts.origin == time }
157
+ is_asserted_by { ts.numeric == 3 }
158
+ is_asserted_by { ts.symbol == :days }
159
+
160
+ end
161
+
162
+ example 'since option with calendar mismatch' do
163
+ time = DateTime.new(2001,2,3,4,5,6,7.quo(24),Date::GREGORIAN)
164
+ expect { TimeStep.new("3 days", since: time) }.to raise_error(RuntimeError)
165
+ expect { TimeStep.new("3 days", since: time, calendar: "noleap") }.to raise_error(RuntimeError)
166
+
167
+ time = DateTime::NoLeap.new(2001,2,3,4,5,6,7.quo(24))
168
+ expect { TimeStep.new("3 days", since: time) }.to raise_error(RuntimeError)
169
+ expect { TimeStep.new("3 days", since: time, calendar: "allleap") }.to raise_error(RuntimeError)
170
+ end
124
171
 
125
172
  end
126
173
 
@@ -281,6 +328,15 @@ describe "TimeStep#index_at" do
281
328
 
282
329
  end
283
330
 
331
+ example 'unix' do
332
+
333
+ unixtime = TimeStep.new("seconds since 1970-01-01 00:00:00")
334
+ time = DateTime.parse("2001-01-01 00:00:00 +09:00")
335
+
336
+ is_asserted_by { unixtime.index_at(time) == 978274800 }
337
+
338
+ end
339
+
284
340
  end
285
341
 
286
342
  describe "TimeStep#days_at" do
@@ -90,7 +90,6 @@ describe "TimeStep::Pair#forward" do
90
90
 
91
91
  is_asserted_by { pair.forward(0) == 978274800 }
92
92
  is_asserted_by { pair.forward_time(0) == DateTime.new(2000,12,31,15,0,0,0) }
93
- is_asserted_by { Time.at(pair.forward(0), in: "+00:00") == ts.origin.to_time }
94
93
 
95
94
  end
96
95
 
@@ -1,6 +1,6 @@
1
1
 
2
2
  Gem::Specification::new do |s|
3
- version = "0.9.3"
3
+ version = "0.9.5"
4
4
 
5
5
  files = Dir.glob("**/*") - [
6
6
  Dir.glob("timesteps-*.gem"),
@@ -12,9 +12,12 @@ Gem::Specification::new do |s|
12
12
  s.name = "timesteps"
13
13
  s.summary = "A library for handling discrete time series in constant increments"
14
14
  s.description = <<-HERE
15
- A library for handling discrete time series in constant increments.
16
- The main purpose of this library is to describe the time axis
17
- when dealing with time series of observational data and climate data.
15
+ A library for time conversion and intercomparison of multiple time series data
16
+ in the case of handling time series data of the type that specifies the time using
17
+ indexes of time steps since origin time. It handles time units notation like
18
+ "hours since 2001-01-01 00:00:00", which is originate from udunits library and
19
+ also is used in CF-convension of NetCDF. The main purpose of this library is to
20
+ describe the time axis when dealing with time series of observational data and climate data.
18
21
  HERE
19
22
  s.version = version
20
23
  s.licenses = ['MIT']
@@ -22,5 +25,5 @@ Gem::Specification::new do |s|
22
25
  s.email = ""
23
26
  s.homepage = 'https://github.com/himotoyoshi/timesteps'
24
27
  s.files = files
25
- s.required_ruby_version = ">= 2.5.1"
28
+ s.required_ruby_version = ">= 2.4.1"
26
29
  end
metadata CHANGED
@@ -1,18 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timesteps
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.9.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hiroki Motoyoshi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-04 00:00:00.000000000 Z
11
+ date: 2020-05-08 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: " A library for handling discrete time series in constant increments.\n
14
- \ The main purpose of this library is to describe the time axis \n when dealing
15
- with time series of observational data and climate data.\n"
13
+ description: " A library for time conversion and intercomparison of multiple time
14
+ series data \n in the case of handling time series data of the type that specifies
15
+ the time using \n indexes of time steps since origin time. It handles time units
16
+ notation like \n \"hours since 2001-01-01 00:00:00\", which is originate from udunits
17
+ library and \n also is used in CF-convension of NetCDF. The main purpose of this
18
+ library is to \n describe the time axis when dealing with time series of observational
19
+ data and climate data.\n"
16
20
  email: ''
17
21
  executables: []
18
22
  extensions: []
@@ -24,14 +28,17 @@ files:
24
28
  - Rakefile
25
29
  - lib/timesteps.rb
26
30
  - lib/timesteps/calendar.rb
31
+ - lib/timesteps/datetime_360day.rb
32
+ - lib/timesteps/datetime_allleap.rb
33
+ - lib/timesteps/datetime_noleap.rb
27
34
  - lib/timesteps/datetimelike.rb
28
35
  - lib/timesteps/format.rb
29
36
  - lib/timesteps/grads.rb
30
37
  - lib/timesteps/parse_timestamp.rb
31
38
  - lib/timesteps/timestep.rb
32
- - lib/timesteps/timestepconverter.rb
33
- - lib/timesteps/timestepdatetimeext.rb
34
- - lib/timesteps/timesteppair.rb
39
+ - lib/timesteps/timestep_converter.rb
40
+ - lib/timesteps/timestep_datetime_ext.rb
41
+ - lib/timesteps/timestep_pair.rb
35
42
  - spec/allleap_spec.rb
36
43
  - spec/fixed360day_spec.rb
37
44
  - spec/noleap_spec.rb
@@ -50,7 +57,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
50
57
  requirements:
51
58
  - - ">="
52
59
  - !ruby/object:Gem::Version
53
- version: 2.5.1
60
+ version: 2.4.1
54
61
  required_rubygems_version: !ruby/object:Gem::Requirement
55
62
  requirements:
56
63
  - - ">="