#!/usr/bin/perl
use strict;
use warnings;
use Time::Local qw(timelocal_nocheck);
# calculate Age, days from last birthday and days to next birthday for
# a given birth date.
# birthdate is a string of the format 'YYYY-MM-DD'
# - good for accepting dates from databases
# If the birthdate is today, then days from = days to = 0
# returns age, days from, days to
# NOTE: this script does no date validation
# NOTE: this script uses the current year to calculate age.
# NOTE: if you modify this script to use anything other than current y
+ear,
# there may be leap year implications
sub birth_date_age_today {
my $birthdate = shift || return 0;
$birthdate =~ m/^(\d\d\d\d)-(\d\d)-(\d\d)$/ or return 0;
my ($byyyy,$bmm,$bdd) = ($1,$2,$3);
--$bmm;
my ($yyyy) = (localtime)[5];
$yyyy += 1900;
my $cur_day_of_year = (localtime)[7];
# nocheck or feb 29 birthdays will have problems
my $birth_day_of_year = (localtime timelocal_nocheck(0, 0, 0, $bdd
+, $bmm, $yyyy - 1900))[7];
# calculate age
my $age = $yyyy - $byyyy;
my $daysto;
my $daysfrom;
if ($cur_day_of_year < $birth_day_of_year) {
# haven't hit birthday yet this year
$age--;
$daysto = $birth_day_of_year - $cur_day_of_year;
# last year's birthday
$yyyy--;
$birth_day_of_year = (localtime timelocal_nocheck(0, 0, 0, $bd
+d, $bmm, $yyyy - 1900))[7];
# correct for days (2100 isn't a leap year)
$daysfrom = (($yyyy % 4 or $yyyy == 2100) ? 365 : 366) - $birt
+h_day_of_year + $cur_day_of_year;
}
elsif ($cur_day_of_year > $birth_day_of_year) {
# passed birthday this year
$daysfrom = $cur_day_of_year - $birth_day_of_year;
# next year's birthday
# Note: we get the number of days to the birthday in the next
+year ($yyyy - 1899)
# but we use the current year for checking leap year because w
+e need to know how
# many days are left in this year
$birth_day_of_year = (localtime timelocal_nocheck(0, 0, 0, $bd
+d, $bmm, $yyyy - 1899))[7];
# correct for leap days (2100 isn't a leap year)
$daysto = (($yyyy % 4 or $yyyy == 2100) ? 365 : 366) - $cur_da
+y_of_year + $birth_day_of_year;
}
else { $daysfrom = $daysto = 0 }
return $age, $daysfrom, $daysto;
}
# a simple test script
# run through every date (birthdate) of a given year
# print the results (relative to current date)
my %days = (
1 => 31,
2 => 28,
3 => 31,
4 => 30,
5 => 31,
6 => 30,
7 => 31,
8 => 31,
9 => 30,
10 => 31,
11 => 30,
12 => 31,
);
my $yyyy = 1965;
# This is not totally correct! Just simplified for this test
$days{2} = ($yyyy % 4 or $yyyy == 1900 or $yyyy == 2100) ? 28 : 29;
for (my $mm = 1; $mm <= 12; ++$mm) {
for (my $dd = 1; $dd <= $days{$mm}; ++$dd) {
my $testdate = sprintf("$yyyy-%02d-%02d", $mm, $dd);
my ($age, $daysfrom, $daysto) = birth_date_age_today($testdate
+);
print "birthdate $testdate age $age from last $daysfrom day
+s to $daysto\n";
}
}
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.