cfreak has asked for the wisdom of the Perl Monks concerning the following question:

This may take a minute to explain: I'm writing a simple calendar
program for the web. A piece of my program takes a range of dates
and formats in HTML a traditional looking graph calendar. If not given
a range then the code takes a month and year (which it converts to a range
using 1 as the first day and whatever the last day of the month is as the
last day.)

This all works quite well, except for April of any given year. For ease
in identifying dates I'm using epoch time at midnight for each day
and adding 86400 to increment each day. Whenever I enter April
somewhere my code adds 1 hour or 3600 seconds to my day increment ($tepoch).
This unfortunatly thinks that it has reached the last day and removes
April 30. The weird thing is that the program doesn't understand
months, its only using the range of days 1-30 for April. But for
other months with 30 days this problem does not occur.

Here is the offending piece of code:

267 # Sets up HTML tables to graph a calendar 268 sub graph_calendar { 269 # Form options 270 my (%form) = @_; 271 272 # Setup the return variable 273 my $tms = ""; 274 275 # If a range is not specified ($form{'pdays'} - today - $f +orm{'ndays'}) then 276 # find the epoch of the first day of the requested month a +nd the epoch 277 # of the last day of the requested month (for the requeste +d year) 278 my($pday,$nday); 279 if(!$form{'pdays'} || !$form{'ndays'}) { 280 $pday = timelocal(0,0,0,1,$form{'gmonth'},$form{'gyear +'}); 281 $nday = timelocal(0,0,0,month_days($form{'gmonth'},$fo +rm{'gyear'}),$form{'gmonth'},$form{'gyear'}); 282 } 283 else{ 284 #else: a range is specifed 285 $pday = ($form{'pdays'} * 2) - $form{'pdays'}; #make p +days negative 286 $pday = ($pday * 86400) + time(); # pdays ago 287 $nday = ($form{'ndays'} * 86400)+ time(); # ndays from + now 288 289 } 290 291 # Table headers 292 my $tsetup = "<table"; 293 if($form{'bgcolor'}) { 294 $tsetup .= " bgcolor=\"#$form{'bgcolor'}\""; 295 } 296 if($form{'bgimage'}) { 297 $tsetup .= " background=\"$form{'bgimage'}\""; 298 } 299 300 $form{'border'} or $form{'border'} = 1; 301 $form{'cellspacing'} or $form{'cellspacing'} = 0; 302 $form{'cellpadding'} or $form{'cellpadding'} = 3; 303 $form{'lines'} or $form{'lines'} = 10; 304 305 my $line_height = $form{'lines'} * 10; 306 my $trans = $conf->trans_image(); 307 $tsetup .= " cellspacing=\"$form{'cellspacing'}\" cellpadd +ing=\"$form{'cellpadding'}\" border=\"$form{'border'}\" width=\"98%\" +>\n"; 308 309 310 # Problem lurking in here somewhere 311 312 # Get the day/month/year for $pday 313 my @local = localtime($pday); 314 315 # Make sure $pday is set to midnight 316 my $tepoch = timelocal(0,0,0,1,$local[4],($local[5] + 1900 +)); 317 318 # Counters for days/months/years 319 my $daycounter = 1; 320 my $monthcounter = $local[4]; 321 my $yearcounter = $local[5] + 1900; 322 323 # Number of seconds in a day 324 my $add = 86400; 325 326 # Slots 0-6 = days of week Sun-Sat 327 my $slot = 0; 328 329 # HTML for days of the week 330 my $day_name_string = "<tr>"; 331 foreach my $dayname(qw(Sunday Monday Tuesday Wednesday Thu +rsday Friday Saturday)) { 332 $day_name_string .= "<td width=\"14%\" valign=\"top\"> +\n"; 333 $day_name_string .= "<p align=\"center\" style=\"font- +family:Arial,Helvetica,Sans-Serif;font-size:12pt\">\n"; 334 $day_name_string .= "<b>$dayname</b>\n"; 335 $day_name_string .= "</td>\n"; 336 } 337 $day_name_string .= "</tr>\n"; 338 339 # Loop while epoch range gets smaller 340 while($tepoch <= $nday) { 341 if($daycounter == 1) { # If the beginning of the +month 342 my @local2 = localtime($tepoch); 343 $slot = $local[6]; # Find what day of the week th +is month begins on 344 $tms .= $tsetup; # Start a n +ew table 345 $tms .= "<tr>\n"; 346 $tms .= "<td colspan=\"7\" width=\"100%\">\n"; 347 $tms .= "<p align=\"center\" style=\"font-family:A +rial,Helvetica,Sans-Serif;font-size:18pt\">\n"; 348 $tms .= get_monthname($monthcounter) . " $yearcoun +ter\n"; 349 $tms .= "</p></td></tr>\n"; 350 $tms .= "$day_name_string\n"; 351 352 if($slot) { # If slot > 0 print empty <TD></TD> up + until day before begining day of week 353 foreach my $z(0 .. ($slot - 1)) { 354 $tms .= "<td width=\"14%\">\&nbsp;</td>\n" +; 355 } 356 } 357 } 358 # Insert this day of the week 359 $tms .= "<td width=\"14%\" valign=\"top\">\n"; 360 $tms .= "<img src=\"$trans\" align=\"left\" width=\"1\ +" height=\"$line_height\" valign=\"top\">\n"; 361 $tms .= "<span style=\"font-family:Arial,Helvetica,San +s-Serif;font-size:14pt;\">\n"; 362 $tms .= "<b>$daycounter</b></span><br>\n"; # Day numbe +r 363 $tms .= "<!--$tepoch-->\n"; # epoch time, used in addi +ng descriptions later 364 $tms .= "</td>\n"; 365 $tepoch = $tepoch + $add; # Add the next day 366 $daycounter++; # Count the action day number up 367 368 # If the last day of the month has been printed 369 if($daycounter > month_days($monthcounter,$yearcounter +)) { 370 $daycounter = 1; # Reset day counter to 1 371 $monthcounter++; # Increment Month counter 372 foreach my $q($slot .. 5) { # Insert blank slots u +ntil the TR row is filled 373 $tms .= "<td width=\"14%\">\&nbsp;</td>\n"; 374 } 375 # End the HTML table 376 $tms .= "</tr>\n"; 377 $tms .= "</table>\n"; 378 if($monthcounter > 11) { # If December 379 $monthcounter = 0; # Set month January 380 $yearcounter ++; # Increment the year 381 } + 382 } 383 else { 384 # else: 385 $slot++; # Increment the slot ( +day of week) 386 if($slot > 6) { # If > sat 387 $tms .="</tr><tr>\n"; # End the row. 388 $slot = 0; # Set to Sunday 389 } 390 } 391 } 392 return $tms; # Return the Tables 393 }

