I Know What You Did Last Sunday

Wherein we ponder the question: when we have a month of weeks, each with an ending weekend, which weekend end ends the month?

THE WEEKLY CHALLENGE – PERL & RAKU #175 Task 1


When a day that you happen to know is Wednesday starts off by sounding like Sunday, there is something seriously wrong somewhere.

John Wyndham, The Day of the Triffids


Last Sunday

Submitted by: Mohammad S Anwar

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

ANALYSIS

We’re wise enough to know when to haul in a library to do our dirty work, and in the case of date and time manipulations now is that time. With leap years and whatnot, tracking days of the week is a fool’s errand. In the long run, it just doesn’t pay not to: doable, surely, but subject to too many pitfalls to make making certain you didn’t miss every single one a tedious slog. After all, if someone has gone through an enormous amount of trouble to figure out the hoary details already, why not honor their efforts?

METHOD

Before even looking at the API for our chosen module, two alternate strategies come to mind:

  1. Once for every month in the year, check the day of the week for the last day and count backwards from there until we find a Sunday
  2. Look at every day starting on January 1, note the month and date if it is a Sunday. Then we preserve the previously saved month and date variables when either the month changes or we run out of days.

Each has their advantages I suppose. I think we’ll try implementing the first because, well, I haven’t done that before. Seems like it should work.

PERL 5 SOLUTION

For our library, we’ll use the venerable DateTime module. This has the constructor DateTime->last_day_of_month which is configured with the attributes for year and month, the year in YYYY format, the months starting at 1. A new DateTime object is then instantiated for the last day of that month. Next we subtract one day from the object until the day_of_week method returns 7 — using until as a conditional structure, if the day is already 7 we subtract nothing.

To output we get the method format_cldr, which gives us access to the Unicode Common Locale Data Repository formats, which are quite richly featured — way more so than strftime. So we’re going to use that, because it’s the 21st century, baby.

This neatly and quickly homes in on the Sunday in question. A short loop through all 12 months in the given year and we’re done.

use warnings;
use strict;
use utf8;
use feature ":5.26";
use feature qw(signatures);
no warnings 'experimental::signatures';

use DateTime ;


my $year = shift @ARGV // 2022;

for my $month ( 1..12 ) {
    my $dt = DateTime->last_day_of_month( year  => $year, 
                                          month => $month );
    $dt->subtract( days => 1 ) until $dt->day_of_week == 7;
    say $dt->format_cldr( "MMM dd, YYYY" );
}



The Perl Weekly Challenge, that idyllic glade wherein we stumble upon the holes for these sweet descents, is now known as

The Weekly Challenge – Perl and Raku

It is the creation of the lovely Mohammad Sajid Anwar and a veritable swarm of contributors from all over the world, who gather, as might be expected, weekly online to solve puzzles. Everyone is encouraged to visit, learn and contribute at

https://theweeklychallenge.org