business_time 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7dc74d9cffafd72acce648d07bdceed471344dfd
4
- data.tar.gz: 6394c590be260dddde6c2738090cf00c03060368
3
+ metadata.gz: f2f2a3838d12a29f3825e56dfb6d3d588ad88dc9
4
+ data.tar.gz: ca0ec6507d0587296d85375f6a0c25caf2ff8654
5
5
  SHA512:
6
- metadata.gz: c0321b6695f50318379b00423f54aca445eb53a5b1c2ee9b1ba1a164a442f4090c56bd6a541a00e3b527bc80ab4f0ba139e407aa6f12e84b445afe7958885692
7
- data.tar.gz: 633875c242cb89ae62ec2d9e2361ff16e7b2b91ad5216c7b2198f36d1631eaa4f33f502b86f4d13b05ba5fc77e34c76c398706d403c70024f84cef17c0940834
6
+ metadata.gz: a8afbc63ea4ed9c3b96bd967079144b3eef20b2b592d1fd33e9e65df379eb49af8ba7570bf18f57033c02a442755829cebbdbd926d960676780d49e24cfade27
7
+ data.tar.gz: 9c8bc1f7392c4e191bd61a1609fe8568e9131a915721a77678d3c8f8977f193284a9bf04a4632a74f035de1a5d8c4b252767b6ddb8295df232d2da3fda2481a5
@@ -166,6 +166,16 @@ Timezone relative date handling gets more and more complicated every time you lo
166
166
 
167
167
  == Releases
168
168
 
169
+ 0.9.0 - PR#143 - performance improvements on hour date calculations
170
+ PR#144 - new feature - Fiscal date methods.
171
+
172
+ 0.8.0 - Ruby 2.4 compatibility 4/1/2017 (yes, this is the same as 0.9.0)
173
+ I released the 2.4 upgrade separately than the other new features
174
+ so that people have an upgrade path to 2.4 without mixing in new
175
+ features.
176
+ Forces a particular date format for Regex
177
+ A small change to include the version number in the project itself.
178
+
169
179
  0.7.6 - Fixed a defect where timezone was not preserved when dealing with beginning_or_workday and end_of_workday.
170
180
  Thanks bazzargh.
171
181
 
@@ -220,6 +230,20 @@ Timezone relative date handling gets more and more complicated every time you lo
220
230
  need the baggage.
221
231
 
222
232
 
233
+ == A note on stability and change
234
+
235
+ Sometimes people ask me why this gem doesn't release more often. My opinions on that are best discussed in person in a friendly discussion, but I'll attempt some of that here.
236
+
237
+ First, a big part of the reason is that the projects I do use this gem on are happy with it's current functionality. It is 'suitable for the purpose' for which I released it, and as such, maintenance I do on this gem is a gift to the community.
238
+
239
+ Second, out of the ~1.3 million downloads (according to rubygems.org), the number of real 'issues' with this gem have been minimal. Most of the issues that are opened are really people with slightly different requirements than I have regarding whether 'off hours' work counts as the previous or the next business day, a disagreement on the semantics of days vs. hours, etc. I take care to try to explain these choices in the open issues, but to my mind, they aren't true issues if it's just a difference of opinion. Even so, I'll gladly accept pull requests that resolve this difference of opinion as a configuration option... just don't expect me to do your job for you. I've already given you 90% of what you need.
240
+
241
+ Third, a business time gem is, well, relevant to businesses. Many businesses don't move quickly. My government clients move even more slowly. Stability is favored in these environments.
242
+
243
+ Fourth, new features can wait. To the person that adds them they can be mission critical, but with modern packaging processes, they can use their version without waiting for their changes to be included in the upstream version. Their changes don't break your code.
244
+
245
+ I'm proud of the work in this gem; the stability is a big part of that. This gem has lived longer than many others that have attempted to do the same thing. I expect it to be here chugging away when Ruby has become the next COBOL.
246
+
223
247
  == Copyright
224
248
 
225
- Copyright (c) 2010-2016 bokmann. See LICENSE for details.
249
+ Copyright (c) 2010-2017 bokmann. See LICENSE for details.
@@ -4,6 +4,7 @@ require 'active_support/time'
4
4
  require 'time'
5
5
  require 'yaml'
6
6
 
7
+ require 'business_time/parsed_time'
7
8
  require 'business_time/version'
8
9
  require 'business_time/config'
9
10
  require 'business_time/business_hours'
@@ -7,16 +7,33 @@ module BusinessTime
7
7
  # manually, or with a yaml file and the load method.
8
8
  class Config
9
9
  DEFAULT_CONFIG = {
10
- holidays: [],
11
- beginning_of_workday: '9:00 am',
12
- end_of_workday: '5:00 pm',
10
+ holidays: SortedSet.new,
11
+ beginning_of_workday: ParsedTime.parse('9:00 am'),
12
+ end_of_workday: ParsedTime.parse('5:00 pm'),
13
13
  work_week: %w(mon tue wed thu fri),
14
14
  work_hours: {},
15
15
  work_hours_total: {},
16
16
  _weekdays: nil,
17
+ fiscal_month_offset: 10,
17
18
  }
