workpattern 0.3.4 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +8 -4
- data/.travis.yml +18 -3
- data/CHANGELOG.md +88 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +19 -4
- data/LICENSE.txt +21 -0
- data/README.md +56 -80
- data/Rakefile +9 -0
- data/lib/workpattern.rb +31 -91
- data/lib/workpattern/clock.rb +21 -20
- data/lib/workpattern/constants.rb +72 -0
- data/lib/workpattern/day.rb +211 -290
- data/lib/workpattern/version.rb +2 -4
- data/lib/workpattern/week.rb +239 -321
- data/lib/workpattern/week_pattern.rb +144 -0
- data/lib/workpattern/workpattern.rb +156 -187
- data/workpattern.gemspec +32 -18
- metadata +40 -28
- data/CHANGELOG +0 -35
- data/config/website.yml +0 -2
- data/lib/workpattern/hour.rb +0 -209
- data/lib/workpattern/utility/base.rb +0 -32
- data/test/test_clock.rb +0 -31
- data/test/test_day.rb +0 -522
- data/test/test_helper.rb +0 -3
- data/test/test_hour.rb +0 -389
- data/test/test_week.rb +0 -362
- data/test/test_workpattern.rb +0 -276
- data/test/test_workpattern_module.rb +0 -93
data/workpattern.gemspec
CHANGED
@@ -1,25 +1,39 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "workpattern/version"
|
4
3
|
|
5
|
-
|
6
|
-
s.name = "workpattern"
|
7
|
-
s.version = Workpattern::VERSION
|
8
|
-
s.authors = ["Barrie Callender"]
|
9
|
-
s.email = ["barrie@callenb.org"]
|
10
|
-
s.homepage = ""
|
11
|
-
s.summary = %q{temporal calculations}
|
12
|
-
s.description = %q{Workpattern performs date calculations that take into account working and resting periods.}
|
4
|
+
require_relative "lib/workpattern/version"
|
13
5
|
|
14
|
-
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "workpattern"
|
8
|
+
spec.version = Workpattern::VERSION
|
9
|
+
spec.authors = ["Barrie Callender"]
|
10
|
+
spec.email = ["barrie@callenb.org"]
|
15
11
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
spec.summary = "Calculates dates and durations whilst taking into account working and non-working periods down to a minute"
|
13
|
+
spec.description = "Calculates dates and durations whilst taking into account working and non-working times down to a minute. Business working time with holidays are a breeze."
|
14
|
+
spec.homepage = "http://workpattern.org"
|
15
|
+
spec.license = "MIT"
|
16
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 1.9.3")
|
20
17
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
spec.metadata["homepage_url"] = spec.homepage
|
19
|
+
spec.metadata["source_code_uri"] = "https://github.com/callenb/workpattern"
|
20
|
+
spec.metadata["changelog_uri"] = "https://workpattern.org/2021/02/25/changelog.html"
|
21
|
+
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
25
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
26
|
+
end
|
27
|
+
spec.require_paths = ["lib"]
|
28
|
+
|
29
|
+
# Uncomment to register a new dependency of your gem
|
30
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
31
|
+
|
32
|
+
# For more information and examples about making a new gem, checkout our
|
33
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
34
|
+
spec.add_runtime_dependency 'tzinfo'
|
35
|
+
spec.add_runtime_dependency 'sorted_set' if RUBY_VERSION >= "2.4"
|
36
|
+
spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
37
|
+
spec.require_paths = ["lib"]
|
38
|
+
|
25
39
|
end
|
metadata
CHANGED
@@ -1,31 +1,45 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: workpattern
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Barrie Callender
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: tzinfo
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0
|
20
|
-
type: :
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0
|
27
|
-
|
28
|
-
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sorted_set
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Calculates dates and durations whilst taking into account working and
|
42
|
+
non-working times down to a minute. Business working time with holidays are a breeze.
|
29
43
|
email:
|
30
44
|
- barrie@callenb.org
|
31
45
|
executables: []
|
@@ -34,35 +48,33 @@ extra_rdoc_files: []
|
|
34
48
|
files:
|
35
49
|
- ".gitignore"
|
36
50
|
- ".travis.yml"
|
37
|
-
- CHANGELOG
|
51
|
+
- CHANGELOG.md
|
52
|
+
- CODE_OF_CONDUCT.md
|
38
53
|
- Gemfile
|
39
54
|
- Gemfile.lock
|
55
|
+
- LICENSE.txt
|
40
56
|
- README.md
|
41
57
|
- Rakefile
|
42
|
-
- config/website.yml
|
43
58
|
- lib/workpattern.rb
|
44
59
|
- lib/workpattern/clock.rb
|
60
|
+
- lib/workpattern/constants.rb
|
45
61
|
- lib/workpattern/day.rb
|
46
|
-
- lib/workpattern/hour.rb
|
47
|
-
- lib/workpattern/utility/base.rb
|
48
62
|
- lib/workpattern/version.rb
|
49
63
|
- lib/workpattern/week.rb
|
64
|
+
- lib/workpattern/week_pattern.rb
|
50
65
|
- lib/workpattern/workpattern.rb
|
51
66
|
- script/console
|
52
67
|
- script/destroy
|
53
68
|
- script/generate
|
54
69
|
- script/txt2html
|
55
|
-
- test/test_clock.rb
|
56
|
-
- test/test_day.rb
|
57
|
-
- test/test_helper.rb
|
58
|
-
- test/test_hour.rb
|
59
|
-
- test/test_week.rb
|
60
|
-
- test/test_workpattern.rb
|
61
|
-
- test/test_workpattern_module.rb
|
62
70
|
- workpattern.gemspec
|
63
|
-
homepage:
|
64
|
-
licenses:
|
65
|
-
|
71
|
+
homepage: http://workpattern.org
|
72
|
+
licenses:
|
73
|
+
- MIT
|
74
|
+
metadata:
|
75
|
+
homepage_url: http://workpattern.org
|
76
|
+
source_code_uri: https://github.com/callenb/workpattern
|
77
|
+
changelog_uri: https://workpattern.org/2021/02/25/changelog.html
|
66
78
|
post_install_message:
|
67
79
|
rdoc_options: []
|
68
80
|
require_paths:
|
@@ -71,16 +83,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
71
83
|
requirements:
|
72
84
|
- - ">="
|
73
85
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
86
|
+
version: 1.9.3
|
75
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
88
|
requirements:
|
77
89
|
- - ">="
|
78
90
|
- !ruby/object:Gem::Version
|
79
91
|
version: '0'
|
80
92
|
requirements: []
|
81
|
-
|
82
|
-
rubygems_version: 2.1.4
|
93
|
+
rubygems_version: 3.0.9
|
83
94
|
signing_key:
|
84
95
|
specification_version: 4
|
85
|
-
summary:
|
96
|
+
summary: Calculates dates and durations whilst taking into account working and non-working
|
97
|
+
periods down to a minute
|
86
98
|
test_files: []
|
data/CHANGELOG
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
## Workpattern v0.3.4 (Sep 27, 2013) ##
|
2
|
-
|
3
|
-
* diff doesn't calculate properly from working to resting day (#15) * Barrie Callender *
|
4
|
-
|
5
|
-
|
6
|
-
## Workpattern v0.3.3 (Sep 23, 2013) ##
|
7
|
-
|
8
|
-
* Failed to subtract 1 minute from end of resting hour (#12) * Barrie Callender *
|
9
|
-
* Failed to add minutes starting from a resting period in a patterned hour (#13) * Barrie Callender *
|
10
|
-
* Failed to subtract the exact amount of minutes from a patterned hour (#14) * Barrie Callender *
|
11
|
-
* The two tests no longer fail with Ruby 2.0 (#11) * Barrie Callender *
|
12
|
-
|
13
|
-
|
14
|
-
## Workpattern v0.3.2 (Mar 14, 2013) ##
|
15
|
-
|
16
|
-
* Changed methods on Hour module so as to not clash with Rails (#10) * Barrie Callender *
|
17
|
-
* Applied DRY principle to workpattern method in Workpattern class * Barrie Callender *
|
18
|
-
* Removed file from emacs backup * Barrie Callender *
|
19
|
-
|
20
|
-
## Workpattern v0.3.1 (Oct 14, 2012) ##
|
21
|
-
|
22
|
-
* RDOC documentation not right on rubydoc.info (#5) * Barrie Callender *
|
23
|
-
|
24
|
-
## Workpattern v0.3.0 (Jul 19, 2012) ##
|
25
|
-
|
26
|
-
* incomplete tests for week (#2) * Barrie Callender *
|
27
|
-
* getting wrong time when hour had exactly the right number of minutes (#9) * Barrie Callender *
|
28
|
-
* jruby-19mode failed with SystemStackError: stack level too deep (#8) * Barrie Callender *
|
29
|
-
* midnight flag should override hour and minutes (#7) * Barrie Callender *
|
30
|
-
* available minutes not calculating correctly for a time of 00:01 (#6) * Barrie Callender *
|
31
|
-
|
32
|
-
## Workpattern v0.2.0 (May 31, 2012) ##
|
33
|
-
|
34
|
-
* Rewritten from scratch effectively first version * Barrie Callender *
|
35
|
-
* Please discard any version of Workpattern before this - some poor souls may have come across v0.1.0. - sorry! * Barrie Callender *
|
data/config/website.yml
DELETED
data/lib/workpattern/hour.rb
DELETED
@@ -1,209 +0,0 @@
|
|
1
|
-
module Workpattern
|
2
|
-
|
3
|
-
# Represents the 60 minutes of an hour using an <tt>Integer</tt>
|
4
|
-
#
|
5
|
-
# @since 0.2.0
|
6
|
-
#
|
7
|
-
module Hour
|
8
|
-
|
9
|
-
# Returns the total working minutes in the hour
|
10
|
-
#
|
11
|
-
# @return [Integer] working minutes in the hour
|
12
|
-
#
|
13
|
-
def wp_total
|
14
|
-
return wp_minutes(0,59)
|
15
|
-
end
|
16
|
-
|
17
|
-
# Sets the minutes to either working (type=1) or resting (type=0)
|
18
|
-
#
|
19
|
-
# @param [Integer] start minute at start of range
|
20
|
-
# @param [Integer] finish minute at end of range
|
21
|
-
# @param [Integer] type defines whether working (1) or resting (0)
|
22
|
-
#
|
23
|
-
def wp_workpattern(start,finish,type=1)
|
24
|
-
return wp_working(start,finish) if type==1
|
25
|
-
return wp_resting(start,finish) if type==0
|
26
|
-
end
|
27
|
-
|
28
|
-
# Returns the first working minute in the hour or 60 if there are no working minutes
|
29
|
-
#
|
30
|
-
# @return [Integer] first working minute or 60 if none found
|
31
|
-
#
|
32
|
-
def wp_first
|
33
|
-
0.upto(59) {|minute| return minute if self.wp_minutes(minute,minute)==1}
|
34
|
-
return nil
|
35
|
-
end
|
36
|
-
|
37
|
-
# Returns the last working minute in the hour or nil if there are no working minutes
|
38
|
-
#
|
39
|
-
# @return [Integer] last working minute or nil if none found
|
40
|
-
#
|
41
|
-
def wp_last
|
42
|
-
59.downto(0) {|minute| return minute if self.wp_minutes(minute,minute)==1}
|
43
|
-
return nil
|
44
|
-
end
|
45
|
-
|
46
|
-
# Returns true if the given minute is working and false if it isn't
|
47
|
-
#
|
48
|
-
# @param [Integer] start is the minute being tested
|
49
|
-
# @return [Boolean] true if minute is working, otherwise false
|
50
|
-
#
|
51
|
-
def wp_working?(start)
|
52
|
-
return true if wp_minutes(start,start)==1
|
53
|
-
return false
|
54
|
-
end
|
55
|
-
|
56
|
-
# Returns the total number of minutes between and including two minutes
|
57
|
-
#
|
58
|
-
# @param [Integer] start first minute in range
|
59
|
-
# @param [Integer] finish last minute in range
|
60
|
-
# @return [Integer] number of minutes from <tt>start</tt> to <tt>finish</tt> inclusive
|
61
|
-
#
|
62
|
-
def wp_minutes(start,finish)
|
63
|
-
return (self & wp_mask(start,finish)).to_s(2).count('1')
|
64
|
-
end
|
65
|
-
|
66
|
-
# Returns the DateTime and remainding minutes when adding a duration to a minute in the hour.
|
67
|
-
# A negative duration will subtract the minutes.
|
68
|
-
#
|
69
|
-
# @param [DateTime] time is the full date but only the minute element is used
|
70
|
-
# @param [Integer] duration is the number of minutes to add and can be negative (subtraction)
|
71
|
-
# @param [Boolean] next_hour used in subtraction to specify the starting point as midnight (00:00 the next day)
|
72
|
-
# @return [DateTime,Integer,Boolean] The <tt>DateTime</tt> calculated along with remaining minutes and a flag indicating if starting point is next hour
|
73
|
-
#
|
74
|
-
def wp_calc(time,duration,next_hour=false)
|
75
|
-
return wp_subtract(time,duration, next_hour) if duration < 0
|
76
|
-
return wp_add(time,duration) if duration > 0
|
77
|
-
return time,duration
|
78
|
-
end
|
79
|
-
|
80
|
-
# Returns the number of minutes between two minutes
|
81
|
-
# @param [Integer] start first minute in range
|
82
|
-
# @param [Integer] finish last minute in range
|
83
|
-
# @return [Integer] number of working minutes in the range
|
84
|
-
#
|
85
|
-
def wp_diff(start,finish)
|
86
|
-
start,finish=finish,start if start > finish
|
87
|
-
return 0 if start==finish
|
88
|
-
return (self & wp_mask(start,finish-1)).to_s(2).count('1')
|
89
|
-
end
|
90
|
-
|
91
|
-
private
|
92
|
-
|
93
|
-
# Sets a working pattern
|
94
|
-
#
|
95
|
-
# @param [Integer] start is first minute in the range
|
96
|
-
# @param [Integer] finish is last minute in the range
|
97
|
-
#
|
98
|
-
def wp_working(start,finish)
|
99
|
-
return self | wp_mask(start,finish)
|
100
|
-
end
|
101
|
-
|
102
|
-
# sets a resting pattern
|
103
|
-
#
|
104
|
-
# @param [Integer] start is first minute in the range
|
105
|
-
# @param [Integer] finish is last minute in the range
|
106
|
-
#
|
107
|
-
def wp_resting(start,finish)
|
108
|
-
return self & ((2**60-1)-wp_mask(start,finish))
|
109
|
-
end
|
110
|
-
|
111
|
-
# Creates a bit mask of 1's over the specified range
|
112
|
-
#
|
113
|
-
# @param [Integer] start is first minute in the range
|
114
|
-
# @param [Integer] finish is the last minute in the range
|
115
|
-
#
|
116
|
-
def wp_mask(start,finish)
|
117
|
-
return ((2**(finish+1)-1)-(2**start-1))
|
118
|
-
end
|
119
|
-
|
120
|
-
# Handles the addition of minutes to a time
|
121
|
-
#
|
122
|
-
# @param [DateTime] time is the full date but only the minute element is used
|
123
|
-
# @param [Integer] duration is the number of minutes to add and can be negative (subtraction)
|
124
|
-
# @return [DateTime, Integer] The resulting DateTime and any remaining minutes
|
125
|
-
#
|
126
|
-
def wp_add(time,duration)
|
127
|
-
start = time.min
|
128
|
-
available_minutes=wp_minutes(start,59)
|
129
|
-
|
130
|
-
if not_enough_minutes duration, available_minutes
|
131
|
-
result_date = time + HOUR - (MINUTE*start)
|
132
|
-
result_remainder = duration-available_minutes
|
133
|
-
elsif exact_amount_of_minutes(start,duration)
|
134
|
-
result_date = time + (MINUTE*duration)
|
135
|
-
result_remainder = 0
|
136
|
-
else # more than enough minutes
|
137
|
-
step = start + duration
|
138
|
-
duration-=wp_minutes(start,step)
|
139
|
-
until (duration==0)
|
140
|
-
step+=1
|
141
|
-
duration-=wp_minutes(step,step)
|
142
|
-
end
|
143
|
-
step+=1
|
144
|
-
result_date = time - (MINUTE*time.min) + (MINUTE*step)
|
145
|
-
result_remainder = 0
|
146
|
-
end
|
147
|
-
return result_date, result_remainder
|
148
|
-
end
|
149
|
-
|
150
|
-
# Handles the subtraction of minutes from a time.
|
151
|
-
# @param [DateTime] time is the full date but only the minute element is used
|
152
|
-
# @param [Integer] duration is the number of minutes to add and can be negative (subtraction)
|
153
|
-
# @param [Boolean] next_hour indicates if the 59th second is the first one to be included
|
154
|
-
# @return [DateTime, Integer] The resulting DateTime and any remaining minutes
|
155
|
-
#
|
156
|
-
def wp_subtract(time,duration,next_hour)
|
157
|
-
if next_hour
|
158
|
-
if wp_working?(59)
|
159
|
-
duration+=1
|
160
|
-
time=time+(MINUTE*59)
|
161
|
-
return wp_calc(time,duration)
|
162
|
-
end
|
163
|
-
return time, duration if wp_total==0
|
164
|
-
else
|
165
|
-
start=time.min
|
166
|
-
available_minutes=0
|
167
|
-
available_minutes = wp_minutes(0,start-1) if start > 0
|
168
|
-
end
|
169
|
-
|
170
|
-
if not_enough_minutes duration,available_minutes
|
171
|
-
result_date = time - (MINUTE*start)
|
172
|
-
result_remainder = duration+available_minutes
|
173
|
-
elsif duration.abs==available_minutes
|
174
|
-
result_date = time - (MINUTE*(start-wp_first))
|
175
|
-
result_remainder = 0
|
176
|
-
else
|
177
|
-
step = start + duration
|
178
|
-
duration+=wp_minutes(step,start-1)
|
179
|
-
until (duration==0)
|
180
|
-
step-=1
|
181
|
-
duration+=wp_minutes(step,step)
|
182
|
-
end
|
183
|
-
result_date = time - (MINUTE * (start-step))
|
184
|
-
result_remainder = 0
|
185
|
-
end
|
186
|
-
return result_date, result_remainder
|
187
|
-
|
188
|
-
end
|
189
|
-
|
190
|
-
private
|
191
|
-
|
192
|
-
def not_enough_minutes(duration,available_minutes)
|
193
|
-
return true if (duration.abs-available_minutes)>0
|
194
|
-
return false
|
195
|
-
end
|
196
|
-
|
197
|
-
def exact_amount_of_minutes(start,duration)
|
198
|
-
return true if wp_minutes(start,start+duration-1)==duration
|
199
|
-
false
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
# Hours are represented by a bitwise <tt>Integer</tt> class so the code is mixed in to that class
|
205
|
-
# @ since 0.3.0
|
206
|
-
#
|
207
|
-
class Integer
|
208
|
-
include Workpattern::Hour
|
209
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
module Workpattern
|
2
|
-
|
3
|
-
# Mixins expected to be used in more than one class
|
4
|
-
#
|
5
|
-
# @since 0.2.0
|
6
|
-
#
|
7
|
-
module Utility
|
8
|
-
|
9
|
-
# Returns the supplied <tt>DateTime</tt> at the very start of the day.
|
10
|
-
#
|
11
|
-
# @param [DateTime] adate is the <tt>DateTime</tt> to be changed
|
12
|
-
# @return [DateTime]
|
13
|
-
#
|
14
|
-
# @todo Consider mixin for DateTime class
|
15
|
-
#
|
16
|
-
def midnight_before(adate)
|
17
|
-
return adate -(HOUR * adate.hour) - (MINUTE * adate.min)
|
18
|
-
end
|
19
|
-
|
20
|
-
# Returns the supplied <tt>DateTime</tt> at the very start of the next day.
|
21
|
-
#
|
22
|
-
# @param [DateTime] adate is the <tt>DateTime</tt> to be changed
|
23
|
-
# @return [DateTime]
|
24
|
-
#
|
25
|
-
# @todo Consider mixin for DateTime class
|
26
|
-
#
|
27
|
-
def midnight_after(adate)
|
28
|
-
return midnight_before(adate.next_day)
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
32
|
-
end
|