rounding 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +3 -0
- data/README.md +239 -0
- data/Rakefile +8 -0
- data/bin/console +11 -0
- data/lib/rounding.rb +5 -0
- data/lib/rounding/active_support_ext/time_with_zone.rb +7 -0
- data/lib/rounding/core_ext/date_time.rb +53 -0
- data/lib/rounding/core_ext/numeric.rb +18 -0
- data/lib/rounding/core_ext/time.rb +5 -0
- data/lib/rounding/time_extensions.rb +34 -0
- data/lib/rounding/version.rb +3 -0
- data/rounding.gemspec +25 -0
- data/spec/rounding_spec.rb +318 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b4d99f27fefc944b1bcc3a0a47db81474752063b
|
4
|
+
data.tar.gz: 4a189b36da5764596dc6ab7aafab2ebecc1ecdd8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 27f3843718eeedbd3729d67dd769342b5e862345a98bdac80b7a1c60eaf074b06018c319658cfa55f76dfa03efc0ea6795deafed07d1f4ca8e86a516e8ce3e24
|
7
|
+
data.tar.gz: e53bc824025c5c8c3f78474678a0e738b93d3513f0e6c77eae8735d6d4009301c839413101e62c984c15e3bfc78ccb0cdc308577a2f8403ebf6c498f5c4ee343
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,3 @@
|
|
1
|
+
Rounding is dedicated to the public domain by its author, Brian Hempel. No rights are reserved. No restrictions are placed on the use of Rounding. That freedom also means, of course, that no warrenty of fitness is claimed; use Rounding at your own risk.
|
2
|
+
|
3
|
+
Public domain dedication is explained by the CC0 1.0 summary (and only the summary) at https://creativecommons.org/publicdomain/zero/1.0/
|
data/README.md
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
# Rounding
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/rounding.svg)](http://badge.fury.io/rb/rounding)
|
4
|
+
[![Build Status](https://travis-ci.org/brianhempel/rounding.svg)](https://travis-ci.org/brianhempel/rounding)
|
5
|
+
|
6
|
+
Rounding allows you to round any numeric value to anything you want. You can also round a Time to, for example, the nearest 15 minutes.
|
7
|
+
|
8
|
+
Some quick examples:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
require 'rounding'
|
12
|
+
|
13
|
+
26.round_to(10) # => 30
|
14
|
+
8.77.floor_to(2.5) # => 7.5
|
15
|
+
101.ceil_to(25) # => 125
|
16
|
+
Time.now.round_to(15.minutes) # => 2014-09-08 22:30:00 -0400
|
17
|
+
```
|
18
|
+
|
19
|
+
Rounding is compatible with ActiveSupport's Time extensions, but also works fine without ActiveSupport.
|
20
|
+
|
21
|
+
## Installation
|
22
|
+
|
23
|
+
Add this line to your application's Gemfile:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
gem 'rounding'
|
27
|
+
```
|
28
|
+
|
29
|
+
And then execute:
|
30
|
+
|
31
|
+
$ bundle
|
32
|
+
|
33
|
+
Or install it yourself like so:
|
34
|
+
|
35
|
+
$ gem install rounding
|
36
|
+
|
37
|
+
## Usage
|
38
|
+
|
39
|
+
First, require the gem.
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
require 'rounding'
|
43
|
+
```
|
44
|
+
|
45
|
+
Rounding adds three methods to all Numeric objects: `round_to`, `floor_to`, and `ceil_to`.
|
46
|
+
|
47
|
+
`round_to` rounds to the nearest multiple of the chosen step.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
254.round_to(100) # => 300
|
51
|
+
1.4.round_to(3) # => 0
|
52
|
+
1.5.round_to(3) # => 3
|
53
|
+
1.6.round_to(3) # => 3
|
54
|
+
-8.round_to(3) # => -9
|
55
|
+
```
|
56
|
+
|
57
|
+
`floor_to` rounds down to a multiple of the chosen step.
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
299.floor_to(100) # => 200
|
61
|
+
1.81.floor_to(0.5) # => 1.5
|
62
|
+
60.floor_to(15) # => 60
|
63
|
+
-8.floor_to(3) # => -9
|
64
|
+
```
|
65
|
+
|
66
|
+
`ceil_to` rounds up to a multiple of the chosen step.
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
201.ceil_to(100) # => 300
|
70
|
+
1.71.ceil_to(0.5) # => 2.0
|
71
|
+
60.ceil_to(15) # => 60
|
72
|
+
-8.ceil_to(3) # => -6
|
73
|
+
```
|
74
|
+
|
75
|
+
For all methods, the class of the result depends on the input arguments.
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
16.round_to(10) # => 20
|
79
|
+
16.round_to(10.0) # => 20.0
|
80
|
+
16.0.round_to(10) # => 20
|
81
|
+
16.0.round_to(10.0) # => 20.0
|
82
|
+
```
|
83
|
+
|
84
|
+
If you need super-precise rounding, use Rationals.
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
time = Time.now.to_f # => 1410230400.4758651
|
88
|
+
time.round_to(0.0001) # => 1410230400.4759002 # Float is not exact
|
89
|
+
time.round_to(1.to_r/10_000) # => (14102304004759/10000)
|
90
|
+
```
|
91
|
+
|
92
|
+
You can provide an offset if you want the multiples to start counting from something other than zero.
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
# rounding by 10 with an offset of 3 will round to 3, 13, 23, 33, 43, 53 etc.
|
96
|
+
18.round_to(10, 3) # => 23
|
97
|
+
18.floor_to(10, 3) # => 13
|
98
|
+
18.ceil_to(10, 3) # => 23
|
99
|
+
0.ceil_to(10, 3) # => 3
|
100
|
+
0.floor_to(10, 3) # => -7
|
101
|
+
```
|
102
|
+
|
103
|
+
### Usage with Time and TimeWithZone objects
|
104
|
+
|
105
|
+
You can round times to whatever you like. The units are seconds.
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
time = Time.now # => 2014-09-08 22:57:34 -0400
|
109
|
+
|
110
|
+
# to next 10 minutes...
|
111
|
+
time.ceil_to(60*10) # => 2014-09-08 23:00:00 -0400
|
112
|
+
|
113
|
+
# to previous 15 minutes...
|
114
|
+
time.floor_to(60*15) # => 2014-09-08 22:45:00 -0400
|
115
|
+
|
116
|
+
# to nearest hour...
|
117
|
+
time.round_to(60*60) # => 2014-09-08 23:00:00 -0400
|
118
|
+
```
|
119
|
+
|
120
|
+
If you need to round to something smaller than one second, use rationals to avoid precision loss.
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
time.xmlschema(6) # => "2014-09-08T22:57:34.433197-04:00"
|
124
|
+
time.round_to(1.to_r/1000).xmlschema(6) # => "2014-09-08T22:57:34.433000-04:00"
|
125
|
+
```
|
126
|
+
|
127
|
+
Times are rounded in their time zone.
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
ONE_DAY = 60*60*24
|
131
|
+
|
132
|
+
time.round_to(ONE_DAY) # => 2014-09-09 00:00:00 -0400
|
133
|
+
```
|
134
|
+
|
135
|
+
If you want to round in UTC, use `round_in_utc_to`, `floor_in_utc_to`, and `ceil_in_utc_to`.
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
time.round_in_utc_to(ONE_DAY) # => 2014-09-08 20:00:00 -0400
|
139
|
+
time.floor_in_utc_to(ONE_DAY) # => 2014-09-08 20:00:00 -0400
|
140
|
+
time.ceil_in_utc_to(ONE_DAY) # => 2014-09-09 20:00:00 -0400
|
141
|
+
```
|
142
|
+
|
143
|
+
If you want the result in UTC instead of the original time zone, convert to UTC first.
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
time.dup.utc.round_to(ONE_DAY) # => 2014-09-09 00:00:00 UTC
|
147
|
+
```
|
148
|
+
|
149
|
+
You can provide a base value to round around.
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
# round to Wednesday
|
153
|
+
|
154
|
+
wednesday = Time.parse("2014-09-03 -0400")
|
155
|
+
one_week = ONE_DAY*7
|
156
|
+
|
157
|
+
time.round_to(one_week, wednesday) # => 2014-09-10 00:00:00 -0400
|
158
|
+
```
|
159
|
+
|
160
|
+
If you've loaded ActiveSupport, you can use ActiveSupport's duration sugar to write expressions like `1.day` instead of `60*60*24`.
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
require "active_support/time"
|
164
|
+
|
165
|
+
time.round_to(1.day) # => 2014-09-09 00:00:00 -0400
|
166
|
+
time.round_to(5.minutes) # => 2014-09-08 23:00:00 -0400
|
167
|
+
```
|
168
|
+
|
169
|
+
ActiveSupport's TimeWithZone is fully supported.
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
time = ActiveSupport::TimeZone["Bern"].parse("2014-09-08 22:57:34 -0400")
|
173
|
+
# => Tue, 09 Sep 2014 04:57:34 CEST +02:00
|
174
|
+
|
175
|
+
time.round_to(12.hours) # => Tue, 09 Sep 2014 00:00:00 CEST +02:00
|
176
|
+
time.round_to(12.hours).class # => ActiveSupport::TimeWithZone
|
177
|
+
```
|
178
|
+
|
179
|
+
For rounding to the month or year, you should use ActiveSupport's time extensions. Months and years have variable numbers of days and thus are not correctly supported by Rounding.
|
180
|
+
|
181
|
+
### Usage with DateTime objects
|
182
|
+
|
183
|
+
Rounding also works with DateTime objects. Unlike Time objects, you will be rounding to a chosen number of days rather than a number of seconds.
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
require 'date'
|
187
|
+
|
188
|
+
date_time = DateTime.now # => Mon, 08 Sep 2014 23:46:16 -0400
|
189
|
+
|
190
|
+
date_time.round_to(1) # => Tue, 09 Sep 2014 00:00:00 -0400
|
191
|
+
```
|
192
|
+
|
193
|
+
Use rational fractions of a day to round to the desired unit.
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
# 1 hour
|
197
|
+
date_time.floor_to(1.to_r/24) # => Mon, 08 Sep 2014 23:00:00 -0400
|
198
|
+
# 5 minutes
|
199
|
+
date_time.floor_to(1.to_r/24/60*5) # => Mon, 08 Sep 2014 23:45:00 -0400
|
200
|
+
```
|
201
|
+
|
202
|
+
ActiveSupport's duration helpers can save you from writing ugly expressions.
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
date_time.floor_to(1.hour) # => Mon, 08 Sep 2014 23:00:00 -0400
|
206
|
+
date_time.floor_to(5.minutes) # => Mon, 08 Sep 2014 23:45:00 -0400
|
207
|
+
```
|
208
|
+
|
209
|
+
The `round_in_utc_to`, `floor_in_utc_to`, and `ceil_in_utc_to` are also available on DateTime objects. However, to round around the UNIX epoch in your time zone, you will need to provide a custom center for rounding.
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
fortnight = 2.weeks
|
213
|
+
|
214
|
+
# UNIX epoch is a Thursday in UTC, Julian epoch is a Monday
|
215
|
+
|
216
|
+
date_time.round_to(fortnight) # => Mon, 15 Sep 2014 00:00:00 -0400
|
217
|
+
date_time.round_in_utc_to(fortnight) # => Wed, 10 Sep 2014 20:00:00 -0400
|
218
|
+
|
219
|
+
unix_epoch_minus_four = DateTime.new(1970, 1, 1, 0, 0, 0, "-0400")
|
220
|
+
date_time.round_to(fortnight, unix_epoch_minus_four) # => Thu, 11 Sep 2014 00:00:00 -0400
|
221
|
+
```
|
222
|
+
|
223
|
+
Happy rounding!
|
224
|
+
|
225
|
+
## License
|
226
|
+
|
227
|
+
Rounding is dedicated to the public domain by its author, Brian Hempel. No rights are reserved. No restrictions are placed on the use of Rounding. That freedom also means, of course, that no warrenty of fitness is claimed; use Rounding at your own risk.
|
228
|
+
|
229
|
+
Public domain dedication is explained by the CC0 1.0 summary (and only the summary) at https://creativecommons.org/publicdomain/zero/1.0/
|
230
|
+
|
231
|
+
## Contributing
|
232
|
+
|
233
|
+
1. Fork it ( https://github.com/brianhempel/rounding/fork )
|
234
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
235
|
+
3. Run the tests with `rspec`
|
236
|
+
4. There is also a `bin/console` command to load up a REPL for playing around
|
237
|
+
5. Commit your changes (`git commit -am 'Add some feature'`)
|
238
|
+
6. Push to the branch (`git push origin my-new-feature`)
|
239
|
+
7. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
4
|
+
require "rounding"
|
5
|
+
require "active_support/time"
|
6
|
+
require "pry"
|
7
|
+
|
8
|
+
TIME_ZONE = ActiveSupport::TimeZone["Bern"]
|
9
|
+
AST = ActiveSupport::TimeZone["Kuwait"] # something without DST
|
10
|
+
|
11
|
+
binding.pry
|
data/lib/rounding.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rounding/time_extensions'
|
2
|
+
|
3
|
+
class DateTime < Date
|
4
|
+
include Rounding::TimeExtensions
|
5
|
+
|
6
|
+
UNIX_EPOCH = 2440588
|
7
|
+
|
8
|
+
raise "DateTime#to_r already defined! Definitions may conflict" if method_defined?(:to_r)
|
9
|
+
def to_r
|
10
|
+
no_offset = new_offset(0)
|
11
|
+
no_offset.jd + no_offset.day_fraction
|
12
|
+
end
|
13
|
+
|
14
|
+
def floor_to(step, around=-offset)
|
15
|
+
step = decode_duration(step)
|
16
|
+
around = decode_duration(around)
|
17
|
+
super(step, around)
|
18
|
+
end
|
19
|
+
|
20
|
+
def ceil_to(step, around=-offset)
|
21
|
+
step = decode_duration(step)
|
22
|
+
around = decode_duration(around)
|
23
|
+
super(step, around)
|
24
|
+
end
|
25
|
+
|
26
|
+
def round_to(step, around=-offset)
|
27
|
+
step = decode_duration(step)
|
28
|
+
around = decode_duration(around)
|
29
|
+
super(step, around)
|
30
|
+
end
|
31
|
+
|
32
|
+
def floor_in_utc_to(step)
|
33
|
+
floor_to(step, UNIX_EPOCH)
|
34
|
+
end
|
35
|
+
|
36
|
+
def ceil_in_utc_to(step)
|
37
|
+
ceil_to(step, UNIX_EPOCH)
|
38
|
+
end
|
39
|
+
|
40
|
+
def round_in_utc_to(step)
|
41
|
+
round_to(step, UNIX_EPOCH)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def decode_duration(value)
|
47
|
+
if defined?(ActiveSupport::Duration) && ActiveSupport::Duration === value
|
48
|
+
value.to_r / 1.day.to_r
|
49
|
+
else
|
50
|
+
value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Numeric
|
2
|
+
def floor_to(step, around=0)
|
3
|
+
whole, _ = (self - around).divmod(step)
|
4
|
+
whole * step + around
|
5
|
+
end
|
6
|
+
|
7
|
+
def ceil_to(step, around=0)
|
8
|
+
whole, remainder = (self - around).divmod(step)
|
9
|
+
num_steps = remainder > 0 ? whole + 1 : whole
|
10
|
+
num_steps * step + around
|
11
|
+
end
|
12
|
+
|
13
|
+
def round_to(step, around=0)
|
14
|
+
whole, remainder = (self - around).divmod(step)
|
15
|
+
num_steps = remainder*2 >= step ? whole + 1 : whole
|
16
|
+
num_steps * step + around
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Rounding::TimeExtensions
|
2
|
+
def floor_to(step, around=-utc_offset)
|
3
|
+
around = around.to_r
|
4
|
+
rational_self = self.to_r
|
5
|
+
difference = rational_self - rational_self.floor_to(step, around)
|
6
|
+
self - difference
|
7
|
+
end
|
8
|
+
|
9
|
+
def ceil_to(step, around=-utc_offset)
|
10
|
+
around = around.to_r
|
11
|
+
rational_self = self.to_r
|
12
|
+
difference = rational_self - rational_self.ceil_to(step, around)
|
13
|
+
self - difference
|
14
|
+
end
|
15
|
+
|
16
|
+
def round_to(step, around=-utc_offset)
|
17
|
+
around = around.to_r
|
18
|
+
rational_self = self.to_r
|
19
|
+
difference = rational_self - rational_self.round_to(step, around)
|
20
|
+
self - difference
|
21
|
+
end
|
22
|
+
|
23
|
+
def floor_in_utc_to(step)
|
24
|
+
floor_to(step, 0)
|
25
|
+
end
|
26
|
+
|
27
|
+
def ceil_in_utc_to(step)
|
28
|
+
ceil_to(step, 0)
|
29
|
+
end
|
30
|
+
|
31
|
+
def round_in_utc_to(step)
|
32
|
+
round_to(step, 0)
|
33
|
+
end
|
34
|
+
end
|
data/rounding.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rounding/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "rounding"
|
8
|
+
spec.version = Rounding::VERSION
|
9
|
+
spec.authors = ["Brian Hempel"]
|
10
|
+
spec.email = ["plasticchicken@gmail.com"]
|
11
|
+
spec.summary = %q{Floor/nearest/ceiling rounding by arbitrary steps for Integers, Floats, Times, TimeWithZones, and DateTimes.}
|
12
|
+
spec.description = spec.summary
|
13
|
+
spec.homepage = "https://github.com/brianhempel/rounding"
|
14
|
+
spec.license = "Public Domain"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
# spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency "activesupport"
|
25
|
+
end
|
@@ -0,0 +1,318 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
2
|
+
require "rounding"
|
3
|
+
require "date"
|
4
|
+
require "active_support/time"
|
5
|
+
|
6
|
+
TIME_ZONE = ActiveSupport::TimeZone["Bern"]
|
7
|
+
AST = ActiveSupport::TimeZone["Kuwait"] # something without DST
|
8
|
+
|
9
|
+
ONE_DAY = 60*60*24
|
10
|
+
ONE_WEEK = ONE_DAY * 7
|
11
|
+
WEDNESDAY = Time.new(2014, 9, 3, 0, 0, 0, "-06:00")
|
12
|
+
|
13
|
+
describe "Rounding" do
|
14
|
+
|
15
|
+
def self.it_rounds_correctly(method, input, step, expected)
|
16
|
+
it "should be #{expected.inspect} for #{input.class} #{input.inspect} step by #{step.inspect}" do
|
17
|
+
result = input.send(method, step)
|
18
|
+
expect(result).to eq(expected)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should be class #{expected.class.inspect} for #{input.inspect} step by #{step.inspect}" do
|
22
|
+
result = input.send(method, step)
|
23
|
+
expect(result.class).to eq(expected.class)
|
24
|
+
end
|
25
|
+
|
26
|
+
if input.respond_to?(:utc_offset)
|
27
|
+
it "should have utc_offset #{expected.utc_offset.inspect} for #{input.inspect} step by #{step.inspect}" do
|
28
|
+
result_utc_offset = input.send(method, step).utc_offset
|
29
|
+
expect(result_utc_offset).to eq(expected.utc_offset)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
if input.respond_to?(:offset)
|
34
|
+
it "should have offset #{expected.offset.inspect} for #{input.inspect} step by #{step.inspect}" do
|
35
|
+
result_offset = input.send(method, step).offset
|
36
|
+
expect(result_offset).to eq(expected.offset)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#floor_to" do
|
42
|
+
FLOOR_TO_EXPECTATIONS = {
|
43
|
+
[3, 2] => 2,
|
44
|
+
[2, 2] => 2,
|
45
|
+
[0, 2] => 0,
|
46
|
+
[-1, 2] => -2,
|
47
|
+
[-2, 2] => -2,
|
48
|
+
[104, 5] => 100,
|
49
|
+
[3.0, 2] => 2,
|
50
|
+
[2.0, 2] => 2,
|
51
|
+
[0.0, 2] => 0,
|
52
|
+
[-1.0, 2] => -2,
|
53
|
+
[-2.0, 2] => -2,
|
54
|
+
[104.0, 5] => 100,
|
55
|
+
[3, 2.5] => 2.5,
|
56
|
+
[-3, 2.5] => -5.0,
|
57
|
+
[105, 2.5] => 105.0,
|
58
|
+
[4.9, 2.5] => 2.5,
|
59
|
+
[Time.new(2014, 9, 5, 18, 8, 29, "-04:00"), 60] => Time.new(2014, 9, 5, 18, 8, 00, "-04:00"),
|
60
|
+
[Time.new(2014, 9, 5, 18, 8, 30, "-05:00"), 60] => Time.new(2014, 9, 5, 18, 8, 00, "-05:00"),
|
61
|
+
[Time.new(2014, 9, 5, 18, 8, 31, "-06:00"), 60] => Time.new(2014, 9, 5, 18, 8, 00, "-06:00"),
|
62
|
+
[Time.new(2014, 9, 5, 11, 59, 59, "-07:00"), ONE_DAY] => Time.new(2014, 9, 5, 0, 0, 00, "-07:00"),
|
63
|
+
[Time.new(2014, 9, 5, 12, 0, 00, "-08:00"), ONE_DAY] => Time.new(2014, 9, 5, 0, 0, 00, "-08:00"),
|
64
|
+
[Time.new(2014, 9, 5, 12, 0, 01, "-09:00"), ONE_DAY] => Time.new(2014, 9, 5, 0, 0, 00, "-09:00"),
|
65
|
+
[Time.new(2014, 9, 5, 12, 0, 00, "-08:00"), ONE_DAY*365] => Time.new(2013, 12, 21, 0, 0, 00, "-08:00"),
|
66
|
+
[Time.at(1409955065, 284499), 1.to_r/1000] => Time.at(1409955065, 284000),
|
67
|
+
[Time.at(1409955065, 284500), 1.to_r/1000] => Time.at(1409955065, 284000),
|
68
|
+
[Time.at(1409955065, 284501), 1.to_r/1000] => Time.at(1409955065, 284000),
|
69
|
+
[TIME_ZONE.local(2014, 9, 5, 18, 8, 30), 60] => TIME_ZONE.local(2014, 9, 5, 18, 8, 00),
|
70
|
+
[DateTime.new(2014, 9, 5, 18, 8, 29, "-04:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 8, 00, "-04:00"),
|
71
|
+
[DateTime.new(2014, 9, 5, 18, 8, 30, "-05:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 8, 00, "-05:00"),
|
72
|
+
[DateTime.new(2014, 9, 5, 18, 8, 31, "-06:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 8, 00, "-06:00"),
|
73
|
+
[DateTime.new(2014, 9, 5, 11, 59, 59, "-07:00"), 1] => DateTime.new(2014, 9, 5, 0, 0, 00, "-07:00"),
|
74
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 1] => DateTime.new(2014, 9, 5, 0, 0, 00, "-08:00"),
|
75
|
+
[DateTime.new(2014, 9, 5, 12, 0, 01, "-09:00"), 1] => DateTime.new(2014, 9, 5, 0, 0, 00, "-09:00"),
|
76
|
+
[DateTime.new(2014, 9, 5, 11, 59, 59, "-07:00"), 1.day] => DateTime.new(2014, 9, 5, 0, 0, 00, "-07:00"),
|
77
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 1.day] => DateTime.new(2014, 9, 5, 0, 0, 00, "-08:00"),
|
78
|
+
[DateTime.new(2014, 9, 5, 12, 0, 01, "-09:00"), 1.day] => DateTime.new(2014, 9, 5, 0, 0, 00, "-09:00"),
|
79
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 365] => DateTime.new(2014, 6, 6, 0, 0, 00, "-08:00"), # rounds around Julian epoch: -4712-01-01 00:00:00
|
80
|
+
[DateTime.jd(106138433640660311.to_r/43200000000), 1.to_r/1000/ONE_DAY] => DateTime.jd(1768973894011.to_r/720000), # fractional seconds test
|
81
|
+
}
|
82
|
+
|
83
|
+
FLOOR_TO_EXPECTATIONS.each do |(input, step), expected|
|
84
|
+
it_rounds_correctly(:floor_to, input, step, expected)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "allows an around offset to center the rounding" do
|
88
|
+
expect(4.floor_to(2.5, 1)).to eq(3.5)
|
89
|
+
expect(4.5.floor_to(2, 1)).to eq(3.0)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "allows a time around offset to center the rounding" do
|
93
|
+
time = Time.new(2014, 9, 5, 12, 0, 00, "-06:00")
|
94
|
+
expect(time.floor_to(ONE_WEEK, WEDNESDAY)).to eq(Time.new(2014, 9, 3, 0, 0, 0, "-06:00"))
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#ceil_to" do
|
99
|
+
CEIL_TO_EXPECTATIONS = {
|
100
|
+
[3, 2] => 4,
|
101
|
+
[2, 2] => 2,
|
102
|
+
[0, 2] => 0,
|
103
|
+
[-1, 2] => 0,
|
104
|
+
[-2, 2] => -2,
|
105
|
+
[104, 5] => 105,
|
106
|
+
[3.0, 2] => 4,
|
107
|
+
[2.0, 2] => 2,
|
108
|
+
[0.0, 2] => 0,
|
109
|
+
[-1.0, 2] => 0,
|
110
|
+
[-2.0, 2] => -2,
|
111
|
+
[104.0, 5] => 105,
|
112
|
+
[3, 2.5] => 5.0,
|
113
|
+
[-3, 2.5] => -2.5,
|
114
|
+
[105, 2.5] => 105.0,
|
115
|
+
[4.9, 2.5] => 5.0,
|
116
|
+
[Time.new(2014, 9, 5, 18, 8, 29, "-04:00"), 60] => Time.new(2014, 9, 5, 18, 9, 00, "-04:00"),
|
117
|
+
[Time.new(2014, 9, 5, 18, 8, 30, "-05:00"), 60] => Time.new(2014, 9, 5, 18, 9, 00, "-05:00"),
|
118
|
+
[Time.new(2014, 9, 5, 18, 8, 31, "-06:00"), 60] => Time.new(2014, 9, 5, 18, 9, 00, "-06:00"),
|
119
|
+
[Time.new(2014, 9, 5, 11, 59, 59, "-07:00"), 60*60*24] => Time.new(2014, 9, 6, 0, 0, 00, "-07:00"),
|
120
|
+
[Time.new(2014, 9, 5, 12, 0, 00, "-08:00"), 60*60*24] => Time.new(2014, 9, 6, 0, 0, 00, "-08:00"),
|
121
|
+
[Time.new(2014, 9, 5, 12, 0, 01, "-09:00"), 60*60*24] => Time.new(2014, 9, 6, 0, 0, 00, "-09:00"),
|
122
|
+
[Time.new(2014, 9, 5, 12, 0, 00, "-08:00"), ONE_DAY*365] => Time.new(2014, 12, 21, 0, 0, 00, "-08:00"),
|
123
|
+
[Time.at(1409955065, 284499), 1.to_r/1000] => Time.at(1409955065, 285000),
|
124
|
+
[Time.at(1409955065, 284500), 1.to_r/1000] => Time.at(1409955065, 285000),
|
125
|
+
[Time.at(1409955065, 284501), 1.to_r/1000] => Time.at(1409955065, 285000),
|
126
|
+
[TIME_ZONE.local(2014, 9, 5, 18, 8, 30), 60] => TIME_ZONE.local(2014, 9, 5, 18, 9, 00),
|
127
|
+
[DateTime.new(2014, 9, 5, 18, 8, 29, "-04:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 9, 00, "-04:00"),
|
128
|
+
[DateTime.new(2014, 9, 5, 18, 8, 30, "-05:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 9, 00, "-05:00"),
|
129
|
+
[DateTime.new(2014, 9, 5, 18, 8, 31, "-06:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 9, 00, "-06:00"),
|
130
|
+
[DateTime.new(2014, 9, 5, 11, 59, 59, "-07:00"), 1] => DateTime.new(2014, 9, 6, 0, 0, 00, "-07:00"),
|
131
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 1] => DateTime.new(2014, 9, 6, 0, 0, 00, "-08:00"),
|
132
|
+
[DateTime.new(2014, 9, 5, 12, 0, 01, "-09:00"), 1] => DateTime.new(2014, 9, 6, 0, 0, 00, "-09:00"),
|
133
|
+
[DateTime.new(2014, 9, 5, 11, 59, 59, "-07:00"), 1.day] => DateTime.new(2014, 9, 6, 0, 0, 00, "-07:00"),
|
134
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 1.day] => DateTime.new(2014, 9, 6, 0, 0, 00, "-08:00"),
|
135
|
+
[DateTime.new(2014, 9, 5, 12, 0, 01, "-09:00"), 1.day] => DateTime.new(2014, 9, 6, 0, 0, 00, "-09:00"),
|
136
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 365] => DateTime.new(2015, 6, 6, 0, 0, 00, "-08:00"), # rounds around Julian epoch: -4712-01-01 00:00:00
|
137
|
+
[DateTime.jd(106138433640660311.to_r/43200000000), 1.to_r/1000/ONE_DAY] => DateTime.jd(212276867281321.to_r/86400000), # fractional seconds test
|
138
|
+
}
|
139
|
+
|
140
|
+
CEIL_TO_EXPECTATIONS.each do |(input, step), expected|
|
141
|
+
it_rounds_correctly(:ceil_to, input, step, expected)
|
142
|
+
end
|
143
|
+
|
144
|
+
it "allows an around offset to center the rounding" do
|
145
|
+
expect(4.ceil_to(2.5, 1)).to eq(6.0)
|
146
|
+
expect(4.5.ceil_to(2, 1)).to eq(5.0)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "allows a time around offset to center the rounding" do
|
150
|
+
time = Time.new(2014, 9, 5, 12, 0, 00, "-06:00")
|
151
|
+
expect(time.ceil_to(ONE_WEEK, WEDNESDAY)).to eq(Time.new(2014, 9, 10, 0, 0, 0, "-06:00"))
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "#round_to" do
|
156
|
+
TO_NEAREST_EXPECTATIONS = {
|
157
|
+
[3, 2] => 4,
|
158
|
+
[2, 2] => 2,
|
159
|
+
[0, 2] => 0,
|
160
|
+
[-1, 2] => 0,
|
161
|
+
[-2, 2] => -2,
|
162
|
+
[102, 5] => 100,
|
163
|
+
[103, 5] => 105,
|
164
|
+
[104, 5] => 105,
|
165
|
+
[105, 5] => 105,
|
166
|
+
[84, 10] => 80,
|
167
|
+
[85, 10] => 90,
|
168
|
+
[3.0, 2] => 4,
|
169
|
+
[2.0, 2] => 2,
|
170
|
+
[0.0, 2] => 0,
|
171
|
+
[-1.0, 2] => 0,
|
172
|
+
[-2.0, 2] => -2,
|
173
|
+
[102.0, 5] => 100,
|
174
|
+
[103.0, 5] => 105,
|
175
|
+
[104.0, 5] => 105,
|
176
|
+
[105.0, 5] => 105,
|
177
|
+
[84.0, 10] => 80,
|
178
|
+
[85.0, 10] => 90,
|
179
|
+
[3, 2.5] => 2.5,
|
180
|
+
[-3, 2.5] => -2.5,
|
181
|
+
[1.24, 2.5] => 0.0,
|
182
|
+
[1.25, 2.5] => 2.5,
|
183
|
+
[103, 2.5] => 102.5,
|
184
|
+
[104, 2.5] => 105.0,
|
185
|
+
[105, 2.5] => 105.0,
|
186
|
+
[4.9, 2.5] => 5.0,
|
187
|
+
[Time.new(2014, 9, 5, 18, 8, 29, "-04:00"), 60] => Time.new(2014, 9, 5, 18, 8, 00, "-04:00"),
|
188
|
+
[Time.new(2014, 9, 5, 18, 8, 30, "-05:00"), 60] => Time.new(2014, 9, 5, 18, 9, 00, "-05:00"),
|
189
|
+
[Time.new(2014, 9, 5, 18, 8, 31, "-06:00"), 60] => Time.new(2014, 9, 5, 18, 9, 00, "-06:00"),
|
190
|
+
[Time.new(2014, 9, 5, 11, 59, 59, "-07:00"), 60*60*24] => Time.new(2014, 9, 5, 0, 0, 00, "-07:00"),
|
191
|
+
[Time.new(2014, 9, 5, 12, 0, 00, "-08:00"), 60*60*24] => Time.new(2014, 9, 6, 0, 0, 00, "-08:00"),
|
192
|
+
[Time.new(2014, 9, 5, 12, 0, 01, "-09:00"), 60*60*24] => Time.new(2014, 9, 6, 0, 0, 00, "-09:00"),
|
193
|
+
[Time.new(2014, 9, 5, 12, 0, 00, "-08:00"), ONE_DAY*365] => Time.new(2014, 12, 21, 0, 0, 00, "-08:00"),
|
194
|
+
[Time.at(1409955065, 284499), 1.to_r/1000] => Time.at(1409955065, 284000),
|
195
|
+
[Time.at(1409955065, 284500), 1.to_r/1000] => Time.at(1409955065, 285000),
|
196
|
+
[Time.at(1409955065, 284501), 1.to_r/1000] => Time.at(1409955065, 285000),
|
197
|
+
[TIME_ZONE.local(2014, 9, 5, 18, 8, 30), 60] => TIME_ZONE.local(2014, 9, 5, 18, 9, 00),
|
198
|
+
[DateTime.new(2014, 9, 5, 18, 8, 29, "-04:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 8, 00, "-04:00"),
|
199
|
+
[DateTime.new(2014, 9, 5, 18, 8, 30, "-05:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 9, 00, "-05:00"),
|
200
|
+
[DateTime.new(2014, 9, 5, 18, 8, 31, "-06:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 9, 00, "-06:00"),
|
201
|
+
[DateTime.new(2014, 9, 5, 11, 59, 59, "-07:00"), 1] => DateTime.new(2014, 9, 5, 0, 0, 00, "-07:00"),
|
202
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 1] => DateTime.new(2014, 9, 6, 0, 0, 00, "-08:00"),
|
203
|
+
[DateTime.new(2014, 9, 5, 12, 0, 01, "-09:00"), 1] => DateTime.new(2014, 9, 6, 0, 0, 00, "-09:00"),
|
204
|
+
[DateTime.new(2014, 9, 5, 11, 59, 59, "-07:00"), 1.day] => DateTime.new(2014, 9, 5, 0, 0, 00, "-07:00"),
|
205
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 1.day] => DateTime.new(2014, 9, 6, 0, 0, 00, "-08:00"),
|
206
|
+
[DateTime.new(2014, 9, 5, 12, 0, 01, "-09:00"), 1.day] => DateTime.new(2014, 9, 6, 0, 0, 00, "-09:00"),
|
207
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 365] => DateTime.new(2014, 6, 6, 0, 0, 00, "-08:00"), # rounds around Julian epoch: -4712-01-01 00:00:00
|
208
|
+
[DateTime.jd(106138433640660311.to_r/43200000000), 1.to_r/1000/ONE_DAY] => DateTime.jd(212276867281321.to_r/86400000), # fractional seconds test
|
209
|
+
}
|
210
|
+
|
211
|
+
TO_NEAREST_EXPECTATIONS.each do |(input, step), expected|
|
212
|
+
it_rounds_correctly(:round_to, input, step, expected)
|
213
|
+
end
|
214
|
+
|
215
|
+
it "allows an around offset to center the rounding" do
|
216
|
+
expect(4.round_to(2.5, 1)).to eq(3.5)
|
217
|
+
expect(4.5.round_to(2, 1)).to eq(5.0)
|
218
|
+
end
|
219
|
+
|
220
|
+
it "allows a time around offset to center the rounding" do
|
221
|
+
time = Time.new(2014, 9, 5, 12, 0, 00, "-06:00")
|
222
|
+
expect(time.round_to(ONE_WEEK, WEDNESDAY)).to eq(Time.new(2014, 9, 3, 0, 0, 0, "-06:00"))
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe "#floor_in_utc_to" do
|
227
|
+
FLOOR_IN_UTC_TO_EXPECTATIONS = {
|
228
|
+
[Time.new(2014, 9, 5, 18, 8, 29, "-04:00"), 60] => Time.new(2014, 9, 5, 18, 8, 00, "-04:00"),
|
229
|
+
[Time.new(2014, 9, 5, 18, 8, 30, "-05:00"), 60] => Time.new(2014, 9, 5, 18, 8, 00, "-05:00"),
|
230
|
+
[Time.new(2014, 9, 5, 18, 8, 31, "-06:00"), 60] => Time.new(2014, 9, 5, 18, 8, 00, "-06:00"),
|
231
|
+
[Time.new(2014, 9, 5, 4, 59, 59, "-07:00"), 60*60*24] => Time.new(2014, 9, 4, 17, 0, 00, "-07:00"),
|
232
|
+
[Time.new(2014, 9, 5, 4, 0, 00, "-08:00"), 60*60*24] => Time.new(2014, 9, 4, 16, 0, 00, "-08:00"),
|
233
|
+
[Time.new(2014, 9, 5, 3, 0, 01, "-09:00"), 60*60*24] => Time.new(2014, 9, 4, 15, 0, 00, "-09:00"),
|
234
|
+
[Time.at(1409955065, 284499), 1.to_r/1000] => Time.at(1409955065, 284000),
|
235
|
+
[Time.at(1409955065, 284500), 1.to_r/1000] => Time.at(1409955065, 284000),
|
236
|
+
[Time.at(1409955065, 284501), 1.to_r/1000] => Time.at(1409955065, 284000),
|
237
|
+
[Time.new(2014, 9, 5, 12, 0, 00, "-08:00"), ONE_DAY*365] => Time.new(2013, 12, 20, 16, 0, 00, "-08:00"),
|
238
|
+
[AST.local(2014, 9, 5, 18, 8, 30), 60*60*24] => AST.local(2014, 9, 5, 3, 0, 00),
|
239
|
+
[DateTime.new(2014, 9, 5, 18, 8, 29, "-04:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 8, 00, "-04:00"),
|
240
|
+
[DateTime.new(2014, 9, 5, 18, 8, 30, "-05:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 8, 00, "-05:00"),
|
241
|
+
[DateTime.new(2014, 9, 5, 18, 8, 31, "-06:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 8, 00, "-06:00"),
|
242
|
+
[DateTime.new(2014, 9, 5, 11, 59, 59, "-07:00"), 1] => DateTime.new(2014, 9, 4, 17, 0, 00, "-07:00"),
|
243
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 1] => DateTime.new(2014, 9, 4, 16, 0, 00, "-08:00"),
|
244
|
+
[DateTime.new(2014, 9, 5, 12, 0, 01, "-09:00"), 1] => DateTime.new(2014, 9, 4, 15, 0, 00, "-09:00"),
|
245
|
+
[DateTime.new(2014, 9, 5, 11, 59, 59, "-07:00"), 1.day] => DateTime.new(2014, 9, 4, 17, 0, 00, "-07:00"),
|
246
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 1.day] => DateTime.new(2014, 9, 4, 16, 0, 00, "-08:00"),
|
247
|
+
[DateTime.new(2014, 9, 5, 12, 0, 01, "-09:00"), 1.day] => DateTime.new(2014, 9, 4, 15, 0, 00, "-09:00"),
|
248
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 365] => DateTime.new(2013, 12, 20, 16, 0, 00, "-08:00"), # rounds around UTC epoch: 1970-01-01 00:00:00
|
249
|
+
[DateTime.jd(106138433640660311.to_r/43200000000), 1.to_r/1000/ONE_DAY] => DateTime.jd(1768973894011.to_r/720000), # fractional seconds test
|
250
|
+
}
|
251
|
+
|
252
|
+
FLOOR_IN_UTC_TO_EXPECTATIONS.each do |(input, step), expected|
|
253
|
+
it_rounds_correctly(:floor_in_utc_to, input, step, expected)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
describe "#ceil_in_utc_to" do
|
258
|
+
CEIL_IN_UTC_TO_EXPECTATIONS = {
|
259
|
+
[Time.new(2014, 9, 5, 18, 8, 29, "-04:00"), 60] => Time.new(2014, 9, 5, 18, 9, 00, "-04:00"),
|
260
|
+
[Time.new(2014, 9, 5, 18, 8, 30, "-05:00"), 60] => Time.new(2014, 9, 5, 18, 9, 00, "-05:00"),
|
261
|
+
[Time.new(2014, 9, 5, 18, 8, 31, "-06:00"), 60] => Time.new(2014, 9, 5, 18, 9, 00, "-06:00"),
|
262
|
+
[Time.new(2014, 9, 5, 4, 59, 59, "-07:00"), 60*60*24] => Time.new(2014, 9, 5, 17, 0, 00, "-07:00"),
|
263
|
+
[Time.new(2014, 9, 5, 4, 0, 00, "-08:00"), 60*60*24] => Time.new(2014, 9, 5, 16, 0, 00, "-08:00"),
|
264
|
+
[Time.new(2014, 9, 5, 3, 0, 01, "-09:00"), 60*60*24] => Time.new(2014, 9, 5, 15, 0, 00, "-09:00"),
|
265
|
+
[Time.new(2014, 9, 5, 12, 0, 00, "-08:00"), ONE_DAY*365] => Time.new(2014, 12, 20, 16, 0, 00, "-08:00"),
|
266
|
+
[Time.at(1409955065, 284499), 1.to_r/1000] => Time.at(1409955065, 285000),
|
267
|
+
[Time.at(1409955065, 284500), 1.to_r/1000] => Time.at(1409955065, 285000),
|
268
|
+
[Time.at(1409955065, 284501), 1.to_r/1000] => Time.at(1409955065, 285000),
|
269
|
+
[AST.local(2014, 9, 5, 18, 8, 30), 60*60*24] => AST.local(2014, 9, 6, 3, 0, 00),
|
270
|
+
[DateTime.new(2014, 9, 5, 18, 8, 29, "-04:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 9, 00, "-04:00"),
|
271
|
+
[DateTime.new(2014, 9, 5, 18, 8, 30, "-05:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 9, 00, "-05:00"),
|
272
|
+
[DateTime.new(2014, 9, 5, 18, 8, 31, "-06:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 9, 00, "-06:00"),
|
273
|
+
[DateTime.new(2014, 9, 5, 11, 59, 59, "-07:00"), 1] => DateTime.new(2014, 9, 5, 17, 0, 00, "-07:00"),
|
274
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 1] => DateTime.new(2014, 9, 5, 16, 0, 00, "-08:00"),
|
275
|
+
[DateTime.new(2014, 9, 5, 12, 0, 01, "-09:00"), 1] => DateTime.new(2014, 9, 5, 15, 0, 00, "-09:00"),
|
276
|
+
[DateTime.new(2014, 9, 5, 11, 59, 59, "-07:00"), 1.day] => DateTime.new(2014, 9, 5, 17, 0, 00, "-07:00"),
|
277
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 1.day] => DateTime.new(2014, 9, 5, 16, 0, 00, "-08:00"),
|
278
|
+
[DateTime.new(2014, 9, 5, 12, 0, 01, "-09:00"), 1.day] => DateTime.new(2014, 9, 5, 15, 0, 00, "-09:00"),
|
279
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 365] => DateTime.new(2014, 12, 20, 16, 0, 00, "-08:00"), # rounds around UTC epoch: 1970-01-01 00:00:00
|
280
|
+
[DateTime.jd(106138433640660311.to_r/43200000000), 1.to_r/1000/ONE_DAY] => DateTime.jd(212276867281321.to_r/86400000), # fractional seconds test
|
281
|
+
}
|
282
|
+
|
283
|
+
CEIL_IN_UTC_TO_EXPECTATIONS.each do |(input, step), expected|
|
284
|
+
it_rounds_correctly(:ceil_in_utc_to, input, step, expected)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
describe "#round_in_utc_to" do
|
289
|
+
TO_NEAREST_IN_UTC_EXPECTATIONS = {
|
290
|
+
[Time.new(2014, 9, 5, 18, 8, 29, "-04:00"), 60] => Time.new(2014, 9, 5, 18, 8, 00, "-04:00"),
|
291
|
+
[Time.new(2014, 9, 5, 18, 8, 30, "-05:00"), 60] => Time.new(2014, 9, 5, 18, 9, 00, "-05:00"),
|
292
|
+
[Time.new(2014, 9, 5, 18, 8, 31, "-06:00"), 60] => Time.new(2014, 9, 5, 18, 9, 00, "-06:00"),
|
293
|
+
[Time.new(2014, 9, 5, 4, 59, 59, "-07:00"), 60*60*24] => Time.new(2014, 9, 4, 17, 0, 00, "-07:00"),
|
294
|
+
[Time.new(2014, 9, 5, 4, 0, 00, "-08:00"), 60*60*24] => Time.new(2014, 9, 5, 16, 0, 00, "-08:00"),
|
295
|
+
[Time.new(2014, 9, 5, 3, 0, 01, "-09:00"), 60*60*24] => Time.new(2014, 9, 5, 15, 0, 00, "-09:00"),
|
296
|
+
[Time.new(2014, 9, 5, 12, 0, 00, "-08:00"), ONE_DAY*365] => Time.new(2014, 12, 20, 16, 0, 00, "-08:00"),
|
297
|
+
[Time.at(1409955065, 284499), 1.to_r/1000] => Time.at(1409955065, 284000),
|
298
|
+
[Time.at(1409955065, 284500), 1.to_r/1000] => Time.at(1409955065, 285000),
|
299
|
+
[Time.at(1409955065, 284501), 1.to_r/1000] => Time.at(1409955065, 285000),
|
300
|
+
[AST.local(2014, 9, 5, 18, 8, 30), 60*60*24] => AST.local(2014, 9, 6, 3, 0, 00),
|
301
|
+
[DateTime.new(2014, 9, 5, 18, 8, 29, "-04:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 8, 00, "-04:00"),
|
302
|
+
[DateTime.new(2014, 9, 5, 18, 8, 30, "-05:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 9, 00, "-05:00"),
|
303
|
+
[DateTime.new(2014, 9, 5, 18, 8, 31, "-06:00"), 60.to_r/ONE_DAY] => DateTime.new(2014, 9, 5, 18, 9, 00, "-06:00"),
|
304
|
+
[DateTime.new(2014, 9, 5, 11, 59, 59, "-07:00"), 1] => DateTime.new(2014, 9, 5, 17, 0, 00, "-07:00"),
|
305
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 1] => DateTime.new(2014, 9, 5, 16, 0, 00, "-08:00"),
|
306
|
+
[DateTime.new(2014, 9, 5, 12, 0, 01, "-09:00"), 1] => DateTime.new(2014, 9, 5, 15, 0, 00, "-09:00"),
|
307
|
+
[DateTime.new(2014, 9, 5, 11, 59, 59, "-07:00"), 1.day] => DateTime.new(2014, 9, 5, 17, 0, 00, "-07:00"),
|
308
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 1.day] => DateTime.new(2014, 9, 5, 16, 0, 00, "-08:00"),
|
309
|
+
[DateTime.new(2014, 9, 5, 12, 0, 01, "-09:00"), 1.day] => DateTime.new(2014, 9, 5, 15, 0, 00, "-09:00"),
|
310
|
+
[DateTime.new(2014, 9, 5, 12, 0, 00, "-08:00"), 365] => DateTime.new(2014, 12, 20, 16, 0, 00, "-08:00"), # rounds around UTC epoch: 1970-01-01 00:00:00
|
311
|
+
[DateTime.jd(106138433640660311.to_r/43200000000), 1.to_r/1000/ONE_DAY] => DateTime.jd(212276867281321.to_r/86400000), # fractional seconds test
|
312
|
+
}
|
313
|
+
|
314
|
+
TO_NEAREST_IN_UTC_EXPECTATIONS.each do |(input, step), expected|
|
315
|
+
it_rounds_correctly(:round_in_utc_to, input, step, expected)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rounding
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brian Hempel
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-09-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Floor/nearest/ceiling rounding by arbitrary steps for Integers, Floats,
|
70
|
+
Times, TimeWithZones, and DateTimes.
|
71
|
+
email:
|
72
|
+
- plasticchicken@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".travis.yml"
|
79
|
+
- Gemfile
|
80
|
+
- LICENSE.txt
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- bin/console
|
84
|
+
- lib/rounding.rb
|
85
|
+
- lib/rounding/active_support_ext/time_with_zone.rb
|
86
|
+
- lib/rounding/core_ext/date_time.rb
|
87
|
+
- lib/rounding/core_ext/numeric.rb
|
88
|
+
- lib/rounding/core_ext/time.rb
|
89
|
+
- lib/rounding/time_extensions.rb
|
90
|
+
- lib/rounding/version.rb
|
91
|
+
- rounding.gemspec
|
92
|
+
- spec/rounding_spec.rb
|
93
|
+
homepage: https://github.com/brianhempel/rounding
|
94
|
+
licenses:
|
95
|
+
- Public Domain
|
96
|
+
metadata: {}
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 2.2.2
|
114
|
+
signing_key:
|
115
|
+
specification_version: 4
|
116
|
+
summary: Floor/nearest/ceiling rounding by arbitrary steps for Integers, Floats, Times,
|
117
|
+
TimeWithZones, and DateTimes.
|
118
|
+
test_files:
|
119
|
+
- spec/rounding_spec.rb
|