DateUtils 0.3

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.
Files changed (3) hide show
  1. data/README +23 -0
  2. data/lib/date_utils.rb +490 -0
  3. metadata +47 -0
data/README ADDED
@@ -0,0 +1,23 @@
1
+ # == Synopsis
2
+ # Some handy Year, Month, Week objects to make live with Date easier.
3
+ #
4
+ # == Author
5
+ # Rene Paulokat
6
+ #
7
+ # == Copyright
8
+ # Copyright (c) 2007 Rene Paulokat
9
+ #
10
+ # This program is free software; you can redistribute it and/or modify
11
+ # it under the terms of the GNU General Public License as published by
12
+ # the Free Software Foundation; either version 2 of the License, or
13
+ # (at your option) any later version.
14
+ #
15
+ # This program is distributed in the hope that it will be useful,
16
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ # GNU General Public License for more details.
19
+ #
20
+ # You should have received a copy of the GNU General Public License
21
+ # along with this program; if not, write to the Free Software
22
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23
+ #
@@ -0,0 +1,490 @@
1
+ # this Module prepares some handy objects to
2
+ # deal with Date 's
3
+ #--
4
+ # Copyright (c) 2007 Rene Paulokat
5
+ # This program is free software; you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation; either version 2 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
+ #
19
+
20
+ require 'date'
21
+ require 'date_utils'
22
+
23
+
24
+ # DateUils
25
+ # is a simple Collection of classes which offer some
26
+ # handy tools to get a grip on 'Date'
27
+ # ----
28
+ # * DateUtils::Year
29
+ # * DateUtils::Month
30
+ # * DateUtils::Week
31
+ # * DateUtils::Day
32
+ # for complete rdoc visit:
33
+ # http://dateutils.rubyforge.org
34
+ #
35
+ # _usage_:
36
+ #
37
+ # year = DateUtils::Year.new(Date.parse('1977-10-18'))
38
+ # pp year
39
+ #<DateUtils::Year:0xb7c4e19c
40
+ # @date=#<Date: 4886869/2,0,2299161>,
41
+ # @first_day=#<Date: 4886289/2,0,2299161>,
42
+ # @last_day=#<Date: 4887017/2,0,2299161>,
43
+ # @year=1977>
44
+ #
45
+ # year.first_day.to_s
46
+ # => "1977-01-01"
47
+ # pp year.weeks.first
48
+ #<DateUtils::Week:0xb7b37a60
49
+ # @date=#<Date: 4886289/2,0,2299161>,
50
+ # @first_day=#<Date: 4886279/2,0,2299161>,
51
+ # @last_day=#<Date: 4886291/2,0,2299161>,
52
+ # @month=
53
+ # #<DateUtils::Month:0xb7b37704
54
+ # @date=#<Date: 4886289/2,0,2299161>,
55
+ # @first_day=#<Date: 4886289/2,0,2299161>,
56
+ # @last_day=#<Date: 4886349/2,0,2299161>,
57
+ # @month=1,
58
+ # @num_days=31>,
59
+ # @num_week=53>
60
+ #
61
+ #
62
+ # year.distance_to_now_in_words
63
+ # => "29 years,10 months,5 days ago"
64
+ #
65
+ module DateUtils
66
+
67
+ # common to Year/Month/Week
68
+ #
69
+ module Common
70
+ include Comparable
71
+
72
+ # seconds in day
73
+ DAY = 86400
74
+ # seconds in week
75
+ WEEK = 604800
76
+ # seconds in month
77
+ MONTH = 2629743.83
78
+ # seconds in year
79
+ YEAR = 31556926
80
+
81
+ # named distance / singular / plural
82
+ #
83
+ def _words
84
+ { :year => ['year','years'],
85
+ :month => ['month','months'],
86
+ :week => ['week','weeks'],
87
+ :day => ['day', 'days'],
88
+ :same_day => ['less than a day']
89
+ }
90
+ end
91
+
92
+ # is given <date> included in self?
93
+ #
94
+ def include?(date)
95
+ if date.instance_of?(Date)
96
+ self.respond_to?('days') && self.days.include?(date)
97
+ else
98
+ raise ArgumentError, "need Date as input or no instance variable 'days'..."
99
+ end
100
+ end
101
+
102
+ # humanized time-distance to now of given instance
103
+ #
104
+ #
105
+ def distance_to_now_in_words
106
+ distance_in_words(Time.now)
107
+ end
108
+
109
+ # humanized time-distance to given date of given instance
110
+ #
111
+ # somewhen = DateUtils::Year.new(Date::parse('1977-10-18'))
112
+ # pp somewhen
113
+ # #<DateUtils::Year:0x2b637dbb0880
114
+ # @date=#<Date: 4886869/2,0,2299161>,
115
+ # @first_day=#<Date: 4886289/2,0,2299161>,
116
+ # @last_day=#<Date: 4887017/2,0,2299161>,
117
+ # @year=1977>
118
+ #
119
+ # somewhen.distance_to_now_in_words
120
+ # => "29 years,10 months,5 days ago"
121
+ #
122
+ def distance_in_words(date)
123
+ _to_time = nil
124
+ if date.kind_of?(Year) || date.kind_of?(Month) || date.kind_of?(Week) || date.kind_of?(Day)
125
+ _to_time = Time.parse(date.date.ctime)
126
+ elsif date.kind_of?(Date) || date.kind_of?(DateTime)
127
+ _to_time = Time.parse(date.ctime)
128
+ elsif date.kind_of?(Time)
129
+ _to_time = date
130
+ else
131
+ raise ArgumentError.new("date needs to be instance of DateUtls::Year|Month|Week|Day or Date|DateTime|Time")
132
+ end
133
+ _from_time = Time.parse(self.date.ctime)
134
+ return make_words_of(_from_time, _to_time)
135
+ end
136
+
137
+ # is this one 'later' than the other?
138
+ # makes DateUtils:: sortable
139
+ # expects Year || Month || Week || Day
140
+ #
141
+ def <=>(another)
142
+ begin
143
+ date <=> another.date
144
+ rescue NoMethodError => e
145
+ raise ArgumentError.new("<another> does not respond to 'date' / #{e.to_s}")
146
+ end
147
+ end
148
+
149
+ private
150
+
151
+ def self.extract_options_from_args!(args)
152
+ options = args.last.is_a?(Hash) ? args.pop : {}
153
+ options
154
+ end
155
+
156
+ # verbose 'tell' the distance
157
+ #
158
+ def make_words_of(from,to)
159
+ postfix = to.to_i > from.to_i ? 'ago' : 'in future'
160
+ left = to.to_i - from.to_i
161
+ if left < DAY
162
+ return _words[:same_day][0] + " " + postfix
163
+ end
164
+ years = left/YEAR >= 1 ? (left/YEAR).to_i : nil
165
+ left = left - (YEAR*years) unless years.nil?
166
+ months = left/MONTH >= 1 ? (left/MONTH).to_i : nil
167
+ left = left - (MONTH*months) unless months.nil?
168
+ weeks = left/WEEK >= 1 ? (left/WEEK).to_i : nil
169
+ left = left - (WEEK*weeks) unless weeks.nil?
170
+ days = left/DAY >= 1 ? (left/DAY).to_i : nil
171
+ arr = []
172
+ arr.push( years > 1 ? "#{years} #{_words[:year][1]}" : "#{years} #{_words[:year][0]}" ) if years
173
+ arr.push( months > 1 ? "#{months} #{_words[:month][1]}" : "#{months} #{_words[:month][0]}") if months
174
+ arr.push( weeks > 1 ? "#{weeks} #{_words[:week][1]}" : "#{weeks} #{_words[:week][0]}" ) if weeks
175
+ arr.push( days > 1 ? "#{days} #{_words[:day][1]}" : "#{days} #{_words[:day][0]}" ) if days
176
+ return arr.join(',') + " " + postfix
177
+ end
178
+
179
+ end
180
+
181
+
182
+ # represents a timezone
183
+ #
184
+ class GMTZone
185
+
186
+ # collection of String each representing a timezone
187
+ #
188
+ def GMTZone.offsets
189
+ arr = []
190
+ (-12..13).each do |i|
191
+ if i.to_s.include?('-')
192
+ i.to_s.length == 2 ? arr.push("GMT -0" + i.to_s.split('-')[-1].to_s + ":00") : arr.push("GMT " + i.to_s + ":00")
193
+ else
194
+ i.to_s.length == 1 ? arr.push("GMT +0" + i.to_s + ":00") : arr.push("GMT +" + i.to_s + ":00")
195
+ end
196
+ end
197
+ arr
198
+ end
199
+
200
+ end
201
+
202
+ # Represents a 'Week' beginning on Mondays and
203
+ # ending on Sundays
204
+ #
205
+ class Week
206
+ include Common
207
+
208
+ # the first day (Monday) of the week
209
+ attr_reader :first_day
210
+
211
+ # the last day (Sunday) of the week
212
+ attr_reader :last_day
213
+
214
+ # the num of the week
215
+ attr_reader :num_week
216
+
217
+ # the initial / regular Date instance
218
+ attr_reader :date
219
+
220
+ # the Month of the week
221
+ attr_reader :month
222
+
223
+ # create a new Week-instance with the given initial Date or Week-number
224
+ # if 'date' is nil, create an instance with Date.today
225
+ #
226
+ def initialize(val=nil)
227
+ if val.nil?
228
+ _date = Date.today
229
+ else
230
+ _date = val.is_a?(Date) ? val : (raise ArgumentError.new("neither Fixnum nor Date given."))
231
+ end
232
+ set_date(_date)
233
+ create_instance_variables
234
+ end
235
+
236
+ # create a Week-instance
237
+ # call with hash: year and week
238
+ # :call-seq:
239
+ # Week.create(:year => x, :week => y)
240
+ # Week.create(:week => x)
241
+ # Week.create(:year => x)
242
+ #
243
+ def self.create(*args)
244
+ options = Common::extract_options_from_args!(args)
245
+ year_date = options.has_key?(:year) ? Date::civil(options[:year].to_i, 1,1) : Date.today
246
+ unless options.has_key?(:week) && !options[:week].nil?
247
+ return Week.new(year_date)
248
+ end
249
+ return Year.new(year_date).get_week(options[:week].to_i)
250
+ end
251
+
252
+ # return new Week -instance one week after self
253
+ #
254
+ def next
255
+ return Week.new(@last_day + 1)
256
+ end
257
+
258
+ # returns new Week -instance one week before self
259
+ #
260
+ def previous
261
+ return Week.new(@first_day - 1)
262
+ end
263
+
264
+ # returns collection of days as Date -instances
265
+ #
266
+ def days
267
+ arr = []
268
+ @first_day.upto(@last_day) { |date| arr << date }
269
+ arr
270
+ end
271
+
272
+ private
273
+
274
+ # prepare instance variables
275
+ #
276
+ def create_instance_variables
277
+ @month = Month.new(@date)
278
+ @num_week = @date.cweek
279
+ @first_day = @date - ( @date.cwday - 1 )
280
+ @last_day = @date + ( 7 - @date.cwday )
281
+ end
282
+
283
+ # set base-date for self
284
+ #
285
+ def set_date(date)
286
+ @date = date
287
+ end
288
+
289
+ end
290
+
291
+ # Represents a 'Day'
292
+ # future usage to supply 'attributes' - e.g. calendar-events...
293
+ #
294
+ class Day
295
+ attr_reader :date
296
+
297
+ def initialize(date=nil)
298
+ @date = date || Date.today
299
+ end
300
+
301
+ end
302
+
303
+ # Represents a 'Month'
304
+ #
305
+ class Month
306
+ include Common
307
+
308
+ # the initial / regular Date instance
309
+ attr_reader :date
310
+
311
+ # the first day of the Month -instance
312
+ attr_reader :first_day
313
+
314
+ # the last day of the Month -instance
315
+ attr_reader :last_day
316
+
317
+ # the Month -number
318
+ attr_reader :month
319
+
320
+ # the number of days in Month
321
+ attr_reader :num_days
322
+
323
+ # create a new Month of given Date
324
+ #
325
+ def initialize(val=nil)
326
+ if val.nil?
327
+ _date = Date.today
328
+ else
329
+ if val.is_a?(Date)
330
+ _date = val
331
+ elsif val.is_a?(Fixnum) && val <= 12
332
+ _date = Date::civil(Date.today.year.to_i,val,1)
333
+ else
334
+ raise ArgumentError.new("neither Fixnum nor Date given.")
335
+ end
336
+ end
337
+ @date = _date
338
+ create_instance_variables
339
+ end
340
+
341
+ # create a Month-instance
342
+ # call with hash: year and month
343
+ # :call-seq:
344
+ # Month.create(:year => x, :month => y)
345
+ # Month.create(:month => x)
346
+ # Month.create(:year => x)
347
+ #
348
+ def self.create(*args)
349
+ options = Common::extract_options_from_args!(args)
350
+ int_year = options.has_key?(:year) && options[:year].is_a?(Fixnum) ? options[:year] : nil
351
+ int_month = options.has_key?(:month) && options[:month].is_a?(Fixnum) && options[:month] <= 12 ? options[:month] : nil
352
+ return Month.new(Date::civil(int_year || Date.today.year, int_month || 1))
353
+ end
354
+
355
+ # returns new Month -instance one Month later than self
356
+ #
357
+ def next
358
+ return Month.new(@last_day + 1)
359
+ end
360
+
361
+ # returns a new Month -instance one Month prior to self
362
+ #
363
+ def previous
364
+ return Month.new((@first_day - 1).to_date)
365
+ end
366
+
367
+ # returns collection of days as Date -instances of self
368
+ #
369
+ def days
370
+ arr = []
371
+ @first_day.upto(@last_day) { |date| arr << date }
372
+ arr
373
+ end
374
+
375
+ private
376
+
377
+ def set_date(date)
378
+ @date = date
379
+ end
380
+
381
+ def create_instance_variables
382
+ @month = @date.month
383
+ @first_day = @date.mday > 1 ? (@date - ( @date.mday - 1)) : @date
384
+ @num_days = 31 if [1,3,5,7,8,10,12].include?(@month)
385
+ @num_days = 30 if [4,6,9,11].include?(@month)
386
+ ( date.leap? ? (@num_days = 29) : (@num_days = 28) ) if @month == 2
387
+ @last_day = @first_day + ( @num_days - 1 )
388
+ end
389
+
390
+ end
391
+
392
+ # represents a Year
393
+ #
394
+ class Year
395
+ include Common
396
+
397
+ # the initial Date of the Year -instance
398
+ attr_reader :date
399
+
400
+ # the Year as an Integer of self
401
+ attr_reader :year
402
+
403
+ # first day of this year
404
+ attr_reader :first_day
405
+
406
+ # last day of this year
407
+ attr_reader :last_day
408
+
409
+ # create a new Year -instance with given Date
410
+ #
411
+ def initialize(date=nil)
412
+ date = Date.today if date.nil?
413
+ unless date.kind_of?(Date)
414
+ raise ArgumentError, "needs Date as input!"
415
+ end
416
+ @year = date.year
417
+ @date = date
418
+ @first_day = Date::parse("#{@year}-01-01")
419
+ @last_day = Date::parse("#{@year}-12-31")
420
+ end
421
+
422
+ # create a Year-instance
423
+ # call with hash: year
424
+ # :call-seq:
425
+ # Year.create(:year => x)
426
+ #
427
+ def self.create(*args)
428
+ options = Common::extract_options_from_args!(args)
429
+ date_year = options.has_key?(:year) ? Date.civil(options[:year]) : (raise ArgumentError.new("no key :year in hash."))
430
+ return Year.new(date_year)
431
+ end
432
+
433
+ # returns collection of Month -instances of self
434
+ #
435
+ def months
436
+ arr = []
437
+ for i in 1..12
438
+ arr.push( Month.new(Date.civil(@year,i) ) )
439
+ end
440
+ arr
441
+ end
442
+
443
+ # returns collection of Week -instances of self
444
+ # neccessarily overlaps year boundarys
445
+ #
446
+ def weeks
447
+ d = Date.civil(@year)
448
+ arr = []
449
+ week = Week.new(d)
450
+ arr.push(week)
451
+ for i in 1..52
452
+ week = week.next
453
+ arr.push(week)
454
+ end
455
+ arr
456
+ end
457
+
458
+ # returns Week 'num' of self
459
+ #
460
+ def get_week(num)
461
+ ! num.kind_of?(Fixnum) || num > 52 ? ArgumentError.new("invalid week-number 'num'"): self.weeks[num -1]
462
+ end
463
+
464
+ # returns Month 'num' of self
465
+ #
466
+ def get_month(num)
467
+ ! num.kind_of?(Fixnum) || num > 12 ? ArgumentError.new("invalid week-number 'num'"): self.months[num-1]
468
+ end
469
+
470
+ # returns new Year instance one year later
471
+ #
472
+ def next
473
+ begin
474
+ return Year.new(Date::parse("#{@date.to_s.split('-')[0].to_i + 1}-#{@date.month}-#{@date.day}"))
475
+ rescue ArgumentError => e
476
+ return Year.new(Date::parse("#{@date.to_s.split('-')[0].to_i + 1}-#{@date.month}-#{@date.day - 1}"))
477
+ end
478
+ end
479
+
480
+ # returns new Year instance one year previous
481
+ #
482
+ def previous
483
+ begin
484
+ return Year.new(Date::parse("#{@date.to_s.split('-')[0].to_i - 1}-#{@date.month}-#{@date.day}"))
485
+ rescue ArgumentError => e
486
+ return Year.new(Date::parse("#{@date.to_s.split('-')[0].to_i - 1}-#{@date.month}-#{@date.day - 1}"))
487
+ end
488
+ end
489
+ end
490
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.3
3
+ specification_version: 1
4
+ name: DateUtils
5
+ version: !ruby/object:Gem::Version
6
+ version: "0.3"
7
+ date: 2007-08-23 00:00:00 +02:00
8
+ summary: Some handy utils to deal with Date
9
+ require_paths:
10
+ - lib
11
+ email: rene@so36.net
12
+ homepage: http://rcms.oopen.de
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: date_utils
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Rene Paulokat
31
+ files:
32
+ - lib/date_utils.rb
33
+ - README
34
+ test_files: []
35
+
36
+ rdoc_options: []
37
+
38
+ extra_rdoc_files:
39
+ - README
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ requirements: []
45
+
46
+ dependencies: []
47
+