File Coverage

blib/lib/DateTime/Duration.pm
Criterion Covered Total %
statement 158 160 98.7
branch 56 62 90.3
condition 12 15 80.0
subroutine 51 51 100.0
pod 33 33 100.0
total 310 321 96.5


line stmt bran cond sub pod time code
1             package DateTime::Duration;
2              
3 49     49   806 use strict;
  49         102  
  49         1439  
4 49     49   251 use warnings;
  49         101  
  49         1220  
5 49     49   267 use namespace::autoclean;
  49         125  
  49         287  
6              
7             our $VERSION = '1.60';
8              
9 49     49   3630 use Carp ();
  49         138  
  49         1236  
10 49     49   254 use DateTime;
  49         104  
  49         1559  
11 49     49   19661 use DateTime::Helpers;
  49         130  
  49         1530  
12 49     49   19112 use DateTime::Types;
  49         252  
  49         701  
13 49     49   1657413 use Params::ValidationCompiler 0.26 qw( validation_for );
  49         897055  
  49         3058  
14 49     49   434 use Scalar::Util qw( blessed );
  49         130  
  49         2843  
15              
16             use overload (
17 49         332 fallback => 1,
18             '+' => '_add_overload',
19             '-' => '_subtract_overload',
20             '*' => '_multiply_overload',
21             '<=>' => '_compare_overload',
22             'cmp' => '_compare_overload',
23 49     49   399 );
  49         134  
24              
25             sub MAX_NANOSECONDS () {1_000_000_000} # 1E9 = almost 32 bits
26              
27             my @all_units = qw( months days minutes seconds nanoseconds );
28              
29             {
30             my %units = map {
31             $_ => {
32              
33             # XXX - what we really want is to accept an integer, Inf, -Inf,
34             # and NaN, but I can't figure out how to accept NaN since it never
35             # compares to anything.
36             type => t('Defined'),
37             default => 0,
38             }
39             } qw(
40             years
41             months
42             weeks
43             days
44             hours
45             minutes
46             seconds
47             nanoseconds
48             );
49              
50             my $check = validation_for(
51             name => '_check_new_params',
52             name_is_optional => 1,
53             params => {
54             %units,
55             end_of_month => {
56             type => t('EndOfMonthMode'),
57             optional => 1,
58             },
59             },
60             );
61              
62             sub new {
63 32024     32024 1 390974 my $class = shift;
64 32024         731268 my %p = $check->(@_);
65              
66 32024         1874268 my $self = bless {}, $class;
67              
68 32024         77068 $self->{months} = ( $p{years} * 12 ) + $p{months};
69              
70 32024         55602 $self->{days} = ( $p{weeks} * 7 ) + $p{days};
71              
72 32024         49936 $self->{minutes} = ( $p{hours} * 60 ) + $p{minutes};
73              
74 32024         48648 $self->{seconds} = $p{seconds};
75              
76 32024 100       62381 if ( $p{nanoseconds} ) {
77 39         85 $self->{nanoseconds} = $p{nanoseconds};
78 39         115 $self->_normalize_nanoseconds;
79             }
80             else {
81              
82             # shortcut - if they don't need nanoseconds
83 31985         53162 $self->{nanoseconds} = 0;
84             }
85              
86             $self->{end_of_month} = (
87             defined $p{end_of_month} ? $p{end_of_month}
88 32024 100       85720 : $self->{months} < 0 ? 'preserve'
    100          
89             : 'wrap'
90             );
91              
92 32024         151250 return $self;
93             }
94             }
95              
96             # make the signs of seconds, nanos the same; 0 < abs(nanos) < MAX_NANOS
97             # NB this requires nanoseconds != 0 (callers check this already)
98             sub _normalize_nanoseconds {
99 48     48   85 my $self = shift;
100              
101             return
102             if ( $self->{nanoseconds} == DateTime::INFINITY()
103             || $self->{nanoseconds} == DateTime::NEG_INFINITY()
104 48 100 100     468 || $self->{nanoseconds} eq DateTime::NAN() );
      100        
105              
106 45         138 my $seconds = $self->{seconds} + $self->{nanoseconds} / MAX_NANOSECONDS;
107 45         95 $self->{seconds} = int($seconds);
108 45         78 $self->{nanoseconds} = $self->{nanoseconds} % MAX_NANOSECONDS;
109 45 100       120 $self->{nanoseconds} -= MAX_NANOSECONDS if $seconds < 0;
110             }
111              
112 12     12 1 19 sub clone { bless { %{ $_[0] } }, ref $_[0] }
  12         84  
