Merge branch 'b-3.6.1' of ../kivitendo-erp_20220811
[kivitendo-erp.git] / modules / fallback / DateTime / Event / Cron.pm
diff --git a/modules/fallback/DateTime/Event/Cron.pm b/modules/fallback/DateTime/Event/Cron.pm
deleted file mode 100644 (file)
index a835aa7..0000000
+++ /dev/null
@@ -1,885 +0,0 @@
-package DateTime::Event::Cron;
-
-use 5.006;
-use strict;
-use warnings;
-use Carp;
-
-use vars qw($VERSION);
-
-$VERSION = '0.08';
-
-use constant DEBUG => 0;
-
-use DateTime;
-use DateTime::Set;
-use Set::Crontab;
-
-my %Object_Attributes;
-
-###
-
-sub from_cron {
-  # Return cron as DateTime::Set
-  my $class = shift;
-  my %sparms = @_ == 1 ? (cron => shift) : @_;
-  my %parms;
-  $parms{cron}      = delete $sparms{cron};
-  $parms{user_mode} = delete $sparms{user_mode};
-  $parms{cron} or croak "Cron string parameter required.\n";
-  my $dtc = $class->new(%parms);
-  $dtc->as_set(%sparms);
-}
-
-sub from_crontab {
-  # Return list of DateTime::Sets based on entries from
-  # a crontab file.
-  my $class = shift;
-  my %sparms = @_ == 1 ? (file => shift) : @_;
-  my $file = delete $sparms{file};
-  delete $sparms{cron};
-  my $fh = $class->_prepare_fh($file);
-  my @cronsets;
-  while (<$fh>) {
-    chomp;
-    my $set;
-    eval { $set = $class->from_cron(%sparms, cron => $_) };
-    push(@cronsets, $set) if ref $set && !$@;
-  }
-  @cronsets;
-}
-
-sub as_set {
-  # Return self as DateTime::Set
-  my $self = shift;
-  my %sparms = @_;
-  Carp::cluck "Recurrence callbacks overriden by ". ref $self . "\n"
-    if $sparms{next} || $sparms{recurrence} || $sparms{previous};
-  delete $sparms{next};
-  delete $sparms{previous};
-  delete $sparms{recurrence};
-  $sparms{next}     = sub { $self->next(@_) };
-  $sparms{previous} = sub { $self->previous(@_) };
-  DateTime::Set->from_recurrence(%sparms);
-}
-
-###
-
-sub new {
-  my $class = shift;
-  my $self = {};
-  bless $self, $class;
-  my %parms = @_ == 1 ? (cron => shift) : @_;
-  my $crontab = $self->_make_cronset(%parms);
-  $self->_cronset($crontab);
-  $self;
-}
-
-sub new_from_cron { new(@_) }
-
-sub new_from_crontab {
-  my $class = shift;
-  my %parms = @_ == 1 ? (file => shift()) : @_;
-  my $fh = $class->_prepare_fh($parms{file});
-  delete $parms{file};
-  my @dtcrons;
-  while (<$fh>) {
-    my $dtc;
-    eval { $dtc = $class->new(%parms, cron => $_) };
-    if (ref $dtc && !$@) {
-      push(@dtcrons, $dtc);
-      $parms{user_mode} = 1 if defined $dtc->user;
-    }
-  }
-  @dtcrons;
-}
-
-###
-
-sub _prepare_fh {
-  my $class = shift;
-  my $fh = shift;
-  if (! ref $fh) {
-    my $file = $fh;
-    local(*FH);
-    $fh = do { local *FH; *FH }; # doubled *FH avoids warning
-    open($fh, "<$file")
-      or croak "Error opening $file for reading\n";
-  }
-  $fh;
-}
-
-###
-
-sub valid {
-  # Is the given date valid according the current cron settings?
-  my($self, $date) = @_;
-  return if !$date || $date->second;
-  $self->minute->contains($date->minute)      &&
-  $self->hour->contains($date->hour)          &&
-  $self->days_contain($date->day, $date->dow) &&
-  $self->month->contains($date->month);
-}
-
-sub match {
-  # Does the given date match the cron spec?
-  my($self, $date) = @_;
-  $date = DateTime->now unless $date;
-  $self->minute->contains($date->minute)      &&
-  $self->hour->contains($date->hour)          &&
-  $self->days_contain($date->day, $date->dow) &&
-  $self->month->contains($date->month);
-}
-
-### Return adjacent dates without altering original date
-
-sub next {
-  my($self, $date) = @_;
-  $date = DateTime->now unless $date;
-  $self->increment($date->clone);
-}
-
-sub previous {
-  my($self, $date) = @_;
-  $date = DateTime->now unless $date;
-  $self->decrement($date->clone);
-}
-
-### Change given date to adjacent dates
-
-sub increment {
-  my($self, $date) = @_;
-  $date = DateTime->now unless $date;
-  return $date if $date->is_infinite;
-  do {
-    $self->_attempt_increment($date);
-  } until $self->valid($date);
-  $date;
-}
-
-sub decrement {
-  my($self, $date) = @_;
-  $date = DateTime->now unless $date;
-  return $date if $date->is_infinite;
-  do {
-    $self->_attempt_decrement($date);
-  } until $self->valid($date);
-  $date;
-}
-
-###
-
-sub _attempt_increment {
-  my($self, $date) = @_;
-  ref $date or croak "Reference to datetime object reqired\n";
-  $self->valid($date) ?
-    $self->_valid_incr($date) :
-    $self->_invalid_incr($date);
-}
-
-sub _attempt_decrement {
-  my($self, $date) = @_;
-  ref $date or croak "Reference to datetime object reqired\n";
-  $self->valid($date) ?
-    $self->_valid_decr($date) :
-    $self->_invalid_decr($date);
-}
-
-sub _valid_incr { shift->_minute_incr(@_) }
-
-sub _valid_decr { shift->_minute_decr(@_) }
-
-sub _invalid_incr {
-  # If provided date is valid, return it. Otherwise return
-  # nearest valid date after provided date.
-  my($self, $date) = @_;
-  ref $date or croak "Reference to datetime object reqired\n";
-
-  print STDERR "\nI GOT: ", $date->datetime, "\n" if DEBUG;
-
-  $date->truncate(to => 'minute')->add(minutes => 1)
-    if $date->second;
-
-  print STDERR "RND: ", $date->datetime, "\n" if DEBUG;
-
-  # Find our greatest invalid unit and clip
-  if (!$self->month->contains($date->month)) {
-    $date->truncate(to => 'month');
-  }
-  elsif (!$self->days_contain($date->day, $date->dow)) {
-    $date->truncate(to => 'day');
-  }
-  elsif (!$self->hour->contains($date->hour)) {
-    $date->truncate(to => 'hour');
-  }
-  else {
-    $date->truncate(to => 'minute');
-  }
-
-  print STDERR "BBT: ", $date->datetime, "\n" if DEBUG;
-
-  return $date if $self->valid($date);
-
-  print STDERR "ZZT: ", $date->datetime, "\n" if DEBUG;
-
-  # Extraneous durations clipped. Start searching.
-  while (!$self->valid($date)) {
-    $date->add(months => 1) until $self->month->contains($date->month);
-    print STDERR "MON: ", $date->datetime, "\n" if DEBUG;
-
-    my $day_orig = $date->day;
-    $date->add(days => 1) until $self->days_contain($date->day, $date->dow);
-    $date->truncate(to => 'month') && next if $date->day < $day_orig;
-    print STDERR "DAY: ", $date->datetime, "\n" if DEBUG;
-
-    my $hour_orig = $date->hour;
-    $date->add(hours => 1) until $self->hour->contains($date->hour);
-    $date->truncate(to => 'day') && next if $date->hour < $hour_orig;
-    print STDERR "HOR: ", $date->datetime, "\n" if DEBUG;
-
-    my $min_orig = $date->minute;
-    $date->add(minutes => 1) until $self->minute->contains($date->minute);
-    $date->truncate(to => 'hour') && next if $date->minute < $min_orig;
-    print STDERR "MIN: ", $date->datetime, "\n" if DEBUG;
-  }
-  print STDERR "SET: ", $date->datetime, "\n" if DEBUG;
-  $date;
-}
-
-sub _invalid_decr {
-  # If provided date is valid, return it. Otherwise
-  # return the nearest previous valid date.
-  my($self, $date) = @_;
-  ref $date or croak "Reference to datetime object reqired\n";
-
-  print STDERR "\nD GOT: ", $date->datetime, "\n" if DEBUG;
-
-  if (!$self->month->contains($date->month)) {
-    $date->truncate(to => 'month');
-  }
-  elsif (!$self->days_contain($date->day, $date->dow)) {
-    $date->truncate(to => 'day');
-  }
-  elsif (!$self->hour->contains($date->hour)) {
-    $date->truncate(to => 'hour');
-  }
-  else {
-    $date->truncate(to => 'minute');
-  }
-
-  print STDERR "BBT: ", $date->datetime, "\n" if DEBUG;
-
-  return $date if $self->valid($date);
-
-  print STDERR "ZZT: ", $date->datetime, "\n" if DEBUG;
-
-  # Extraneous durations clipped. Start searching.
-  while (!$self->valid($date)) {
-    if (!$self->month->contains($date->month)) {
-      $date->subtract(months => 1) until $self->month->contains($date->month);
-      $self->_unit_peak($date, 'month');
-      print STDERR "MON: ", $date->datetime, "\n" if DEBUG;
-    }
-    if (!$self->days_contain($date->day, $date->dow)) {
-      my $day_orig = $date->day;
-      $date->subtract(days => 1)
-        until $self->days_contain($date->day, $date->dow);
-      $self->_unit_peak($date, 'month') && next if ($date->day > $day_orig);
-      $self->_unit_peak($date, 'day');
-      print STDERR "DAY: ", $date->datetime, "\n" if DEBUG;
-    }
-    if (!$self->hour->contains($date->hour)) {
-      my $hour_orig = $date->hour;
-      $date->subtract(hours => 1) until $self->hour->contains($date->hour);
-      $self->_unit_peak($date, 'day') && next if ($date->hour > $hour_orig);
-      $self->_unit_peak($date, 'hour');
-      print STDERR "HOR: ", $date->datetime, "\n" if DEBUG;
-    }
-    if (!$self->minute->contains($date->minute)) {
-      my $min_orig = $date->minute;
-      $date->subtract(minutes => 1)
-        until $self->minute->contains($date->minute);
-      $self->_unit_peak($date, 'hour') && next if ($date->minute > $min_orig);
-      print STDERR "MIN: ", $date->datetime, "\n" if DEBUG;
-    }
-  }
-  print STDERR "SET: ", $date->datetime, "\n" if DEBUG;
-  $date;
-}
-
-###
-
-sub _unit_peak {
-  my($self, $date, $unit) = @_;
-  $date && $unit or croak "DateTime ref and unit required.\n";
-  $date->truncate(to => $unit)
-       ->add($unit . 's' => 1)
-       ->subtract(minutes => 1);
-}
-
-### Unit cascades
-
-sub _minute_incr {
-  my($self, $date) = @_;
-  croak "datetime object required\n" unless $date;
-  my $cur = $date->minute;
-  my $next = $self->minute->next($cur);
-  $date->set(minute => $next);
-  $next <= $cur ? $self->_hour_incr($date) : $date;
-}
-
-sub _hour_incr {
-  my($self, $date) = @_;
-  croak "datetime object required\n" unless $date;
-  my $cur = $date->hour;
-  my $next = $self->hour->next($cur);
-  $date->set(hour => $next);
-  $next <= $cur ? $self->_day_incr($date) : $date;
-}
-
-sub _day_incr {
-  my($self, $date) = @_;
-  croak "datetime object required\n" unless $date;
-  $date->add(days => 1);
-  $self->_invalid_incr($date);
-}
-
-sub _minute_decr {
-  my($self, $date) = @_;
-  croak "datetime object required\n" unless $date;
-  my $cur = $date->minute;
-  my $next = $self->minute->previous($cur);
-  $date->set(minute => $next);
-  $next >= $cur ? $self->_hour_decr($date) : $date;
-}
-
-sub _hour_decr {
-  my($self, $date) = @_;
-  croak "datetime object required\n" unless $date;
-  my $cur = $date->hour;
-  my $next = $self->hour->previous($cur);
-  $date->set(hour => $next);
-  $next >= $cur ? $self->_day_decr($date) : $date;
-}
-
-sub _day_decr {
-  my($self, $date) = @_;
-  croak "datetime object required\n" unless $date;
-  $date->subtract(days => 1);
-  $self->_invalid_decr($date);
-}
-
-### Factories
-
-sub _make_cronset { shift; DateTime::Event::Cron::IntegratedSet->new(@_) }
-
-### Shortcuts
-
-sub days_contain { shift->_cronset->days_contain(@_) }
-
-sub minute   { shift->_cronset->minute  }
-sub hour     { shift->_cronset->hour    }
-sub day      { shift->_cronset->day     }
-sub month    { shift->_cronset->month   }
-sub dow      { shift->_cronset->dow     }
-sub user     { shift->_cronset->user    }
-sub command  { shift->_cronset->command }
-sub original { shift->_cronset->original }
-
-### Static acessors/mutators
-
-sub _cronset { shift->_attr('cronset', @_) }
-
-sub _attr {
-  my $self = shift;
-  my $name = shift;
-  if (@_) {
-    $Object_Attributes{$self}{$name} = shift;
-  }
-  $Object_Attributes{$self}{$name};
-}
-
-### debugging
-
-sub _dump_sets {
-  my($self, $date) = @_;
-  foreach (qw(minute hour day month dow)) {
-    print STDERR "$_: ", join(',',$self->$_->list), "\n";
-  }
-  if (ref $date) {
-    $date = $date->clone;
-    my @mod;
-    my $mon = $date->month;
-    $date->truncate(to => 'month');
-    while ($date->month == $mon) {
-      push(@mod, $date->day) if $self->days_contain($date->day, $date->dow);
-      $date->add(days => 1);
-    }
-    print STDERR "mod for month($mon): ", join(',', @mod), "\n";
-  }
-  print STDERR "day_squelch: ", $self->_cronset->day_squelch, " ",
-               "dow_squelch: ", $self->_cronset->dow_squelch, "\n";
-  $self;
-}
-
-###
-
-sub DESTROY { delete $Object_Attributes{shift()} }
-
-##########
-
-{
-
-package DateTime::Event::Cron::IntegratedSet;
-
-# IntegratedSet manages the collection of field sets for
-# each cron entry, including sanity checks. Individual
-# field sets are accessed through their respective names,
-# i.e., minute hour day month dow.
-#
-# Also implements some merged field logic for day/dow
-# interactions.
-
-use strict;
-use Carp;
-
-my %Range = (
-  minute => [0..59],
-  hour   => [0..23],
-  day    => [1..31],
-  month  => [1..12],
-  dow    => [1..7],
-);
-
-my @Month_Max = qw( 31 29 31 30 31 30 31 31 30 31 30 31 );
-
-my %Object_Attributes;
-
-sub new {
-  my $self = [];
-  bless $self, shift;
-  $self->_range(\%Range);
-  $self->set_cron(@_);
-  $self;
-}
-
-sub set_cron {
-  # Initialize
-  my $self = shift;
-  my %parms = @_;
-  my $cron = $parms{cron};
-  my $user_mode = $parms{user_mode};
-  defined $cron or croak "Cron entry fields required\n";
-  $self->_attr('original', $cron);
-  my @line;
-  if (ref $cron) {
-    @line = grep(!/^\s*$/, @$cron);
-  }
-  else {
-    $cron =~ s/^\s+//;
-    $cron =~ s/\s+$//;
-    @line = split(/\s+/, $cron);
-  }
-  @line >= 5 or croak "At least five cron entry fields required.\n";
-  my @entry = splice(@line, 0, 5);
-  my($user, $command);
-  unless (defined $user_mode) {
-    # auto-detect
-    if (@line > 1 && $line[0] =~ /^\w+$/) {
-      $user_mode = 1;
-    }
-  }
-  $user = shift @line if $user_mode;
-  $command = join(' ', @line);
-  $self->_attr('command', $command);
-  $self->_attr('user', $user);
-  my $i = 0;
-  foreach my $name (qw( minute hour day month dow )) {
-    $self->_attr($name, $self->make_valid_set($name, $entry[$i]));
-    ++$i;
-  }
-  my @day_list  = $self->day->list;
-  my @dow_list  = $self->dow->list;
-  my $day_range = $self->range('day');
-  my $dow_range = $self->range('dow');
-  $self->day_squelch(scalar @day_list == scalar @$day_range &&
-                     scalar @dow_list != scalar @$dow_range ? 1 : 0);
-  $self->dow_squelch(scalar @dow_list == scalar @$dow_range &&
-                     scalar @day_list != scalar @$day_range ? 1 : 0);
-  unless ($self->day_squelch) {
-    my @days = $self->day->list;
-    my $pass = 0;
-    MONTH: foreach my $month ($self->month->list) {
-      foreach (@days) {
-        ++$pass && last MONTH if $_ <= $Month_Max[$month - 1];
-      }
-    }
-    croak "Impossible last day for provided months.\n" unless $pass;
-  }
-  $self;
-}
-
-# Field range queries
-sub range {
-  my($self, $name) = @_;
-  my $val = $self->_range->{$name} or croak "Unknown field '$name'\n";
-  $val;
-}
-
-# Perform sanity checks when setting up each field set.
-sub make_valid_set {
-  my($self, $name, $str) = @_;
-  my $range = $self->range($name);
-  my $set = $self->make_set($str, $range);
-  my @list = $set->list;
-  croak "Malformed cron field '$str'\n" unless @list;
-  croak "Field value ($list[-1]) out of range ($range->[0]-$range->[-1])\n"
-    if $list[-1] > $range->[-1];
-  if ($name eq 'dow' && $set->contains(0)) {
-    shift(@list);
-    push(@list, 7) unless $set->contains(7);
-    $set = $self->make_set(join(',',@list), $range);
-  }
-  croak "Field value ($list[0]) out of range ($range->[0]-$range->[-1])\n"
-    if $list[0] < $range->[0];
-  $set;
-}
-
-# No sanity checks
-sub make_set { shift; DateTime::Event::Cron::OrderedSet->new(@_) }
-
-# Flags for when day/dow are applied.
-sub day_squelch { shift->_attr('day_squelch', @_ ) }
-sub dow_squelch { shift->_attr('dow_squelch', @_ ) }
-
-# Merged logic for day/dow
-sub days_contain {
-  my($self, $day, $dow) = @_;
-  defined $day && defined $dow
-    or croak "Day of month and day of week required.\n";
-  my $day_c = $self->day->contains($day);
-  my $dow_c = $self->dow->contains($dow);
-  return $dow_c if $self->day_squelch;
-  return $day_c if $self->dow_squelch;
-  $day_c || $dow_c;
-}
-
-# Set Accessors
-sub minute   { shift->_attr('minute' ) }
-sub hour     { shift->_attr('hour'   ) }
-sub day      { shift->_attr('day'    ) }
-sub month    { shift->_attr('month'  ) }
-sub dow      { shift->_attr('dow'    ) }
-sub user     { shift->_attr('user'   ) }
-sub command  { shift->_attr('command') }
-sub original { shift->_attr('original') }
-
-# Accessors/mutators
-sub _range       { shift->_attr('range', @_) }
-
-sub _attr {
-  my $self = shift;
-  my $name = shift;
-  if (@_) {
-    $Object_Attributes{$self}{$name} = shift;
-  }
-  $Object_Attributes{$self}{$name};
-}
-
-sub DESTROY { delete $Object_Attributes{shift()} }
-
-}
-
-##########
-
-{
-
-package DateTime::Event::Cron::OrderedSet;
-
-# Extends Set::Crontab with some progression logic (next/prev)
-
-use strict;
-use Carp;
-use base 'Set::Crontab';
-
-my %Object_Attributes;
-
-sub new {
-  my $class = shift;
-  my($string, $range) = @_;
-  defined $string && ref $range
-    or croak "Cron field and range ref required.\n";
-  my $self = Set::Crontab->new($string, $range);
-  bless $self, $class;
-  my @list = $self->list;
-  my(%next, %prev);
-  foreach (0 .. $#list) {
-    $next{$list[$_]} = $list[($_+1)%@list];
-    $prev{$list[$_]} = $list[($_-1)%@list];
-  }
-  $self->_attr('next', \%next);
-  $self->_attr('previous', \%prev);
-  $self;
-}
-
-sub next {
-  my($self, $entry) = @_;
-  my $hash = $self->_attr('next');
-  croak "Missing entry($entry) in set\n" unless exists $hash->{$entry};
-  my $next = $hash->{$entry};
-  wantarray ? ($next, $next <= $entry) : $next;
-}
-
-sub previous {
-  my($self, $entry) = @_;
-  my $hash = $self->_attr('previous');
-  croak "Missing entry($entry) in set\n" unless exists $hash->{$entry};
-  my $prev = $hash->{$entry};
-  wantarray ? ($prev, $prev >= $entry) : $prev;
-}
-
-sub _attr {
-  my $self = shift;
-  my $name = shift;
-  if (@_) {
-    $Object_Attributes{$self}{$name} = shift;
-  }
-  $Object_Attributes{$self}{$name};
-}
-
-sub DESTROY { delete $Object_Attributes{shift()} }
-
-}
-
-###
-
-1;
-
-__END__
-
-=head1 NAME
-
-DateTime::Event::Cron - DateTime extension for generating recurrence
-sets from crontab lines and files.
-
-=head1 SYNOPSIS
-
-  use DateTime::Event::Cron;
-
-  # check if a date matches (defaults to current time)
-  my $c = DateTime::Event::Cron->new('* 2 * * *');
-  if ($c->match) {
-    # do stuff
-  }
-  if ($c->match($date)) {
-    # do something else for datetime $date
-  }
-
-  # DateTime::Set construction from crontab line
-  $crontab = '*/3 15 1-10 3,4,5 */2';
-  $set = DateTime::Event::Cron->from_cron($crontab);
-  $iter = $set->iterator(after => DateTime->now);
-  while (1) {
-    my $next = $iter->next;
-    my $now  = DateTime->now;
-    sleep(($next->subtract_datetime_absolute($now))->seconds);
-    # do stuff...
-  }
-
-  # List of DateTime::Set objects from crontab file
-  @sets = DateTime::Event::Cron->from_crontab(file => '/etc/crontab');
-  $now = DateTime->now;
-  print "Now: ", $now->datetime, "\n";
-  foreach (@sets) {
-    my $next = $_->next($now);
-    print $next->datetime, "\n";
-  }
-
-  # DateTime::Set parameters
-  $crontab = '* * * * *';
-
-  $now = DateTime->now;
-  %set_parms = ( after => $now );
-  $set = DateTime::Event::Cron->from_cron(cron => $crontab, %set_parms);
-  $dt = $set->next;
-  print "Now: ", $now->datetime, " and next: ", $dt->datetime, "\n";
-
-  # Spans for DateTime::Set
-  $crontab = '* * * * *';
-  $now = DateTime->now;
-  $now2 = $now->clone;
-  $span = DateTime::Span->from_datetimes(
-            start => $now->add(minutes => 1),
-           end   => $now2->add(hours => 1),
-         );
-  %parms = (cron => $crontab, span => $span);
-  $set = DateTime::Event::Cron->from_cron(%parms);
-  # ...do things with the DateTime::Set
-
-  # Every RTFCT relative to 12am Jan 1st this year
-  $crontab = '7-10 6,12-15 10-28/2 */3 3,4,5';
-  $date = DateTime->now->truncate(to => 'year');
-  $set = DateTime::Event::Cron->from_cron(cron => $crontab, after => $date);
-
-  # Rather than generating DateTime::Set objects, next/prev
-  # calculations can be made directly:
-
-  # Every day at 10am, 2pm, and 6pm. Reference date
-  # defaults to DateTime->now.
-  $crontab = '10,14,18 * * * *';
-  $dtc = DateTime::Event::Cron->new_from_cron(cron => $crontab);
-  $next_datetime = $dtc->next;
-  $last_datetime = $dtc->previous;
-  ...
-
-  # List of DateTime::Event::Cron objects from
-  # crontab file
-  @dtc = DateTime::Event::Cron->new_from_crontab(file => '/etc/crontab');
-
-  # Full cron lines with user, such as from /etc/crontab
-  # or files in /etc/cron.d, are supported and auto-detected:
-  $crontab = '* * * * * gump /bin/date';
-  $dtc = DateTime::Event::Cron->new(cron => $crontab);
-
-  # Auto-detection of users is disabled if you explicitly
-  # enable/disable via the user_mode parameter:
-  $dtc = DateTime::Event::Cron->new(cron => $crontab, user_mode => 1);
-  my $user = $dtc->user;
-  my $command = $dtc->command;
-
-  # Unparsed original cron entry
-  my $original = $dtc->original;
-
-=head1 DESCRIPTION
-
-DateTime::Event::Cron generated DateTime events or DateTime::Set objects
-based on crontab-style entries.
-
-=head1 METHODS
-
-The cron fields are typical crontab-style entries. For more information,
-see L<crontab(5)> and extensions described in L<Set::Crontab>. The
-fields can be passed as a single string or as a reference to an array
-containing each field. Only the first five fields are retained.
-
-=head2 DateTime::Set Factories
-
-See L<DateTime::Set> for methods provided by Set objects, such as
-C<next()> and C<previous()>.
-
-=over 4
-
-=item from_cron($cronline)
-
-=item from_cron(cron => $cronline, %parms, %set_parms)
-
-Generates a DateTime::Set recurrence for the cron line provided. See
-new() for details on %parms. Optionally takes parameters for
-DateTime::Set.
-
-=item from_crontab(file => $crontab_fh, %parms, %set_parms)
-
-Returns a list of DateTime::Set recurrences based on lines from a
-crontab file. C<$crontab_fh> can be either a filename or filehandle
-reference. See new() for details on %parm. Optionally takes parameters
-for DateTime::Set which will be passed along to each set for each line.
-
-=item as_set(%set_parms)
-
-Generates a DateTime::Set recurrence from an existing
-DateTime::Event::Cron object.
-
-=back
-
-=head2 Constructors
-
-=over 4
-
-=item new_from_cron(cron => $cronstring, %parms)
-
-Returns a DateTime::Event::Cron object based on the cron specification.
-Optional parameters include the boolean 'user_mode' which indicates that
-the crontab entry includes a username column before the command.
-
-=item new_from_crontab(file => $fh, %parms)
-
-Returns a list of DateTime::Event::Cron objects based on the lines of a
-crontab file. C<$fh> can be either a filename or a filehandle reference.
-Optional parameters include the boolean 'user_mode' as mentioned above.
-
-=back
-
-=head2 Other methods
-
-=over 4
-
-=item next()
-
-=item next($date)
-
-Returns the next valid datetime according to the cron specification.
-C<$date> defaults to DateTime->now unless provided.
-
-=item previous()
-
-=item previous($date)
-
-Returns the previous valid datetime according to the cron specification.
-C<$date> defaults to DateTime->now unless provided.
-
-=item increment($date)
-
-=item decrement($date)
-
-Same as C<next()> and C<previous()> except that the provided datetime is
-modified to the new datetime.
-
-=item match($date)
-
-Returns whether or not the given datetime (defaults to current time)
-matches the current cron specification. Dates are truncated to minute
-resolution.
-
-=item valid($date)
-
-A more strict version of match(). Returns whether the given datetime is
-valid under the current cron specification. Cron dates are only accurate
-to the minute -- datetimes with seconds greater than 0 are invalid by
-default. (note: never fear, all methods accepting dates will accept
-invalid dates -- they will simply be rounded to the next nearest valid
-date in all cases except this particular method)
-
-=item command()
-
-Returns the command string, if any, from the original crontab entry.
-Currently no expansion is performed such as resolving environment
-variables, etc.
-
-=item user()
-
-Returns the username under which this cron command was to be executed,
-assuming such a field was present in the original cron entry.
-
-=item original()
-
-Returns the original, unparsed cron string including any user or
-command fields.
-
-=back
-
-=head1 AUTHOR
-
-Matthew P. Sisk E<lt>sisk@mojotoad.comE<gt>
-
-=head1 COPYRIGHT
-
-Copyright (c) 2003 Matthew P. Sisk. All rights reserved. All wrongs
-revenged. This program is free software; you can distribute it and/or
-modify it under the same terms as Perl itself.
-
-=head1 SEE ALSO
-
-DateTime(3), DateTime::Set(3), DateTime::Event::Recurrence(3),
-DateTime::Event::ICal(3), DateTime::Span(3), Set::Crontab(3), crontab(5)
-
-=cut