Re: Perl calendar
by zentara (Cardinal) on Jun 23, 2008 at 13:42 UTC
|
Look at HTML::CalendarMonthSimple and see how he wrote the code. If it contains modules that are not standard, manually rewrite those functions. You can install the CalendarMonthSimple package, directly in your script, so you would only need Date::Calc ( or manually rewritten functions for it).
| [reply] |
|
|
Unfortunately Date::Calc is full of compiled C-code so replacing it with self-written Perl code will not be for the faint hearted.
CountZero A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James
| [reply] |
Re: Perl calendar
by psini (Deacon) on Jun 23, 2008 at 13:24 UTC
|
It is certainly possible. But the mandatory question is: why do it w/o using existing modules?
The only thing to remember is that february has 29 days if and only if $year%4==0 && ($year%100!=0 || $year%400==0) I've seen too many broken implementation of leap years...
Update: expression corrected (Thanks, Moritz)
Careful with that hash Eugene.
| [reply] [d/l] |
|
|
I've seen too many broken implementation of leap years...
Me too. Speaking of which, what should
!$year%4 && ($year%100 || $year%400)
do? if a number is divisible by 400, it is always also divisible by 100. (Update: not sure if that sentence makes sense. Other way round: if it's not divisible by 400 it's also not divisible by 100. Does that make more sense?)
My suggestion is not to re-invent the wheel, and work around the "no external module" limitation. I quite like Date::Simple module which does about everything you want for date processing (if you don't need times), and is very intuitive.
I'd construct a leap year condition like that, but I might be wrong - which is why I used a module:
my $is_leep = ($year % 400 == 0) || (($year % 4 == 0) && $year % 100 !
+= 0))
| [reply] [d/l] [select] |
|
|
| [reply] [d/l] |
|
|
Thanks for the input. The reason for no modules is, no modules other then what is currently installed in the default installation can be used, nor can any modules be installed (firewall and admin restrictions).
Its one of the more cumbersome tasks I'm working on, and I need to overcome the lack of modules here using what's available. timelocal appears to provide the easiest way of doing this, and is part of the standard installation.
I will take the leap year into account. Thanks for pointing that out!
Can I assume timelocal will handle the leap year correctly here?
my $_next_month = timelocal(0, 0, 0, 1, $_month % 12, $_next_year);
my $_last_day = (localtime($_next_month - 86400))[3];
| [reply] [d/l] |
|
|
The reason for no modules is, no modules other then what is currently installed in the default installation can be used, nor can any modules be installed (firewall and admin restrictions).
I can't even count how many times I've seen this. Heck, I've even seen it at $work. Hasn't stopped me from using CPAN modules where they make sense. I first had to convince my manager that this was a good idea. That wasn't hard. "Free code." As in, hours or days or even weeks of work, already done, likely reasonably well tested (look - unit tests!), that I don't have to repeat. That can propel me a bunch of the way through my current task. Note: I had this conversation independently from any conversation on how to get around the restrictions. Merely that the restrictions were impeding my ability to be as productive as possible.
Then I found two ways around the restrictions. One was technical, one was social. The social one was more difficult, and likely will be for you, too. In this case, I befriended someone on the team that controlled the global installations of perl, and had him install XML::Twig on all platforms. What I actually did here was trade him work. He was tasked with something that my team was in a better position to do, which would look good on my yearly review to own (so I wanted it anyway), but was going to be a royal PITA for him. I suggested that I'd do it if he installed XML::Twig everywhere. He jumped at the trade. (He then got a bit frustrated in getting expat installed everywhere, but didn't complain much.)
The technical solution works for most modules, but I didn't use it for XML::Twig because of expat. For these, where a simple untar && perl Makefile.PL && make && make install would work (or the equivalent using Build.PL), I just simply check the tarballs into our source code repository. During our build process, I install them *to* the source tree (not globally - don't have write access there) using a simple algorithm which even works on Windows.
At this point, the modules I need are built into my tree, and I can use them.
Once I put this infrastructure in, it has been really cheap to get lots of work done: just add new CPAN modules.
Update: roboticus likened this to an XY Problem (see wikipedia or even google). I kinda think of this more of having an articial limitation (box) placed on your work, and needing to think outside of that limitation to actually solve it. In an XY Problem, it seems (to me) to be the consensus that the petitioner does a partial solve on X, and asks about the partial solution Y. In this case, the limitation is given to the petitioner who is then tasked to work within these boundaries. The XY problem is not the one posed to PM ("How do I do this without external modules?"), but the limitation itself ("No external modules" when the real problem is likely more along the lines of "we don't want to muck about with our standard perl installs as that's going to make upgrading or porting to new machines or even platforms such a royal pain that we won't be able to afford the work.") Understanding your IT department's real concerns can help you make great strides in getting your own work done as cheaply as possible. If you're into Agile or related methodologies, consider your IT department as a stakeholder. That may make things much more obvious.
| [reply] |
|
|
Unix time does not count leap seconds. This article shows the discontinuity that occurs when a leap second is encountered: (Wikipedia entry for Unix time).
| [reply] |
|
|
Can I assume timelocal will handle the leap year correctly here?
Yes.
localtime and timelocal do deal correctly with leap years, but I don't know how it handles leap seconds. They might be a problem because they could make you leak into a different day than you might expect. (Don't know if that's a real problem, but it's one of the many problems i can think of).
| [reply] |
Re: Perl calendar
by apl (Monsignor) on Jun 23, 2008 at 13:28 UTC
|
| [reply] |
Re: Perl calendar
by Anonymous Monk on Jun 23, 2008 at 14:44 UTC
|
Well, if you want to optimize for maximum laziness...
my $cal = `cal`;
chomp $cal;
print <<"EOT";
<pre>
$cal
</pre>
EOT
:)
| [reply] [d/l] |
Re: Perl calendar
by Cristoforo (Curate) on Jun 23, 2008 at 21:11 UTC
|
Here's one that I wrote a while ago using Time::Local. It works out for a plain text file but if you wanted to print it to a web page, the $cal string would need carriage returns of <br> instead of "\n" and whitespace padding using &nbsp. This method of incrementing the days doesn't rely on adding '86400' to your previous day.
#!/usr/bin/perl
use strict;
use warnings;
use Time::Local;
my @names = qw/ JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC/;
my $year = shift ||'2007';
for my $month (0..11) {
print " $names[$month] $year\n";
print calendar($year, $month), "\n\n";
}
sub calendar {
my ($year, $month) = @_;
my @mon_days = qw/31 28 31 30 31 30 31 31 30 31 30 31/;
++$mon_days[1] if $year % 4 == 0 && ($year % 400 == 0 || $year % 1
+00 != 0);
my $cal = " Sun Mon Tue Wed Thu Fri Sat\n";
# Months are indexed beginning at 0
my $time = timegm(0,0,0,1,$month,$year);
my $wday = (gmtime $time)[6];
$cal .= " " x $wday;
my $mday = 1;
while ($mday <= $mon_days[$month]) {
$cal .= sprintf "%4s", $mday++;
$cal .= "\n" if ($wday + $mday -1) % 7 == 0;
}
return $cal;
}
Chris | [reply] [d/l] |
Re: Perl calendar
by pc88mxer (Vicar) on Jun 23, 2008 at 13:34 UTC
|
AFAIK, both localtime() and Time::Local (a core module) work on Windows and Linux, and you can use them to perform date calculations.
Unix time, the value returned by time(), does not take into account leap seconds. Therefore days are always 86400 seconds long which makes it useful for performing date arithmetic. However, be aware that localtime() may not work with a Unix time that represents a date past January 19th, 2038. This is known as the Year 2038 problem. The good news is that a fix for perl is actively being worked on (link).
| [reply] [d/l] [select] |