113              
114 4     4 1 630 sub years { abs( $_[0]->in_units('years') ) }
115 4     4 1 630 sub months { abs( $_[0]->in_units( 'months', 'years' ) ) }
116 4     4 1 869 sub weeks { abs( $_[0]->in_units('weeks') ) }
117 4     4 1 23 sub days { abs( $_[0]->in_units( 'days', 'weeks' ) ) }
118 10     10 1 638 sub hours { abs( $_[0]->in_units('hours') ) }
119 7     7 1 650 sub minutes { abs( $_[0]->in_units( 'minutes', 'hours' ) ) }
120 7     7 1 693 sub seconds { abs( $_[0]->in_units('seconds') ) }
121 4     4 1 635 sub nanoseconds { abs( $_[0]->in_units( 'nanoseconds', 'seconds' ) ) }
122              
123 8 100   8 1 4992 sub is_positive { $_[0]->_has_positive && !$_[0]->_has_negative }
124 10 100   10 1 39 sub is_negative { !$_[0]->_has_positive && $_[0]->_has_negative }
125              
126             sub _has_positive {
127 18 100   18   35 ( grep { $_ > 0 } @{ $_[0] }{@all_units} ) ? 1 : 0;
  90         277  
  18         72  
128             }
129              
130             sub _has_negative {
131 13 100   13   31 ( grep { $_ < 0 } @{ $_[0] }{@all_units} ) ? 1 : 0;
  65         195  
  13         32  
132             }
133              
134             sub is_zero {
135 32690 100   32690 1 57978 return 0 if grep { $_ != 0 } @{ $_[0] }{@all_units};
  163450         347034  
  32690         107639  
136 747         4136 return 1;
137             }
138              
139 30     30 1 844 sub delta_months { $_[0]->{months} }
140 36     36 1 225 sub delta_days { $_[0]->{days} }
141 29     29 1 200 sub delta_minutes { $_[0]->{minutes} }
142 47     47 1 257 sub delta_seconds { $_[0]->{seconds} }
143 33     33 1 174 sub delta_nanoseconds { $_[0]->{nanoseconds} }
144              
145             sub deltas {
146 63897     63897 1 105969 map { $_ => $_[0]->{$_} } @all_units;
  319485         702282  
147             }
148              
149             sub in_units {
150 64     64 1 143 my $self = shift;
151 64         157 my @units = @_;
152              
153 64         139 my %units = map { $_ => 1 } @units;
  95         273  
154              
155 64         112 my %ret;
156              
157             my ( $months, $days, $minutes, $seconds )
158 64         98 = @{$self}{qw( months days minutes seconds )};
  64         161  
159              
160 64 100       164 if ( $units{years} ) {
161 12         40 $ret{years} = int( $months / 12 );
162 12         25 $months -= $ret{years} * 12;
163             }
164              
165 64 100       137 if ( $units{months} ) {
166 8         16 $ret{months} = $months;
167             }
168              
169 64 100       131 if ( $units{weeks} ) {
170 11         34 $ret{weeks} = int( $days / 7 );
171 11         19 $days -= $ret{weeks} * 7;
172             }
173              
174 64 100       124 if ( $units{days} ) {
175 8         27 $ret{days} = $days;
176             }
177              
178 64 100       123 if ( $units{hours} ) {
179 21         57 $ret{hours} = int( $minutes / 60 );
180 21         40 $minutes -= $ret{hours} * 60;
181             }
182              
183 64 100       131 if ( $units{minutes} ) {
184 11         22 $ret{minutes} = $minutes;
185             }
186              
187 64 100       122 if ( $units{seconds} ) {
188 16         37 $ret{seconds} = $seconds;
189 16         23 $seconds = 0;
190             }
191              
192 64 100       120 if ( $units{nanoseconds} ) {
193 8         21 $ret{nanoseconds} = $seconds * MAX_NANOSECONDS + $self->{nanoseconds};
194             }
195              
196 64 100       473 wantarray ? @ret{@units} : $ret{ $units[0] };
197             }
198              
199 541 100   541 1 2206 sub is_wrap_mode { $_[0]->{end_of_month} eq 'wrap' ? 1 : 0 }
200 3 50   3 1 28 sub is_limit_mode { $_[0]->{end_of_month} eq 'limit' ? 1 : 0 }
201 1081 100   1081 1 4385 sub is_preserve_mode { $_[0]->{end_of_month} eq 'preserve' ? 1 : 0 }
202              
203 2     2 1 15 sub end_of_month_mode { $_[0]->{end_of_month} }
204              
205             sub calendar_duration {
206 3     3 1 48 my $self = shift;
207              
208             return ( ref $self )
209 3         9 ->new( map { $_ => $self->{$_} } qw( months days end_of_month ) );
  9         25  
210             }
211              
212             sub clock_duration {
213 3     3 1 8 my $self = shift;
214              
215             return ( ref $self )
216 3         10 ->new( map { $_ => $self->{$_} }
  12         34  
217             qw( minutes seconds nanoseconds end_of_month ) );
218             }
219              
220             sub inverse {
221 22890     22890 1 35081 my $self = shift;
222 22890         39311 my %p = @_;
223              
224 22890         31066 my %new;
225 22890         44084 foreach my $u (@all_units) {
226 114450         197867 $new{$u} = $self->{$u};
227              
228             # avoid -0 bug
229 114450 100       234678 $new{$u} *= -1 if $new{$u};
230             }
231              
232             $new{end_of_month} = $p{end_of_month}
233 22890 100       46845 if exists $p{end_of_month};
234              
235 22890         77656 return ( ref $self )->new(%new);
236             }
237              
238             sub add_duration {
239 17     17 1 37 my ( $self, $dur ) = @_;
240              
241 17         30 foreach my $u (@all_units) {
242 85         144 $self->{$u} += $dur->{$u};
243             }
244              
245 17 100       45 $self->_normalize_nanoseconds if $self->{nanoseconds};
246              
247 17         72 return $self;
248             }
249              
250             sub add {
251 5     5 1 16 my $self = shift;
252              
253 5         12 return $self->add_duration( $self->_duration_object_from_args(@_) );
254             }
255              
256             sub subtract {
257 5     5 1 8 my $self = shift;
258              
259 5         18 return $self->subtract_duration( $self->_duration_object_from_args(@_) );
260             }
261              
262             # Syntactic sugar for add and subtract: use a duration object if it's
263             # supplied, otherwise build a new one from the arguments.
264             sub _duration_object_from_args {
265 10     10   13 my $self = shift;
266              
267 10 50 66     48 return $_[0]
      66        
268             if @_ == 1 && blessed( $_[0] ) && $_[0]->isa(__PACKAGE__);
269              
270 8         18 return __PACKAGE__->new(@_);
271             }
272              
273 11     11 1 27 sub subtract_duration { return $_[0]->add_duration( $_[1]->inverse ) }
274              
275             {
276             my $check = validation_for(
277             name => '_check_multiply_params',
278             name_is_optional => 1,
279             params => [
280             { type => t('Int') },
281             ],
282             );
283              
284             sub multiply {
285 4     4 1 9 my $self = shift;
286 4         124 my ($multiplier) = $check->(@_);
287              
288 3         56 foreach my $u (@all_units) {
289 15         25 $self->{$u} *= $multiplier;
290             }
291              
292 3 100       11 $self->_normalize_nanoseconds if $self->{nanoseconds};
293              
294 3         10 return $self;
295             }
296             }
297              
298             sub compare {
299 5     5 1 643 my ( undef, $dur1, $dur2, $dt ) = @_;
300              
301 5   66     21 $dt ||= DateTime->now;
302              
303 5         15 return DateTime->compare(
304             $dt->clone->add_duration($dur1),
305             $dt->clone->add_duration($dur2)
306             );
307             }
308              
309             sub _add_overload {
310 1     1   14 my ( $d1, $d2, $rev ) = @_;
311              
312 1 50       4 ( $d1, $d2 ) = ( $d2, $d1 ) if $rev;
313              
314 1 50       4 if ( DateTime::Helpers::isa( $d2, 'DateTime' ) ) {
315 0         0 $d2->add_duration($d1);
316 0         0 return;
317             }
318              
319             # will also work if $d1 is a DateTime.pm object
320 1         6 return $d1->clone->add_duration($d2);
321             }
322              
323             sub _subtract_overload {
324 6     6   21 my ( $d1, $d2, $rev ) = @_;
325              
326 6 50       15 ( $d1, $d2 ) = ( $d2, $d1 ) if $rev;
327              
328 6 50       18 Carp::croak(
329             'Cannot subtract a DateTime object from a DateTime::Duration object')
330             if DateTime::Helpers::isa( $d2, 'DateTime' );
331              
332 6         18 return $d1->clone->subtract_duration($d2);
333             }
334              
335             sub _multiply_overload {
336 3     3   97 my $self = shift;
337              
338 3         9 my $new = $self->clone;
339              
340 3         9 return $new->multiply(shift);
341             }
342              
343             sub _compare_overload {
344 1     1   228 Carp::croak( 'DateTime::Duration does not overload comparison.'
345             . ' See the documentation on the compare() method for details.'
346             );
347             }
348              
349             1;
350              
351             # ABSTRACT: Duration objects for date math
352              
353             __END__
354              
355             =pod
356              
357             =encoding UTF-8
358              
359             =head1 NAME
360              
361             DateTime::Duration - Duration objects for date math
362              
363             =head1 VERSION
364              
365             version 1.60
366              
367             =head1 SYNOPSIS
368              
369             use DateTime::Duration;
370              
371             $dur = DateTime::Duration->new(
372             years => 3,
373             months => 5,
374             weeks => 1,
375             days => 1,
376             hours => 6,
377             minutes => 15,
378             seconds => 45,
379             nanoseconds => 12000,
380             end_of_month => 'limit',
381             );
382              
383             my ( $days, $hours, $seconds )
384             = $dur->in_units( 'days', 'hours', 'seconds' );
385              
386             # Human-readable accessors, always positive, but consider using
387             # DateTime::Format::Duration instead
388             $dur->years;
389             $dur->months;
390             $dur->weeks;
391             $dur->days;
392             $dur->hours;
393             $dur->minutes;
394             $dur->seconds;
395             $dur->nanoseconds;
396              
397             $dur->is_wrap_mode;
398             $dur->is_limit_mode;
399             $dur->is_preserve_mode;
400              
401             print $dur->end_of_month_mode;
402              
403             # Multiply all values by -1
404             my $opposite = $dur->inverse;
405              
406             my $bigger = $dur1 + $dur2;
407             my $smaller = $dur1 - $dur2; # the result could be negative
408             my $bigger = $dur1 * 3;
409              
410             my $base_dt = DateTime->new( year => 2000 );
411             my @sorted
412             = sort { DateTime::Duration->compare( $a, $b, $base_dt ) } @durations;
413              
414             if ( $dur->is_positive ) {...}
415             if ( $dur->is_zero ) {...}
416             if ( $dur->is_negative ) {...}
417              
418             =head1 DESCRIPTION
419              
420             This is a simple class for representing duration objects. These objects are
421             used whenever you do date math with L<DateTime>.
422              
423             See the L<How DateTime Math Works|DateTime/"How DateTime Math Works"> section
424             of the L<DateTime> documentation for more details. The short course: One cannot
425             in general convert between seconds, minutes, days, and months, so this class
426             will never do so. Instead, create the duration with the desired units to begin
427             with, for example by calling the appropriate subtraction/delta method on a
428             L<DateTime> object.
429              
430             =head1 METHODS
431              
432             Like L<DateTime> itself, C<DateTime::Duration> returns the object from mutator
433             methods in order to make method chaining possible.
434              
435             C<DateTime::Duration> has the following methods:
436              
437             =head2 DateTime::Duration->new( ... )
438              
439             This class method accepts the following parameters:
440              
441             =over 4
442              
443             =item * years
444              
445             An integer containing the number of years in the duration. This is optional.
446              
447             =item * months
448              
449             An integer containing the number of months in the duration. This is optional.
450              
451             =item * weeks
452              
453             An integer containing the number of weeks in the duration. This is optional.
454              
455             =item * days
456              
457             An integer containing the number of days in the duration. This is optional.
458              
459             =item * hours
460              
461             An integer containing the number of hours in the duration. This is optional.
462              
463             =item * minutes
464              
465             An integer containing the number of minutes in the duration. This is optional.
466              
467             =item * seconds
468              
469             An integer containing the number of seconds in the duration. This is optional.
470              
471             =item * nanoseconds
472              
473             An integer containing the number of nanoseconds in the duration. This is
474             optional.
475              
476             =item * end_of_month
477              
478             This must be either C<"wrap">, C<"limit">, or C<"preserve">. This parameter
479             specifies how date math that crosses the end of a month is handled.
480              
481             In C<"wrap"> mode, adding months or years that result in days beyond the end of
482             the new month will roll over into the following month. For instance, adding one
483             year to Feb 29 will result in Mar 1.
484              
485             If you specify C<"limit">, the end of the month is never crossed. Thus, adding
486             one year to Feb 29, 2000 will result in Feb 28, 2001. If you were to then add
487             three more years this will result in Feb 28, 2004.
488              
489             If you specify C<"preserve">, the same calculation is done as for C<"limit">
490             except that if the original date is at the end of the month the new date will
491             also be. For instance, adding one month to Feb 29, 2000 will result in Mar 31,
492             2000.
493              
494             For positive durations, this parameter defaults to C<"wrap">. For negative
495             durations, the default is C<"preserve">. This should match how most people
496             "intuitively" expect datetime math to work.
497              
498             =back
499              
500             All of the duration units can be positive or negative. However, if any of the
501             numbers are negative, the entire duration is negative.
502              
503             All of the numbers B<must be integers>.
504              
505             Internally, years as just treated as 12 months. Similarly, weeks are treated as
506             7 days, and hours are converted to minutes. Seconds and nanoseconds are both
507             treated separately.
508              
509             =head2 $dur->clone
510              
511             Returns a new object with the same properties as the object on which this
512             method was called.
513              
514             =head2 $dur->in_units( ... )
515              
516             Returns the length of the duration in the units (any of those that can be
517             passed to C<< DateTime::Duration->new >>) given as arguments. All lengths are
518             integral, but may be negative. Smaller units are computed from what remains
519             after taking away the larger units given, so for example:
520              
521             my $dur = DateTime::Duration->new( years => 1, months => 15 );
522              
523             $dur->in_units('years'); # 2
524             $dur->in_units('months'); # 27
525             $dur->in_units( 'years', 'months' ); # (2, 3)
526             $dur->in_units( 'weeks', 'days' ); # (0, 0) !
527              
528             The last example demonstrates that there will not be any conversion between
529             units which don't have a fixed conversion rate. The only conversions possible
530             are:
531              
532             =over 4
533              
534             =item * years <=> months
535              
536             =item * weeks <=> days
537              
538             =item * hours <=> minutes
539              
540             =item * seconds <=> nanoseconds
541              
542             =back
543              
544             For the explanation of why this is the case, please see the L<How DateTime Math
545             Works|DateTime/"How DateTime Math Works"> section of the DateTime documentation
546              
547             Note that the numbers returned by this method may not match the values given to
548             the constructor.
549              
550             In list context, C<< $dur->in_units >> returns the lengths in the order of the
551             units given. In scalar context, it returns the length in the first unit (but
552             still computes in terms of all given units).
553              
554             If you need more flexibility in presenting information about durations, please
555             take a look a L<DateTime::Format::Duration>.
556              
557             =head2 $dur->is_positive, $dur->is_zero, $dur->is_negative
558              
559             Indicates whether or not the duration is positive, zero, or negative.
560              
561             If the duration contains both positive and negative units, then it will return
562             false for B<all> of these methods.
563              
564             =head2 $dur->is_wrap_mode, $dur->is_limit_mode, $dur->is_preserve_mode
565              
566             Indicates what mode is used for end of month wrapping.
567              
568             =head2 $dur->end_of_month_mode
569              
570             Returns one of C<"wrap">, C<"limit">, or C<"preserve">.
571              
572             =head2 $dur->calendar_duration
573              
574             Returns a new object with the same I<calendar> delta (months and days only) and
575             end of month mode as the current object.
576              
577             =head2 $dur->clock_duration
578              
579             Returns a new object with the same I<clock> deltas (minutes, seconds, and
580             nanoseconds) and end of month mode as the current object.
581              
582             =head2 $dur->inverse( ... )
583              
584             Returns a new object with the same deltas as the current object, but multiplied
585             by -1. The end of month mode for the new object will be the default end of
586             month mode, which depends on whether the new duration is positive or negative.
587              
588             You can set the end of month mode in the inverted duration explicitly by
589             passing an C<end_of_month> parameter to the C<< $dur->inverse >> method.
590              
591             =head2 $dur->add_duration($duration_object), $dur->subtract_duration($duration_object)
592              
593             Adds or subtracts one duration from another.
594              
595             =head2 $dur->add( ... ), $dur->subtract( ... )
596              
597             These accept either constructor parameters for a new C<DateTime::Duration>
598             object or an already-constructed duration object.
599              
600             =head2 $dur->multiply($number)
601              
602             Multiplies each unit in the C<DateTime::Duration> object by the specified
603             integer number.
604              
605             =head2 DateTime::Duration->compare( $duration1, $duration2, $base_datetime )
606              
607             This is a class method that can be used to compare or sort durations.
608             Comparison is done by adding each duration to the specified L<DateTime> object
609             and comparing the resulting datetimes. This is necessary because without a
610             base, many durations are not comparable. For example, 1 month may or may not be
611             longer than 29 days, depending on what datetime it is added to.
612              
613             If no base datetime is given, then the result of C<< DateTime->now >> is used
614             instead. Using this default will give non-repeatable results if used to compare
615             two duration objects containing different units. It will also give
616             non-repeatable results if the durations contain multiple types of units, such
617             as months and days.
618              
619             However, if you know that both objects only consist of one type of unit (months
620             I<or> days I<or> hours, etc.), and each duration contains the same type of
621             unit, then the results of the comparison will be repeatable.
622              
623             =head2 $dur->delta_months, $dur->delta_days, $dur->delta_minutes, $dur->delta_seconds, $dur->delta_nanoseconds
624              
625             These methods provide the information L<DateTime> needs for doing date math.
626             The numbers returned may be positive or negative. This is mostly useful for
627             doing date math in L<DateTime>.
628              
629             =head2 $dur->deltas
630              
631             Returns a hash with the keys "months", "days", "minutes", "seconds", and
632             "nanoseconds", containing all the delta information for the object. This is
633             mostly useful for doing date math in L<DateTime>.
634              
635             =head2 $dur->years, $dur->months, $dur->weeks, $dur->days, $dur->hours, $dur->minutes, $dur->seconds, $dur->nanoseconds
636              
637             These methods return numbers indicating how many of the given unit the object
638             represents, after having done a conversion to any larger units. For example,
639             days are first converted to weeks, and then the remainder is returned. These
640             numbers are always positive.
641              
642             Here's what each method returns:
643              
644             $dur->years == abs( $dur->in_units('years') )
645             $dur->months == abs( ( $dur->in_units( 'months', 'years' ) )[0] )
646             $dur->weeks == abs( $dur->in_units( 'weeks' ) )
647             $dur->days == abs( ( $dur->in_units( 'days', 'weeks' ) )[0] )
648             $dur->hours == abs( $dur->in_units( 'hours' ) )
649             $dur->minutes == abs( ( $dur->in_units( 'minutes', 'hours' ) )[0] )
650             $dur->seconds == abs( $dur->in_units( 'seconds' ) )
651             $dur->nanoseconds == abs( ( $dur->in_units( 'nanoseconds', 'seconds' ) )[0] )
652              
653             If this seems confusing, remember that you can always use the C<<
654             $dur->in_units >> method to specify exactly what you want.
655              
656             Better yet, if you are trying to generate output suitable for humans, use the
657             C<DateTime::Format::Duration> module.
658              
659             =head2 Overloading
660              
661             This class overloads addition, subtraction, and mutiplication.
662              
663             Comparison is B<not> overloaded. If you attempt to compare durations using C<<
664             <=> >> or C<cmp>, then an exception will be thrown! Use the C<compare> class
665             method instead.
666              
667             =head1 SEE ALSO
668              
669             datetime@perl.org mailing list
670              
671             =head1 SUPPORT
672              
673             Support for this module is provided via the datetime@perl.org email list. See
674             http://lists.perl.org/ for more details.
675              
676             Bugs may be submitted at L<https://github.com/houseabsolute/DateTime.pm/issues>.
677              
678             There is a mailing list available for users of this distribution,
679             L<mailto:datetime@perl.org>.
680              
681             =head1 SOURCE
682              
683             The source code repository for DateTime can be found at L<https://github.com/houseabsolute/DateTime.pm>.
684              
685             =head1 AUTHOR
686              
687             Dave Rolsky <autarch@urth.org>
688              
689             =head1 COPYRIGHT AND LICENSE
690              
691             This software is Copyright (c) 2003 - 2023 by Dave Rolsky.
692              
693             This is free software, licensed under:
694              
695             The Artistic License 2.0 (GPL Compatible)
696              
697             The full text of the license can be found in the
698             F<LICENSE> file included with this distribution.
699              
700             =cut