Replies are listed 'Best First'.
Re: Weird time issue
by chipmunk (Parson) on Jun 23, 2001 at 01:52 UTC
    Sounds like you're having an issue with Daylight Savings Time. Try using noon instead of midnight; that way when DST hits you'll still be in the same day.
      Only in the monthdays function. If you make it in both you have the same issue.
Re: Weird time issue (boo)
by boo_radley (Parson) on Jun 23, 2001 at 00:21 UTC
    Gosh, this seems almost canonical but... have you looked at CPAN?

    There's a supergroovy module called HTML::CalendarMonth that you'd probably enjoy using. It's got gobs of functionality and it's never given me a problem for the two times I've used it.

    There are some basic examples located here : http://mojotoad.com/sisk/projects/HTML-CalendarMonth/examples.html.
    Note that these are more or less basic examples. There's a lot of goodness that comes with the package.

    use HTML::CalendarMonth; use HTML::AsSubs; # Using HTML::AsSubs $c = HTML::CalendarMonth->new( month => 3, year => 69 ); $c->item($c->year, $c->month)->attr(bgcolor => 'wheat'); $c->item($c->year, $c->month)->wrap_content(font({size => '+2'})); $c->item(12, 16, 28)->wrap_content(strong()); print $c->as_HTML;
Re: Weird time issue
by mr.dunstan (Monk) on Jun 23, 2001 at 00:10 UTC
    whoo, I can't tell what the problem is here but I can tell you that the last time I did this, I used Date::Calc to handle all the nasty math ...

    mr.dunstan
Re: Weird time issue
by particle (Vicar) on Jun 23, 2001 at 00:15 UTC
    wait a second... you coded your own april fool's joke?!?!?

    ~Particle