18
19
 
19
20
  class << self
21
+ def beginning_of_workday=(time)
22
+ config[:beginning_of_workday] = ParsedTime.parse(time)
23
+ end
24
+
25
+ def end_of_workday=(time)
26
+ config[:end_of_workday] = ParsedTime.parse(time)
27
+ end
28
+
29
+ def work_hours=(work_hours)
30
+ work_hours.each_with_object(config[:work_hours] = {}) do |(day, hours), c|
31
+ c[day] = hours.map do |time|
32
+ ParsedTime.parse(time)
33
+ end
34
+ end
35
+ end
36
+
20
37
  private
21
38
 
22
39
  def config
@@ -42,9 +59,17 @@ module BusinessTime
42
59
  end
43
60
 
44
61
  def threadsafe_cattr_accessor(name)
62
+ threadsafe_cattr_reader(name)
63
+ threadsafe_cattr_setter(name)
64
+ end
65
+
66
+ def threadsafe_cattr_reader(name)
45
67
  define_singleton_method name do
46
68
  config[name]
47
69
  end
70
+ end
71
+
72
+ def threadsafe_cattr_setter(name)
48
73
  define_singleton_method "#{name}=" do |value|
49
74
  config[name] = value
50
75
  end
@@ -55,13 +80,13 @@ module BusinessTime
55
80
  # by saying
56
81
  # BusinessTime::Config.beginning_of_workday = "8:30 am"
57
82
  # someplace in the initializers of your application.
58
- threadsafe_cattr_accessor :beginning_of_workday
83
+ threadsafe_cattr_reader :beginning_of_workday
59
84
 
60
85
  # You can set this yourself, either by the load method below, or
61
86
  # by saying
62
87
  # BusinessTime::Config.end_of_workday = "5:30 pm"
63
88
  # someplace in the initializers of your application.
64
- threadsafe_cattr_accessor :end_of_workday
89
+ threadsafe_cattr_reader :end_of_workday
65
90
 
66
91
  # You can set this yourself, either by the load method below, or
67
92
  # by saying
@@ -79,18 +104,20 @@ module BusinessTime
79
104
  # and end_of_workday. Keys will be added ad weekdays.
80
105
  # Example:
81
106
  # {:mon => ["9:00","17:00"],:tue => ["9:00","17:00"].....}
82
- threadsafe_cattr_accessor :work_hours
107
+ threadsafe_cattr_reader :work_hours
83
108
 
84
109
  # total work hours for a day. Never set, always calculated.
85
110
  threadsafe_cattr_accessor :work_hours_total
86
111
 
87
112
  threadsafe_cattr_accessor :_weekdays # internal
88
113
 
114
+ threadsafe_cattr_accessor :fiscal_month_offset
115
+
89
116
  class << self
90
117
  def end_of_workday(day=nil)
91
118
  if day
92
119
  wday = work_hours[int_to_wday(day.wday)]
93
- wday ? (wday.last =~ /^0{1,2}\:0{1,2}$/ ? "23:59:59" : wday.last) : config[:end_of_workday]
120
+ wday ? (wday.last == ParsedTime.new(0, 0) ? ParsedTime.new(23, 59, 59) : wday.last) : config[:end_of_workday]
94
121
  else
95
122
  config[:end_of_workday]
96
123
  end
@@ -113,10 +140,11 @@ module BusinessTime
113
140
  def weekdays
114
141
  return _weekdays unless _weekdays.nil?
115
142
 
116
- self._weekdays = (!work_hours.empty? ? work_hours.keys : work_week).each_with_object([]) do |day_name, days|
117
- day_num = wday_to_int(day_name)
118
- days << day_num unless day_num.nil?
119
- end
143
+ days = (!work_hours.empty? ? work_hours.keys : work_week).map do |day_name|
144
+ wday_to_int(day_name)
145
+ end.compact
146
+
147
+ self._weekdays = SortedSet.new(days)
120
148
  end
121
149
 
122
150
  # loads the config data from a yaml file written as:
@@ -13,4 +13,49 @@ class Date
13
13
  (self...to_date).select(&:workday?)
14
14
  end
15
15
  end
