timesteps 0.9.5 → 0.9.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +16 -25
- data/lib/timesteps.rb +4 -3
- data/lib/timesteps/{parse_timestamp.rb → datetime_parse_timestamp.rb} +6 -3
- data/lib/timesteps/datetimelike.rb +6 -6
- data/lib/timesteps/{format.rb → datetimelike_format.rb} +0 -0
- data/lib/timesteps/timeperiod.rb +202 -0
- data/lib/timesteps/timestep.rb +107 -101
- data/lib/timesteps/{calendar.rb → timestep_calendar.rb} +5 -0
- data/lib/timesteps/timestep_converter.rb +1 -1
- data/lib/timesteps/timestep_pair.rb +2 -2
- data/lib/timesteps/timestep_query.rb +49 -0
- data/spec/timestep_spec.rb +20 -20
- data/spec/timesteppair_spec.rb +2 -2
- data/timesteps.gemspec +1 -1
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0feffe90d4bd2fdd8c478624bc78b67e3a7ab1c5905e236767c7734ba8c6b098
|
4
|
+
data.tar.gz: 4e924fa6b145f2b7cb06836d408b05e8bb34e8133797a3b7702ba29033af4400
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52773368aa3a11f6ac7e6e2e71b56e8ebb84f78b2c6807ac509f77a8342566cae41fb4b93a1c0c03f4fd1fbed07ae698144fb208f433b5a663a08cbf80ff83cb
|
7
|
+
data.tar.gz: 61d67459512fa64a4e7b8967b7300af0c9719b61c2bf4f66c478b5c08a064c38d889f0d2830bb7399d81ba02c516b194ccaab85406855a688204c06347cd6117
|
data/README.md
CHANGED
@@ -2,16 +2,16 @@ timesteps
|
|
2
2
|
================
|
3
3
|
|
4
4
|
A library for handling discrete time series in constant increments.
|
5
|
-
The
|
5
|
+
The primary purpose of this library 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
|
11
|
+
* TimeStep holds an origin time and an unit time interval.
|
12
12
|
* Parsing a time step expression like "hours since 2001-01-01 00:00:00" (originate from udunits library)
|
13
|
-
* Obtaining time value for index value (0 for the origin time)
|
14
|
-
* Obtaining index value for time value
|
13
|
+
* Obtaining time value for the index value (0 for the origin time)
|
14
|
+
* Obtaining index value for the time value
|
15
15
|
* Treating non-standard calendar-type such as 'noleap', 'allleap', and '360_day'
|
16
16
|
* Comparing the index values between different time step definitions
|
17
17
|
|
@@ -29,27 +29,26 @@ require "timesteps"
|
|
29
29
|
Description
|
30
30
|
-----------
|
31
31
|
|
32
|
-
This library
|
32
|
+
This library is for time conversion and time index comparison of multiple time series. This library treats the time series data of the type that specifies the time using indexes of time steps since origin time.
|
33
33
|
|
34
34
|
#### Time steps
|
35
35
|
|
36
|
-
The main class of this library is the TimeStep class, which holds the origin time and the interval representing the unit time step.
|
36
|
+
The main class of this library is the TimeStep class, which holds the origin time and the interval representing the unit time step. For the initialization of the TimeStep object, the following notation is used.
|
37
37
|
|
38
38
|
* "second since 1970-01-01 00:00:00 +00:00"
|
39
39
|
* "hour since 2001-01-01 00:00:00 JST"
|
40
40
|
* "3 days since 2001-01-01 00:00:00 +00:00"
|
41
41
|
* "10 years since 1901-01-01 00:00:00 +00:00"
|
42
42
|
|
43
|
-
|
43
|
+
These notations are imported from Unidata's [UDUNITS](https://www.unidata.ucar.edu/software/udunits/) library. These are also used in [CF conventions](http://cfconventions.org) of NetCDF. However, note that there are some differences between our library and the udunits library about the date-time expressions.
|
44
44
|
|
45
|
-
In this library, the elapsed time from the origin is expressed as an index value. For the case of "3 hours since 2001-01-01 00:00:00", the index values
|
46
|
-
are expressed as,
|
45
|
+
In this library, the elapsed time from the origin is expressed as an index value. For the case of "3 hours since 2001-01-01 00:00:00", the index values are expressed as,
|
47
46
|
|
48
47
|
* "2001-01-01 00:00:00" => 0 (0 / 3 hours) ( 0 days)
|
49
48
|
* "2001-01-01 03:00:00" => 1 (1 / 3 hours) ((1/8) days)
|
50
49
|
* "2001-01-02 00:00:00" => 8 (8 / 3 hours) ( 1 days)
|
51
50
|
|
52
|
-
|
51
|
+
These are expressed as a Ruby script.
|
53
52
|
|
54
53
|
```ruby
|
55
54
|
ts = TimeStep.new("3 hours since 2001-01-01 00:00:00")
|
@@ -67,10 +66,7 @@ ts.days_at(8) ### => 1 [Integer]
|
|
67
66
|
#### Treatment of year and month units
|
68
67
|
|
69
68
|
The time units like day, hour, minute, second have constant intervals,
|
70
|
-
but the time units like years and months are not. So, the year and
|
71
|
-
month units are given special treatment in this library.
|
72
|
-
One year is counted at the same month and day as the origin time, and
|
73
|
-
one month is counted at the same day as the origin time.
|
69
|
+
but the time units like years and months are not. So, the year and month units are given special treatment in this library. One year is counted at the same month and day as the origin time, and one month is counted on the same day as the origin time.
|
74
70
|
|
75
71
|
```ruby
|
76
72
|
ts = TimeStep.new("year since 2000-01-15 00:00:00")
|
@@ -106,7 +102,7 @@ The following calendars, including non-standard calendars, can be handled.
|
|
106
102
|
* allleap, 366_day
|
107
103
|
* 360_day
|
108
104
|
|
109
|
-
You can find the description for these
|
105
|
+
You can find the description for these calendars at the document of CF-Conventions ([4.4.1 Calendar](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html#calendar)).
|
110
106
|
|
111
107
|
```ruby
|
112
108
|
ts = TimeStep.new("day since 2000-01-01", calendar: "standard")
|
@@ -119,13 +115,11 @@ ts = TimeStep.new("day since 2000-01-01", calendar: "360_day")
|
|
119
115
|
ts.time_at(59) ### => #<DateTime::Fixed360Day: 2000-02-30T00:00:00+00:00 ...>
|
120
116
|
```
|
121
117
|
|
122
|
-
In this library, DateTime class is adopted as the object that represents date and time (not Time class). Non-standard calendars ("proleptic_gregorian", "
|
118
|
+
In this library, the DateTime class is adopted as the object that represents date and time (not Time class). Non-standard calendars ("proleptic_gregorian", "julian") can be handled by the DateTime class, with appropriate use of the start parameter. But, other non-standard calendars ("noleap", "allleap", "360_day") can not. So, DateTimeLike class and its subclasses DateTime::NoLeap, DateTime::AllLeap, DateTime::Fixed360Day are introduced. Since many (not all) of methods in the DateTime class are also implemented in DateTimeLike class, users don't need to be too aware of these class differences.
|
123
119
|
|
124
120
|
#### Parsing datetime string
|
125
121
|
|
126
|
-
In `standard` calendar, use DateTime.parse as usual.
|
127
|
-
In other calendar, you can use DateTime.parse_timestamp, which is
|
128
|
-
special method to parse date time string with specification of calendar.
|
122
|
+
In `standard` calendar, use DateTime.parse as usual. In other calendars, you can use DateTime.parse_timestamp, which is a particular method to parse a date-time string with a specification of the calendar.
|
129
123
|
|
130
124
|
```ruby
|
131
125
|
DateTime.parse_timestamp("1200-01-01") ### "standard"
|
@@ -143,7 +137,7 @@ ts = TimeStep.new("days since 2001-01-01", calendar: "allleap")
|
|
143
137
|
ts.parse("2001-02-29") ### => #<DateTime::AllLeap 2001-02-29T ...>
|
144
138
|
```
|
145
139
|
|
146
|
-
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
|
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.
|
147
141
|
|
148
142
|
```ruby
|
149
143
|
DateTime.parse_timestamp("-0001-01-01")
|
@@ -159,12 +153,9 @@ DateTime.parse_timestamp("BC 0001-01-01")
|
|
159
153
|
# B.C. 1
|
160
154
|
```
|
161
155
|
|
162
|
-
#### Comparing
|
156
|
+
#### Comparing multiple time series
|
163
157
|
|
164
|
-
TimeStep::Pair is a class to compare indices of two time series,
|
165
|
-
which is initialized by two time step object. It is possible to
|
166
|
-
compute the other index corresponding to the time represented
|
167
|
-
by one of the indices using TimeStep::Pair.
|
158
|
+
TimeStep::Pair is a class to compare indices of two time series, which is initialized by two time step object. It is possible to compute the other index corresponding to the time represented by one of the indices using TimeStep::Pair.
|
168
159
|
|
169
160
|
|
170
161
|
```ruby
|
data/lib/timesteps.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
|
2
2
|
require "date"
|
3
3
|
require "timesteps/datetimelike"
|
4
|
+
require "timesteps/datetimelike_format"
|
4
5
|
require "timesteps/datetime_noleap"
|
5
6
|
require "timesteps/datetime_allleap"
|
6
7
|
require "timesteps/datetime_360day"
|
7
|
-
require "timesteps/
|
8
|
-
require "timesteps/format"
|
8
|
+
require "timesteps/datetime_parse_timestamp"
|
9
9
|
require "timesteps/timestep_datetime_ext"
|
10
|
-
require "timesteps/
|
10
|
+
require "timesteps/timestep_calendar"
|
11
11
|
require "timesteps/timestep"
|
12
12
|
require "timesteps/timestep_pair"
|
13
13
|
require "timesteps/timestep_converter"
|
14
|
+
require "timesteps/timeperiod"
|
@@ -16,7 +16,6 @@ class DateTime
|
|
16
16
|
# @return [DateTimeFixedDPY]
|
17
17
|
|
18
18
|
def self.parse_timestamp (spec, calendar: "standard", bc: false, format: nil)
|
19
|
-
raise "invalid option 'calendar'" if self != DateTime
|
20
19
|
case calendar.downcase.intern
|
21
20
|
when :standard, :gregorian
|
22
21
|
klass = DateTime
|
@@ -39,9 +38,13 @@ class DateTime
|
|
39
38
|
end
|
40
39
|
if format
|
41
40
|
hash = DateTime._strptime(spec, format)
|
42
|
-
raise "
|
41
|
+
raise "date-time string '#{spec}' doesn't match with the given format '#{format}'" unless hash
|
43
42
|
else
|
44
|
-
|
43
|
+
if spec =~ /\A([+\-]?\d{4})(\-(\d{1,2}))?\z/
|
44
|
+
hash = { year: $1.to_i, mon: $3 ? $3.to_i : 1, mday: 1 }
|
45
|
+
else
|
46
|
+
hash = DateTime._parse(spec)
|
47
|
+
end
|
45
48
|
end
|
46
49
|
year, month, day, hour, minute, second, sec_fraction, offset =
|
47
50
|
hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset)
|
@@ -75,16 +75,16 @@ class DateTimeLike
|
|
75
75
|
|
76
76
|
def check_valid_datetime
|
77
77
|
unless valid_date?
|
78
|
-
raise "invalid date"
|
78
|
+
raise "invalid date for #{self.class} [year: #{@year}, month: #{@month}, day: #{@day}]"
|
79
79
|
end
|
80
80
|
unless valid_time?
|
81
|
-
raise "invalid time"
|
82
|
-
end
|
81
|
+
raise "invalid time for #{self.class} [hour: #{@hour}, minute: #{@minute}, second: #{@second}]"
|
82
|
+
end
|
83
83
|
end
|
84
84
|
|
85
85
|
def valid_time?
|
86
86
|
begin
|
87
|
-
DateTime.new(2001,1,1
|
87
|
+
DateTime.new(2001, 1, 1, @hour, @minute, @second)
|
88
88
|
true
|
89
89
|
rescue
|
90
90
|
false
|
@@ -199,7 +199,7 @@ class DateTimeLike
|
|
199
199
|
end
|
200
200
|
|
201
201
|
# Returns the difference between the two dates
|
202
|
-
# if the other is a
|
202
|
+
# if the other is a datetime object.
|
203
203
|
# If the other is a numeric value,
|
204
204
|
# returns a date object pointing other days before self.
|
205
205
|
def - (other_or_days)
|
@@ -209,7 +209,7 @@ class DateTimeLike
|
|
209
209
|
when self.class
|
210
210
|
return self.jd - other_or_days.jd
|
211
211
|
else
|
212
|
-
raise "
|
212
|
+
raise "other shoud be date-time object or numeric value"
|
213
213
|
end
|
214
214
|
end
|
215
215
|
|
File without changes
|
@@ -0,0 +1,202 @@
|
|
1
|
+
|
2
|
+
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
|
10
|
+
@last = time_at(1)
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :last
|
14
|
+
|
15
|
+
def start
|
16
|
+
return @origin
|
17
|
+
end
|
18
|
+
|
19
|
+
def include_start?
|
20
|
+
return @include_start
|
21
|
+
end
|
22
|
+
|
23
|
+
def include_last?
|
24
|
+
return @include_last
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the value as a string for inspection.
|
28
|
+
#
|
29
|
+
def inspect
|
30
|
+
left_paren = @include_start ? "[" : "("
|
31
|
+
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
|
+
end
|
40
|
+
|
41
|
+
def include? (other)
|
42
|
+
case other
|
43
|
+
when TimePeriod
|
44
|
+
if ( other.origin < @origin ) ||
|
45
|
+
( other.origin == @origin && ( not include_start? ) && other.include_start? )
|
46
|
+
left = false
|
47
|
+
else
|
48
|
+
left = true
|
49
|
+
end
|
50
|
+
if ( @last < other.last ) ||
|
51
|
+
( @last == other.last && ( not include_last? ) && other.include_last? )
|
52
|
+
right = false
|
53
|
+
else
|
54
|
+
right = true
|
55
|
+
end
|
56
|
+
return left & right
|
57
|
+
else
|
58
|
+
if include_start?
|
59
|
+
left = @origin <= other
|
60
|
+
else
|
61
|
+
left = @origin < other
|
62
|
+
end
|
63
|
+
if include_last?
|
64
|
+
right = other <= @last
|
65
|
+
else
|
66
|
+
right = other < @last
|
67
|
+
end
|
68
|
+
return left & right
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def overlap? (other)
|
73
|
+
case other
|
74
|
+
when TimePeriod
|
75
|
+
if ( @origin < other.last ) ||
|
76
|
+
( @origin == other.last && include_start? && other.include_last? )
|
77
|
+
left = true
|
78
|
+
else
|
79
|
+
left = false
|
80
|
+
end
|
81
|
+
if ( other.origin < @last ) ||
|
82
|
+
( other.origin == @last && include_last? && other.include_start? )
|
83
|
+
right = true
|
84
|
+
else
|
85
|
+
right = false
|
86
|
+
end
|
87
|
+
return left && right
|
88
|
+
else
|
89
|
+
return include?(other)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def contact? (other)
|
94
|
+
case other
|
95
|
+
when TimePeriod
|
96
|
+
if @origin <= other.last
|
97
|
+
left = true
|
98
|
+
else
|
99
|
+
left = false
|
100
|
+
end
|
101
|
+
if other.origin <= @last
|
102
|
+
right = true
|
103
|
+
else
|
104
|
+
right = false
|
105
|
+
end
|
106
|
+
return left && right
|
107
|
+
else
|
108
|
+
left = @origin <= other
|
109
|
+
right = other <= @last
|
110
|
+
return left & right
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def merge (other)
|
115
|
+
raise "can't merge period without contacted period" unless contact?(other)
|
116
|
+
if ( other.origin < @origin ) ||
|
117
|
+
( other.origin == @origin && ( not include_start? ) && other.include_start? )
|
118
|
+
left = other.origin
|
119
|
+
left_boundary = other.include_start? ? "[" : "("
|
120
|
+
else
|
121
|
+
left = @origin
|
122
|
+
left_boundary = include_start? ? "[" : "("
|
123
|
+
end
|
124
|
+
if ( @last < other.last ) ||
|
125
|
+
( @last == other.last && ( not include_last? ) && other.include_last? )
|
126
|
+
right = other.last
|
127
|
+
right_boundary = other.include_last? ? "]" : ")"
|
128
|
+
else
|
129
|
+
right = @last
|
130
|
+
right_boundary = include_last? ? ")" : "]"
|
131
|
+
end
|
132
|
+
ridx = index_at(right)
|
133
|
+
lidx = index_at(left)
|
134
|
+
numeric = (ridx - lidx) * @numeric
|
135
|
+
origin = left
|
136
|
+
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)
|
139
|
+
end
|
140
|
+
|
141
|
+
def clip (other)
|
142
|
+
raise "can't clip period without contacted period" unless contact?(other)
|
143
|
+
if ( @origin < other.origin ) ||
|
144
|
+
( @origin == other.origin && include_start? && ( not other.include_start? ) )
|
145
|
+
left = other.origin
|
146
|
+
left_boundary = other.include_start? ? "[" : "("
|
147
|
+
else
|
148
|
+
left = @origin
|
149
|
+
left_boundary = include_start? ? "[" : "("
|
150
|
+
end
|
151
|
+
if ( other.last < @last ) ||
|
152
|
+
( other.last == @last && include_last? && ( not other.include_last? ) )
|
153
|
+
right = other.last
|
154
|
+
right_boundary = other.include_last? ? "]" : ")"
|
155
|
+
else
|
156
|
+
right = @last
|
157
|
+
right_boundary = include_last? ? ")" : "]"
|
158
|
+
end
|
159
|
+
ridx = index_at(right)
|
160
|
+
lidx = index_at(left)
|
161
|
+
numeric = (ridx - lidx) * @numeric
|
162
|
+
origin = left
|
163
|
+
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)
|
166
|
+
end
|
167
|
+
|
168
|
+
def split (time, boundary: ")[")
|
169
|
+
raise "can't split period without contacted time" unless contact?(time)
|
170
|
+
# left
|
171
|
+
numeric = index_at(time) * @numeric
|
172
|
+
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)
|
175
|
+
# right
|
176
|
+
numeric = (1 - index_at(time)) * @numeric
|
177
|
+
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)
|
180
|
+
return left_period, right_period
|
181
|
+
end
|
182
|
+
|
183
|
+
def next
|
184
|
+
return TimePeriod.new(interval_spec, since: @last, calendar: @calendar.name, bc: @bc, boundary: boundary)
|
185
|
+
end
|
186
|
+
|
187
|
+
def prev
|
188
|
+
origin = index_at(-1)
|
189
|
+
return TimePeriod.new(interval_spec, since: origin, calendar: @calendar.name, bc: @bc, boundary: boundary)
|
190
|
+
end
|
191
|
+
|
192
|
+
def shift (index)
|
193
|
+
return TimePeriod.new(interval_spec, since: time_at(index), calendar: @calendar.name, bc: @bc, boundary: boundary)
|
194
|
+
end
|
195
|
+
|
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
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
|
data/lib/timesteps/timestep.rb
CHANGED
@@ -21,22 +21,22 @@ class TimeStep
|
|
21
21
|
# * minutes, minute, mins, min
|
22
22
|
# * seconds, second, secs, sec, s
|
23
23
|
# * milliseconds, millisecond, msecs, msec, ms
|
24
|
-
# * microseconds, microsecond
|
24
|
+
# * microseconds, microsecond
|
25
25
|
# If you have already origin time object or general date string,
|
26
26
|
# you can use `since` option,
|
27
27
|
# TimeStep.new("3 hours", since: time)
|
28
28
|
# TimeStep.new("3 hours", since: "2001010121", format: '%Y%m%d%H')
|
29
|
-
# The option `calendar` specifies the calendar for datetime calculation,
|
30
|
-
# * standard, gregorian -> DateTime with Date::ITALY as start
|
31
|
-
# * proleptic_gregorian -> DateTime with Date::GREGORIAN as start
|
32
|
-
# * proleptic_julian, julian -> DateTime with Date::JULIAN as start
|
33
|
-
# * noleap, 365_day -> DateTimeNoLeap
|
34
|
-
# * allleap, 366_day -> DateTimeAllLeap
|
35
|
-
# * 360_day -> DateTimeFixed360Day
|
36
|
-
# The option `bc` is a flag whether AD/BC or EC when parsing timestamp for
|
37
|
-
# negative year.
|
38
29
|
# The option count specifies the number of time steps, which is hint for
|
39
30
|
# some methods (#each etc).
|
31
|
+
# The option `calendar` specifies the name of calendar for datetime calculation,
|
32
|
+
# * "standard", "gregorian" -> DateTime with Date::ITALY as start
|
33
|
+
# * "proleptic_gregorian" -> DateTime with Date::GREGORIAN as start
|
34
|
+
# * "proleptic_julian", "julian" -> DateTime with Date::JULIAN as start
|
35
|
+
# * "noleap", "365_day" -> DateTimeNoLeap
|
36
|
+
# * "allleap", "366_day" -> DateTimeAllLeap
|
37
|
+
# * "360_day" -> DateTimeFixed360Day
|
38
|
+
# The option `bc` is a flag whether AD/BC or EC when parsing timestamp for
|
39
|
+
# negative year.
|
40
40
|
#
|
41
41
|
# @param spec [String]
|
42
42
|
# @option since [DateTime, DateTimeLike, String]
|
@@ -46,32 +46,38 @@ class TimeStep
|
|
46
46
|
# @option count [Integer] number of time steps (as hint for some methods)
|
47
47
|
#
|
48
48
|
def initialize (spec, since: nil, format: nil, count: nil, calendar: "standard", bc: false)
|
49
|
-
|
50
|
-
when String
|
51
|
-
@calendar = Calendar.new(calendar, bc: bc)
|
52
|
-
else
|
53
|
-
@calendar = calendar
|
54
|
-
end
|
49
|
+
@calendar = Calendar.new(calendar, bc: bc)
|
55
50
|
if since
|
56
51
|
parse_interval(spec)
|
57
52
|
case since
|
58
53
|
when String
|
59
54
|
@origin = @calendar.parse(since, format: format)
|
60
55
|
else
|
61
|
-
|
56
|
+
unless @calendar.valid_datetime_type?(since)
|
57
|
+
raise "calendar of the given date-time object doesn't match with the given calendar in option"
|
58
|
+
end
|
62
59
|
@origin = since
|
63
60
|
end
|
64
61
|
else
|
65
|
-
|
66
|
-
parse_interval(
|
67
|
-
@origin = @calendar.parse(
|
62
|
+
spec1, spec2 = spec.split(/\s+since\s+/)
|
63
|
+
parse_interval(spec1)
|
64
|
+
@origin = @calendar.parse(spec2)
|
68
65
|
end
|
69
|
-
@intervalspec = format("%g %s", @numeric, @symbol)
|
70
|
-
@originspec = @origin.strftime("%Y-%m-%d %H:%M:%S.%N %:z")
|
71
|
-
@definition = format("%s since %s", @intervalspec, @originspec)
|
72
66
|
@count = count
|
73
67
|
end
|
74
68
|
|
69
|
+
def interval_spec
|
70
|
+
return format("%g %s", @numeric, @symbol)
|
71
|
+
end
|
72
|
+
|
73
|
+
def origin_spec
|
74
|
+
return @origin.strftime("%Y-%m-%d %H:%M:%S.%N %:z")
|
75
|
+
end
|
76
|
+
|
77
|
+
def definition
|
78
|
+
format("%s since %s", interval_spec, origin_spec)
|
79
|
+
end
|
80
|
+
|
75
81
|
# @private
|
76
82
|
PATTERN_NUMERIC = '[\+\-]?\d*(?:\.\d+)?(?:[eE][\+\-]?\d+)?'
|
77
83
|
# @private
|
@@ -86,7 +92,7 @@ class TimeStep
|
|
86
92
|
end
|
87
93
|
symbol = $2
|
88
94
|
else
|
89
|
-
raise "
|
95
|
+
raise "the interval specification '#{spec}' is invalid."
|
90
96
|
end
|
91
97
|
@interval = @numeric
|
92
98
|
case symbol
|
@@ -128,10 +134,7 @@ class TimeStep
|
|
128
134
|
|
129
135
|
private :parse_interval
|
130
136
|
|
131
|
-
attr_reader :
|
132
|
-
:intervalspec,
|
133
|
-
:originspec,
|
134
|
-
:numeric,
|
137
|
+
attr_reader :numeric,
|
135
138
|
:symbol,
|
136
139
|
:interval,
|
137
140
|
:origin,
|
@@ -155,13 +158,15 @@ class TimeStep
|
|
155
158
|
# @return [DateTime, nil]
|
156
159
|
def limit= (time)
|
157
160
|
if time
|
158
|
-
@count = (
|
161
|
+
@count = next_index_of(time).to_i
|
159
162
|
else
|
160
163
|
@count = nil
|
161
164
|
end
|
162
165
|
return limit
|
163
166
|
end
|
164
167
|
|
168
|
+
# Sets count by giving maximum time.
|
169
|
+
#
|
165
170
|
def set_limit (time, format: nil)
|
166
171
|
case time
|
167
172
|
when String
|
@@ -193,9 +198,9 @@ class TimeStep
|
|
193
198
|
|
194
199
|
def debug_info
|
195
200
|
return {
|
196
|
-
"definition" =>
|
197
|
-
"
|
198
|
-
"
|
201
|
+
"definition" => definition,
|
202
|
+
"interval_spec" => interval_spec,
|
203
|
+
"origin_spec" => origin_spec,
|
199
204
|
"calendar" => @calendar.name,
|
200
205
|
"numeric" => @numeric,
|
201
206
|
"symbol" => @symbol.to_s,
|
@@ -219,7 +224,7 @@ class TimeStep
|
|
219
224
|
#
|
220
225
|
# @return [Boolean]
|
221
226
|
def == (other)
|
222
|
-
return
|
227
|
+
return definition == other.definition && @calendar == other.calendar
|
223
228
|
end
|
224
229
|
|
225
230
|
def user_to_days (index)
|
@@ -240,17 +245,16 @@ class TimeStep
|
|
240
245
|
def time_at (*indices)
|
241
246
|
if indices.size == 1
|
242
247
|
index = indices.first
|
243
|
-
raise ArgumentError, "index should be numeric" unless index.is_a?(Numeric)
|
244
|
-
index = index.to_r
|
248
|
+
raise ArgumentError, "index argument should be a numeric" unless index.is_a?(Numeric)
|
245
249
|
case @symbol
|
246
250
|
when :years
|
247
251
|
unless index.denominator == 1
|
248
|
-
raise "index
|
252
|
+
raise ArgumentError, "index argument should be an integer for years"
|
249
253
|
end
|
250
254
|
return @origin.next_year(index*@numeric)
|
251
255
|
when :months
|
252
256
|
unless index.denominator == 1
|
253
|
-
raise "index
|
257
|
+
raise ArgumentError, "index argument should be an integer for months"
|
254
258
|
end
|
255
259
|
return @origin.next_month(index*@numeric)
|
256
260
|
else
|
@@ -264,22 +268,22 @@ class TimeStep
|
|
264
268
|
end
|
265
269
|
end
|
266
270
|
|
267
|
-
# Calculate the
|
271
|
+
# Calculate the duration in days since origin time at the given index.
|
268
272
|
#
|
269
273
|
# @param indices [Array]
|
270
274
|
# @return [DateTime, Array<DateTime>]
|
271
|
-
def
|
275
|
+
def duration_at (*indices)
|
272
276
|
if indices.size == 1
|
273
277
|
index = indices.first
|
274
278
|
case @symbol
|
275
279
|
when :years
|
276
280
|
unless index.denominator == 1
|
277
|
-
raise "index
|
281
|
+
raise ArgumentError, "index argument should be an integer for years"
|
278
282
|
end
|
279
283
|
days = @origin.next_year(@numeric*index) - @origin
|
280
284
|
when :months
|
281
285
|
unless index.denominator == 1
|
282
|
-
raise "index
|
286
|
+
raise ArgumentError, "index argument should be an integer for months"
|
283
287
|
end
|
284
288
|
days = @origin.next_month(@numeric*index) - @origin
|
285
289
|
else
|
@@ -288,7 +292,7 @@ class TimeStep
|
|
288
292
|
days = days.to_i if days.denominator == 1
|
289
293
|
return days
|
290
294
|
else
|
291
|
-
return indices.map{ |index|
|
295
|
+
return indices.map{ |index| duration_at(index) }
|
292
296
|
end
|
293
297
|
end
|
294
298
|
|
@@ -319,55 +323,7 @@ class TimeStep
|
|
319
323
|
return times.map{|time| index_at(time, format: format) }
|
320
324
|
end
|
321
325
|
end
|
322
|
-
|
323
|
-
def range (ge: nil, gt: nil, lt: nil, le: nil)
|
324
|
-
raise "lower limit is not given" if ge.nil? and gt.nil?
|
325
|
-
raise "upper limit is not given" if lt.nil? and le.nil?
|
326
|
-
raise "lower limits are duplicated" if ge and gt
|
327
|
-
raise "upper limits are duplicated" if lt and le
|
328
|
-
if ge
|
329
|
-
case ge
|
330
|
-
when Numeric
|
331
|
-
min = ge.floor
|
332
|
-
else
|
333
|
-
min = prev_index_of(ge)
|
334
|
-
end
|
335
|
-
end
|
336
|
-
if gt
|
337
|
-
case gt
|
338
|
-
when Numeric
|
339
|
-
if lt.to_r.denominator == 1
|
340
|
-
min = gt.to_i + 1
|
341
|
-
else
|
342
|
-
min = gt.ceil
|
343
|
-
end
|
344
|
-
else
|
345
|
-
min = next_index_of(gt)
|
346
|
-
end
|
347
|
-
end
|
348
|
-
if lt
|
349
|
-
case lt
|
350
|
-
when Numeric
|
351
|
-
if lt.to_r.denominator == 1
|
352
|
-
max = lt.to_i - 1
|
353
|
-
else
|
354
|
-
max = lt.floor
|
355
|
-
end
|
356
|
-
else
|
357
|
-
max = prev_index_of(lt)
|
358
|
-
end
|
359
|
-
end
|
360
|
-
if le
|
361
|
-
case le
|
362
|
-
when Numeric
|
363
|
-
max = le.ceil
|
364
|
-
else
|
365
|
-
max = next_index_of(le)
|
366
|
-
end
|
367
|
-
end
|
368
|
-
return (min..max).to_a
|
369
|
-
end
|
370
|
-
|
326
|
+
|
371
327
|
# Returns TimeStep object which has origin time determined
|
372
328
|
# by the given `index`.
|
373
329
|
#
|
@@ -376,12 +332,12 @@ class TimeStep
|
|
376
332
|
# @return [TimeStep]
|
377
333
|
def shift_origin (index)
|
378
334
|
time = time_at(index)
|
379
|
-
return TimeStep.new(
|
335
|
+
return TimeStep.new(interval_spec, since: time, calendar: @calendar.name, bc: @calendar.bc?)
|
380
336
|
end
|
381
337
|
|
382
|
-
def
|
383
|
-
time = @origin +
|
384
|
-
return TimeStep.new(
|
338
|
+
def shift_origin_with_duration (duration)
|
339
|
+
time = @origin + duration
|
340
|
+
return TimeStep.new(interval_spec, since: time, calendar: @calendar.name, bc: @calendar.bc?)
|
385
341
|
end
|
386
342
|
|
387
343
|
# Returns TimeStep object which has origin time specified
|
@@ -395,14 +351,14 @@ class TimeStep
|
|
395
351
|
when String
|
396
352
|
time = @calendar.parse(time)
|
397
353
|
end
|
398
|
-
return TimeStep.new(
|
354
|
+
return TimeStep.new(interval_spec, since: time, calendar: @calendar.name, bc: @calendar.bc?)
|
399
355
|
end
|
400
356
|
|
401
357
|
include Enumerable
|
402
358
|
|
403
359
|
def each (limit = nil, incr = 1, &block)
|
404
360
|
if limit.nil?
|
405
|
-
raise "
|
361
|
+
raise "count (or limit) is required by #step" unless @count
|
406
362
|
limit = @count - 1
|
407
363
|
end
|
408
364
|
if block
|
@@ -419,7 +375,7 @@ class TimeStep
|
|
419
375
|
end
|
420
376
|
|
421
377
|
def times (&block)
|
422
|
-
raise "
|
378
|
+
raise "count (or limit) is required by #step" unless @count
|
423
379
|
(0...@count).each(&block)
|
424
380
|
end
|
425
381
|
|
@@ -427,15 +383,16 @@ class TimeStep
|
|
427
383
|
#
|
428
384
|
#
|
429
385
|
def in (unit)
|
430
|
-
return TimeStep::Pair.new(self, format("%s since %s", unit,
|
386
|
+
return TimeStep::Pair.new(self, format("%s since %s", unit, origin_spec), calendar: @calendar.name, bc: @calendar.bc?)
|
431
387
|
end
|
432
388
|
|
389
|
+
# Returns next integer index of the given time
|
433
390
|
def next_index_of (time)
|
434
391
|
case time
|
435
392
|
when String
|
436
393
|
time = @calendar.parse(time)
|
437
394
|
end
|
438
|
-
index = index_at(time)
|
395
|
+
index = index_at(time)
|
439
396
|
if index.denominator == 1
|
440
397
|
return index.to_i + 1
|
441
398
|
else
|
@@ -443,21 +400,70 @@ class TimeStep
|
|
443
400
|
end
|
444
401
|
end
|
445
402
|
|
403
|
+
# Returns previous integer index of the given time
|
446
404
|
def prev_index_of (time)
|
447
|
-
|
405
|
+
case time
|
406
|
+
when String
|
407
|
+
time = @calendar.parse(time)
|
408
|
+
end
|
409
|
+
index = index_at(time)
|
410
|
+
if index.denominator == 1
|
411
|
+
return index.to_i - 1
|
412
|
+
else
|
413
|
+
return index.floor
|
414
|
+
end
|
448
415
|
end
|
449
416
|
|
417
|
+
# Returns next time of the given time
|
450
418
|
def next_time_of (time)
|
451
419
|
return time_at(next_index_of(time))
|
452
420
|
end
|
453
421
|
|
422
|
+
# Returns previous time of the given time
|
454
423
|
def prev_time_of (time)
|
455
424
|
return time_at(prev_index_of(time))
|
456
425
|
end
|
457
426
|
|
427
|
+
# Parses date-time string with appropreate calendar
|
428
|
+
#
|
429
|
+
# @option format [String]
|
458
430
|
def parse (time, format: nil)
|
459
431
|
return @calendar.parse(time, format: format)
|
460
432
|
end
|
461
433
|
|
434
|
+
def index_for_period (period)
|
435
|
+
if period.include_start?
|
436
|
+
idx1 = index_at(period.origin).ceil
|
437
|
+
else
|
438
|
+
idx1 = next_index_of(period.origin)
|
439
|
+
end
|
440
|
+
if period.include_last?
|
441
|
+
idx2 = index_at(period.last).floor
|
442
|
+
else
|
443
|
+
idx2 = prev_index_of(period.last)
|
444
|
+
end
|
445
|
+
return (idx1..idx2).to_a
|
446
|
+
end
|
447
|
+
|
448
|
+
def period (start, last, boundary: "[)")
|
449
|
+
case start
|
450
|
+
when Numeric
|
451
|
+
idx1 = start
|
452
|
+
else
|
453
|
+
idx1 = index_at(start)
|
454
|
+
end
|
455
|
+
case last
|
456
|
+
when Numeric
|
457
|
+
idx2 = last
|
458
|
+
else
|
459
|
+
idx2 = index_at(last)
|
460
|
+
end
|
461
|
+
origin = time_at(idx1)
|
462
|
+
numeric = (idx2 - idx1) * @numeric
|
463
|
+
interval_spec = format("%g %s", numeric, @symbol)
|
464
|
+
return TimePeriod.new(interval_spec, since: origin, calendar: @calendar.name, bc: @bc, boundary: boundary)
|
465
|
+
end
|
466
|
+
|
467
|
+
|
462
468
|
end
|
463
469
|
|
@@ -21,7 +21,12 @@ class TimeStep
|
|
21
21
|
SYM_360_day => DateTime::Fixed360Day,
|
22
22
|
}
|
23
23
|
|
24
|
+
# Construct the object
|
25
|
+
#
|
24
26
|
def initialize (calendar = "standard", bc: false)
|
27
|
+
unless calendar.is_a?(String)
|
28
|
+
raise ArgumentError, "argument calendar '#{calendar}' should be string"
|
29
|
+
end
|
25
30
|
@name = calendar
|
26
31
|
@bc = bc
|
27
32
|
case @name.downcase.intern
|
@@ -26,7 +26,7 @@ class TimeStep::Pair
|
|
26
26
|
when TimeStep
|
27
27
|
@from = from
|
28
28
|
else
|
29
|
-
raise "
|
29
|
+
raise ArgumentError, "from argument '#{from}' should be a time-step or a string"
|
30
30
|
end
|
31
31
|
|
32
32
|
case to
|
@@ -35,7 +35,7 @@ class TimeStep::Pair
|
|
35
35
|
when TimeStep
|
36
36
|
@to = to
|
37
37
|
else
|
38
|
-
raise "
|
38
|
+
raise ArgumentError, "to argument '#{to}' should be a time-step or a string"
|
39
39
|
end
|
40
40
|
|
41
41
|
@from_origin = @from.origin
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "timesteps"
|
2
|
+
|
3
|
+
class TimeStep::Query
|
4
|
+
|
5
|
+
def initialize (timestep, format: nil)
|
6
|
+
@timestep = timestep
|
7
|
+
@format = foramt
|
8
|
+
end
|
9
|
+
|
10
|
+
def __format__ (time)
|
11
|
+
return ( @template.nil? ) ? time : time.strftime(@template)
|
12
|
+
end
|
13
|
+
|
14
|
+
private :__format__
|
15
|
+
|
16
|
+
def just_time? (time)
|
17
|
+
return @timestep.index_at(time).denominator == 1
|
18
|
+
end
|
19
|
+
|
20
|
+
def just_before_time_of (time)
|
21
|
+
idx = @timestep.index_at(time)
|
22
|
+
if idx.denomiator == 1
|
23
|
+
time0 = time
|
24
|
+
else
|
25
|
+
time0 = @timestep.time_at(idx.floor)
|
26
|
+
end
|
27
|
+
return __format__(time0)
|
28
|
+
end
|
29
|
+
|
30
|
+
def just_after_time_of (time)
|
31
|
+
idx = @timestep.index_at(time)
|
32
|
+
if idx.denomiator == 1
|
33
|
+
time0 = time
|
34
|
+
else
|
35
|
+
time0 = @timestep.time_at(idx.ceil)
|
36
|
+
end
|
37
|
+
return __format__(time0)
|
38
|
+
end
|
39
|
+
|
40
|
+
def prev_time_of (time)
|
41
|
+
return __format__(@timestep.prev_time_of(time))
|
42
|
+
end
|
43
|
+
|
44
|
+
def next_time_of (time)
|
45
|
+
return __format__(@timestep.next_time_of(time))
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
data/spec/timestep_spec.rb
CHANGED
@@ -231,7 +231,7 @@ describe "TimeStep#time_at" do
|
|
231
231
|
is_asserted_by { ts.time_at(-366) == ts.origin.prev_month(366) }
|
232
232
|
|
233
233
|
# months timestep don't permit fractional index
|
234
|
-
expect { ts.time_at(1.5) }.to raise_error(
|
234
|
+
expect { ts.time_at(1.5) }.to raise_error(ArgumentError)
|
235
235
|
|
236
236
|
end
|
237
237
|
|
@@ -250,7 +250,7 @@ describe "TimeStep#time_at" do
|
|
250
250
|
is_asserted_by { ts.time_at(-366) == ts.origin.prev_year(366) }
|
251
251
|
|
252
252
|
# years timestep don't permit fractional index
|
253
|
-
expect { ts.time_at(1.5) }.to raise_error(
|
253
|
+
expect { ts.time_at(1.5) }.to raise_error(ArgumentError)
|
254
254
|
|
255
255
|
end
|
256
256
|
|
@@ -339,7 +339,7 @@ describe "TimeStep#index_at" do
|
|
339
339
|
|
340
340
|
end
|
341
341
|
|
342
|
-
describe "TimeStep#
|
342
|
+
describe "TimeStep#duration_at" do
|
343
343
|
|
344
344
|
example 'seconds' do
|
345
345
|
|
@@ -347,25 +347,25 @@ describe "TimeStep#days_at" do
|
|
347
347
|
|
348
348
|
ts = TimeStep.new("1 seconds since 2001-02-03 04:05:06 +07:00", calendar: calendar)
|
349
349
|
|
350
|
-
is_asserted_by { ts.
|
351
|
-
is_asserted_by { ts.
|
352
|
-
is_asserted_by { ts.
|
353
|
-
is_asserted_by { ts.
|
350
|
+
is_asserted_by { ts.duration_at( 1 ) == 1.quo(86400) }
|
351
|
+
is_asserted_by { ts.duration_at( 100 ) == 100.quo(86400) }
|
352
|
+
is_asserted_by { ts.duration_at( 0.5 ) == 0.5.to_r.quo(86400) }
|
353
|
+
is_asserted_by { ts.duration_at( -0.5 ) == -0.5.to_r.quo(86400) }
|
354
354
|
|
355
355
|
end
|
356
356
|
|
357
357
|
end
|
358
358
|
|
359
|
-
example '
|
359
|
+
example 'duration' do
|
360
360
|
|
361
361
|
CALENDAR_NAMES.each do |calendar|
|
362
362
|
|
363
363
|
ts = TimeStep.new("1 days since 2001-02-03 04:05:06 +07:00", calendar: calendar)
|
364
364
|
|
365
|
-
is_asserted_by { ts.
|
366
|
-
is_asserted_by { ts.
|
367
|
-
is_asserted_by { ts.
|
368
|
-
is_asserted_by { ts.
|
365
|
+
is_asserted_by { ts.duration_at( 1 ) == 1 }
|
366
|
+
is_asserted_by { ts.duration_at( 100 ) == 100 }
|
367
|
+
is_asserted_by { ts.duration_at( 0.5 ) == 0.5 }
|
368
|
+
is_asserted_by { ts.duration_at( -0.5 ) == -0.5 }
|
369
369
|
|
370
370
|
end
|
371
371
|
|
@@ -377,10 +377,10 @@ describe "TimeStep#days_at" do
|
|
377
377
|
|
378
378
|
ts = TimeStep.new("1 months since 2001-02-03 04:05:06 +07:00", calendar: calendar)
|
379
379
|
|
380
|
-
is_asserted_by { ts.
|
381
|
-
is_asserted_by { ts.
|
382
|
-
is_asserted_by { ts.
|
383
|
-
is_asserted_by { ts.
|
380
|
+
is_asserted_by { ts.duration_at( 1 ) == ts.origin.next_month - ts.origin }
|
381
|
+
is_asserted_by { ts.duration_at( 100 ) == ts.origin.next_month(100) - ts.origin }
|
382
|
+
is_asserted_by { ts.duration_at( -1 ) == ts.origin.prev_month - ts.origin }
|
383
|
+
is_asserted_by { ts.duration_at( -100 ) == ts.origin.prev_month(100) - ts.origin }
|
384
384
|
|
385
385
|
end
|
386
386
|
|
@@ -392,10 +392,10 @@ describe "TimeStep#days_at" do
|
|
392
392
|
|
393
393
|
ts = TimeStep.new("1 years since 2001-02-03 04:05:06 +07:00", calendar: calendar)
|
394
394
|
|
395
|
-
is_asserted_by { ts.
|
396
|
-
is_asserted_by { ts.
|
397
|
-
is_asserted_by { ts.
|
398
|
-
is_asserted_by { ts.
|
395
|
+
is_asserted_by { ts.duration_at( 1 ) == ts.origin.next_year - ts.origin }
|
396
|
+
is_asserted_by { ts.duration_at( 100 ) == ts.origin.next_year(100) - ts.origin }
|
397
|
+
is_asserted_by { ts.duration_at( -1 ) == ts.origin.prev_year - ts.origin }
|
398
|
+
is_asserted_by { ts.duration_at( -100 ) == ts.origin.prev_year(100) - ts.origin }
|
399
399
|
|
400
400
|
end
|
401
401
|
|
data/spec/timesteppair_spec.rb
CHANGED
@@ -63,7 +63,7 @@ describe "TimeStep::Pair#forward" do
|
|
63
63
|
is_asserted_by { pair.forward(1) == 4 }
|
64
64
|
is_asserted_by { pair.forward(10) == 31 }
|
65
65
|
|
66
|
-
expect { pair.forward(1.5) }.to raise_error(
|
66
|
+
expect { pair.forward(1.5) }.to raise_error(ArgumentError)
|
67
67
|
end
|
68
68
|
|
69
69
|
example "different years" do
|
@@ -77,7 +77,7 @@ describe "TimeStep::Pair#forward" do
|
|
77
77
|
is_asserted_by { pair.forward(1) == 4 }
|
78
78
|
is_asserted_by { pair.forward(10) == 31 }
|
79
79
|
|
80
|
-
expect { pair.forward(1.5) }.to raise_error(
|
80
|
+
expect { pair.forward(1.5) }.to raise_error(ArgumentError)
|
81
81
|
|
82
82
|
end
|
83
83
|
|
data/timesteps.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timesteps
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.6
|
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-
|
11
|
+
date: 2020-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: " A library for time conversion and intercomparison of multiple time
|
14
14
|
series data \n in the case of handling time series data of the type that specifies
|
@@ -27,18 +27,20 @@ files:
|
|
27
27
|
- README.md
|
28
28
|
- Rakefile
|
29
29
|
- lib/timesteps.rb
|
30
|
-
- lib/timesteps/calendar.rb
|
31
30
|
- lib/timesteps/datetime_360day.rb
|
32
31
|
- lib/timesteps/datetime_allleap.rb
|
33
32
|
- lib/timesteps/datetime_noleap.rb
|
33
|
+
- lib/timesteps/datetime_parse_timestamp.rb
|
34
34
|
- lib/timesteps/datetimelike.rb
|
35
|
-
- lib/timesteps/
|
35
|
+
- lib/timesteps/datetimelike_format.rb
|
36
36
|
- lib/timesteps/grads.rb
|
37
|
-
- lib/timesteps/
|
37
|
+
- lib/timesteps/timeperiod.rb
|
38
38
|
- lib/timesteps/timestep.rb
|
39
|
+
- lib/timesteps/timestep_calendar.rb
|
39
40
|
- lib/timesteps/timestep_converter.rb
|
40
41
|
- lib/timesteps/timestep_datetime_ext.rb
|
41
42
|
- lib/timesteps/timestep_pair.rb
|
43
|
+
- lib/timesteps/timestep_query.rb
|
42
44
|
- spec/allleap_spec.rb
|
43
45
|
- spec/fixed360day_spec.rb
|
44
46
|
- spec/noleap_spec.rb
|