#!/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";
}
}
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.