Skip Menu |

This queue is for tickets about the DateTime-Event-Cron CPAN distribution.

Report information
The Basics
Id: 25980
Status: resolved
Priority: 0/
Queue: DateTime-Event-Cron

People
Owner: MSISK [...] cpan.org
Requestors: krishnoid [...] wapacut.com
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 0.07
Fixed in: (no value)



Subject: year crossings, time zones, pig and elephant DNA just don't splice
When I run the attached test case, I get the following output. The test case is used to parse a crontab entry and retrieve the next DateTime according to that crontab entry. It considers 'now' as March 30, 2007 and April 2, 2007 (see below), and generates the following output: 0:> crontestcase.pl Script start is 2007-03-30T19:21:08 Cron spec (15 15 5 1 *) ok, startlater calc'd as (2008-01-05T15:15:00) Cron spec (15 15 10 1 *) ok, startlater calc'd as (2008-01-10T15:15:00) Cron spec (15 15 5 2 *) ok, startlater calc'd as (2008-02-05T15:15:00) Cron spec (15 15 10 2 *) ok, startlater calc'd as (2008-02-10T15:15:00) Note it times out during calculating March: Cron (15 15 5 3 *) calculation timed out, retrying with UTC Cron spec (15 15 5 3 *) ok, startlater calc'd as (2008-03-05T15:15:00) Cron (15 15 10 3 *) calculation timed out, retrying with UTC Cron spec (15 15 10 3 *) ok, startlater calc'd as (2008-03-10T15:15:00) But the rest is ok. Cron spec (15 15 5 4 *) ok, startlater calc'd as (2007-04-05T15:15:00) Cron spec (15 15 10 4 *) ok, startlater calc'd as (2007-04-10T15:15:00) Cron spec (15 15 5 5 *) ok, startlater calc'd as (2007-05-05T15:15:00) Cron spec (15 15 10 5 *) ok, startlater calc'd as (2007-05-10T15:15:00) Cron spec (15 15 5 6 *) ok, startlater calc'd as (2007-06-05T15:15:00) Cron spec (15 15 10 6 *) ok, startlater calc'd as (2007-06-10T15:15:00) Cron spec (15 15 5 7 *) ok, startlater calc'd as (2007-07-05T15:15:00) Cron spec (15 15 10 7 *) ok, startlater calc'd as (2007-07-10T15:15:00) Cron spec (15 15 5 8 *) ok, startlater calc'd as (2007-08-05T15:15:00) Cron spec (15 15 10 8 *) ok, startlater calc'd as (2007-08-10T15:15:00) Cron spec (15 15 5 9 *) ok, startlater calc'd as (2007-09-05T15:15:00) Cron spec (15 15 10 9 *) ok, startlater calc'd as (2007-09-10T15:15:00) Cron spec (15 15 5 10 *) ok, startlater calc'd as (2007-10-05T15:15:00) Cron spec (15 15 10 10 *) ok, startlater calc'd as (2007-10-10T15:15:00) Cron spec (15 15 5 11 *) ok, startlater calc'd as (2007-11-05T15:15:00) Cron spec (15 15 10 11 *) ok, startlater calc'd as (2007-11-10T15:15:00) Cron spec (15 15 5 12 *) ok, startlater calc'd as (2007-12-05T15:15:00) Cron spec (15 15 10 12 *) ok, startlater calc'd as (2007-12-10T15:15:00) Now try April 2, 2007: Script start is 2007-04-02T19:21:08 Mistakenly reporting 2009 instead of 2008, and for only February 9, it reports 2010 (if you dump *all* 1..28 of February, Feb 9 is the only one that jumps to the next year, strangely). Cron spec (15 15 5 1 *) ok, startlater calc'd as (2009-01-05T15:15:00) Cron spec (15 15 9 1 *) ok, startlater calc'd as (2009-01-09T15:15:00) Cron spec (15 15 5 2 *) ok, startlater calc'd as (2009-02-05T15:15:00) Cron spec (15 15 9 2 *) ok, startlater calc'd as (2010-02-09T15:15:00) Chokes on March again. Cron (15 15 5 3 *) calculation timed out, retrying with UTC Cron spec (15 15 5 3 *) ok, startlater calc'd as (2008-03-05T15:15:00) Cron (15 15 9 3 *) calculation timed out, retrying with UTC Cron spec (15 15 9 3 *) ok, startlater calc'd as (2008-03-09T15:15:00) The rest is good up till ... Cron spec (15 15 5 4 *) ok, startlater calc'd as (2007-04-05T15:15:00) Cron spec (15 15 9 4 *) ok, startlater calc'd as (2007-04-09T15:15:00) Cron spec (15 15 5 5 *) ok, startlater calc'd as (2007-05-05T15:15:00) Cron spec (15 15 9 5 *) ok, startlater calc'd as (2007-05-09T15:15:00) Cron spec (15 15 5 6 *) ok, startlater calc'd as (2007-06-05T15:15:00) Cron spec (15 15 9 6 *) ok, startlater calc'd as (2007-06-09T15:15:00) Cron spec (15 15 5 7 *) ok, startlater calc'd as (2007-07-05T15:15:00) Cron spec (15 15 9 7 *) ok, startlater calc'd as (2007-07-09T15:15:00) Cron spec (15 15 5 8 *) ok, startlater calc'd as (2007-08-05T15:15:00) Cron spec (15 15 9 8 *) ok, startlater calc'd as (2007-08-09T15:15:00) Cron spec (15 15 5 9 *) ok, startlater calc'd as (2007-09-05T15:15:00) Cron spec (15 15 9 9 *) ok, startlater calc'd as (2007-09-09T15:15:00) Cron spec (15 15 5 10 *) ok, startlater calc'd as (2007-10-05T15:15:00) Cron spec (15 15 9 10 *) ok, startlater calc'd as (2007-10-09T15:15:00) November, when it jumps to 2008. Cron spec (15 15 5 11 *) ok, startlater calc'd as (2008-11-05T15:15:00) Cron spec (15 15 9 11 *) ok, startlater calc'd as (2008-11-09T15:15:00) Cron spec (15 15 5 12 *) ok, startlater calc'd as (2008-12-05T15:15:00) Cron spec (15 15 9 12 *) ok, startlater calc'd as (2008-12-09T15:15:00) Ubuntu 6.10, DateTime::Event::Cron 0.07 and the dependencies it was able to pull in from the standard distribution. If you can't reproduce this, please let me know and I'll add more details.
Subject: crontestcase.pl
#!/usr/bin/perl # # sub debug (@ ) { print @_, "\n" }; sub next_time_of_cron_spec ($ ); my $curtime = 1175307668; # March 30 2007 $scriptstartdt = DateTime->from_epoch(epoch => $curtime); $scriptstartdt->set_time_zone('America/Los_Angeles'); debug "Script start is $scriptstartdt"; foreach $month (qw(jan feb mar apr may jun jul aug sep oct nov dec)) { foreach $dom (5,10) { next_time_of_cron_spec("15 15 $dom $month *"); } } $scriptstartdt += DateTime::Duration->new(seconds => 86400 * 3); # Apr 2 debug "Script start is $scriptstartdt"; foreach $month (qw(jan feb mar apr may jun jul aug sep oct nov dec)) { foreach $dom (5, 9) { next_time_of_cron_spec("15 15 $dom $month *"); } } sub next_time_of_cron_spec ($ ) { my ($cronspec) = @_; my $valid = undef; use DateTime::Event::Cron; # DateTime object representing next occurrence per cron spec my $startlaterdt; # DateTime::Set of cron occurrences my $crondtset; # need an eval because DateTime::Event::Cron croak()'s on an invalid cron # spec. # We standardize 'now' to be the start time of the scheduler script. # This is to eliminate dependencies on how long various parts of the # script took to run and to avoid timing issues when stepping through # code in the debugger. if ($cronspec =~ m/\S/) { # handle named months and dow per crontab(5) -- currently # DateTime::Event::Cron cant handle named months/dow, so we simulate it # here INIT { %calnametonum = qw(jan 1 feb 2 mar 3 apr 4 may 5 jun 6 jul 7 aug 8 sep 9 oct 10 nov 11 dec 12 mon 1 tue 2 wed 3 thu 4 fri 5 sat 6 sun 7); $calregexp = '(' . join('|', keys %calnametonum) . ')'; }; $cronspec = lc $cronspec; $cronspec =~ s/$calregexp/$calnametonum{$1}/gi; eval { $crondtset = DateTime::Event::Cron->from_cron (cron=>$cronspec, after=>$scriptstartdt); }; } if (ref $crondtset) { # ugly ugly hack -- DateTime::Event::Cron has a bug where it hangs on # calculating next year current month for certain cron specs # e.g., today is 2007-3-30, calculating 23 59 3 29 * hangs # so we alarm it and recalculate using utc if problems eval { # NB: newline required in die local $SIG{ALRM} = sub { die "alarm\n" }; alarm 2; $startlaterdt = $crondtset->next; alarm 0; }; if ($@) { # propagate unexpected errors die unless $@ eq "alarm\n"; debug "Cron ($cronspec) calculation timed out, retrying with UTC"; my $scriptstartdtutc = $scriptstartdt->clone; $scriptstartdtutc->set_time_zone('UTC'); $crondtset = DateTime::Event::Cron->from_cron (cron=>$cronspec, after=>$scriptstartdtutc); $startlaterdt = $crondtset->next; $valid=1; } else { $valid=1; } debug "Cron spec ($cronspec) ok, startlater calc'd as ($startlaterdt)"; } ref $startlaterdt or do { my $delay = 5; use DateTime::Duration; debug "Cron spec ($cronspec) not parseable"; $startlaterdt = $scriptstartdt->clone + DateTime::Duration->new(seconds => $delay); $valid = 0; }; # times are passed around as strings, and those strings are to # be interpreted in the timezone local to the scheduler machine # $startlaterdt->set_time_zone('local'); # $startlaterdt stringifies to sql-friendly ISO8601 date format return ("$startlaterdt", $valid); }
From: krishnoid [...] wapacut.com
On Fri Mar 30 22:58:21 2007, krishnoid@wapacut.com wrote: Show quoted text
> When I run the attached test case, I get the following output. The test > case is used to parse a crontab entry and retrieve the next DateTime > according to that crontab entry.
Also try running the .t tests in the DateTime-Event-Cron distribution, but instead of: sub make_datetime { @_ == 6 or die "Invalid argument count\n"; DateTime->new( year => $_[0], month => $_[1], day => $_[2], hour => $_[3], minute => $_[4], second => $_[5] ); } try: sub make_datetime { @_ == 6 or die "Invalid argument count\n"; DateTime->new( year => $_[0], month => $_[1], day => $_[2], hour => $_[3], minute => $_[4], second => $_[5] , time_zone => 'America/Los_Angeles'); } I got one hang in cascade.t and one failure in cron.t .
I've been unable to replicate these bugs; I'm guessing it might have been a transient issue somewhere down in the DateTime suite. If you can produce the errors again, please reopen this ticket.