beginning_of_fortnight 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/beginning_of_fortnight.rb +189 -0
  2. metadata +62 -0
@@ -0,0 +1,189 @@
1
+ #
2
+ # Author:: Simon Baird
3
+ # Source:: https://github.com/simonbaird/beginning_of_fortnight
4
+ # License:: 'BSD-new' where the copyright holder is Simon Baird
5
+ #
6
+ # Extends ActiveSupport to provide these methods for Time and Date objects:
7
+ # * beginning_of_fortnight
8
+ # * end_of_fortnight
9
+ # * next_fortnight
10
+ #
11
+ # These methods should work similarly to beginning_of_week, end_of_week and next_week.
12
+ #
13
+ # This gem requires that you have a version of activesupport that defines beginning_of_week.
14
+ #
15
+ # =Installation
16
+ #
17
+ # sudo gem install beginning_of_fortnight
18
+ #
19
+ # =Usage
20
+ #
21
+ # ===Basic usage
22
+ #
23
+ # require 'rubygems'
24
+ # require 'beginning_of_fortnight'
25
+ #
26
+ # now = Time.now
27
+ # puts now.beginning_of_fortnight
28
+ # puts now.end_of_fortnight
29
+ #
30
+ # ===Explicitly setting a reference date
31
+ #
32
+ # require 'rubygems'
33
+ # require 'beginning_of_fortnight'
34
+ #
35
+ # now = Time.now
36
+ #
37
+ # # Globally define fortnights such that this date is the first half of a fortnight
38
+ # ref_date = Time.parse('13-Oct-2010')
39
+ # BeginningOfFortnight.reference_date = ref_date
40
+ #
41
+ # puts now.beginning_of_fortnight # uses ref_date
42
+ #
43
+ # # Change your mind...
44
+ # BeginningOfFortnight.reference_date = Time.parse('20-Oct-2010')
45
+ # puts now.beginning_of_fortnight # should be different
46
+ #
47
+ # # You can also pass in a single use reference date if you want to mix it up
48
+ # other_ref_date = Time.parse('27-Oct-2010')
49
+ # puts now.beginning_of_fortnight(other_ref_date)
50
+ #
51
+ #
52
+
53
+ begin
54
+ # Try to load just the time components
55
+ # (Only possible in ActiveRecord 3.0)
56
+ require 'active_support/time'
57
+ rescue LoadError
58
+ # Presume we must have ActiveRecord 2.x so require the whole lot of active_support
59
+ # (Decided it's not worth the effort to try to cherry pick just the time components)
60
+ require 'active_support'
61
+ end
62
+
63
+ #
64
+ # Just a namespace and an accessor for the reference
65
+ # date used to define fortnight boundaries.
66
+ #
67
+ #--
68
+ # (Maybe this could use cattr_accessor. Not sure if it's worth it).
69
+ #++
70
+ #
71
+ module BeginningOfFortnight
72
+ #
73
+ # Fairly arbitrary choice of reference date
74
+ #
75
+ DEFAULT_REF_DATE = Time.at(0)
76
+
77
+ #
78
+ # Provide an accessor for @@reference_date. Uses the default value if not set.
79
+ #
80
+ def self.reference_date
81
+ (@@reference_date ||= DEFAULT_REF_DATE).to_time
82
+ end
83
+
84
+ #
85
+ # The 'reference_date' here is used to define where the fortnight boundary should be.
86
+ # The way it works is that the reference_date is specified such that it falls in the first
87
+ # half of the fortnightly period.
88
+ #
89
+ # You can just ignore this it will use a default value but if you want to be explicit then
90
+ # set a date, for example:
91
+ #
92
+ # # Define fortnight boundary
93
+ # BeginningOfFortnight.reference_date = Time.parse('13-Oct-2010')
94
+ #
95
+ # # A date should work also
96
+ # BeginningOfFortnight.reference_date = Date.new(2010,10,13)
97
+ #
98
+ def self.reference_date=(reference_date)
99
+ @@reference_date = reference_date
100
+ end
101
+ end
102
+
103
+
104
+ #
105
+ # These methods should work similar to beginning_of_week and friends.
106
+ #
107
+ # In all these methods, if the optional argument <tt>reference_date</tt>
108
+ # is not given then the default reference date is used. See
109
+ # BeginningOfFortnight#reference_date.
110
+ #
111
+ # reference_date can be a Date or a Time object.
112
+ #
113
+ #--
114
+ # ActiveRecord 2.x puts these methods in a big long name space,
115
+ # ie ActiveSupport::CoreExtensions::Time::Calculations
116
+ # ActiveSupport 3.x just adds methods directly to Time.
117
+ # Will try the 3.x approach and hopefully it will work okay in 2.x also.
118
+ #++
119
+ #
120
+ class Time
121
+ #
122
+ # The beginning of the fortnight.
123
+ #
124
+ def beginning_of_fortnight(reference_date=nil)
125
+ # Can pass in a reference date, otherwise use the configured default
126
+ reference_date ||= BeginningOfFortnight.reference_date
127
+
128
+ # The to_time is in case reference_date is passed in as a Date object
129
+ reference_week = reference_date.to_time.beginning_of_week
130
+
131
+ # How many weeks since reference week?
132
+ weeks_since_reference = ((self - reference_week) / 1.week).to_i
133
+
134
+ #
135
+ # If the reference time is later than self, ie in the future,
136
+ # then we flip the odd/even test here.
137
+ #
138
+ # Some explanation:
139
+ #
140
+ # In this diagram, '|' is a fortnight boundary, '+' is a week boundary and R is the reference week.
141
+ # R
142
+ # | a + b | c + d |
143
+ #
144
+ # The value of weeks_since_reference for dates at a, b, c and d is as follows:
145
+ # When self is earlier than reference_date:
146
+ # a (in first half) : -1, hence odd weeks_since_reference is in first half
147
+ # b (in second half): 0, hence even weeks_since_reference is in second half (because -0.5.to_i is 0 for example)
148
+ # When self is later than reference_date:
149
+ # c (in first half) : 0, hence even weeks_since_reference is in first half
150
+ # d (in second half): 1, hence odd weeks_since_reference is in second half
151
+ #
152
+ in_first_half = (reference_week > self ? weeks_since_reference.odd? : weeks_since_reference.even?)
153
+
154
+ # The value of in_first_half decides which week to use
155
+ (in_first_half ? self : self - 1.week).beginning_of_week
156
+ end
157
+
158
+ #
159
+ # The end of the fortnight.
160
+ #
161
+ def end_of_fortnight(reference_date=nil)
162
+ (beginning_of_fortnight(reference_date) + 1.week).end_of_week
163
+ end
164
+
165
+ #
166
+ # The start of the fortnight after this one.
167
+ #
168
+ def next_fortnight(reference_date=nil)
169
+ beginning_of_fortnight(reference_date) + 2.weeks
170
+ end
171
+ end
172
+
173
+ #
174
+ # The Date methods are defined dynamically.
175
+ #
176
+ # See:
177
+ # * Time#beginning_of_fortnight
178
+ # * Time#end_of_fortnight
179
+ # * Time#next_fortnight
180
+ #
181
+ class Date
182
+ # Going to be lazy here... in a good way (?)
183
+ # Redoing the in_first_half logic for Date objects is not quite trivial
184
+ [:beginning_of_fortnight, :end_of_fortnight, :next_fortnight].each do |method|
185
+ define_method(method) do |*args|
186
+ self.to_time.send(method,*args).to_date
187
+ end
188
+ end
189
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: beginning_of_fortnight
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Simon Baird
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-03-16 00:00:00 +10:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Extends ActiveSupport to provides beginning/end_of_fortnight methods similar to beginning/end_of_week
22
+ email: simon.baird@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - lib/beginning_of_fortnight.rb
31
+ has_rdoc: true
32
+ homepage: http://github.com/simonbaird/beginning_of_fortnight
33
+ licenses: []
34
+
35
+ post_install_message:
36
+ rdoc_options: []
37
+
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ segments:
52
+ - 0
53
+ version: "0"
54
+ requirements: []
55
+
56
+ rubyforge_project:
57
+ rubygems_version: 1.3.6
58
+ signing_key:
59
+ specification_version: 3
60
+ summary: beginning_of_fortnight for ActiveSupport
61
+ test_files: []
62
+