datet 0.0.0

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/lib/datet.rb ADDED
@@ -0,0 +1,1102 @@
1
+ #This class handels various time- and date-specific behaviour in a friendly way.
2
+ #===Examples
3
+ # datet = Datet.new #=> 2012-05-03 20:35:16 +0200
4
+ # datet = Datet.new(Time.now) #=> 2012-05-03 20:35:16 +0200
5
+ # datet.months + 5 #=> 2012-10-03 20:35:16 +0200
6
+ # datet.days + 64 #=> 2012-12-06 20:35:16 +010
7
+ class Datet
8
+ @@months_lcase = {
9
+ "jan" => 1,
10
+ "january" => 1,
11
+ "feb" => 2,
12
+ "february" => 2,
13
+ "mar" => 3,
14
+ "march" => 3,
15
+ "apr" => 4,
16
+ "april" => 4,
17
+ "may" => 5,
18
+ "jun" => 6,
19
+ "june" => 6,
20
+ "jul" => 7,
21
+ "july" => 7,
22
+ "aug" => 8,
23
+ "august" => 8,
24
+ "sep" => 9,
25
+ "september" => 9,
26
+ "oct" => 10,
27
+ "october" => 11,
28
+ "nov" => 11,
29
+ "november" => 11,
30
+ "dec" => 12,
31
+ "december" => 12
32
+ }
33
+
34
+ #Initializes the object. Default is the current time. A time-object can be given.
35
+ def initialize(time = Time.now, *args)
36
+ if time.is_a?(Time)
37
+ self.update_from_time(time)
38
+ else
39
+ begin
40
+ time = Time.new(*([time] | args))
41
+ self.update_from_time(time)
42
+ rescue ArgumentError => e
43
+ days_left = 0
44
+ months_left = 0
45
+ hours_left = 0
46
+ mins_left = 0
47
+ secs_left = 0
48
+ usecs_left = 0
49
+
50
+ #Check larger month the allowed.
51
+ if args[0] and args[0] > 12
52
+ months_left = args[0] - 12
53
+ args[0] = 12
54
+ end
55
+
56
+ #Check larger date than allowed.
57
+ datet = Datet.new(time, args[0], 1)
58
+ dim = datet.days_in_month
59
+
60
+ if args[1] and args[1] > dim
61
+ days_left = args[1] - dim
62
+ args[1] = dim if days_left > 0
63
+ end
64
+
65
+ #Check larger hour than allowed.
66
+ if args[2] and args[2] >= 24
67
+ hours_left = args[2] + 1
68
+ args[2] = 0
69
+ end
70
+
71
+ #Check larger minute than allowed.
72
+ if args[3] and args[3] >= 60
73
+ mins_left = args[3] + 1
74
+ args[3] = 0
75
+ end
76
+
77
+ #Check larger secs than allowed.
78
+ if args[4] and args[4] >= 60
79
+ secs_left = args[4] + 1
80
+ args[4] = 0
81
+ end
82
+
83
+ #Check larger usecs than allowed.
84
+ if args[5] and args[5] >= 60
85
+ usecs_left = args[5] + 1
86
+ args[5] = 0
87
+ end
88
+
89
+ #Generate new stamp.
90
+ time = Time.new(*([time] | args))
91
+ self.update_from_time(time)
92
+
93
+ self.mins + mins_left if mins_left > 0
94
+ self.hours + hours_left if hours_left > 0
95
+ self.days + days_left if days_left > 0
96
+ self.months + months_left if months_left > 0
97
+ self.secs + secs_left if secs_left > 0
98
+ self.usecs + usecs_left if usecs_left > 0
99
+ end
100
+ end
101
+ end
102
+
103
+ #Updates the current variables to the given time.
104
+ #===Examples
105
+ # datet.update_from_time(Time.now)
106
+ def update_from_time(time)
107
+ @t_year = time.year
108
+ @t_month = time.month
109
+ @t_day = time.day
110
+ @t_hour = time.hour
111
+ @t_min = time.min
112
+ @t_sec = time.sec
113
+ @t_usec = time.usec
114
+
115
+ nil
116
+ end
117
+
118
+ #Returns a new Time-object based on the data of the Datet-object.
119
+ def time
120
+ return Time.new(@t_year, @t_month, @t_day, @t_hour, @t_min, @t_sec)
121
+ end
122
+
123
+ #Goes forward day-by-day and stops at a date matching the criteria given.
124
+ #
125
+ #===Examples
126
+ # datet.time #=> 2012-05-03 19:36:08 +0200
127
+ #
128
+ #Try to find next saturday.
129
+ # datet.find(:day, :day_in_week => 5) #=> 2012-05-05 19:36:08 +0200
130
+ #
131
+ #Try to find next wednesday by Time's wday-method.
132
+ # datet.find(:day, :wday => 3) #=> 2012-05-09 19:36:08 +0200
133
+ def find(incr, args)
134
+ count = 0
135
+ while true
136
+ if args[:day_in_week] and self.day_in_week == args[:day_in_week]
137
+ return self
138
+ elsif args[:wday] and self.time.wday == args[:wday].to_i
139
+ return self
140
+ end
141
+
142
+ if incr == :day
143
+ self.add_days(1)
144
+ elsif incr == :month
145
+ self.add_months(1)
146
+ else
147
+ raise "Invalid increment: #{incr}."
148
+ end
149
+
150
+ count += 1
151
+ raise "Endless loop?" if count > 999
152
+ end
153
+ end
154
+
155
+ #Add a given amount of seconds to the object.
156
+ def add_usecs(usecs = 1)
157
+ usecs = usecs.to_i
158
+ cur_usecs = @t_usec
159
+ next_usec = cur_usecs + usecs
160
+
161
+ if next_usec >= 60
162
+ @t_usec = 0
163
+ self.add_secs(1)
164
+ usecs_left = (usecs - 1) - (60 - cur_usecs)
165
+ self.add_usecs(usecs_left) if usecs_left > 0
166
+ elsif next_usec < 0
167
+ @t_usec = 59
168
+ self.add_secs(-1)
169
+ usecs_left = usecs + cur_usecs + 1
170
+ self.add_usecs(usecs_left) if usecs_left > 0
171
+ else
172
+ time = self.stamp(:datet => false, :usec => next_usec)
173
+ end
174
+
175
+ return self
176
+ end
177
+
178
+ #Add a given amount of seconds to the object.
179
+ def add_secs(secs = 1)
180
+ secs = secs.to_i
181
+ cur_secs = @t_sec
182
+ next_sec = cur_secs + secs
183
+
184
+ if next_sec >= 60
185
+ @t_sec = 0
186
+ self.add_mins(1)
187
+ secs_left = (secs - 1) - (60 - cur_secs)
188
+ return self.add_secs(secs_left) if secs_left > 0
189
+ elsif next_sec < 0
190
+ @t_sec = 59
191
+ self.add_mins(-1)
192
+ secs_left = secs + cur_secs + 1
193
+ self.add_secs(secs_left) if secs_left > 0
194
+ else
195
+ @t_sec = next_sec
196
+ end
197
+
198
+ return self
199
+ end
200
+
201
+ #Add a given amount of minutes to the object.
202
+ #===Examples
203
+ # datet = Datet.new #=> 2012-05-03 17:39:45 +0200
204
+ # datet.add_mins(30)
205
+ # datet.time #=> 2012-05-03 18:08:45 +0200
206
+ def add_mins(mins = 1)
207
+ mins = mins.to_i
208
+ cur_mins = @t_min
209
+ next_min = cur_mins + mins
210
+
211
+ if next_min >= 60
212
+ @t_min = 0
213
+ self.add_hours(1)
214
+ mins_left = (mins - 1) - (60 - cur_mins)
215
+ self.add_mins(mins_left) if mins_left > 0
216
+ elsif next_min < 0
217
+ @t_min = 59
218
+ self.add_hours(-1)
219
+ mins_left = mins + cur_mins + 1
220
+ self.add_mins(mins_left) if mins_left > 0
221
+ else
222
+ @t_min = next_min
223
+ end
224
+
225
+ return self
226
+ end
227
+
228
+ #Adds a given amount of hours to the object.
229
+ #===Examples
230
+ # datet = Datet.new
231
+ # datet.add_hours(2)
232
+ def add_hours(hours = 1)
233
+ hours = hours.to_i
234
+ cur_hour = @t_hour
235
+ next_hour = cur_hour + hours
236
+
237
+ if next_hour >= 24
238
+ @t_hour = 0
239
+ self.add_days(1)
240
+ hours_left = (hours - 1) - (24 - cur_hour)
241
+ self.add_hours(hours_left) if hours_left > 0
242
+ elsif next_hour < 0
243
+ @t_hour = 23
244
+ .add_days(-1)
245
+ hours_left = hours + cur_hour + 1
246
+ self.add_hours(hours_left) if hours_left < 0
247
+ else
248
+ @t_hour = next_hour
249
+ end
250
+
251
+ return self
252
+ end
253
+
254
+ #Adds a given amount of days to the object.
255
+ #===Examples
256
+ # datet = Datet.new #=> 2012-05-03 17:42:27 +0200
257
+ # datet.add_days(29)
258
+ # datet.time #=> 2012-06-01 17:42:27 +0200
259
+ def add_days(days = 1)
260
+ days = days.to_i
261
+ return self if days == 0
262
+ dim = self.days_in_month
263
+ cur_day = @t_day
264
+ next_day = cur_day + days
265
+
266
+ if next_day > dim
267
+ @t_day = 1
268
+ self.add_months(1)
269
+ days_left = (days - 1) - (dim - cur_day)
270
+ self.add_days(days_left) if days_left > 0
271
+ elsif next_day <= 0
272
+ self.date = 1
273
+ self.add_months(-1)
274
+
275
+ @t_day = self.days_in_month
276
+ days_left = days + 1
277
+ self.add_days(days_left) if days_left != 0
278
+ else
279
+ @t_day = next_day
280
+ end
281
+
282
+ return self
283
+ end
284
+
285
+ #Adds a given amount of months to the object.
286
+ #===Examples
287
+ # datet.time #=> 2012-06-01 17:42:27 +0200
288
+ # datet.add_months(2)
289
+ # datet.time #=> 2012-08-01 17:42:27 +0200
290
+ def add_months(months = 1)
291
+ months = months.to_i
292
+ cur_month = @t_month
293
+ cur_day = @t_day
294
+ next_month = cur_month + months.to_i
295
+
296
+ if next_month > 12
297
+ @t_month = 1
298
+ @t_day = 1
299
+ self.add_years(1)
300
+ months_left = (months - 1) - (12 - cur_month)
301
+ self.add_months(months_left) if months_left > 0
302
+ elsif next_month < 1
303
+ @t_month = 12
304
+ self.add_years(-1)
305
+ else
306
+ @t_month = next_month
307
+ @t_day = 1
308
+ end
309
+
310
+ dim = self.days_in_month
311
+
312
+ if dim < cur_day
313
+ @t_day = dim
314
+ else
315
+ @t_day = cur_day
316
+ end
317
+
318
+ return self
319
+ end
320
+
321
+ #Adds a given amount of years to the object.
322
+ #===Examples
323
+ # datet.time #=> 2012-08-01 17:42:27 +0200
324
+ # datet.add_years(3)
325
+ # datet.time #> 2014-08-01 17:42:27 +0200
326
+ def add_years(years = 1)
327
+ next_year = @t_year + years.to_i
328
+ @t_year = next_year
329
+ return self
330
+ end
331
+
332
+ #Is a year a leap year in the Gregorian calendar? Copied from Date-class.
333
+ #===Examples
334
+ # if Datet.gregorian_leap?(2005)
335
+ # print "2005 is a gregorian-leap year."
336
+ # else
337
+ # print "2005 is not a gregorian-leap year."
338
+ # end
339
+ def self.gregorian_leap?(y)
340
+ if Date.respond_to?(:gregorian_leap?)
341
+ return Date.gregorian_leap?(y)
342
+ elsif y % 4 == 0 && y % 100 != 0
343
+ return true
344
+ elsif y % 400 == 0
345
+ return true
346
+ else
347
+ return false
348
+ end
349
+ end
350
+
351
+ #Returns the number of days in the month.
352
+ #===Examples
353
+ # datet = Datet.new
354
+ # print "There are #{datet.days_in_month} days in the current month."
355
+ def days_in_month
356
+ return 29 if month == 2 and Datet.gregorian_leap?(self.year)
357
+
358
+ #Thanks to ActiveSupport: http://rubydoc.info/docs/rails/2.3.8/ActiveSupport/CoreExtensions/Time/Calculations
359
+ days_in_months = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
360
+ return days_in_months[@t_month]
361
+ end
362
+
363
+ #Returns the day in the week. Monday being 1 and sunday being 6.
364
+ def day_in_week
365
+ diw = self.time.strftime("%w").to_i
366
+ if diw == 0
367
+ diw = 6
368
+ else
369
+ diw -= 1
370
+ end
371
+
372
+ return diw
373
+ end
374
+
375
+ #Returns the days name as a string.
376
+ def day_name
377
+ return self.time.strftime("%A")
378
+ end
379
+
380
+ #Returns the months name as a string.
381
+ def month_name
382
+ return self.time.strftime("%B")
383
+ end
384
+
385
+ #Returns the year as an integer.
386
+ def year
387
+ return @t_year
388
+ end
389
+
390
+ #Returns the hour as an integer.
391
+ def hour
392
+ return @t_hour
393
+ end
394
+
395
+ #Returns the minute as an integer.
396
+ def min
397
+ return @t_min
398
+ end
399
+
400
+ #Returns the seconds as an integer.
401
+ def sec
402
+ return @t_sec
403
+ end
404
+
405
+ #Returns the microsecond as an integer.
406
+ def usec
407
+ return @t_usec
408
+ end
409
+
410
+ #Changes the year to the given year.
411
+ # datet = Datet.now #=> 2014-05-03 17:46:11 +0200
412
+ # datet.year = 2005
413
+ # datet.time #=> 2005-05-03 17:46:11 +0200
414
+ def year=(newyear)
415
+ @t_year = newyear.to_i
416
+ end
417
+
418
+ #Returns the month as an integer.
419
+ def month
420
+ Thread.current[:datet_mode] = :months
421
+ return @t_month
422
+ end
423
+
424
+ #Returns the day in month as an integer.
425
+ def date
426
+ Thread.current[:datet_mode] = :days
427
+ return @t_day
428
+ end
429
+
430
+ #Returns the weekday of the week as an integer. Monday being the first and sunday being the last.
431
+ def wday_mon
432
+ wday = self.time.wday
433
+ return 0 if wday == 6
434
+ return wday - 1
435
+ end
436
+
437
+ #Changes the date to a given date.
438
+ #===Examples
439
+ # datet.time #=> 2005-05-03 17:46:11 +0200
440
+ # datet.date = 8
441
+ # datet.time #=> 2005-05-08 17:46:11 +0200
442
+ def date=(newday)
443
+ newday = newday.to_i
444
+
445
+ if newday <= 0
446
+ self.add_days(newday - 1)
447
+ else
448
+ @t_day = newday
449
+ end
450
+
451
+ return self
452
+ end
453
+
454
+ #Changes the hour to a given new hour.
455
+ #===Examples
456
+ # datet.time #=> 2012-05-09 19:36:08 +0200
457
+ # datet.hour = 5
458
+ # datet.time #=> 2012-05-09 05:36:08 +0200
459
+ def hour=(newhour)
460
+ newhour = newhour.to_i
461
+ day = @t_day
462
+
463
+ loop do
464
+ break if newhour >= 0
465
+ day += -1
466
+ newhour += 24
467
+ end
468
+
469
+ loop do
470
+ break if newhour < 24
471
+ day += 1
472
+ newhour += -24
473
+ end
474
+
475
+ @t_hour = newhour
476
+
477
+ self.date = day if day != @t_day
478
+ return self
479
+ end
480
+
481
+ #Changes the minute to a given new minute.
482
+ #===Examples
483
+ # datet.time #=> 2012-05-09 05:36:08 +0200
484
+ # datet.min = 35
485
+ # datet.time #=> 2012-05-09 05:35:08 +0200
486
+ def min=(newmin)
487
+ @t_min = newmin.to_i
488
+ end
489
+
490
+ #Changes the second to a given new second.
491
+ #===Examples
492
+ # datet.time #=> 2012-05-09 05:35:08 +0200
493
+ # datet.sec = 20
494
+ # datet.time #=> 2012-05-09 05:35:20 +0200
495
+ def sec=(newsec)
496
+ @t_sec = newsec.to_i
497
+ end
498
+
499
+ alias :day :date
500
+
501
+ #Changes the month to a given new month.
502
+ #===Examples
503
+ # datet.time #=> 2012-05-09 05:35:20 +0200
504
+ # datet.month = 7
505
+ # datet.time #=> 2012-07-09 05:35:20 +0200
506
+ def month=(newmonth)
507
+ @t_month = newmonth
508
+ end
509
+
510
+ #Turns the given argument into a new Time-object.
511
+ #===Examples
512
+ # time = Datet.arg_to_time(datet) #=> <Time>-object
513
+ # time = Datet.arg_to_time(Time.now) #=> <Time>-object
514
+ def self.arg_to_time(datet)
515
+ if datet.is_a?(Datet)
516
+ return datet.time
517
+ elsif datet.is_a?(Time)
518
+ return datet
519
+ else
520
+ raise "Could not handle object of class: '#{datet.class.name}'."
521
+ end
522
+ end
523
+
524
+ include Comparable
525
+ def <=>(timeobj)
526
+ secs = Datet.arg_to_time(timeobj).to_i
527
+
528
+ if secs > self.to_i
529
+ return -1
530
+ elsif secs < self.to_i
531
+ return 1
532
+ else
533
+ return 0
534
+ end
535
+ end
536
+
537
+ #This method is used for adding values to the object based on the current set mode.
538
+ #===Examples
539
+ #Add two months to the datet.
540
+ # datet.months
541
+ # datet.add_something(2)
542
+ def add_something(val)
543
+ val = -val if Thread.current[:datet_addmode] == "-"
544
+ return self.add_years(val) if Thread.current[:datet_mode] == :years
545
+ return self.add_hours(val) if Thread.current[:datet_mode] == :hours
546
+ return self.add_days(val) if Thread.current[:datet_mode] == :days
547
+ return self.add_months(val) if Thread.current[:datet_mode] == :months
548
+ return self.add_mins(val) if Thread.current[:datet_mode] == :mins
549
+ return self.add_secs(val) if Thread.current[:datet_mode] == :secs
550
+ return self.add_usecs(val) if Thread.current[:datet_mode] == :usecs
551
+ raise "No such mode: '#{Thread.current[:datet_mode]}'."
552
+ end
553
+
554
+ #Minus something.
555
+ #===Examples
556
+ # datet.months - 5
557
+ # datet.years - 2
558
+ def -(val)
559
+ Thread.current[:datet_addmode] = "-"
560
+ self.add_something(val)
561
+ end
562
+
563
+ #Add something.
564
+ #===Examples
565
+ # datet.months + 5
566
+ # datet.months + 2
567
+ def +(val)
568
+ Thread.current[:datet_addmode] = "+"
569
+ self.add_something(val)
570
+ end
571
+
572
+ #Sets the mode to hours and gets ready to plus or minus.
573
+ #===Examples
574
+ # datet.time #=> 2005-05-08 17:46:11 +0200
575
+ # datet.hours + 5
576
+ # datet.time #=> 2005-05-08 22:46:11 +0200
577
+ def hours
578
+ Thread.current[:datet_mode] = :hours
579
+ return self
580
+ end
581
+
582
+ #Sets the mode to minutes and gets ready to plus or minus.
583
+ #===Examples
584
+ # datet.time #=> 2005-05-08 22:46:11 +0200
585
+ # datet.mins + 5
586
+ # datet.mins #=> 2005-05-08 22:51:11 +0200
587
+ def mins
588
+ Thread.current[:datet_mode] = :mins
589
+ return self
590
+ end
591
+
592
+ #Sets the mode to seconds and gets ready to plus or minus.
593
+ def secs
594
+ Thread.current[:datet_mode] = :secs
595
+ return self
596
+ end
597
+
598
+ #Sets the mode to mili-seconds and gets ready to plus or minus.
599
+ def usecs
600
+ Thread.current[:datet_mode] = :usecs
601
+ return self
602
+ end
603
+
604
+ #Sets the mode to days and gets ready to plus or minus.
605
+ #===Examples
606
+ # datet.time #=> 2005-05-08 22:51:11 +0200
607
+ # datet.days + 26
608
+ # datet.time #=> 2005-06-03 22:51:11 +0200
609
+ def days
610
+ Thread.current[:datet_mode] = :days
611
+ return self
612
+ end
613
+
614
+ #Sets the mode to months and gets ready to plus or minus.
615
+ #===Examples
616
+ # datet.time #=> 2005-06-03 22:51:11 +0200
617
+ # datet.months + 14
618
+ # datet.time #=> 2006-08-01 22:51:11 +0200
619
+ def months
620
+ Thread.current[:datet_mode] = :months
621
+ return self
622
+ end
623
+
624
+ #Sets the mode to years and gets ready to plus or minus.
625
+ #===Examples
626
+ # datet.time #=> 2006-08-01 22:51:11 +0200
627
+ # datet.years + 5
628
+ # datet.time #=> 2011-08-01 22:51:11 +0200
629
+ def years
630
+ Thread.current[:datet_mode] = :years
631
+ return self
632
+ end
633
+
634
+ #Returns a new Datet- or Time-object based on the arguments.
635
+ #===Examples
636
+ # time = datet.stamp(:datet => false, :min => 15, :day => 5) #=> 2012-07-05 05:15:20 +0200
637
+ def stamp(args)
638
+ vars = {:year => @t_year, :month => @t_month, :day => @t_day, :hour => @t_hour, :min => @t_min, :sec => @t_sec, :usec => @t_usec}
639
+
640
+ args.each do |key, value|
641
+ vars[key.to_sym] = value.to_i if key != :datet
642
+ end
643
+
644
+ time = Time.local(vars[:year], vars[:month], vars[:day], vars[:hour], vars[:min], vars[:sec], vars[:usec])
645
+
646
+ if !args.key?(:datet) or args[:datet]
647
+ return Datet.new(time)
648
+ end
649
+
650
+ return time
651
+ end
652
+
653
+ #Returns the time as a database-valid string.
654
+ #===Examples
655
+ # datet.time #=> 2011-08-01 22:51:11 +0200
656
+ # datet.dbstr #=> "2011-08-01 22:51:11"
657
+ # datet.dbstr(:time => false) #=> "2011-08-01"
658
+ def dbstr(args = {})
659
+ str = "#{"%04d" % @t_year}-#{"%02d" % @t_month}-#{"%02d" % @t_day}"
660
+
661
+ if !args.key?(:time) or args[:time]
662
+ str << " #{"%02d" % @t_hour}:#{"%02d" % @t_min}:#{"%02d" % @t_sec}"
663
+ end
664
+
665
+ return str
666
+ end
667
+
668
+ #Parses the date from a database-format.
669
+ #===Examples
670
+ # datet = Datet.from_dbstr("2011-08-01 22:51:11")
671
+ # datet.time #=> 2011-08-01 22:51:11 +0200
672
+ def self.from_dbstr(date_string)
673
+ if date_string.is_a?(Time)
674
+ return Datet.new(date_string)
675
+ elsif date_string.is_a?(Date)
676
+ return Datet.new(date_string.to_time)
677
+ end
678
+
679
+ return false if Datet.is_nullstamp?(date_string)
680
+ return Datet.new(Time.local(*Date.parse(date_string.to_s)))
681
+ end
682
+
683
+ #Alias for 'from_dbstr'.
684
+ def self.parse(str)
685
+ return Datet.from_dbstr(str)
686
+ end
687
+
688
+ #Returns true of the given stamp is a 'nullstamp'.
689
+ #===Examples
690
+ # Datet.is_nullstamp?("0000-00-00") #=> true
691
+ # Datet.is_nullstamp?("0000-00-00 00:00:00") #=> true
692
+ # Datet.is_nullstamp?("") #=> true
693
+ # Datet.is_nullstamp?("1985-06-17") #=> false
694
+ def self.is_nullstamp?(stamp)
695
+ return true if !stamp or stamp == "0000-00-00" or stamp == "0000-00-00 00:00:00" or stamp.to_s.strip == ""
696
+ return false
697
+ end
698
+
699
+ #Returns the day of the year (0-365) as an integer.
700
+ #===Examples
701
+ # Datet.new.day_of_year #=> 123
702
+ def day_of_year
703
+ return self.time.strftime("%j").to_i
704
+ end
705
+
706
+ #Returns the day as a localized string.
707
+ #===Examples
708
+ # Datet.new.day_str #=> "Monday"
709
+ # Datet.new.day_str(:short => true) #=> "Mon"
710
+ def day_str(args = nil)
711
+ ret = Datet.days_arr[self.time.strftime("%w").to_i]
712
+ if args.is_a?(Hash) and args[:short]
713
+ ret = ret.slice(0, 3)
714
+ end
715
+
716
+ return ret
717
+ end
718
+
719
+ #Returns how many days there is between the two timestamps given as an integer.
720
+ #===Examples
721
+ # d1 = Datet.new #=> 2012-05-03 18:04:12 +0200
722
+ # d2 = Datet.new #=> 2012-05-03 18:04:16 +0200
723
+ # d2.months + 5 #=> 2012-10-03 18:04:16 +0200
724
+ # Datet.days_between(d1, d2) #=> 153
725
+ def self.days_between(t1, t2)
726
+ raise "Timestamp 2 should be larger than timestamp 1." if t2 < t1
727
+
728
+ doy1 = t1.day_of_year
729
+ doy2 = t2.day_of_year
730
+
731
+ yot1 = t1.year
732
+ yot2 = t2.year
733
+
734
+ if yot1 == yot2
735
+ days_between = doy2 - doy1
736
+ return days_between
737
+ end
738
+
739
+ upto = 365 - doy1
740
+ after = doy2
741
+
742
+ return upto + after
743
+ end
744
+
745
+ #Returns a string based on the date and time.
746
+ #===Examples
747
+ # datet.out #=> "03/05 2012 - 18:04"
748
+ # datet.out(:time => false) #=> "03/05 2012"
749
+ # datet.out(:date => false) #=> "18:04"
750
+ def out(args = {})
751
+ str = ""
752
+ date_shown = false
753
+ time_shown = false
754
+
755
+ if !args.key?(:date) or args[:date]
756
+ date_shown = true
757
+ str << "#{"%02d" % @t_day}/#{"%02d" % @t_month}"
758
+
759
+ if !args.key?(:year) or args[:year]
760
+ str << " #{"%04d" % @t_year}"
761
+ end
762
+ end
763
+
764
+ if !args.key?(:time) or args[:time]
765
+ show_time = true
766
+
767
+ if args.key?(:zerotime) and !args[:zerotime]
768
+ if @t_hour == 0 and @t_min == 0
769
+ show_time = false
770
+ end
771
+ end
772
+
773
+ if show_time
774
+ time_shown = true
775
+ str << " - " if date_shown
776
+ str << "#{"%02d" % @t_hour}:#{"%02d" % @t_min}"
777
+ end
778
+ end
779
+
780
+ return str
781
+ end
782
+
783
+ #Parses various objects into Datet-objects.
784
+ #===Examples
785
+ # datet = Datet.in("1985-06-17") #=> 1985-06-17 00:00:00 +0200
786
+ # datet = Datet.in("1985-06-17 10:00:00") #=> 1985-06-17 10:00:00 +0200
787
+ # datet = Datet.in("17/06 1985 10:00") #=> 1985-06-17 10:00:00 +0200
788
+ def self.in(timestr)
789
+ if timestr.is_a?(Time)
790
+ return Datet.new(timestr)
791
+ elsif timestr.is_a?(Date)
792
+ return Datet.new(timestr.to_time)
793
+ elsif timestr.is_a?(Datet)
794
+ return timestr
795
+ end
796
+
797
+ if match = timestr.to_s.match(/^(\d+)\/(\d+) (\d+)/)
798
+ #MySQL date format
799
+ timestr = timestr.gsub(match[0], "")
800
+ date = match[1]
801
+ month = match[2]
802
+ year = match[3]
803
+
804
+ if match = timestr.match(/\s*(\d+):(\d+)/)
805
+ #MySQL datetime format
806
+ timestr = timestr.gsub(match[0], "")
807
+ hour = match[1]
808
+ minute = match[2]
809
+ end
810
+
811
+ return Datet.new(Time.local(year, month, date, hour, minute))
812
+ elsif match = timestr.to_s.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/)
813
+ return Datet.new(Time.local(match[3], match[2], match[1]))
814
+ elsif match = timestr.to_s.match(/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{5,6})$/)
815
+ #Datet.code format
816
+ return Datet.new(Time.local(match[1], match[2], match[3], match[4], match[5], match[6], match[7]))
817
+ elsif match = timestr.to_s.match(/^\s*(\d{4})-(\d{1,2})-(\d{1,2})(|\s+(\d{2}):(\d{2}):(\d{2})(|\.\d+)\s*)(|\s+(UTC))(|\s+(\+|\-)(\d{2})(\d{2}))$/)
818
+ #Database date format (with possibility of .0 in the end - microseconds? -knj.
819
+
820
+ if match[11] and match[13] and match[14]
821
+ if match[12] == "+" or match[12] == "-"
822
+ sign = match[12]
823
+ else
824
+ sign = "+"
825
+ end
826
+
827
+ utc_str = "#{sign}#{match[13]}:#{match[14]}"
828
+ elsif match[8]
829
+ utc_str = match[8].to_i
830
+ else
831
+ utc_str = nil
832
+ end
833
+
834
+ time = Time.local(match[1].to_i, match[2].to_i, match[3].to_i, match[5].to_i, match[6].to_i, match[7].to_i, utc_str)
835
+ return Datet.new(time)
836
+ elsif match = timestr.to_s.match(/^\s*(\d{2,4})-(\d{1,2})-(\d{1,2})(|\s+(\d{1,2}):(\d{1,2}):(\d{1,2})(:(\d{1,2})|)\s*)$/)
837
+ time = Time.local(match[1].to_i, match[2].to_i, match[3].to_i, match[5].to_i, match[6].to_i, match[7].to_i)
838
+ return Datet.new(time)
839
+ end
840
+
841
+ raise Knj::Errors::InvalidData.new("Wrong format: '#{timestr}', class: '#{timestr.class.name}'")
842
+ end
843
+
844
+ #Returns a hash with the month-no as key and month-name as value. It uses the method "_" to translate the months names. So GetText or another method has to be defined.
845
+ def self.months_arr(args = {})
846
+ ret = {
847
+ 1 => _("January"),
848
+ 2 => _("February"),
849
+ 3 => _("March"),
850
+ 4 => _("April"),
851
+ 5 => _("May"),
852
+ 6 => _("June"),
853
+ 7 => _("July"),
854
+ 8 => _("August"),
855
+ 9 => _("September"),
856
+ 10 => _("October"),
857
+ 11 => _("November"),
858
+ 12 => _("December")
859
+ }
860
+
861
+ if args["short"]
862
+ ret_short = {}
863
+ ret.each do |key, val|
864
+ ret_short[key] = val[0..2]
865
+ end
866
+
867
+ return ret_short
868
+ end
869
+
870
+ return ret
871
+ end
872
+
873
+ #Returns a hash with the day-number as value (starting with 1 for monday). It uses the method "_" to translate the months names.
874
+ def self.days_arr(args = {})
875
+ ret = {
876
+ 1 => _("Monday"),
877
+ 2 => _("Tuesday"),
878
+ 3 => _("Wednesday"),
879
+ 4 => _("Thursday"),
880
+ 5 => _("Friday"),
881
+ 6 => _("Saturday"),
882
+ 0 => _("Sunday")
883
+ }
884
+
885
+ if args["short"]
886
+ ret_short = {}
887
+ ret.each do |key, val|
888
+ ret_short[key] = val[0..2]
889
+ end
890
+
891
+ return ret_short
892
+ end
893
+
894
+ return ret
895
+ end
896
+
897
+ #Returns the month-number for a given string (starting with 1 for january).
898
+ #===Examples
899
+ # Datet.month_str_to_no("JaNuArY") #=> 1
900
+ # Datet.month_str_to_no("DECEMBER") #=> 12
901
+ # Datet.month_str_to_no("kasper") #=> <Error>-raised
902
+ def self.month_str_to_no(str)
903
+ str = str.to_s.downcase.strip
904
+ return @@months_lcase[str] if @@months_lcase.key?(str)
905
+ raise "No month to return from that string: '#{str}'."
906
+ end
907
+
908
+ def loc_wday
909
+ return _(self.time.strftime("%A"))
910
+ end
911
+
912
+ def loc_wday_small
913
+ return _(self.time.strftime("%a"))
914
+ end
915
+
916
+ def loc_month
917
+ return _(self.time.strftime("%B"))
918
+ end
919
+
920
+ def to_s
921
+ return self.time.to_s
922
+ end
923
+
924
+ #This returns a code-string that can be used to recreate the Datet-object.
925
+ #===Examples
926
+ # code = datet.code #=> "1985061710000000000"
927
+ # newdatet = Datet.in(code) #=> 1985-06-17 10:00:00 +0200
928
+ def code
929
+ return "#{"%04d" % @t_year}#{"%02d" % @t_month}#{"%02d" % @t_day}#{"%02d" % @t_hour}#{"%02d" % @t_min}#{"%02d" % @t_sec}#{"%05d" % @t_usec}"
930
+ end
931
+
932
+ #Returns the unix timestamp for this object.
933
+ #===Examples
934
+ # datet.unixt #=> 487843200
935
+ # datet.to_i #=> 487843200
936
+ def unixt
937
+ return self.time.to_i
938
+ end
939
+
940
+ alias :to_i :unixt
941
+
942
+ #Returns the HTTP-date that can be used in headers and such.
943
+ #===Examples
944
+ # datet.httpdate #=> "Mon, 17 Jun 1985 08:00:00 GMT"
945
+ def httpdate
946
+ require "time"
947
+ return self.time.httpdate
948
+ end
949
+
950
+ #Returns various information about the offset as a hash.
951
+ #===Examples
952
+ # datet.time #=> 1985-06-17 10:00:00 +0200
953
+ # datet.offset_info #=> {:sign=>"+", :hours=>2, :mins=>0, :secs=>0}
954
+ def offset_info
955
+ offset_secs = self.time.gmt_offset
956
+
957
+ offset_hours = (offset_secs.to_f / 3600.0).floor
958
+ offset_secs -= offset_hours * 3600
959
+
960
+ offset_minutes = (offset_secs.to_f / 60.0).floor
961
+ offset_secs -= offset_minutes * 60
962
+
963
+ if offset_hours > 0
964
+ sign = "+"
965
+ else
966
+ sign = ""
967
+ end
968
+
969
+ return {
970
+ :sign => sign,
971
+ :hours => offset_hours,
972
+ :mins => offset_minutes,
973
+ :secs => offset_secs
974
+ }
975
+ end
976
+
977
+ #Returns the offset as a string.
978
+ #===Examples
979
+ # datet.offset_str #=> "+0200"
980
+ def offset_str
981
+ offset_info_data = self.offset_info
982
+ return "#{offset_info_data[:sign]}#{"%02d" % offset_info_data[:hours]}#{"%02d" % offset_info_data[:mins]}"
983
+ end
984
+
985
+ #Returns 'localtime' as of 1.9 - even in 1.8 which does it different.
986
+ #===Examples
987
+ # datet.localtime_str #=> "1985-06-17 10:00:00 +0200"
988
+ def localtime_str
989
+ return "#{"%04d" % @t_year}-#{"%02d" % @t_month}-#{"%02d" % @t_day} #{"%02d" % @t_hour}:#{"%02d" % @t_min}:#{"%02d" % @t_sec} #{self.offset_str}"
990
+ end
991
+
992
+ #Returns a human readable string based on the difference from the current time and date.
993
+ #===Examples
994
+ # datet.time #=> 1985-06-17 10:00:00 +0200
995
+ # datet.ago_str #=> "27 years ago"
996
+ # datet = Datet.new #=> 2012-05-03 20:31:58 +0200
997
+ # datet.ago_str #=> "18 seconds ago"
998
+ def ago_str(args = {})
999
+ args = {
1000
+ :year_ago_str => "%s year ago",
1001
+ :years_ago_str => "%s years ago",
1002
+ :month_ago_str => "%s month ago",
1003
+ :months_ago_str => "%s months ago",
1004
+ :day_ago_str => "%s day ago",
1005
+ :days_ago_str => "%s days ago",
1006
+ :hour_ago_str => "%s hour ago",
1007
+ :hours_ago_str => "%s hours ago",
1008
+ :min_ago_str => "%s minute ago",
1009
+ :mins_ago_str => "%s minutes ago",
1010
+ :sec_ago_str => "%s second ago",
1011
+ :secs_ago_str => "%s seconds ago",
1012
+ :right_now_str => "right now"
1013
+ }.merge(args)
1014
+
1015
+ secs_ago = Time.now.to_i - self.to_i
1016
+
1017
+ mins_ago = secs_ago.to_f / 60.0
1018
+ hours_ago = mins_ago / 60.0
1019
+ days_ago = hours_ago / 24.0
1020
+ months_ago = days_ago / 30.0
1021
+ years_ago = months_ago / 12.0
1022
+
1023
+ if years_ago > 0.9 and years_ago < 1.5
1024
+ return sprintf(args[:year_ago_str], years_ago.to_i)
1025
+ elsif years_ago >= 1.5
1026
+ return sprintf(args[:years_ago_str], years_ago.to_i)
1027
+ elsif months_ago > 0.9 and months_ago < 1.5
1028
+ return sprintf(args[:month_ago_str], months_ago.to_i)
1029
+ elsif months_ago >= 1.5
1030
+ return sprintf(args[:months_ago_str], months_ago.to_i)
1031
+ elsif days_ago > 0.9 and days_ago < 1.5
1032
+ return sprintf(args[:day_ago_str], days_ago.to_i)
1033
+ elsif days_ago >= 1.5
1034
+ return sprintf(args[:days_ago_str], days_ago.to_i)
1035
+ elsif hours_ago > 0.9 and hours_ago < 1.5
1036
+ return sprintf(args[:hour_ago_str], hours_ago.to_i)
1037
+ elsif hours_ago >= 1.5
1038
+ return sprintf(args[:hours_ago_str], hours_ago.to_i)
1039
+ elsif mins_ago > 0.9 and mins_ago < 1.5
1040
+ return sprintf(args[:min_ago_str], mins_ago.to_i)
1041
+ elsif mins_ago >= 1.5
1042
+ return sprintf(args[:mins_ago_str], mins_ago.to_i)
1043
+ elsif secs_ago >= 0.1 and secs_ago < 1.5
1044
+ return sprintf(args[:sec_ago_str], secs_ago.to_i)
1045
+ elsif secs_ago >= 1.5
1046
+ return sprintf(args[:secs_ago_str], secs_ago.to_i)
1047
+ end
1048
+
1049
+ return args[:right_now_str]
1050
+ end
1051
+
1052
+ #Returns the object as a human understandable string.
1053
+ #===Examples
1054
+ # datet.time #=> 2012-05-03 20:31:58 +0200
1055
+ # datet.human_str #=> "20:31"
1056
+ def human_str(args = {})
1057
+ args = {
1058
+ :time => true,
1059
+ :number_endings => {
1060
+ 0 => "th",
1061
+ 1 => "st",
1062
+ 2 => "nd",
1063
+ 3 => "rd",
1064
+ 4 => "th",
1065
+ 5 => "th",
1066
+ 6 => "th",
1067
+ 7 => "th",
1068
+ 8 => "th",
1069
+ 9 => "th"
1070
+ }
1071
+ }.merge(args)
1072
+
1073
+ now = Time.now
1074
+
1075
+ #Generate normal string.
1076
+ date_str = ""
1077
+
1078
+ if now.day != @t_day and now.month == @t_month and now.year == @t_year
1079
+ last_digit = @t_day.to_s[-1, 1].to_i
1080
+
1081
+ if ending = args[:number_endings][last_digit]
1082
+ #ignore.
1083
+ else
1084
+ ending = "."
1085
+ end
1086
+
1087
+ date_str << "#{@t_day}#{ending} "
1088
+ elsif now.day != @t_day or now.month != @t_month or now.year != @t_year
1089
+ date_str << "#{@t_day}/#{@t_month} "
1090
+ end
1091
+
1092
+ if now.year != @t_year
1093
+ date_str << "#{@t_year} "
1094
+ end
1095
+
1096
+ if args[:time]
1097
+ date_str << "#{@t_hour}:#{"%02d" % @t_min}"
1098
+ end
1099
+
1100
+ return date_str
1101
+ end
1102
+ end