User not logged in - login - register
Home Calendar Books School Tool Photo Gallery Message Boards Users Statistics Advertise Site Info
go to bottom | |
 Message Boards » » Perl Question - List of dates Page [1]  
darkone
(\/) (;,,,;) (\/)
11609 Posts
user info
edit post

I'm using perl to, as part of a larger script, create a list of dates for an entire year formatted YYYYMMDD.

For example, if the user specifies the year 2002, it will create the following list and write it to a text file:


20020101
20020102
20020103
.
.
.
20021231


Obviously I have to account for pesky things like leap years. Now, I'm a perl n00b and I am not a programmer by trade. I have code that works and does what I need it to, but I'm sure that it's needlessly complicated. Therefore, my question to TWW is, given the criteria I listed above, how would you do this in perl?

[Edited on May 23, 2008 at 5:37 PM. Reason : not enough Y]

5/23/2008 5:36:44 PM

qntmfred
retired
40555 Posts
user info
edit post

use the DateTime module?

5/23/2008 6:35:04 PM

Arab13
Art Vandelay
45166 Posts
user info
edit post

if the year is divisible by 4 with a whole number and none extra point it to a second set of dates with leap year added

you're gonna need 2 lists for it i think, but the rest is pretty simple

^ have you tried this yet?

5/26/2008 1:49:22 PM

agentlion
All American
13936 Posts
user info
edit post

two lists? what are you talking about?

all you need to do is on the fly generate a list of numbers that are always the same, then when you get to then to february 29 just run a statement like

if( 0 == $year % 4 and 0 != $year % 100 or 0 == $year % 400 ) {
print "$year0229";
}

it is a leap year if it is divisible by 4 but not by 100, except if it is for 400

5/26/2008 3:40:37 PM

agentlion
All American
13936 Posts
user info
edit post

without using any additional modules or any "smart" date handling (i.e. interpreting the dates purely as numbers), then something like this might work (not tested or debugged, no error checking, and assumes $year and $outFileName are provided already)


open (OUTFILE, ">$outFileName");
select OUTFILE; # select default output stream

print "Dates in $year\n"; # header

for ($month = 1; $month<=12; $month++) {
$daysInMonth = 31; #default days in month is 31 because it is most frequent
if ($month == 4 or $month == 6 or $month == 9 or $month == 11) $daysInMonth = 30;
elseif ($month == 2) { #leap year calculation
if (0 == $year % 4 and 0 != $year % 100 or 0 == $year % 400 ) $daysInMonth = 29;
else $daysInMonth = 28;
}

for ($day=1; $day<=$daysInMonth; $day++) {
print "$year";
($month<10) ? print "0$month" : print "$month";
($day<10) ? print "0$day" : print "$day\n";
}
}
close OUTFILE

5/26/2008 3:58:40 PM

darkone
(\/) (;,,,;) (\/)
11609 Posts
user info
edit post

I feel like a dumb ass for not thinking to do this:

"0$day"


My initial stumbling block when first coding my solution was the leading zero on months and days. I was like, "shit, I can't just have a month variable be an interger and go from there because I need the leading zero. I guess I'll use strings."

^That's a more elegant solution that the solution I finally coded. I'll probably clean that up a bit a swap out my needlessly complicated algorithm.

Maybe when I get back to the office, I'll post my original code so you guys can have a laugh.

5/28/2008 10:36:21 PM

agentlion
All American
13936 Posts
user info
edit post

Quote :
"I can't just have a month variable be an interger and go from there because I need the leading zero. I guess I'll use strings."

