use strict; use warnings; use POSIX qw( strftime ); use Time::Local qw( timegm_nocheck ); # Supplied definitions. my $base_year = 2004; my $base_month = 1; # 0-based my $base_day = 1; # 1-based my @weeks_in_month = ( 4, # Feb 5, # Mar 4, # Apr 4, # May 5, # Jun 4, # Jul 4, # Aug 5, # Sep 4, # Oct 4, # Nov 5, # Dec 4, # Jan ); # Derived constants. my @days_before_month = (0); for (0..11) { $days_before_month[$_+1] = $days_before_month[$_] + $weeks_in_month[$_] * 7; } my $days_in_year = $days_before_month[12]; # The guts. sub first_day_of_accounting_month { my ($year, $month) = @_; my $day = $base_day + ($year - $base_year) * $days_in_year + $days_before_month[$month]; my $time = timegm_nocheck(0,0,0, $day, $base_month, $base_year); } sub first_day_of_accounting_year { push(@_, 0); goto &first_day_of_accounting_month; } # Generate a bunch of data for demo purposes. # The output format can easily be changed. my $date_format = '%b %d, %Y'; for my $year (2004 .. 2015) { my $time; $time = first_day_of_accounting_year($year); print("Accounting year $year\n"); print(strftime($date_format, gmtime($time)) . "\n"); print("\n"); for my $month (0..11) { # Feb..Jan $time = first_day_of_accounting_month($year, $month); print(strftime($date_format, gmtime($time)) . "\n"); } print("\n"); print("\n"); }