16
+
17
+ # Adapted from:
18
+ # https://github.com/activewarehouse/activewarehouse/blob/master/lib/active_warehouse/core_ext/time/calculations.rb
19
+
20
+ def week
21
+ cyw = ((yday - 1) / 7) + 1
22
+ cyw = 52 if cyw == 53
23
+ cyw
24
+ end
25
+
26
+ def quarter
27
+ ((month - 1) / 3) + 1
28
+ end
29
+
30
+ def fiscal_month_offset
31
+ BusinessTime::Config.fiscal_month_offset
32
+ end
33
+
34
+ def fiscal_year_week
35
+ fyw = ((fiscal_year_yday - 1) / 7) + 1
36
+ fyw = 52 if fyw == 53
37
+ fyw
38
+ end
39
+
40
+ def fiscal_year_month
41
+ shifted_month = month - (fiscal_month_offset - 1)
42
+ shifted_month += 12 if shifted_month <= 0
43
+ shifted_month
44
+ end
45
+
46
+ def fiscal_year_quarter
47
+ ((fiscal_year_month - 1) / 3) + 1
48
+ end
49
+
50
+ def fiscal_year
51
+ month >= fiscal_month_offset ? year + 1 : year
52
+ end
53
+
54
+ def fiscal_year_yday
55
+ offset_days = 0
56
+ 1.upto(fiscal_month_offset - 1) { |m| offset_days += ::Time.days_in_month(m, year) }
57
+ shifted_year_day = yday - offset_days
58
+ shifted_year_day += 365 if shifted_year_day <= 0
59
+ shifted_year_day
60
+ end
16
61
  end
@@ -0,0 +1,34 @@
1
+ module BusinessTime
2
+ class ParsedTime
3
+ include Comparable
4
+
5
+ attr_reader :hour, :min, :sec
6
+
7
+ def initialize(hour, min = 0, sec = 0)
8
+ @hour = hour
9
+ @min = min
10
+ @sec = sec
11
+ end
12
+
13
+ def self.parse(time_or_string)
14
+ if time_or_string.is_a?(String)
15
+ time = Time.parse(time_or_string)
16
+ else
17
+ time = time_or_string
18
+ end
19
+ new(time.hour, time.min, time.sec)
20
+ end
21
+
22
+ def to_s
23
+ "#{hour}:#{min}:#{sec}"
24
+ end
25
+
26
+ def -(other)
27
+ (hour - other.hour) * 3600 + (min - other.min) * 60 + sec - other.sec
28
+ end
29
+
30
+ def <=>(other)
31
+ [hour, min, sec] <=> [other.hour, other.min, other.sec]
32
+ end
33
+ end
34
+ end
@@ -17,7 +17,7 @@ module BusinessTime
17
17
  # Note: It pretends that this day is a workday whether or not it really is a
18
18
  # workday.
19
19
  def end_of_workday(day)
20
- end_of_workday = Time.parse(BusinessTime::Config.end_of_workday(day))
20
+ end_of_workday = BusinessTime::Config.end_of_workday(day)
21
21
  change_business_time(day,end_of_workday.hour,end_of_workday.min,end_of_workday.sec)
22
22
  end
23
23
 
@@ -26,7 +26,7 @@ module BusinessTime
26
26
  # Note: It pretends that this day is a workday whether or not it really is a
27
27
  # workday.
28
28
  def beginning_of_workday(day)
29
- beginning_of_workday = Time.parse(BusinessTime::Config.beginning_of_workday(day))
29
+ beginning_of_workday = BusinessTime::Config.beginning_of_workday(day)
30
30
  change_business_time(day,beginning_of_workday.hour,beginning_of_workday.min,beginning_of_workday.sec)
31
31
  end
32
32
 
@@ -116,15 +116,15 @@ module BusinessTime
116
116
  if hours = BusinessTime::Config.work_hours[day]
117
117
  BusinessTime::Config.work_hours_total[day] ||= begin
118
118
  hours_last = hours.last
119
- if hours_last == '00:00'
120
- (Time.parse('23:59') - Time.parse(hours.first)) + 1.minute
119
+ if hours_last == ParsedTime.new(0, 0)
120
+ (ParsedTime.new(23, 59) - hours.first) + 1.minute
121
121
  else
122
- Time.parse(hours_last) - Time.parse(hours.first)
122
+ hours_last - hours.first
123
123
  end
124
124
  end
125
125
  else
126
126
  BusinessTime::Config.work_hours_total[:default] ||= begin
127
- Time.parse(BusinessTime::Config.end_of_workday) - Time.parse(BusinessTime::Config.beginning_of_workday)
127
+ BusinessTime::Config.end_of_workday - BusinessTime::Config.beginning_of_workday
128
128
  end
129
129
  end
130
130
  end
@@ -1,3 +1,3 @@
1
1
  module BusinessTime
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: business_time
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - bokmann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-01 00:00:00.000000000 Z
11
+ date: 2017-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -111,6 +111,7 @@ files:
111
111
  - lib/business_time/core_ext/date.rb
112
112
  - lib/business_time/core_ext/integer.rb
113
113
  - lib/business_time/core_ext/time.rb
114
+ - lib/business_time/parsed_time.rb
114
115
  - lib/business_time/time_extensions.rb
115
116
  - lib/business_time/version.rb
116
117
  - lib/generators/business_time/config_generator.rb