File Coverage

blib/lib/Net/ICal/Period.pm
Criterion Covered Total %
statement 18 101 17.8
branch 0 48 0.0
condition 0 6 0.0
subroutine 6 16 37.5
pod 6 10 60.0
total 30 181 16.5


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2             # -*- Mode: perl -*-
3             #======================================================================
4             #
5             # This package is free software and is provided "as is" without
6             # express or implied warranty. It may be used, redistributed and/or
7             # modified under the same terms as perl itself. ( Either the Artistic
8             # License or the GPL. )
9             #
10             # $Id: Period.pm,v 1.19 2001/08/04 04:59:36 srl Exp $
11             #
12             # (C) COPYRIGHT 2000-2001, Reefknot developers.
13             #
14             # See the AUTHORS file included in the distribution for a full list.
15             #======================================================================
16              
17             =head1 NAME
18              
19             Net::ICal::Period -- represent a period of time
20              
21             =cut
22              
23             package Net::ICal::Period;
24 1     1   5 use strict;
  1         2  
  1         33  
25              
26 1     1   6 use UNIVERSAL;
  1         2  
  1         5  
27 1     1   26 use base qw(Net::ICal::Property);
  1         2  
  1         77  
28              
29 1     1   6 use Data::Dumper;
  1         2  
  1         61  
30 1     1   6 use Net::ICal::Duration;
  1         2  
  1         6  
31 1     1   24 use Net::ICal::Time;
  1         1  
  1         6  
