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

Description
I have been looking at this php code that calculates US holidays. I have been trying to translate this into perl for me to use this in a portion of my application. I was wondering if someone could help me translate the following piece.

Piece Needed to translate

if (!$week || ($week == "")) { $lastday = date("t", mktime(0,0,0,$month,1,$year)); $temp = (date("w",mktime(0,0,0,$month,$lastday,$year)) - $day_of_ +week) % 7; } else { $temp = ($day_of_week - date("w",mktime(0,0,0,$month,1,$year))) % + 7; }

As you can see the too main things that need to be replaced are the "date" and "mktime" fuction.

Thanks in advance for your help :-)



For anyone interested in the whole code

#!/usr/local/bin/perl -w use CGI; use POSIX; use Date::Calc qw(:all); #use diagnostics; # Code taken from # http://abledesign.com/programs/holiday_code.php # US Holiday Calculations in PHP # Version 1.02 # by Dan Kaplan <design@abledesign.com> # #($year,$month,$day) = Today(); ($y) = Today(); # Get current year # format to use: # # get_holiday("year", "month", "day_of_week", "week_of_month"); # get_holiday("year", "month", "day_of_week"); # no 4th field indic +ates last week of month check # format_date("year", "month", "day"); print "<p><b>$y Holidays</b></p>"; print "<ul>"; print "<li>New Year's Day = ". format_date($y, 1, 1); print "<br>New Year's Day Observed = ". observed_day($y, 1, 1); print "<li>Martin Luther King Day Observed (Third Monday in January) = + ". &get_holiday($y, 1, 1, 3); print "<li>Valentine's Day = ". format_date($y, 2, 14); print "<li>President's Day Observed (Third Monday in February) = ". &g +et_holiday($y, 2, 1, 3); print "<li>St. Patrick's Day = ". format_date($y, 3, 17); print "<li>Easter = ". calculate_easter($y); print "<li>Cinco De Mayo = ". format_date($y, 5, 5); print "<li>Memorial Day Observed (Last Monday in May) = ". &get_holida +y($y, 5, 1, ""); print "<li>Independence Day = ". format_date($y, 7, 4); print "<br>Independence Day Observed = ". observed_day($y, 7, 4); print "<li>Labor Day Observed (First Monday in September) = ". &get_ho +liday($y, 9, 1, 1); print "<li>Columbus Day Observed (Second Monday in October) = ". &get_ +holiday($y, 10, 1, 2); print "<li>Halloween = ". format_date($y, 10, 31); # Veteran's Day Observed - November 11th ? print "<li>Thanksgiving (Fourth Thursday in November) = ". &get_holida +y($y, 11, 4, 4); print "<li>Christmas Day = ". format_date($y, 12, 25); print "</ul>"; exit(0); sub format_date { my ($year, $month, $day) = @_; # pad single digit months/days with a leading zero for consist +ency (aesthetics) # and format the date as desired: YYYY-MM-DD by default if (length($month) == 1) { $month = "0$month"; } if (length($day) == 1) { $day = "0$day"; } $date = "$year$month$day"; return $date; } # the following function get_holiday() is based on the work done by # Marcos J. Montes: http:#www.smart.net/~mmontes/ushols.html # if $week is not passed in, then we are checking for the last week of + the month sub get_holiday { my ($year, $month, $day_of_week, $week) = @_; if ( (($week ne "") && (($week > 5) || ($week < 1))) || ($day_ +of_week > 6) || ($day_of_week < 0) ) { # $day_of_week must be between 0 and 6 (Sun=0, ... Sat +=6); # $week must be between 1 and 5 return; } else { #if (!$week || ($week == "")) { # $lastday = date("t", mktime(0,0,0,$month,1,$ye +ar)); # $temp = (date("w",mktime(0,0,0,$month,$lastday +,$year)) - $day_of_week) % 7; #} else { # $temp = ($day_of_week - date("w",mktime(0,0,0, +$month,1,$year))) % 7; #} if (!$week || ($week == "")) { $lastday = date("t", mktime(0,0,0,$month,1,$ye +ar)); $temp = (date("w",mktime(0,0,0,$month,$lastday +,$year)) - $day_of_week) % 7; } else { $temp = ($day_of_week - date("w",mktime(0,0,0, +$month,1,$year))) % 7; } if ($temp < 0) { $temp += 7; } if (!$week || ($week == "")) { $day = $lastday - $temp; } else { $day = (7 * $week) - 6 + $temp; } return format_date($year, $month, $day); } } sub observed_day { my ($year, $month, $day) = @_; # sat -> fri & sun -> mon, any exceptions? # # should check $lastday for bumping forward and $firstday for +bumping back, # although New Year's & Easter look to be the only holidays th +at potentially # move to a different month, and both are accounted for. $dow = date("w", mktime(0, 0, 0, $month, $day, $year)); if ($dow == 0) { $dow = $day + 1; } elsif ($dow == 6) { if (($month == 1) && ($day == 1)) { # New Year's on + a Saturday $year--; $month = 12; $dow = 31; } else { $dow = $day - 1; } } else { $dow = $day; } return format_date($year, $month, $dow); } sub calculate_easter { my ($y) = @_; # In the text below, 'intval($var1/$var2)' represents an integ +er division neglecting # the remainder, while % is division keeping only the remainde +r. So 30/7=4, and 30%7=2 # # This algorithm is from Practical Astronomy With Your Calcula +tor, 2nd Edition by Peter # Duffett-Smith. It was originally from Butcher's Ecclesiastic +al Calendar, published in # 1876. This algorithm has also been published in the 1922 boo +k General Astronomy by # Spencer Jones; in The Journal of the British Astronomical As +sociation (Vol.88, page # 91, December 1977); and in Astronomical Algorithms (1991) by + Jean Meeus. $a = $y%19; $b = intval($y/100); $c = $y%100; $d = intval($b/4); $e = $b%4; $f = intval(($b+8)/25); $g = intval(($b-$f+1)/3); $h = (19*$a+$b-$d-$g+15)%30; $i = intval($c/4); $k = $c%4; $l = (32+2*$e+2*$i-$h-$k)%7; $m = intval(($a+11*$h+22*$l)/451); $p = ($h+$l-7*$m+114)%31; $EasterMonth = intval(($h+$l-7*$m+114)/31); # [3 = March, 4 + = April] $EasterDay = $p+1; # (day in Easter Month) return format_date($y, $EasterMonth, $EasterDay); }

