DateUtils 0.3

Sign up to get free protection for your applications and to get access to all the features.
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
+