This commit was generated by cvs2svn to compensate for changes in r2523,
[freeside.git] / rt / lib / RT / Date.pm
1 #$Header: /home/cvs/cvsroot/freeside/rt/lib/RT/Date.pm,v 1.1 2002-08-12 06:17:07 ivan Exp $
2 # (c) 1996-2000 Jesse Vincent <jesse@fsck.com>
3 # This software is redistributable under the terms of the GNU GPL
4
5 =head1 NAME
6
7   RT::Date - a simple Object Oriented date.
8
9 =head1 SYNOPSIS
10
11   use RT::Date
12
13 =head1 DESCRIPTION
14
15 RT Date is a simple Date Object designed to be speedy and easy for RT to use
16
17 The fact that it assumes that a time of 0 means "never" is probably a bug.
18
19 =begin testing
20
21 ok (require RT::Date);
22
23 =end testing
24
25 =head1 METHODS
26
27 =cut
28
29
30 package RT::Date;
31 use Time::Local;
32 use vars qw($MINUTE $HOUR $DAY $WEEK $MONTH $YEAR);
33
34 $MINUTE = 60;
35 $HOUR   = 60 * $MINUTE;
36 $DAY    = 24 * $HOUR;
37 $WEEK   = 7 * $DAY;
38 $MONTH  = 4 * $WEEK;
39 $YEAR   = 365 * $DAY;
40
41 # {{{ sub new 
42
43 sub new  {
44   my $proto = shift;
45   my $class = ref($proto) || $proto;
46   my $self  = {};
47   bless ($self, $class);
48   $self->Unix(0);
49   return $self;
50 }
51
52 # }}}
53
54 # {{{ sub Set
55
56 =head2 sub Set
57
58 takes a param hash with the fields 'Format' and 'Value'
59
60 if $args->{'Format'} is 'unix', takes the number of seconds since the epoch 
61
62 If $args->{'Format'} is ISO, tries to parse an ISO date.
63
64 If $args->{'Format'} is 'unknown', require Date::Parse and make it figure things
65 out. This is a heavyweight operation that should never be called from within 
66 RT's core. But it's really useful for something like the textbox date entry
67 where we let the user do whatever they want.
68
69 If $args->{'Value'}  is 0, assumes you mean never.
70
71
72 =cut
73
74 sub Set {
75     my $self = shift;
76     my %args = ( Format => 'unix',
77                  Value => time,
78                  @_);
79     if (($args{'Value'} =~ /^\d*$/) and ($args{'Value'} == 0)) {
80         $self->Unix(-1);
81         return($self->Unix());
82     }
83
84     if ($args{'Format'} =~ /^unix$/i) {
85         $self->Unix($args{'Value'});
86     }
87     
88     elsif ($args{'Format'} =~ /^(sql|datemanip|iso)$/i) {
89         
90         if (($args{'Value'} =~ /^(\d{4}?)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/) ||
91             ($args{'Value'} =~ /^(\d{4}?)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)$/) ||
92             ($args{'Value'} =~ /^(\d{4}?)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)\+00$/) ||
93             ($args{'Value'} =~ /^(\d{4}?)(\d\d)(\d\d)(\d\d):(\d\d):(\d\d)$/)) {
94             
95         my $year = $1;
96             my $mon = $2;
97             my $mday = $3;
98             my $hours = $4;
99             my $min = $5;
100             my $sec = $6;
101             
102             #timegm expects month as 0->11
103             $mon--;
104             
105             #now that we've parsed it, deal with the case where everything
106             #was 0
107             if ($mon == -1) {
108                     $self->Unix(-1);
109                 } else {
110
111                     #Dateamnip strings aren't in GMT.
112                     if ($args{'Format'} =~ /^datemanip$/i) {
113                         $self->Unix(timelocal($sec,$min,$hours,$mday,$mon,$year));
114                     }
115                     #ISO and SQL dates are in GMT
116                     else {
117                         $self->Unix(timegm($sec,$min,$hours,$mday,$mon,$year));
118                     }
119                     
120                     $self->Unix(-1) unless $self->Unix;
121                 }
122    }  
123         else {
124             use Carp;
125             Carp::cluck;
126             $RT::Logger->debug( "Couldn't parse date $args{'Value'} as a $args{'Format'}");
127             
128         }
129     }
130     elsif ($args{'Format'} =~ /^unknown$/i) {
131         require Date::Parse;
132         #Convert it to an ISO format string 
133         
134         my $date = Date::Parse::str2time($args{'Value'});
135         
136         #This date has now been set to a date in the _local_ timezone.
137         #since ISO dates are known to be in GMT (for RT's purposes);
138         
139         $RT::Logger->debug("RT::Date used date::parse to make ".$args{'Value'} . " $date\n");
140         
141         
142         return ($self->Set( Format => 'unix', Value => "$date"));
143     }                                                    
144     else {
145         die "Unknown Date format: ".$args{'Format'}."\n";
146     }
147     
148     return($self->Unix());
149 }
150
151 # }}}
152
153 # {{{ sub SetToMidnight 
154
155 =head2 SetToMidnight
156
157 Sets the date to midnight (at the beginning of the day) GMT
158 Returns the unixtime at midnight.
159
160 =cut
161
162 sub SetToMidnight {
163     my $self = shift;
164     
165     use Time::Local;
166     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime($self->Unix);
167     $self->Unix(timegm (0,0,0,$mday,$mon,$year,$wday,$yday));
168     
169     return ($self->Unix);
170     
171     
172 }
173
174
175 # }}}
176
177 # {{{ sub SetToNow
178 sub SetToNow {
179         my $self = shift;
180         return($self->Set(Format => 'unix', Value => time))
181 }
182 # }}}
183
184 # {{{ sub Diff
185
186 =head2 Diff
187
188 Takes either an RT::Date object or the date in unixtime format as a string
189
190 Returns the differnce between $self and that time as a number of seconds
191
192 =cut
193
194 sub Diff {
195     my $self = shift;
196     my $other = shift;
197
198     if (ref($other) eq 'RT::Date') {
199         $other=$other->Unix;
200     }
201     return ($self->Unix - $other);
202 }
203 # }}}
204
205 # {{{ sub DiffAsString
206
207 =head2 sub DiffAsString
208
209 Takes either an RT::Date object or the date in unixtime format as a string
210
211 Returns the differnce between $self and that time as a number of seconds as
212 as string fit for human consumption
213
214 =cut
215
216 sub DiffAsString {
217     my $self = shift;
218     my $other = shift;
219
220
221     if ($other < 1) {
222         return ("");
223     }
224     if ($self->Unix < 1) {
225         return("");
226     }
227     my $diff = $self->Diff($other);
228
229     return ($self->DurationAsString($diff));
230 }
231 # }}}
232
233 # {{{ sub DurationAsString
234
235 =head2 DurationAsString
236
237 Takes a number of seconds. returns a string describing that duration
238
239 =cut
240
241 sub DurationAsString{
242
243     my $self=shift;
244     my $duration = shift;
245     
246     my ($negative, $s);
247     
248     $negative = 'ago' if ($duration < 0);
249
250     $duration = abs($duration);
251
252     if($duration < $MINUTE) {
253         $s=$duration;
254         $string="sec";
255     } elsif($duration < (2 * $HOUR)) {
256         $s = int($duration/$MINUTE);
257         $string="min";
258     } elsif($duration < (2 * $DAY)) {
259         $s = int($duration/$HOUR);
260         $string="hours";
261     } elsif($duration < (2 * $WEEK)) {
262         $s = int($duration/$DAY);
263         $string="days";
264     } elsif($duration < (2 * $MONTH)) {
265         $s = int($duration/$WEEK);
266         $string="weeks";
267     } elsif($duration < $YEAR) {
268         $s = int($duration/$MONTH);
269         $string="months";
270     } else {
271         $s = int($duration/$YEAR);
272         $string="years";
273     }
274     
275     return ("$s $string $negative");
276 }
277
278 # }}}
279
280 # {{{ sub AgeAsString
281
282 =head2 sub AgeAsString
283
284 Takes nothing
285
286 Returns a string that's the differnce between the time in the object and now
287
288 =cut
289
290 sub AgeAsString {
291     my $self = shift;
292     return ($self->DiffAsString(time));
293     }
294 # }}}
295
296 # {{{ sub AsString
297
298 =head2 sub AsString
299
300 Returns the object\'s time as a string with the current timezone.
301
302 =cut
303
304 sub AsString {
305     my $self = shift;
306     return ("Not set") if ($self->Unix <= 0);
307
308     return (scalar(localtime($self->Unix)));
309 }
310 # }}}
311
312 # {{{ sub AddSeconds
313
314 =head2 sub AddSeconds
315
316 Takes a number of seconds as a string
317
318 Returns the new time
319
320 =cut
321
322 sub AddSeconds {
323     my $self = shift;
324     my $delta = shift;
325     
326     $self->Set(Format => 'unix', Value => ($self->Unix + $delta));
327     
328     return ($self->Unix);
329     
330
331 }
332
333 # }}}
334
335 # {{{ sub AddDays
336
337 =head2 AddDays $DAYS
338
339 Adds 24 hours * $DAYS to the current time
340
341 =cut
342
343 sub AddDays {
344     my $self = shift;
345     my $days = shift;
346     $self->AddSeconds($days * $DAY);
347     
348 }
349
350 # }}}
351
352 # {{{ sub AddDay
353
354 =head2 AddDay
355
356 Adds 24 hours to the current time
357
358 =cut
359
360 sub AddDay {
361     my $self = shift;
362     $self->AddSeconds($DAY);
363     
364 }
365
366 # }}}
367
368 # {{{ sub Unix
369
370 =head2 sub Unix [unixtime]
371
372 Optionally takes a date in unix seconds since the epoch format.
373 Returns the number of seconds since the epoch
374
375 =cut
376
377 sub Unix {
378     my $self = shift;
379     
380     $self->{'time'} = shift if (@_);
381     
382     return ($self->{'time'});
383 }
384 # }}}
385
386 # {{{ sub ISO
387
388 =head2 ISO
389
390 Takes nothing
391
392 Returns the object's date in ISO format
393
394 =cut
395
396 sub ISO {
397     my $self=shift;
398     my    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst, $date) ;
399     
400     return ('1970-01-01 00:00:00') if ($self->Unix == -1);
401
402     #  0    1    2     3     4    5     6     7     8
403     ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($self->Unix);
404     #make the year YYYY
405     $year+=1900;
406
407     #the month needs incrementing, as gmtime returns 0-11
408     $mon++;
409         
410     $date = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year,$mon,$mday, $hour,$min,$sec);
411     
412     return ($date);
413 }
414
415 # }}}
416
417
418 # {{{ sub LocalTimezone 
419 =head2 LocalTimezone
420
421   Returns the current timezone. For now, draws off a system timezone, RT::Timezone. Eventually, this may
422 pull from a 'Timezone' attribute of the CurrentUser
423
424 =cut
425
426 sub LocalTimezone {
427     my $self = shift;
428     
429     return ($RT::Timezone);
430 }
431
432 # }}}
433
434
435
436 1;