1#!/usr/bin/perl 2use strict; 3use warnings; 4 5use Time::Moment; 6 7# Calculates age of a person in calendar years. 8# 9# Where a person has been born on February 29th in a leap year, the 10# anniversary in a non-leap year can be taken to be February 28th or 11# March 1st. Some countries have laws defining which date a person 12# born on February 29th comes of age in legal terms. In England and 13# Wales, for example, the legal age of a leapling is March 1st in 14# common years. The same applies in Hong Kong. In Taiwan and in 15# New Zealand, the legal age of a leapling is February 28th in 16# common years. 17# https://en.wikipedia.org/wiki/February_29#Births 18sub calculate_age { 19 @_ == 2 or @_ == 3 or die q/Usage: calculate_age($birth, $event [, $march])/; 20 my ($birth, $event, $march) = @_; 21 22 my $years = $birth->delta_years($event); 23 24 unless ($march) { 25 # Increment if birth is 02-29 and event is 02-28 in a non-leap year 26 ++$years if $birth->day_of_year == 31 + 29 && $birth->is_leap_year 27 && $event->day_of_year == 31 + 28 && !$event->is_leap_year; 28 } 29 return $years; 30} 31 32my @tests = ( 33 [ '2008-02-28T00Z', '2015-02-27T00Z', 0, 6 ], 34 [ '2008-02-28T00Z', '2015-02-28T00Z', 0, 7 ], 35 [ '2008-02-28T00Z', '2015-03-01T00Z', 0, 7 ], 36 [ '2008-02-29T00Z', '2015-02-27T00Z', 0, 6 ], 37 [ '2008-02-29T00Z', '2015-02-28T00Z', 0, 7 ], 38 [ '2008-02-29T00Z', '2015-03-01T00Z', 0, 7 ], 39 [ '2008-03-01T00Z', '2015-02-27T00Z', 0, 6 ], 40 [ '2008-03-01T00Z', '2015-02-28T00Z', 0, 6 ], 41 [ '2008-03-01T00Z', '2015-03-01T00Z', 0, 7 ], 42 [ '2008-02-29T00Z', '2016-02-27T00Z', 0, 7 ], 43 [ '2008-02-29T00Z', '2016-02-28T00Z', 0, 7 ], 44 [ '2008-02-29T00Z', '2016-02-29T00Z', 0, 8 ], 45 [ '2008-02-29T00Z', '2016-03-01T00Z', 0, 8 ], 46 47 [ '2008-02-28T00Z', '2015-02-27T00Z', 1, 6 ], 48 [ '2008-02-28T00Z', '2015-02-28T00Z', 1, 7 ], 49 [ '2008-02-28T00Z', '2015-03-01T00Z', 1, 7 ], 50 [ '2008-02-29T00Z', '2015-02-27T00Z', 1, 6 ], 51 [ '2008-02-29T00Z', '2015-02-28T00Z', 1, 6 ], 52 [ '2008-02-29T00Z', '2015-03-01T00Z', 1, 7 ], 53 [ '2008-03-01T00Z', '2015-02-27T00Z', 1, 6 ], 54 [ '2008-03-01T00Z', '2015-02-28T00Z', 1, 6 ], 55 [ '2008-03-01T00Z', '2015-03-01T00Z', 1, 7 ], 56 [ '2008-02-29T00Z', '2016-02-27T00Z', 1, 7 ], 57 [ '2008-02-29T00Z', '2016-02-28T00Z', 1, 7 ], 58 [ '2008-02-29T00Z', '2016-02-29T00Z', 1, 8 ], 59 [ '2008-02-29T00Z', '2016-03-01T00Z', 1, 8 ], 60); 61 62use Test::More 0.88; 63 64foreach my $test (@tests) { 65 my ($birth, $event, $march, $age) = @$test; 66 my $got = calculate_age(Time::Moment->from_string($birth), 67 Time::Moment->from_string($event), 68 $march); 69 is($got, $age, "calculate_age($birth, $event, $march)"); 70} 71 72done_testing(); 73