aboutsummaryrefslogtreecommitdiff
path: root/challenge-013/athanasius/perl5/ch-1.pl
blob: f243222b071a26c2c023d79d3ede3e3524fa7bae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!perl

################################################################################
=comment

Perl Weekly Challenge 013
=========================

Challenge #1
------------

Write a script to print the date of last *Friday* of every month of a given
year. For example, if the given year is *2019* then it should print the follow-
ing:

2019/01/25
2019/02/22
2019/03/29
2019/04/26
2019/05/31
2019/06/28
2019/07/26
2019/08/30
2019/09/27
2019/10/25
2019/11/29
2019/12/27

=cut
################################################################################

#--------------------------------------#
# Copyright © 2019 PerlMonk Athanasius #
#--------------------------------------#

use strict;
use warnings;
use Const::Fast;
use DateTime;
use Regexp::Common;

const my @DAYS_IN_MONTH  => ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
const my $DAYS_IN_WEEK   =>    7;
const my $DEFAULT_YEAR   => 2019;
const my $FEBRUARY_INDEX =>    1;
const my @OFFSET_1ST_FRI => (  4,  3,  2,  1,  0,  6,  5 );
const my $USAGE          => "USAGE: perl $0 <year>";

$| = 1;

MAIN:
{
    my $year  = get_year();
    my $dt    = DateTime->new(year => $year, month => 1, day => 1);
    my $first = 1 + $OFFSET_1ST_FRI[ $dt->day_of_week - 1 ];
    my @days  = @DAYS_IN_MONTH;
     ++$days[ $FEBRUARY_INDEX ] if $dt->is_leap_year();

    print "\nLast Fridays in each month of $year:\n\n";

    for my $month (0 .. 11)
    {
        my $days  = $days[ $month ];
        my $last  = $first;
           $last += $DAYS_IN_WEEK until $last > $days;
           $first = $last - $days;
           $last -= $DAYS_IN_WEEK;

        printf "%4d/%02d/%02d\n", $year, ($month + 1), $last;
    }
}

sub get_year
{
    scalar @ARGV <= 1
        or die "\n$USAGE\n";

    my $year = $ARGV[0] // $DEFAULT_YEAR;

    $year =~ /^$RE{num}{int}$/
        or die "\nInvalid year '$year': must be an integer\n";

    return $year;
}

################################################################################