32              
33             =head1 SYNOPSIS
34              
35             use Net::ICal;
36             $p = new Net::ICal::Period("19970101T120000","19970101T123000");
37             $p = new Net::ICal::Period("19970101T120000","PT3W2D40S");
38             $p = new Net::ICal::Period(time(),3600);
39             $p = new Net::ICal::Period(
40             new Net::ICal::Time("19970101T120000",
41             "America/Los_Angeles"),
42             new Net::ICal::Duration("2h"));
43              
44             =head1 DESCRIPTION
45              
46             Use this to make an object representing a block of time on a
47             real schedule. You can either say, "This event starts at 12
48             and ends at 2" or "This event starts at 12 and lasts 2 hours."
49              
50             These two ways of specifying events can be treated differently
51             in schedules. If you say, "The meeting is from 12 to 2, but I
52             have to leave at 2," you are implying that the start date and
53             end date are fixed. If you say, "I have a 2-hour drive to
54             Chicago, and I need to leave at 4," you are saying that it will
55             take 2 hours no matter when you leave, and that moving the start
56             time will slide the end time correspondingly.
57              
58             =head1 BASIC METHODS
59              
60             =head2 new($time, $time|$duration)
61              
62             Creates a new period object given to parameters: The first must be a
63             I
64              
65             The second can be either:
66              
67             =over 4
68              
69             =item * a I
70              
71             =item * a valid argument to Net::ICal::Time::new.
72              
73             =item * a I object
74              
75             =item * a valid argument to Net::ICal::Duration::new.
76              
77             =back
78              
79             Either give a start time and an end time, or a start time and a duration.
80              
81             =cut
82              
83              
84             #-------------------------------------------------------------------------
85              
86             =head2 new($time, $time|$duration)
87              
88             Creates a new period object given to parameters: The first must be a
89             I
90              
91             The second can be either:
92              
93             =over 4
94              
95             =item * a I
96              
97             =item * a valid argument to Net::ICal::Time::new.
98              
99             =item * a I object
100              
101             =item * a valid argument to Net::ICal::Duration::new.
102              
103             =back
104              
105             Either give a start time and an end time, or a start time and a duration.
106              
107             =begin testing
108              
109              
110             use Net::ICal::Period;
111              
112             my $p = Net::ICal::Period->new(); # should FAIL
113              
114             ok(!defined($p), "new() with no args fails properly");
115              
116             my $begin = "19890324T123000Z";
117             my $end = '19890324T163000Z';
118             my $durstring = 'PT4H';
119              
120             $p = Net::ICal::Period->new(
121             Net::ICal::Time->new(ical => $begin),
122             Net::ICal::Time->new(ical => $end)
123             );
124              
125             ok(defined($p), "new() with 2 time objects as args succeeds");
126              
127             # TODO: new() tests with all the argument types listed in the
128             # docs. I'm *sure* some of them don't work, because the API
129             # for Time and Duration has changed since that POD was written. -srl
130              
131             ok($p->as_ical eq "$begin/$end", "ical output is correct");
132              
133              
134             $p = Net::ICal::Period->new($begin, $end);
135              
136             ok(defined($p), "new() with 2 time strings as args succeeds");
137              
138             # TODO: new() tests with all the argument types listed in the
139             # docs. I'm *sure* some of them don't work, because the API
140             # for Time and Duration has changed since that POD was written. -srl
141              
142             ok($p->as_ical eq "$begin/$end", "ical output is correct for dtstart/dtend");
143              
144              
145             $p = Net::ICal::Period->new($begin, $durstring);
146              
147             ok(defined($p), "new() with timestring and durstring as args succeeds");
148              
149             # TODO: new() tests with all the argument types listed in the
150             # docs. I'm *sure* some of them don't work, because the API
151             # for Time and Duration has changed since that POD was written. -srl
152              
153             print $p->as_ical . "\n";
154              
155             ok($p->as_ical eq "$begin/$durstring", "ical output is correct for dtstart/duration strings");
156              
157              
158             =end testing
159              
160             =cut
161              
162             sub new{
163 0     0 1   my ($package, $arg1, $arg2) = @_;
164            
165 0 0 0       return undef unless (defined($arg1) && defined($arg2) );
166            
167 0           my $self = {};
168              
169             # Is the string in RFC2445 Format?
170 0 0 0       if(!$arg2 and $arg1 =~ /\//){
171 0           my $tmp = $arg1;
172 0           ($arg1,$arg2) = split(/\//,$tmp);
173             }
174              
175              
176 0 0         if( ref($arg1) eq 'Net::ICal::Time'){
177 0           $self->{START} = $arg1->clone();
178             } else {
179 0           $self->{START} = new Net::ICal::Time(ical => $arg1);
180             }
181            
182              
183 0 0         if(UNIVERSAL::isa($arg2,'Net::ICal::Time')){
    0          
    0          
184 0           $self->{END} = $arg2->clone();
185             } elsif (UNIVERSAL::isa($arg2,'Net::ICal::Duration')) {
186 0           $self->{DURATION} = $arg2->clone();
187             } elsif ($arg2 =~ /^P/) {
188 0           $self->{DURATION} = new Net::ICal::Duration($arg2);
189             } else {
190             # Hope that it is a time string
191 0           $self->{END} = new Net::ICal::Time(ical => $arg2);
192             }
193              
194 0           return bless($self,$package);
195             }
196              
197             #--------------------------------------------------------------------------
198             =pod
199             =head2 clone()
200              
201             Create a copy of this component
202              
203             =begin testing
204              
205             ok($p->clone() ne "Not implemented", "clone method is implemented");
206              
207             $q = $p->clone();
208             ok(defined($q) , "clone method creates a defined object");
209              
210             SKIP: {
211             skip "This test makes the tests crash utterly", 1 unless 0;
212             ok($p->as_ical eq $q->as_ical , "clone method creates an exact copy");
213             };
214              
215             =end testing
216              
217             =cut
218              
219             sub clone {
220 0     0 0   my $self = shift;
221              
222 0           my $class = ref($self);
223 0           return bless( {%$self}, $class );
224              
225             }
226              
227             #----------------------------------------------------------------------------
228              
229             =head2 is_valid()
230              
231             Return true if:
232             There is an end time and:
233             Both start and end times have no timezone ( Floating time) or
234             Both start and end time have (possibly different) timezones or
235             Both start and end times are in UTC and
236             The end time is after the start time.
237              
238             There is a duration and the duration is positive
239              
240             =begin testing
241              
242             ok($p->is_valid() ne "Not implemented", "is_valid method is implemented");
243              
244             =end testing
245              
246             =cut
247              
248             # XXX implement this
249              
250             sub is_valid {
251 0     0 1   return "Not implemented";
252             }
253              
254             #---------------------------------------------------------------------------
255             =pod
256             =head2 start([$time])
257              
258             Accessor for the start time of the event as a I
259             Can also take a valid time string or an integer (number of
260             seconds since the epoch) as a parameter. If a second parameter
261             is given, it'll set this Duration's start time.
262              
263             =begin testing
264              
265             # TODO: write tests
266             ok(0, 'start accessor tests exist');
267              
268             =end testing
269              
270             =cut
271              
272             sub start{
273 0     0 0   my $self = shift;
274 0           my $t = shift;
275              
276 0 0         if($t){
277 0 0         if(UNIVERSAL::isa($t,'Net::ICal::Time')){
278 0           $self->{START} = $t->clone();
279             } else {
280 0           $self->{START} = new Net::ICal::Time($t);
281             }
282             }
283              
284 0           return $self->{START};
285             }
286              
287             #-----------------------------------------------------------------
288             =pod
289             =head2 end([$time])
290              
291             Accessor for the end time. Takes a I
292             or an integer and returns a time object. This routine is coupled to
293             the I accessor. See I below for more imformation.
294              
295             =begin testing
296              
297             # TODO: write tests
298             ok(0, 'end accessor tests exist');
299              
300             =end testing
301              
302             =cut
303              
304             sub end{
305              
306 0     0 0   my $self = shift;
307 0           my $t = shift;
308 0           my $end;
309              
310 0 0         if($t){
311 0 0         if(UNIVERSAL::isa($t,'Net::ICal::Time')){
312 0           $end = $t->clone();
313             } else {
314 0           $end = new Net::ICal::Time($t);
315             }
316            
317             # If duration exists, use the time to compute a new duration
318 0 0         if ($self->{DURATION}){
319 0           $self->{DURATION} = $end->subtract($self->{START});
320             } else {
321 0           $self->{END} = $end;
322             }
323             }
324              
325             # Return end time, possibly computing it from DURATION
326 0 0         if($self->{DURATION}){
327 0           return $self->{START}->add($self->{DURATION});
328             } else {
329 0           return $self->{END};
330             }
331              
332             }
333              
334             #----------------------------------------------------------------------
335             =pod
336             =head2 duration([$duration])
337              
338             Accessor for the duration of the event. Takes a I object and
339             returns a I object.
340              
341             Since the end time and the duration both specify the end time, the
342             object will store one and access to the other will be computed. So,
343              
344             if you create:
345              
346             $p = new Net::ICal::Period("19970101T120000","19970101T123000")
347              
348             And then execute:
349              
350             $p->duration(45*60);
351              
352             The period object will adjust the end time to be 45 minutes after
353             the start time. It will not replace the end time with a
354             duration. This is required so that a CUA can take an incoming
355             component from a server, modify it, and send it back out in the same
356             basic form.
357              
358             =begin testing
359              
360             # TODO: write tests
361             TODO: {
362             local $TODO = "write duration accessor tests";
363             ok(0, 'duration accessor tests exist');
364              
365             }
366             =end testing
367              
368             =cut
369              
370             sub duration{
371 0     0 0   my $self = shift;
372 0           my $d = shift;
373 0           my $dur;
374              
375 0 0         if($d){
376 0 0         if(UNIVERSAL::isa($d,'Net::ICal::Duration')){
377 0           $dur = $d->clone();
378             } else {
379 0           $dur = new Net::ICal::Duration($d);
380             }
381            
382             # If end exists, use the duration to compute a new end
383             # otherwise, set the duration.
384 0 0         if ($self->{END}){
385 0           $self->{END} = $self->{START}->add($dur);
386             } else {
387 0           $self->{DURATION} = $dur;
388             }
389             }
390              
391             # Return duration, possibly computing it from END
392 0 0         if($self->{END}){
393 0           return $self->{END}->subtract($self->{START});
394             } else {
395 0           return $self->{DURATION};
396             }
397              
398             }
399              
400             #------------------------------------------------------------------------
401              
402             =head2 as_ical()
403              
404             Return a string that holds the RFC2445 text form of this period
405              
406             =begin testing
407              
408             TODO: {
409             local $TODO = 'write tests for N::I::Period as_ical';
410             ok(0, "as_ical tests exist");
411             }
412              
413             =end testing
414              
415             =cut
416              
417             sub as_ical {
418 0     0 1   my $self = shift;
419 0           my $out;
420              
421 0           my $colon_clipped_date = $self->{START}->as_ical_value();
422 0           $out = $colon_clipped_date ."/";
423              
424 0 0         if($self->{DURATION}){
425 0           $out .= $self->{DURATION}->as_ical_value();
426             } else {
427 0           $colon_clipped_date = $self->{END}->as_ical_value();
428 0           $out .= $colon_clipped_date;
429             }
430            
431 0           return $out;
432            
433             }
434              
435             =pod
436              
437             =head2 as_ical_value
438              
439             Another name for as_ical.
440              
441             =begin testing
442              
443             # TODO: write tests
444             ok(0, "as_ical_value tests exist");
445              
446             =end testing
447              
448             =cut
449              
450             sub as_ical_value {
451 0     0 1   my $self = shift;
452              
453 0           return $self->as_ical();
454             }
455              
456              
457              
458             =pod
459              
460             =head2 compare([$time])
461              
462             Takes a Net::ICal::Time as a parameter.
463             If the parameter is a Time, returns 0 if I
464             -1 if the time is before the period and 1 if the time is after the period.
465              
466             =begin testing
467              
468             # TODO: write tests
469             ok(0, "compare tests exist");
470              
471             =end testing
472              
473             =cut
474              
475             sub compare {
476 0     0 1   my ($self, $t) = @_;
477 0           my $time;
478              
479 0 0         if($t){
480            
481 0 0         if(UNIVERSAL::isa($t,'Net::ICal::Time')){
482 0           $time = $t->clone();
483             } else {
484 0           $time = new Net::ICal::Time(ical => $t);
485             }
486            
487             # If the time is before the start of the duration
488 0 0         if($self->start->compare($time) < 0) {
489 0           return -1;
490             }
491             # If the time is after the end of the duration
492 0 0         if($self->end->compare($time) >= 0) {
493 0           return 1;
494             }
495              
496 0           return 0;
497             }
498              
499 0           return undef;
500             }
501              
502              
503              
504              
505             =pod
506              
507             =head2 union([$period])
508              
509             Takes another Period as a parameter. Returns 0 if the given I overlaps
510             this period, -1 if the given Period is before this one, and 1 if the given Period
511             is after this one.
512              
513             =begin testing
514              
515             # TODO: write tests
516             ok(0, "union tests exist");
517              
518             =end testing
519              
520             =cut
521              
522             # XXX: Perhaps this should return a Period if the two periods overlap.
523             # Or maybe that's a separate function.
524             sub union {
525              
526 0     0 1   my ($self, $period2) = @_;
527              
528             # does $period2 overlap with this period?
529 0 0         if($period2){
530              
531             # If the start of the parameter period is after this period:
532 0 0         if($self->end->compare($period2->start) >= 0) {
533 0           return 1;
534             }
535             # If the end of this period is before the end of the parameter period
536 0 0         if($self->start->compare($period2->end) <= 0) {
537 0           return -1;
538             }
539 0           return 0;
540             }
541              
542 0           return undef;
543             }
544              
545             1;
546              
547             =head1 SEE ALSO
548              
549             More documentation pointers can be found in L.
550              
551             =cut