TL;DR

Here we are with TASK #1 from The Weekly Challenge #175. Enjoy!

# The challenge

Write a script to list Last Sunday of every month in the given year.

For example, for year 2022, we should get the following:

2022-01-30
2022-02-27
2022-03-27
2022-04-24
2022-05-29
2022-06-26
2022-07-31
2022-08-28
2022-09-25
2022-10-30
2022-11-27
2022-12-25


# The questions

I always get shivers when I see a challenge involving dates (or times) with such a broad span. In the given year screams for a question about which limits should (or could) be assumed.

In the same vein, Iâ€™d also ask where should we anchor the answer to.

Iâ€™m no expert about dates and times, but Socratically I know that I donâ€™t know enough and Iâ€™ll probably never will. I got alive through a single read of UTC is enough for everyone â€¦right? and that convinced me to avoid date and time stuff (at least with a broad span) as much as possible.

Hence, Iâ€™ll assume that whatever applies to Roma (Italy) since the seventies should be correct, everything else is nice to have. Anywayâ€¦ these are test challenges, not production stuff right?!?

# The solution

As usual, weâ€™ll start with Raku, which supports Date handling natively. Iâ€™ll blindly assume that itâ€™s fine for the constraints Iâ€™ve set in the questions!

#!/usr/bin/env raku
use v6;
sub MAIN (Int:D $year = 2022) { .put for sundays-in($year) }

sub sundays-in (Int:D $year) { my$year-start = Date.new(:$year); # find the first sunday in the year my$cursor = $year-start;$cursor++ while $cursor.day-of-week % 7; # find all last sundays in the year return gather loop { # we will compare a candidate sunday against the next one my$candidate = $cursor;$cursor += 7;

# a jump in the month for the "next" sunday means that our
# $candidate was the last one in its month, so take it take$candidate if $cursor.month !=$candidate.month;

# a jump in the year means we've taken the last one in the
# requested year, so we can just say goodbye
last if $cursor.year >$candidate.year;
};
}


The approach is the following:

• find the first Sunday in the target year, this will be our starting point (initializing variable $cursor); • loop to do the same: • advance the cursor ahead one week (assuming that 7 days are one week); • compare whether this advanced date stepped onto the next month with respect to the starting value • if advanced, the previous value is a Last Sunday and gets taken • stop when the year of the new value is the next one (we have it January of the next year). I still cross my finger thinking of applying this to any year. In Perl, we can leverage the venerable DateTime but otherwise more or less translate the solution from Raku: #!/usr/bin/env perl use v5.24; use warnings; use experimental 'signatures'; no warnings 'experimental::signatures'; use DateTime; my$year = shift // 2022;
say for sundays_in($year); sub sundays_in ($year) {
my $year_start = DateTime->new( year =>$year,
month => 1,
day  => 1,
hour => 12,
time_zone => 'floating',
);

# find the first sunday in the year
my $cursor =$year_start->clone;
$cursor->add(days => 1) while$cursor->day_of_week % 7;

# find all last sundays in the year
my @retval;
while ($cursor->year ==$year) {

# we will compare a candidate sunday against the next one
my $candidate =$cursor->clone;
$cursor->add(days => 7); # a jump in the month for the "next" sunday means that our #$candidate was the last one in its month, so take it
push @retval, $candidate->ymd('-') if$cursor->month != \$candidate->month;
}
return @retval;
}


I know I said something about being valid for Roma (Italy), but this is only because I know that nothing specific has happened since the seventies in the last century. To be on the safe side (e.g. for leap stuff) Iâ€™m setting in the middle of the day at 12 oâ€™clock.

So there we have, all the Last Sundays in a year, in a hopefully working solution!

Comments? Octodon, , GitHub, Reddit, or drop me a line!