working-time 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/working-time.rb +12 -0
- data/lib/working_time/date.rb +175 -0
- data/lib/working_time/interval.rb +97 -0
- data/test/helper.rb +10 -0
- data/test/test_working-time.rb +102 -0
- metadata +92 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Carl Hicks
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
= working-time
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
13
|
+
* Send me a pull request. Bonus points for topic branches.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2010 Carl Hicks. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "working-time"
|
8
|
+
gem.summary = %Q{Calculate work hours for a given date range}
|
9
|
+
gem.description = %Q{Need to figure out how many working hours are in a date range? Need to calculate around holidays, on-call schedules, etc? Use this gem!}
|
10
|
+
gem.email = "carl.hicks@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/chicks/working-time"
|
12
|
+
gem.authors = ["Carl Hicks"]
|
13
|
+
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
Rake::TestTask.new(:test) do |test|
|
23
|
+
test.libs << 'lib' << 'test'
|
24
|
+
test.pattern = 'test/**/test_*.rb'
|
25
|
+
test.verbose = true
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'rcov/rcovtask'
|
30
|
+
Rcov::RcovTask.new do |test|
|
31
|
+
test.libs << 'test'
|
32
|
+
test.pattern = 'test/**/test_*.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
rescue LoadError
|
36
|
+
task :rcov do
|
37
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
task :test => :check_dependencies
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "working-time #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.4
|
data/lib/working-time.rb
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
module WorkingTime
|
2
|
+
|
3
|
+
class Hour
|
4
|
+
attr :value
|
5
|
+
def initialize(num)
|
6
|
+
@value = num
|
7
|
+
end
|
8
|
+
def to_i
|
9
|
+
@value
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Date < Date
|
14
|
+
def + (n)
|
15
|
+
case n
|
16
|
+
when Numeric;
|
17
|
+
new_date = self.class.new!(@ajd + n, @of, @sg)
|
18
|
+
if new_date.is_work_day?
|
19
|
+
return new_date
|
20
|
+
else
|
21
|
+
until new_date.is_work_day?
|
22
|
+
#puts "incrementing days! #{new_date}"
|
23
|
+
n += 1
|
24
|
+
new_date = self.class.new!(@ajd + n, @of, @sg)
|
25
|
+
end
|
26
|
+
return new_date
|
27
|
+
end
|
28
|
+
end
|
29
|
+
raise TypeError, 'expected numeric'
|
30
|
+
end
|
31
|
+
|
32
|
+
def is_work_day?
|
33
|
+
# check the day of week
|
34
|
+
WORKING_DAYS.include? self.cwday
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
class Time < Time
|
40
|
+
|
41
|
+
# def to_time() getlocal end
|
42
|
+
|
43
|
+
def to_date
|
44
|
+
jd = Date.civil_to_jd(year, mon, mday, Date::ITALY)
|
45
|
+
Date.new!(Date.jd_to_ajd(jd, 0, 0), 0, Date::ITALY)
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_datetime
|
49
|
+
jd = WorkingTime::DateTime.civil_to_jd(year, mon, mday, DateTime::ITALY)
|
50
|
+
fr = WorkingTime::DateTime.time_to_day_fraction(hour, min, [sec, 59].min) +
|
51
|
+
usec.to_r/86400000000
|
52
|
+
of = utc_offset.to_r/86400
|
53
|
+
WorkingTime::DateTime.new!(WorkingTime::DateTime.jd_to_ajd(jd, fr, of), of, DateTime::ITALY)
|
54
|
+
end
|
55
|
+
|
56
|
+
private :to_date, :to_datetime
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
# Lets just modify the basic DateTime class
|
61
|
+
class DateTime < DateTime
|
62
|
+
|
63
|
+
def self.now (sg=ITALY) WorkingTime::Time.now.__send__(:to_datetime).new_start(sg) end
|
64
|
+
|
65
|
+
# Returns the number of hours left in the day.
|
66
|
+
def hours_left
|
67
|
+
remaining = WorkingTime::Interval.new(self, close_of_business)
|
68
|
+
return remaining.duration
|
69
|
+
end
|
70
|
+
|
71
|
+
def mins_left
|
72
|
+
hours_left * 60
|
73
|
+
end
|
74
|
+
|
75
|
+
def secs_left
|
76
|
+
hours_left * 3600
|
77
|
+
end
|
78
|
+
|
79
|
+
def open_of_business
|
80
|
+
self.class.new(self.year, self.mon, self.day, WORKING_HOURS[0], 0, 0, @of, @sg)
|
81
|
+
end
|
82
|
+
|
83
|
+
def close_of_business
|
84
|
+
self.class.new(self.year, self.mon, self.day, WORKING_HOURS[-1], 0, 0, @of, @sg)
|
85
|
+
end
|
86
|
+
|
87
|
+
def close_of_week
|
88
|
+
date = Date.new(self.year, self.mon, self.day)
|
89
|
+
date = date.next until date.cwday == WORKING_DAYS[-1]
|
90
|
+
self.class.new(date.year, date.mon, date.day, WORKING_HOURS[-1], 0, 0, @of, @sg)
|
91
|
+
end
|
92
|
+
|
93
|
+
def close_of_next_week
|
94
|
+
date = Date.commercial(year, cweek + 1, cwday)
|
95
|
+
date = date.next until date.cwday == WORKING_DAYS[-1]
|
96
|
+
self.class.new(date.year, date.mon, date.day, WORKING_HOURS[-1], 0, 0, @of, @sg)
|
97
|
+
end
|
98
|
+
|
99
|
+
def is_working_time?
|
100
|
+
# check the day of week
|
101
|
+
if WORKING_DAYS.include? cwday
|
102
|
+
#check the hour
|
103
|
+
if WORKING_HOURS.include? hour
|
104
|
+
return true
|
105
|
+
else
|
106
|
+
return false
|
107
|
+
end
|
108
|
+
else
|
109
|
+
return false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# override addition
|
114
|
+
def + (n)
|
115
|
+
case n
|
116
|
+
when Numeric; return self.class.new!(@ajd + n, @of, @sg)
|
117
|
+
when WorkingTime::Hour
|
118
|
+
|
119
|
+
cur_hour = self.hour
|
120
|
+
hours_remaining = n.to_i
|
121
|
+
|
122
|
+
min = self.min
|
123
|
+
sec = self.sec
|
124
|
+
|
125
|
+
date = Date.new(self.year,self.mon,self.day)
|
126
|
+
|
127
|
+
# if our initial value is before the start of the work day, set the cur_hour to the start of the workday
|
128
|
+
if cur_hour < WORKING_HOURS[0]
|
129
|
+
cur_hour = WORKING_HOURS[0]
|
130
|
+
# if our initial value is after the end of the current work day, set the cur_hour to the start of the NEXT workday
|
131
|
+
elsif cur_hour > WORKING_HOURS[-1]
|
132
|
+
cur_hour = WORKING_HOURS[0]
|
133
|
+
date = date.next
|
134
|
+
end
|
135
|
+
|
136
|
+
#puts "Incrementing #{self}"
|
137
|
+
# Add hours to the current hour, incrementing the day until we run out of hours
|
138
|
+
while hours_remaining > 0
|
139
|
+
until cur_hour == WORKING_HOURS[-1] || hours_remaining < 1
|
140
|
+
hours_remaining -= 1
|
141
|
+
cur_hour += 1
|
142
|
+
#puts "Cur: #{cur_hour} / Rem: #{hours_remaining}"
|
143
|
+
end
|
144
|
+
if hours_remaining > 0
|
145
|
+
hours_remaining -= 1
|
146
|
+
cur_hour = WORKING_HOURS[0]
|
147
|
+
# go to the next day
|
148
|
+
date = date.next
|
149
|
+
#puts "Rolling Date: #{date} #{cur_hour}"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
return self.class.new(date.year, date.mon, date.day, cur_hour, min, sec, @of, @sg)
|
153
|
+
end
|
154
|
+
raise TypeError, 'expected numeric or hour'
|
155
|
+
end
|
156
|
+
|
157
|
+
def to_gm_time
|
158
|
+
to_time(new_offset, :gm)
|
159
|
+
end
|
160
|
+
|
161
|
+
def to_local_time
|
162
|
+
to_time(new_offset(DateTime.now.offset-offset), :local)
|
163
|
+
end
|
164
|
+
|
165
|
+
private
|
166
|
+
def to_time(dest, method)
|
167
|
+
#Convert a fraction of a day to a number of microseconds
|
168
|
+
usec = (dest.sec_fraction * 60 * 60 * 24 * (10**6)).to_i
|
169
|
+
Time.send(method, dest.year, dest.month, dest.day, dest.hour, dest.min, dest.sec, usec)
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
module WorkingTime
|
4
|
+
|
5
|
+
class Interval
|
6
|
+
|
7
|
+
attr :start, true
|
8
|
+
attr :stop, true
|
9
|
+
attr :duration, true
|
10
|
+
attr :log, true
|
11
|
+
|
12
|
+
def initialize(start, stop)
|
13
|
+
@start = start
|
14
|
+
@stop = stop
|
15
|
+
@duration = hours_between
|
16
|
+
end
|
17
|
+
|
18
|
+
# Calculates the number of seconds in a work day between two times in the same day
|
19
|
+
def seconds_between(start, stop)
|
20
|
+
|
21
|
+
# we need this to be a float
|
22
|
+
duration = 0.0
|
23
|
+
|
24
|
+
# we just return if the start comes after the stop
|
25
|
+
return duration if start > stop
|
26
|
+
|
27
|
+
# If it's a weekday, examine it.
|
28
|
+
if WORKING_DAYS.include? start.wday
|
29
|
+
|
30
|
+
# If it's inside working hours, calculate
|
31
|
+
if WORKING_HOURS.include? start.hour
|
32
|
+
|
33
|
+
# Figure out how many seconds between now and then
|
34
|
+
hours, mins, secs, ignore_fractions = Date::day_fraction_to_time(stop - start)
|
35
|
+
duration = hours * 60 * 60 + mins * 60 + secs
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
return duration
|
42
|
+
end
|
43
|
+
|
44
|
+
def hours_between
|
45
|
+
|
46
|
+
#LOG.puts "Calculating: #{@start} to #{@stop}" if DEBUG
|
47
|
+
|
48
|
+
# Our placeholder in seconds
|
49
|
+
duration = 0.0
|
50
|
+
|
51
|
+
start_date = Date.new(@start.year, @start.mon, @start.day)
|
52
|
+
stop_date = Date.new(@stop.year, @stop.mon, @stop.day)
|
53
|
+
|
54
|
+
if start_date == stop_date
|
55
|
+
|
56
|
+
# If we closed it in the same day, we need to do a simple calculation
|
57
|
+
result = seconds_between(@start,@stop)
|
58
|
+
duration += result
|
59
|
+
#LOG.puts "Same day: #{@start} to #{@stop} (#{result / 3600})" if DEBUG
|
60
|
+
|
61
|
+
else
|
62
|
+
|
63
|
+
# Loop over each day
|
64
|
+
start_date.upto(stop_date) do |date|
|
65
|
+
|
66
|
+
#LOG.puts "Looking at: #{date}"
|
67
|
+
start_work_time = DateTime.new(date.year, date.mon, date.day, WORKING_HOURS[0])
|
68
|
+
stop_work_time = DateTime.new(date.year, date.mon, date.day, WORKING_HOURS[-1])
|
69
|
+
|
70
|
+
# If we are looking at the first day, we only want to count from the create time, to the end of the working day
|
71
|
+
if date == start_date
|
72
|
+
result = seconds_between(@start,stop_work_time)
|
73
|
+
duration += result
|
74
|
+
#LOG.puts "Start date: #{@start} to #{stop_work_time} (#{result / 3600})" if DEBUG
|
75
|
+
# If we are looking at the end date we only want to count from the beginning of the day to the close time
|
76
|
+
elsif date == stop_date
|
77
|
+
result = seconds_between(start_work_time,@stop)
|
78
|
+
duration += result
|
79
|
+
#LOG.puts "Stop date: #{start_work_time} to #{@stop} (#{result / 3600})" if DEBUG
|
80
|
+
# Otherwise we assume this date falls between start and end
|
81
|
+
else
|
82
|
+
result = seconds_between(start_work_time,stop_work_time)
|
83
|
+
duration += result
|
84
|
+
#LOG.puts "In-between date: #{start_work_time} to #{stop_work_time} (#{result / 3600 })" if DEBUG
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
#LOG.puts ""
|
92
|
+
return duration / 3600
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestWorkingTime < Test::Unit::TestCase
|
4
|
+
def test_same_day_hours_left
|
5
|
+
remaining = WorkingTime::DateTime.parse("2009-07-23T12:00:00+00:00").hours_left
|
6
|
+
assert_equal(6, remaining)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_multi_day_add_hours
|
10
|
+
start = WorkingTime::DateTime.parse("2009-07-23T12:00:00+00:00")
|
11
|
+
stop = WorkingTime::DateTime.parse("2009-07-24T11:00:00+00:00")
|
12
|
+
start = start + WorkingTime::Hour.new(10)
|
13
|
+
assert_equal(stop.to_s,start.to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_multi_month_add_hours
|
17
|
+
start = WorkingTime::DateTime.parse("2009-07-23T12:00:00+00:00")
|
18
|
+
stop = WorkingTime::DateTime.parse("2009-08-31T15:00:00+00:00")
|
19
|
+
start = start + WorkingTime::Hour.new(300)
|
20
|
+
assert_equal(stop.to_s,start.to_s)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_start_of_business
|
24
|
+
today = WorkingTime::DateTime.parse("2009-07-23T12:12:15-07:00").open_of_business
|
25
|
+
start = WorkingTime::DateTime.parse("2009-07-23T08:00:00-07:00")
|
26
|
+
assert_equal(start.to_s,today.to_s)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_datetime_now_class
|
30
|
+
assert_equal("WorkingTime::DateTime", WorkingTime::DateTime.now.class.to_s)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_after_hours_add
|
34
|
+
start = WorkingTime::DateTime.parse("2009-07-23T23:00:00+00:00")
|
35
|
+
stop = WorkingTime::DateTime.parse("2009-07-24T18:00:00+00:00")
|
36
|
+
start = start + WorkingTime::Hour.new(10)
|
37
|
+
assert_equal(stop.to_s,start.to_s)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_after_hours_completion
|
41
|
+
start = WorkingTime::DateTime.parse("2009-07-23T23:00:00+00:00")
|
42
|
+
stop = WorkingTime::DateTime.parse("2009-07-27T08:00:00+00:00")
|
43
|
+
start = start + WorkingTime::Hour.new(11)
|
44
|
+
assert_equal(stop.to_s,start.to_s)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_multi_day_rollover
|
48
|
+
start = WorkingTime::DateTime.parse("2009-09-23T13:14:00+00:00")
|
49
|
+
stop = WorkingTime::DateTime.parse("2009-09-24T10:14:00+00:00")
|
50
|
+
start = start + WorkingTime::Hour.new(8)
|
51
|
+
assert_equal(stop.to_s,start.to_s)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_close_of_week
|
55
|
+
start = WorkingTime::DateTime.parse("2009-09-23T13:14:00+00:00")
|
56
|
+
stop = WorkingTime::DateTime.parse("2009-09-25T18:00:00+00:00")
|
57
|
+
start = start.close_of_week
|
58
|
+
assert_equal(stop.to_s,start.to_s)
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_close_of_next_week
|
62
|
+
start = WorkingTime::DateTime.parse("2009-09-23T13:14:00+00:00")
|
63
|
+
stop = WorkingTime::DateTime.parse("2009-10-02T18:00:00+00:00")
|
64
|
+
start = start.close_of_next_week
|
65
|
+
assert_equal(stop.to_s,start.to_s)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class TestWorkingTimeInterval < Test::Unit::TestCase
|
70
|
+
|
71
|
+
def test_same_day_close
|
72
|
+
start = DateTime.parse("2009-07-29T18:30:00+00:00")
|
73
|
+
stop = DateTime.parse("2009-07-29T22:00:00+00:00")
|
74
|
+
|
75
|
+
interval = WorkingTime::Interval.new(start,stop)
|
76
|
+
assert_equal(3.5, interval.duration)
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_multi_day_close_no_weekend
|
80
|
+
start = DateTime.parse("2009-07-23T12:00:00+00:00")
|
81
|
+
stop = DateTime.parse("2009-07-24T12:00:00+00:00")
|
82
|
+
|
83
|
+
interval = WorkingTime::Interval.new(start,stop)
|
84
|
+
assert_equal(10.0, interval.duration)
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_multi_day_close_weekend
|
88
|
+
start = DateTime.parse("2009-07-23T12:00:00+00:00")
|
89
|
+
stop = DateTime.parse("2009-07-27T12:00:00+00:00")
|
90
|
+
|
91
|
+
interval = WorkingTime::Interval.new(start,stop)
|
92
|
+
assert_equal(20.0, interval.duration)
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_multi_day_after_hours
|
96
|
+
start = DateTime.parse("2009-07-28T18:59:00+00:00")
|
97
|
+
stop = DateTime.parse("2009-07-29T16:00:00+00:00")
|
98
|
+
|
99
|
+
interval = WorkingTime::Interval.new(start,stop)
|
100
|
+
assert_equal(8.0, interval.duration)
|
101
|
+
end
|
102
|
+
end
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: working-time
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 3
|
9
|
+
- 4
|
10
|
+
version: 0.3.4
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Carl Hicks
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-07-27 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: thoughtbot-shoulda
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
description: Need to figure out how many working hours are in a date range? Need to calculate around holidays, on-call schedules, etc? Use this gem!
|
36
|
+
email: carl.hicks@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.rdoc
|
44
|
+
files:
|
45
|
+
- .document
|
46
|
+
- .gitignore
|
47
|
+
- LICENSE
|
48
|
+
- README.rdoc
|
49
|
+
- Rakefile
|
50
|
+
- VERSION
|
51
|
+
- lib/working-time.rb
|
52
|
+
- lib/working_time/date.rb
|
53
|
+
- lib/working_time/interval.rb
|
54
|
+
- test/helper.rb
|
55
|
+
- test/test_working-time.rb
|
56
|
+
has_rdoc: true
|
57
|
+
homepage: http://github.com/chicks/working-time
|
58
|
+
licenses: []
|
59
|
+
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options:
|
62
|
+
- --charset=UTF-8
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
hash: 3
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.3.7
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: Calculate work hours for a given date range
|
90
|
+
test_files:
|
91
|
+
- test/helper.rb
|
92
|
+
- test/test_working-time.rb
|