<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
On 7/12/2012 8:45 PM, Joel Berger wrote:<br>
<blockquote
cite="mid:CAAMA-9PjV02dHNd7EFHn7ZrLTdYGh-vUq41hPAMbrw3MHY16tQ@mail.gmail.com"
type="cite">
<pre wrap="">I tried this using a free web service, and I got right to the point of
dealing with DateTime math, so I leave that to you :-)
The webservice is at <a class="moz-txt-link-freetext" href="http://www.holidaywebservice.com">http://www.holidaywebservice.com</a>
my code is at <a class="moz-txt-link-freetext" href="https://gist.github.com/3102219">https://gist.github.com/3102219</a>
All it does now is get the holidays this month. From there, after
deciding if you have passed the last one, add a month and request
again. Repeat as needed.</pre>
</blockquote>
<br>
I took a crack at it as well. My goal was simplicity without using
a lot of complex (and perhaps poorly documented) objects that like
DateTime::Set::ICal .<br>
<br>
I saw magically generating holidays as the hard part and I'd prefer
not to be tied to a web service, so I found a list of holidays
online and pasted them into a __DATA__ section. <br>
<br>
Once you have that semi-ugly solution, the date logic is very
simple: just compare the whole list of dates to today, or a date of
your choice; discard past dates and return the date with the
smallest delta. <br>
<br>
I don't know what Richard is trying to do, but this script gives
complete control over what's a holiday and once you find the
holidays, it's self-contained. Of course, it will run out of
holidays some day; as written, the script will stop working in
2014. It probably wouldn't take long to add 50 years of holidays.
If you were running this script several times a second on a server
AND you had 50 years of holidays, you might need a more
refined/elegant algorithm (e.g., ignore all years' data except this
year and next year).<br>
<br>
I did find Date::Manip extraordinarily frustrating to work with.
This line took 10 minutes of my life:<br>
<br>
my $sec = Delta_Format($d, 0, "%sh"); # convert to seconds<br>
<br>
because Delta_Format advertises:<br>
<br>
<pre class="sh_perl sh_sourceCode" style="background-color: rgb(255, 255, 255); border: 1px solid rgb(136, 136, 136); color: rgb(0, 0, 0); padding: 1em; white-space: pre; font-weight: normal; font-style: normal; font-variant: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; background-position: initial initial; background-repeat: initial initial; "> <span class="sh_variable" style="color: rgb(178, 104, 24); font-weight: normal; font-style: normal; ">%Xv</span> <span class="sh_symbol">:</span> <span class="sh_keyword" style="color: rgb(178, 104, 24); font-weight: normal; font-style: normal; ">print</span> the value of the field X
<span class="sh_variable" style="color: rgb(178, 104, 24); font-weight: normal; font-style: normal; ">%Xd</span> <span class="sh_symbol">:</span> <span class="sh_keyword" style="color: rgb(178, 104, 24); font-weight: normal; font-style: normal; ">print</span> the value of the field X <span class="sh_keyword" style="color: rgb(178, 104, 24); font-weight: normal; font-style: normal; ">and</span> all
smaller units in terms of X
<span class="sh_variable" style="color: rgb(178, 104, 24); font-weight: normal; font-style: normal; ">%Xh</span> <span class="sh_symbol">:</span> <span class="sh_keyword" style="color: rgb(178, 104, 24); font-weight: normal; font-style: normal; ">print</span> the value of field X <span class="sh_keyword" style="color: rgb(178, 104, 24); font-weight: normal; font-style: normal; ">and</span> all
larger units in terms of X
<span class="sh_variable" style="color: rgb(178, 104, 24); font-weight: normal; font-style: normal; ">%Xt</span> <span class="sh_symbol">:</span> <span class="sh_keyword" style="color: rgb(178, 104, 24); font-weight: normal; font-style: normal; ">print</span> the value of all fields in
terms of X</pre>
<br>
So I originally tried to convert to days directly:<br>
<br>
my $days = Delta_Format($d, 2, "%dt"); # convert to days<br>
<br>
but this always returns zero because the deltas all look like
0:0:0:0:1272:0:0. I would think that 1272 hours "in terms of X"
where X=days would be something like 53 days. But I was wrong,
somehow it's 0 days. I have no idea why the deltas are like this.
Date::Manip::Delta seems to suggest that the deltas returned from
Date::Manip functions should be normalized (whatever "been made
consistent with the type of data they represent" means) and the
deltas I was getting seems non-normalized. So maybe that's a bug or
maybe there's some reason like hours results in an integer
representation or something. But when I switched to seconds, it
works. That kinda sucks, but who knows WTF is supposed to be
happening because X isn't actually ever defined in the description
of Delta_Format() ... Maybe 'd' doesn't means days and is
undefined, so I get a zero. I first thought that X=4 because I
wanted the fourth field... But no, if you review Date::Manip::Delta
... well, it certainly won't condescend to even mentioning
Delta_Format() but it does describe a printf method and says "Here,
X is one of (y,M,w,d,h,m,s)". Examining Date::Manip::Examples might
also have helped clue me to X. So, if you like programming to be
like a text adventure game... Date::Manip is the library for you!<br>
<br>
Anyway, here's what I get when I run this today (just after midnight
in Chicago on 7/13/2012):<br>
<br>
[amead@cow3 perl]$ ./tmp.pl<br>
The next holiday is Labor Day on Sep 3, 2012 in about 52 days<br>
The next holiday after Jan 2, 2013 is Martin Luther King Day on Jan
21, 2013 in about 19 days<br>
<br>
And below is the script. <br>
<br>
-Alan<br>
<br>
#!/usr/bin/perl<br>
<br>
use strict;<br>
use warnings;<br>
<br>
<br>
use Date::Manip;<br>
# I'm going to assume DM6;see the Date::Manip documentation<br>
<br>
# read the holiday data<br>
our %holidays = ();<br>
while (my $line = <DATA>) {<br>
$line =~ s/[\r\n]+//g; # remove newlines<br>
$line =~ s/#.*$//g; # remove comments<br>
$line =~ s/^\s+//g; # remove leading psaces<br>
$line =~ s/\s+$//g; # remove trailing psaces<br>
$line =~ s/\s*\|\s*/|/g; # remove spaces around the delimiter<br>
next unless( $line ); # skip blank/comment lines<br>
my($date, $holiday) = split /\|/, $line;<br>
$holidays{$date} = $holiday; # NB: don't reverse this<br>
}<br>
<br>
close(DATA);<br>
<br>
{ # first example<br>
<br>
my($inseconds, $next_holday, $next_date) = next_holiday();<br>
printf "The next holiday is $next_holday on $next_date in about
%.0f days\n", $inseconds/(24*3600);<br>
<br>
}<br>
<br>
{ # second example<br>
<br>
my $today = 'Jan 2, 2013';<br>
my($inseconds, $next_holday, $next_date) = next_holiday( $today );<br>
printf "The next holiday after $today is $next_holday on
$next_date in about %.0f days\n", $inseconds/(24*3600);<br>
<br>
}<br>
<br>
<br>
sub next_holiday {<br>
my $from_date = shift || 'today';<br>
<br>
my $soonest = 32000000; # slightly more than a year of seconds<br>
my $soonest_date = '';<br>
my $soonest_hol = '';<br>
for my $date ( keys %holidays ) {<br>
my $d = DateCalc($from_date,$date);<br>
#print "date-$date, hol=$holidays{$date}, d=$d\n";<br>
my $sec = Delta_Format($d, 0, "%sh"); # convert to seconds<br>
next unless( $sec >= 0 ); # skip past holidays<br>
#print "$date, $holidays{$date} : sec=$sec, soonest=$soonest\n";<br>
if( $sec < $soonest ) {<br>
$soonest = $sec;<br>
$soonest_date = $date;<br>
$soonest_hol = $holidays{$date};<br>
}<br>
}<br>
<br>
return( $soonest, $soonest_hol, $soonest_date );<br>
<br>
}<br>
<br>
<br>
__DATA__<br>
# cut-and-pasted from
<a class="moz-txt-link-freetext" href="http://www.timeanddate.com/calendar/?year=2012&country=1">http://www.timeanddate.com/calendar/?year=2012&country=1</a><br>
# and <a class="moz-txt-link-freetext" href="http://www.timeanddate.com/calendar/?year=2013&country=1">http://www.timeanddate.com/calendar/?year=2013&country=1</a><br>
Jan 1, 2012|New Year's Day<br>
Jan 2, 2012|New Year's Day observed<br>
Jan 16, 2012|Martin Luther King Day<br>
Feb 14, 2012|Valentine's Day<br>
Feb 20, 2012|Presidents' Day<br>
Apr 8, 2012|Easter Sunday<br>
May 13, 2012|Mother's Day<br>
May 28, 2012|Memorial Day<br>
Jun 17, 2012|Father's Day<br>
Jul 4, 2012|Independence Day<br>
Sep 3, 2012|Labor Day<br>
Oct 8, 2012|Columbus Day (Most regions)<br>
Oct 31, 2012|Halloween<br>
Nov 6, 2012|Election Day<br>
Nov 11, 2012|Veterans Day<br>
Nov 12, 2012|Veterans Day observed<br>
Nov 22, 2012|Thanksgiving Day<br>
Dec 24, 2012|Christmas Eve<br>
Dec 25, 2012|Christmas Day<br>
Dec 31, 2012|New Year's Eve<br>
Jan 1, 2013|New Year's Day<br>
Jan 21, 2013|Martin Luther King Day<br>
Feb 14, 2013|Valentine's Day<br>
Feb 18, 2013|Presidents' Day<br>
Mar 31, 2013|Easter Sunday<br>
May 12, 2013|Mother's Day<br>
May 27, 2013|Memorial Day<br>
Jun 16, 2013|Father's Day<br>
Jul 4, 2013|Independence Day<br>
Sep 2, 2013|Labor Day<br>
Oct 14, 2013|Columbus Day (Most regions)<br>
Oct 31, 2013|Halloween<br>
Nov 11, 2013|Veterans Day<br>
Nov 28, 2013|Thanksgiving Day<br>
Dec 24, 2013|Christmas Eve<br>
Dec 25, 2013|Christmas Day<br>
Dec 31, 2013|New Year's Eve<br>
# paste more data here for additional years...<br>
<br>
<br>
<br>
<pre class="moz-signature" cols="72">--
Alan D. Mead, Ph.D.
Assistant Professor of Industrial and Organizational Psychology
College of Psychology
Illinois Institute of Technology
3101 South Dearborn, 2nd floor
Chicago IL 60616
+312.567.5933 (Campus)
+815.588.3846 (Home Office)
+312.567.3493 (Fax)
<a class="moz-txt-link-freetext" href="http://www.iit.edu/~mead">http://www.iit.edu/~mead</a>
<a class="moz-txt-link-freetext" href="http://www.alanmead.org">http://www.alanmead.org</a>
Announcing the Journal of Computerized Adaptive Testing (JCAT), a
peer-reviewed electronic journal designed to advance the science and
practice of computerized adaptive testing: <a class="moz-txt-link-freetext" href="http://www.iacat.org/jcat">http://www.iacat.org/jcat</a></pre>
<br>
<br>
</body>
</html>