yeah, more or less all the same in Perl - integer, string, numbers, whatever - Perl is smart enough to know the difference (how long till i'm corrected by the Perl gods telling me that "NUH UH - PERL VARIABLES HAVE TYPES!")

5/28/2008 11:03:59 PM

darkone
(\/) (;,,,;) (\/)
11609 Posts
user info
edit post

My code: (don't laugh too much... it does actually work)


@listMonths = ("01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12");
@listDay_28 = ("01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28");
@listDay_29 = ("01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29");
@listDay_30 = ("01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30");
@listDay_31 = ("01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31");


foreach $Month (@listMonths)
{
if ($Month eq "01" or $Month eq "03" or $Month eq "05" or $Month eq "07" or $Month eq "08" or $Month eq "10" or $Month eq "12")
{
foreach $Day (@listDay_31)
{
$Date="$Year$Month$Day";
system("echo \'$Date\' >> \'$DateList\'");
}
}
elsif ($Month eq "04" or $Month eq "06" or $Month eq "09" or $Month eq "11")
{
foreach $Day (@listDay_30)
{
$Date="$Year$Month$Day";
system("echo \'$Date\' >> \'$DateList\'");
}
}
else {
if ($Year eq "2000" or $Year eq "2004" or $Year eq "1998" or $Year eq "2008" or $Year eq "2012") #all leap years in the TRMM dataset
{
foreach $Day (@listDay_29)
{
$Date="$Year$Month$Day";
system("echo \'$Date\' >> \'$DateList\'");
}
}
else
{
foreach $Day (@listDay_28)
{
$Date="$Year$Month$Day";
system("echo \'$Date\' >> \'$DateList\'");
}
}
}
}



I hard coded in the leap year dates because I'm working with data from a satellite that was launched in 1997 and will run out of fuel in 2012.

[Edited on May 30, 2008 at 4:34 PM. Reason : leap year info]

5/30/2008 4:33:23 PM

agentlion
All American
13936 Posts
user info
edit post

a colleague just reminded me of the printf function, which will format your output, for example, with leading zeros. The printing can be further simplified to

for ($day=1; $day<=$daysInMonth; $day++) {
print "\n$year";
printf '%02s', $month;
printf '%02s', $day;
}

6/2/2008 1:10:56 PM

agentlion
All American
13936 Posts
user info
edit post

a little more optimization - this is all you need in the for loop


for ($day=1; $day<=$daysInMonth; $day++)
sprint '%04s%02s%02s\n', $year, $month, $day;

6/2/2008 1:40:42 PM

agentlion
All American
13936 Posts
user info
edit post

ok, now i have Perl geeks at work doing what Perl geeks do best - making the program shorter

this will take care of all the year, month and day printing, including leap years


$month = 1;
foreach (31,28,31,30,31,30,31,31,30,31,30,31) {
$daysInMonth=$_;
$month++;
if ($daysInMonth == 28 && !($year%4) && ($year%100) || !($year%400) ) $daysInMonth = 29;
for ($day=1; $day<=$daysInMonth; $day++) printf "%04s%02s%02s\n",$year,$month,$day;
}


[Edited on June 2, 2008 at 4:10 PM. Reason : .]

6/2/2008 4:09:32 PM

darkone
(\/) (;,,,;) (\/)
11609 Posts
user info
edit post

^wow... I <3 perl

6/2/2008 8:47:51 PM

Scary Larry
Suspended
644 Posts
user info
edit post

I don't mean to butt in with my opinion, but date handling should pretty much never be done by loop or list, and it really sounds like this is going to be used as a work around for a proper implementation of date and time logic. If that's the case you should probably realize how terribly wrong it is to difference dates by file line numbers. Sure it may work, but it's so far from having predictable behavior or utilizing resources efficiently that I'd just err on the side of caution and call it flat out wrong.

6/2/2008 8:59:51 PM

darkone
(\/) (;,,,;) (\/)
11609 Posts
user info
edit post

^ read the intended goal and comment again

6/2/2008 9:02:09 PM

Scary Larry
Suspended
644 Posts
user info
edit post

I read the intended goal, and I honestly can't think of a good reason to generate such a text file. The point I was trying to convey was that the need for such a text in your application implied a greater problem with date handling than simply generating the text file.

Again, if I'm making assumptions about your application I apologize. I've seen too many good script ideas rendered useless in implementation, as hacks were unnecessarily used to treat computer science challenges in the same manner as API challenges.

6/2/2008 9:42:19 PM

qntmfred
retired
40555 Posts
user info
edit post

you know, that reminds me of a problem i was trying to solve at work today

given a start and end DateTime (we're talking c# now), generate a List representing the range of dates between the start and end date separated by a given amount of time. the only way i could think to do it was a loop

List dates = new List<DateTime>();
DateTime curDate = start;
while (curDate<=end)
{
dates.Add(curDate);
curDate.AddMonths(1);
}


it seemed like there should be a better way, but i couldn't think of anything simpler than this

6/2/2008 10:27:44 PM

darkone
(\/) (;,,,;) (\/)
11609 Posts
user info
edit post

^^ The file generated is used as input for a called script.

6/2/2008 10:43:56 PM

LimpyNuts
All American
16859 Posts
user info
edit post

Quote :
"
$month = 1;
foreach (31,28,31,30,31,30,31,31,30,31,30,31) {
$daysInMonth=$_;
$month++;
if ($daysInMonth == 28 && !($year%4) && ($year%100) || !($year%400) ) $daysInMonth = 29;
for ($day=1; $day<=$daysInMonth; $day++) printf "%04s%02s%02s\n",$year,$month,$day;
}
"

Any particular reason you're starting the months at 2? $month++ should go after the output loop.

6/4/2008 10:04:48 PM

agentlion
All American
13936 Posts
user info
edit post

Quote :
"not tested or debugged, no error checking"

6/4/2008 10:06:18 PM

 Message Boards » Tech Talk » Perl Question - List of dates Page [1]  
go to top | |
Admin Options : move topic | lock topic

© 2024 by The Wolf Web - All Rights Reserved.
The material located at this site is not endorsed, sponsored or provided by or on behalf of North Carolina State University.
Powered by CrazyWeb v2.38 - our disclaimer.