Replies are listed 'Best First'.
Re: Perl from PHP
by cbro (Pilgrim) on May 08, 2003 at 14:54 UTC
    $lastday = date("t", mktime(0,0,0,$month,1,$year)); $temp = (date("w",mktime(0,0,0,$month,$lastday, $year)) - $day_of_week) % 7;
    The first line is returning the number of days in the given month. The second line is the day of the week.
    Date::Calc has the functions:
    Days_in_Month($year, $month)
    Day_of_Week($year,$month,$day)

    Maybe those two functions, or at least something from Date::Calc, will help you. ust do perldoc Date::Calc for more details.
    HTH,
    Chris
Re: Perl from PHP
by Thelonius (Priest) on May 08, 2003 at 15:06 UTC
    mktime is a POSIX function, so you can use POSIX::mktime. Although you can (probably should) use one of the Date modules from CPAN, here are a couple of brief functions:
    sub dayofweek { # 0=Sunday .. 6=Saturday # input is Unix epoch time return (4 + int($_[0]/86400)) % 7; } sub daysinmonth { # input is Unix epoch time my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($_[0]); if (++$mon == 12) { $mon = 0; $year++; } ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(POSIX::mktime(0,0,0,1,$mon,$year) - 3600*3); return $mday; }
    Update:Errr, don't use the day of week function. It gives the day of week all right--in London (gmtime)! Here's an even simpler function that works with your time zone:
    sub dayofweek { (localtime $_[0])[6] }
    Duh.
Re: Perl from PHP
by tcf22 (Priest) on May 08, 2003 at 14:54 UTC
    Check out Time::Local. This does the opposite of localtime, so you can get the day of week, etc.
    use Time::Local; my $time = timelocal($sec,$min,$hour,$mday,$mon,$year); my @time_array = localtime($time);
    As for
    date("t", mktime(0,0,0,$month,1,$year));
    I think you may have to just make an array with the last days of every month and use $lastdays[$mon] to get that day. I'm not aware of a perl function that will do that.
Re: Perl from PHP
by jepri (Parson) on May 09, 2003 at 04:05 UTC
    And here is the pretty much obligatory comment that Date::Manip can do pretty much everything that you want, even calculate when Easter is.

    ____________________
    Jeremy
    I didn't believe in evil until I dated it.