motomuse has asked for the wisdom of the Perl Monks concerning the following question:
Oh mighty Perl Monks, answer of your wisdom, I entreat.
I have a subroutine whose original intent was to mung the date so
as to name a file based on whatever the date is of the Friday of
the given week.
So that, for example, if it's Wednesday 10/4/2000, the file gets
gets titled 10_6_2000.html (with the idea that it's appended to
after that).
It worked fine up to some unspecified time ago (I only found
out it was broken when one of my users reported a different
problem entirely). Now it's telling me that Friday is 9/28/2000.
Here's the code in question:
$now = time();
($sec,$min,$hour,$mday,$mon,$year,$wday,$rest) = localtime($now);
if ($wday !=4) {
$dow = $wday;
if ($dow < 4) {
$dow += 7;
}
$then = (($dow - 4) * 60 * 60 * 24);
}
($sec,$min,$hour,$mday,$mon,$year,$rest) = localtime($now - $then);
$mon=$mon+1;
$year=$year+1900;
Why's it not working? Should it have ever worked??
Thanks for your attention.
- Muse
(jcwren) Re: Date munging suddenly broken
by jcwren (Prior) on Oct 05, 2000 at 00:58 UTC
|
I'm not clear how this would have ever worked, since your always subtract $then from $now, which means dates will always be in the past, never in the future.
In addition, according to the 'man -f localtime' page, Sunday is day 0, so Friday would be day 5, not day 4. By changing the 4's to 5's, you at least will get the most recent previous Friday.
If you can take a slight performance hit of loading a slightly large module, use Date::Manip. This is a tried and trusted module, and will allow text descriptions of dates you're looking for, like below.
#!/usr/local/bin/perl -w
use strict;
use Date::Manip;
{
print ParseDate ("next Friday");
}
--Chris
e-mail jcwren | [reply] [d/l] |
|
I know that 4 is Thursday; that's intentional. People in general
start creating their status reports on Thursday -- if they start
on Wednesday, I want them to append to the previous Friday. If it's
Thursday, I want them to append to the coming Friday. Sorry I didn't
make that clear.
Anyway, irrespective of that, performance isn't particularly
an issue with this, so I'll gladly take your advice re: loading
the said module. Thanks!
- Muse
| [reply] |
|
Ah, OK. Here's a version that does it algorithmically, rather than using Date::Manip. You'll have to correct for the "If it's Thursday" problem, but this will generate a list of all Friday's in the year.
Also, just as a side note, if you're not using 'use strict', and -w, I'd highly recommend enabling that. It'll help you track down problems a lot faster.
#!/usr/local/bin/perl -w
use strict;
use Time::Local 'timelocal_nocheck';
{
my $friday_date;
my $now = time (); # Not used, here, but it's where the time would
+ come from
for (my $i = 0; $i < 365; $i++)
{
$now = timelocal_nocheck (0, 0, 0, $i, 0, 2000);
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$rest) = localtime ($
+now);
my $then = ((((5 - $wday) + 7) % 7) * (60 * 60 * 24));
($sec,$min,$hour,$mday,$mon,$year,$rest) = localtime ($now + $th
+en);
$mon += 1;
$year += 1900;
my $temp = sprintf ("%02d/%02d/%04d", $mon, $mday, $year);
if ($friday_date ne $temp)
{
print "$temp\n";
$friday_date = $temp;
}
}
}
--Chris
e-mail jcwren | [reply] [d/l] |
|
So, you want something like:
$now = time;
$hour = (localtime $now)[2];
$now += (12 - $hour)*60*60; # offset to noon-hour so DST doesn't fry u
+s
$dow = (localtime $now)[6];
$now += (($dow < 4 ? -2 : 5) - $dow)*24*60*60;
($y, $m, $d) = (localtime $now)[5,4,3];
$file = sprintf "%d_%d_%d.html", $m+1, $d, $y+1900;
perhaps?
-- Randal L. Schwartz, Perl hacker | [reply] [d/l] |
RE: Date munging suddenly broken
by extremely (Priest) on Oct 05, 2000 at 02:00 UTC
|
It never worked right. here are my results for Oct 3
backwards 8 days...
28, 9, 2000
28, 9, 2000
28, 9, 2000
28, 9, 2000
28, 9, 2000
27, 9, 2000
21, 9, 2000
21, 9, 2000
That isn't right at all... How about this:
sub next_friday {
my $now = shift || time();
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$rest) = localtime($now);
my $then = (($wday-5) * 60 * 60 * 24);
($sec,$min,$hour,$mday,$mon,$year,$rest) = localtime($now - $then);
$mon += 1;
$year += 1900;
return "$year.$mon.$mday";
}
That is evil as heck but it works. If you want this
friday to return next friday, you can ++$wday before the
$then calc.
Notice I fancied it up enough that you can send it
arbritary times or it will default to time(). Notice I
made it a sub. Notice what I did to the logic.
Now, forget all that except as a basic lesson in how
things work and use Date::Manip =)
--
$you = new YOU;
honk() if $you->love(perl) | [reply] [d/l] |
|
It's not a big deal, but if it were me, I wouldn't want to
pollute my code with a bunch of unnecessary lexicals.
I prefer to use array slices. So those two localtime
calls would become:
my $wday = (localtime $now)[6];
....
my($mday, $mon, $year) = (localtime($now-$then))[3..5];
Which, in my opinion, is cleaner. | [reply] [d/l] |
|
|