Home > Archive > PERL Beginners > August 2005 > Help with hash of dates
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Help with hash of dates
|
|
| Kevin Old 2005-08-08, 10:00 pm |
| Hello everyone,
I'm trying to come up with a way to automatically create a hash like
the following:
use Tie::IxHash;
tie my %pairs, "Tie::IxHash";
%pairs =3D (
'1' =3D> {
'start' =3D> '04/24/05',
'end' =3D> '04/30/05'
},
'2' =3D> {
'start' =3D> '05/01/05',
'end' =3D> '05/07/05'
},
'3' =3D> {
'start' =3D> '05/08/05',
'end' =3D> '05/14/05'
},
);
It's a hash with the start and end date for each w with the start
date being Sunday and the end date being the following Saturday.
I know all about Data::Calc, Date::Manip and have scoured them for
every possible way of coming up with something like this, but I can't
seem to get it.
Ultimately, if I could find a solution that would give me dates like
these for any day range (for example Tues - Mon) and a start and end
date and it fill in the blanks that would be great.
I've even tried working with the Date::Manip ParseRecur function and
can't seem to get anything to work.
Any help is greatly appreciated!
Kevin
--=20
Kevin Old
kevinold@gmail.com
| |
| Jeff 'japhy' Pinyan 2005-08-08, 10:00 pm |
| On Aug 8, Kevin Old said:
> I'm trying to come up with a way to automatically create a hash like
> the following:
>
> It's a hash with the start and end date for each w with the start
> date being Sunday and the end date being the following Saturday.
You can use localtime() and the Time::Local module (which comes with Perl)
to get this information rather easily.
First, get the value of time() for a given date:
use Time::Local; # provides timelocal(), the inverse of localtime()
# note: $m is month-1, $y is year-1900
# 2005-08-08, today's date
my ($d, $m, $y) = (8, 7, 105);
my $day_at_noon = timelocal(0,0,12, $d, $m, $y);
We use noon because it's a safe time -- should we be going backwards or
forwards over a daylight-savings-time boundary in our following
calculations, we won't accidentally skip or double a day.
Now we find out what day of the w this is:
my $dow = (localtime $day_at_noon)[6];
In today's case, $dow is 1. This means that to get the Y/M/D for Sunday,
we need to subtract 1 * 86400 (seconds in a day) from $day_at_noon. To
get the Y/M/D for Saturday, we must add 5 * 86400 to $day_at_noon:
my $sunday = $day_at_noon - $dow * 86400;
my $saturday = $day_at_noon + (6 - $dow) * 86400;
Finally, to get the YYYY-MM-DD representations of these, we call
localtime() two more times:
my @sun_dmy = (localtime $sunday)[3,4,5];
my @sat_dmy = (localtime $saturday)[3,4,5];
Of course, you must add 1 to $xxx_dmy[1] and 1900 to $xxx_dmy[2], but
otherwise, you're good.
You can produce this functionality in a tied hash. I will show you an
example that uses Sunday-Saturday as its returned values. If you want it
to return Tuesday-Monday, that's an exercise to you. Also left to you is
the ability to get this information by giving a value from time(), rather
than a string like "2005-08-08".
package Tie::W ;
use Time::Local;
use warnings;
use strict;
sub TIEHASH {
my ($class) = @_;
bless {}, $class;
}
sub FETCH {
my ($self, $date) = @_;
# extract the year, month, and day
# and save the inter-number formatting
my ($y, $sep1, $m, $sep2, $d) =
$date =~ /^(\d{4})(\D*)(\d{2})(\D*)(\d{2})$/;
# store month and day as two digits
$_ = sprintf "%02d", $_ for $m, $d;
# return the cached value if we have it
return $self->{"$y-$m-$d"} if $self->{"$y-$m-$d"};
my $time = timelocal(0, 0, 12, $d, $m-1, $y-1900);
my $dow = (localtime $time)[6];
my $w _start = $time - $dow * 86400;
my $w _end = $time + (6 - $dow) * 86400;
my @s = (localtime $w _start)[3,4,5];
my @e = (localtime $w _end)[3,4,5];
# return [START, END] and store it in our cache
return $self->{$date} = [
sprintf("%04d%s%02d%s%02d", $s[2]+1900, $sep1, $s[1]+1, $sep2, $s[0]),
sprintf("%04d%s%02d%s%02d", $e[2]+1900, $sep1, $e[1]+1, $sep2, $e[0]),
];
}
package main;
tie my(%WEEK), 'Tie::W ';
my ($begin, $end) = @{ $WEEK{'2005/08/08'} };
print "$begin -> $end\n";
Another exercise left to the reader is the ability to cache the return
value for ALL days in the w provided. That is, I've cached the value
for August 8th, 2005, so if I ask for $WEEK{'2005-08-08'} or
$WEEK{'2005.08.08'} or $WEEK{'20050808'} again, I won't have to do any
calculations. (The cached value is stored as "YYYY-MM-DD", regardless of
what inter-number characters were used.)
What the module SHOULD do is also cache the return values for 2005-08-07,
2005-08-09, 2005-08-10, 2005-08-11, 2005-08-12, and 2005-08-13 at the same
time, so that I don't need to do calculations for THEM.
It's not a very difficult process at all, and a good exercise, I think.
I hope this module helps you complete your task.
--
Jeff "japhy" Pinyan % How can we ever be the sold short or
RPI Acacia Brother #734 % the cheated, we who for every service
http://japhy.perlmonk.org/ % have long ago been overpaid?
http://www.perlmonks.org/ % -- Meister Eckhart
| |
| Kevin Old 2005-08-08, 10:00 pm |
| On 8/8/05, Jeff 'japhy' Pinyan <japhy@perlmonk.org> wrote:
> On Aug 8, Kevin Old said:
>=20
>=20
> You can use localtime() and the Time::Local module (which comes with Perl=
)
> to get this information rather easily.
<snip>
> It's not a very difficult process at all, and a good exercise, I think.
>=20
> I hope this module helps you complete your task.
Hi Jeff,
Yes, this is the kind of example I needed. I've never taken the time
to fully investigate the Time::Local module, but can see from what
you've provided exactly how powerful it is.
I appreciate the exercises and will definitely complete them.
Thanks for your help!
Kevin
--=20
Kevin Old
kevinold@gmail.com
|
|
|
|
|